Blame


1 941e1713 2006-02-15 devnull /*
2 941e1713 2006-02-15 devnull * Locking here is not quite right.
3 941e1713 2006-02-15 devnull * Calling qlock(&z->lk) can block the proc,
4 941e1713 2006-02-15 devnull * and when it comes back, boxes and msgs might have been freed
5 941e1713 2006-02-15 devnull * (if the refresh proc was holding the lock and in the middle of a
6 941e1713 2006-02-15 devnull * redial). I've tried to be careful about not assuming boxes continue
7 941e1713 2006-02-15 devnull * to exist across imap commands, but maybe this isn't really tenable.
8 941e1713 2006-02-15 devnull * Maybe instead we should ref count the boxes and messages.
9 941e1713 2006-02-15 devnull */
10 941e1713 2006-02-15 devnull
11 941e1713 2006-02-15 devnull #include "a.h"
12 941e1713 2006-02-15 devnull #include <libsec.h>
13 941e1713 2006-02-15 devnull
14 941e1713 2006-02-15 devnull struct Imap
15 941e1713 2006-02-15 devnull {
16 941e1713 2006-02-15 devnull int connected;
17 941e1713 2006-02-15 devnull int autoreconnect;
18 941e1713 2006-02-15 devnull int ticks; /* until boom! */
19 941e1713 2006-02-15 devnull char* server;
20 941e1713 2006-02-15 devnull int mode;
21 941e1713 2006-02-15 devnull int fd;
22 941e1713 2006-02-15 devnull Biobuf b;
23 941e1713 2006-02-15 devnull Ioproc* io;
24 941e1713 2006-02-15 devnull QLock lk;
25 941e1713 2006-02-15 devnull QLock rlk;
26 941e1713 2006-02-15 devnull Rendez r;
27 941e1713 2006-02-15 devnull
28 941e1713 2006-02-15 devnull Box* inbox;
29 941e1713 2006-02-15 devnull Box* box;
30 941e1713 2006-02-15 devnull Box* nextbox;
31 941e1713 2006-02-15 devnull
32 941e1713 2006-02-15 devnull /* SEARCH results */
33 941e1713 2006-02-15 devnull uint *uid;
34 941e1713 2006-02-15 devnull uint nuid;
35 941e1713 2006-02-15 devnull };
36 941e1713 2006-02-15 devnull
37 941e1713 2006-02-15 devnull static struct {
38 941e1713 2006-02-15 devnull char *name;
39 941e1713 2006-02-15 devnull int flag;
40 941e1713 2006-02-15 devnull } flagstab[] =
41 941e1713 2006-02-15 devnull {
42 941e1713 2006-02-15 devnull "Junk", FlagJunk,
43 941e1713 2006-02-15 devnull "NonJunk", FlagNonJunk,
44 941e1713 2006-02-15 devnull "\\Answered", FlagReplied,
45 941e1713 2006-02-15 devnull "\\Flagged", FlagFlagged,
46 941e1713 2006-02-15 devnull "\\Deleted", FlagDeleted,
47 941e1713 2006-02-15 devnull "\\Draft", FlagDraft,
48 abb0a67b 2006-02-23 devnull "\\Recent", FlagRecent,
49 941e1713 2006-02-15 devnull "\\Seen", FlagSeen,
50 941e1713 2006-02-15 devnull "\\NoInferiors", FlagNoInferiors,
51 941e1713 2006-02-15 devnull "\\NoSelect", FlagNoSelect,
52 941e1713 2006-02-15 devnull "\\Marked", FlagMarked,
53 cbeb0b26 2006-04-01 devnull "\\UnMarked", FlagUnMarked
54 941e1713 2006-02-15 devnull };
55 941e1713 2006-02-15 devnull
56 941e1713 2006-02-15 devnull int chattyimap;
57 941e1713 2006-02-15 devnull
58 b99162de 2006-03-03 devnull static char *tag = "#";
59 941e1713 2006-02-15 devnull
60 941e1713 2006-02-15 devnull static void checkbox(Imap*, Box*);
61 941e1713 2006-02-15 devnull static char* copyaddrs(Sx*);
62 941e1713 2006-02-15 devnull static void freeup(UserPasswd*);
63 941e1713 2006-02-15 devnull static int getbox(Imap*, Box*);
64 941e1713 2006-02-15 devnull static int getboxes(Imap*);
65 941e1713 2006-02-15 devnull static char* gsub(char*, char*, char*);
66 941e1713 2006-02-15 devnull static int imapcmd(Imap*, Box*, char*, ...);
67 941e1713 2006-02-15 devnull static Sx* imapcmdsx(Imap*, Box*, char*, ...);
68 941e1713 2006-02-15 devnull static Sx* imapcmdsx0(Imap*, char*, ...);
69 941e1713 2006-02-15 devnull static Sx* imapvcmdsx(Imap*, Box*, char*, va_list);
70 941e1713 2006-02-15 devnull static Sx* imapvcmdsx0(Imap*, char*, va_list);
71 941e1713 2006-02-15 devnull static int imapdial(char*, int);
72 941e1713 2006-02-15 devnull static int imaplogin(Imap*);
73 941e1713 2006-02-15 devnull static int imapquote(Fmt*);
74 941e1713 2006-02-15 devnull static int imapreconnect(Imap*);
75 941e1713 2006-02-15 devnull static void imaprefreshthread(void*);
76 941e1713 2006-02-15 devnull static void imaptimerproc(void*);
77 941e1713 2006-02-15 devnull static Sx* imapwaitsx(Imap*);
78 941e1713 2006-02-15 devnull static int isatom(Sx *v, char *name);
79 941e1713 2006-02-15 devnull static int islist(Sx *v);
80 941e1713 2006-02-15 devnull static int isnil(Sx *v);
81 941e1713 2006-02-15 devnull static int isnumber(Sx *sx);
82 941e1713 2006-02-15 devnull static int isstring(Sx *sx);
83 941e1713 2006-02-15 devnull static int ioimapdial(Ioproc*, char*, int);
84 941e1713 2006-02-15 devnull static char* nstring(Sx*);
85 941e1713 2006-02-15 devnull static void unexpected(Imap*, Sx*);
86 941e1713 2006-02-15 devnull static Sx* zBrdsx(Imap*);
87 941e1713 2006-02-15 devnull
88 941e1713 2006-02-15 devnull /*
89 941e1713 2006-02-15 devnull * Imap connection maintenance and login.
90 941e1713 2006-02-15 devnull */
91 941e1713 2006-02-15 devnull
92 941e1713 2006-02-15 devnull Imap*
93 941e1713 2006-02-15 devnull imapconnect(char *server, int mode)
94 941e1713 2006-02-15 devnull {
95 941e1713 2006-02-15 devnull Imap *z;
96 941e1713 2006-02-15 devnull
97 941e1713 2006-02-15 devnull fmtinstall('H', encodefmt);
98 941e1713 2006-02-15 devnull fmtinstall('Z', imapquote);
99 941e1713 2006-02-15 devnull
100 941e1713 2006-02-15 devnull z = emalloc(sizeof *z);
101 941e1713 2006-02-15 devnull z->server = estrdup(server);
102 941e1713 2006-02-15 devnull z->mode = mode;
103 941e1713 2006-02-15 devnull z->fd = -1;
104 941e1713 2006-02-15 devnull z->autoreconnect = 0;
105 941e1713 2006-02-15 devnull z->io = ioproc();
106 941e1713 2006-02-15 devnull
107 941e1713 2006-02-15 devnull qlock(&z->lk);
108 941e1713 2006-02-15 devnull if(imapreconnect(z) < 0){
109 941e1713 2006-02-15 devnull free(z);
110 941e1713 2006-02-15 devnull return nil;
111 941e1713 2006-02-15 devnull }
112 941e1713 2006-02-15 devnull
113 941e1713 2006-02-15 devnull z->r.l = &z->rlk;
114 941e1713 2006-02-15 devnull z->autoreconnect = 1;
115 941e1713 2006-02-15 devnull qunlock(&z->lk);
116 941e1713 2006-02-15 devnull
117 941e1713 2006-02-15 devnull proccreate(imaptimerproc, z, STACK);
118 941e1713 2006-02-15 devnull mailthread(imaprefreshthread, z);
119 941e1713 2006-02-15 devnull
120 941e1713 2006-02-15 devnull return z;
121 941e1713 2006-02-15 devnull }
122 941e1713 2006-02-15 devnull
123 941e1713 2006-02-15 devnull void
124 941e1713 2006-02-15 devnull imaphangup(Imap *z, int ticks)
125 941e1713 2006-02-15 devnull {
126 941e1713 2006-02-15 devnull z->ticks = ticks;
127 941e1713 2006-02-15 devnull if(ticks == 0){
128 941e1713 2006-02-15 devnull close(z->fd);
129 941e1713 2006-02-15 devnull z->fd = -1;
130 941e1713 2006-02-15 devnull }
131 941e1713 2006-02-15 devnull }
132 941e1713 2006-02-15 devnull
133 941e1713 2006-02-15 devnull static int
134 941e1713 2006-02-15 devnull imapreconnect(Imap *z)
135 941e1713 2006-02-15 devnull {
136 941e1713 2006-02-15 devnull Sx *sx;
137 941e1713 2006-02-15 devnull
138 941e1713 2006-02-15 devnull z->autoreconnect = 0;
139 941e1713 2006-02-15 devnull z->box = nil;
140 941e1713 2006-02-15 devnull z->inbox = nil;
141 941e1713 2006-02-15 devnull
142 941e1713 2006-02-15 devnull if(z->fd >= 0){
143 941e1713 2006-02-15 devnull close(z->fd);
144 941e1713 2006-02-15 devnull z->fd = -1;
145 941e1713 2006-02-15 devnull }
146 941e1713 2006-02-15 devnull
147 941e1713 2006-02-15 devnull if(chattyimap)
148 941e1713 2006-02-15 devnull fprint(2, "dial %s...\n", z->server);
149 941e1713 2006-02-15 devnull if((z->fd = ioimapdial(z->io, z->server, z->mode)) < 0)
150 941e1713 2006-02-15 devnull return -1;
151 941e1713 2006-02-15 devnull z->connected = 1;
152 941e1713 2006-02-15 devnull Binit(&z->b, z->fd, OREAD);
153 941e1713 2006-02-15 devnull if((sx = zBrdsx(z)) == nil){
154 941e1713 2006-02-15 devnull werrstr("no greeting");
155 941e1713 2006-02-15 devnull goto err;
156 941e1713 2006-02-15 devnull }
157 941e1713 2006-02-15 devnull if(chattyimap)
158 941e1713 2006-02-15 devnull fprint(2, "<I %#$\n", sx);
159 941e1713 2006-02-15 devnull if(sx->nsx >= 2 && isatom(sx->sx[0], "*") && isatom(sx->sx[1], "PREAUTH")){
160 941e1713 2006-02-15 devnull freesx(sx);
161 941e1713 2006-02-15 devnull goto preauth;
162 941e1713 2006-02-15 devnull }
163 941e1713 2006-02-15 devnull if(!oksx(sx)){
164 941e1713 2006-02-15 devnull werrstr("bad greeting - %#$", sx);
165 941e1713 2006-02-15 devnull goto err;
166 941e1713 2006-02-15 devnull }
167 941e1713 2006-02-15 devnull freesx(sx);
168 941e1713 2006-02-15 devnull sx = nil;
169 941e1713 2006-02-15 devnull if(imaplogin(z) < 0)
170 941e1713 2006-02-15 devnull goto err;
171 941e1713 2006-02-15 devnull preauth:
172 941e1713 2006-02-15 devnull if(getboxes(z) < 0 || getbox(z, z->inbox) < 0)
173 941e1713 2006-02-15 devnull goto err;
174 941e1713 2006-02-15 devnull z->autoreconnect = 1;
175 941e1713 2006-02-15 devnull return 0;
176 941e1713 2006-02-15 devnull
177 941e1713 2006-02-15 devnull err:
178 941e1713 2006-02-15 devnull if(z->fd >= 0){
179 941e1713 2006-02-15 devnull close(z->fd);
180 941e1713 2006-02-15 devnull z->fd = -1;
181 941e1713 2006-02-15 devnull }
182 941e1713 2006-02-15 devnull if(sx)
183 941e1713 2006-02-15 devnull freesx(sx);
184 941e1713 2006-02-15 devnull z->autoreconnect = 1;
185 941e1713 2006-02-15 devnull z->connected = 0;
186 941e1713 2006-02-15 devnull return -1;
187 941e1713 2006-02-15 devnull }
188 941e1713 2006-02-15 devnull
189 941e1713 2006-02-15 devnull static int
190 941e1713 2006-02-15 devnull imaplogin(Imap *z)
191 941e1713 2006-02-15 devnull {
192 941e1713 2006-02-15 devnull Sx *sx;
193 941e1713 2006-02-15 devnull UserPasswd *up;
194 941e1713 2006-02-15 devnull
195 941e1713 2006-02-15 devnull if((up = auth_getuserpasswd(auth_getkey, "proto=pass role=client service=imap server=%q", z->server)) == nil){
196 941e1713 2006-02-15 devnull werrstr("getuserpasswd - %r");
197 941e1713 2006-02-15 devnull return -1;
198 941e1713 2006-02-15 devnull }
199 941e1713 2006-02-15 devnull
200 941e1713 2006-02-15 devnull sx = imapcmdsx(z, nil, "LOGIN %Z %Z", up->user, up->passwd);
201 941e1713 2006-02-15 devnull freeup(up);
202 941e1713 2006-02-15 devnull if(sx == nil)
203 941e1713 2006-02-15 devnull return -1;
204 941e1713 2006-02-15 devnull if(!oksx(sx)){
205 941e1713 2006-02-15 devnull freesx(sx);
206 941e1713 2006-02-15 devnull werrstr("login rejected - %#$", sx);
207 941e1713 2006-02-15 devnull return -1;
208 941e1713 2006-02-15 devnull }
209 941e1713 2006-02-15 devnull return 0;
210 941e1713 2006-02-15 devnull }
211 941e1713 2006-02-15 devnull
212 941e1713 2006-02-15 devnull static int
213 941e1713 2006-02-15 devnull getboxes(Imap *z)
214 941e1713 2006-02-15 devnull {
215 941e1713 2006-02-15 devnull int i;
216 941e1713 2006-02-15 devnull Box **r, **w, **e;
217 941e1713 2006-02-15 devnull
218 941e1713 2006-02-15 devnull for(i=0; i<nboxes; i++){
219 941e1713 2006-02-15 devnull boxes[i]->mark = 1;
220 941e1713 2006-02-15 devnull boxes[i]->exists = 0;
221 941e1713 2006-02-15 devnull boxes[i]->maxseen = 0;
222 941e1713 2006-02-15 devnull }
223 941e1713 2006-02-15 devnull if(imapcmd(z, nil, "LIST %Z *", "") < 0)
224 941e1713 2006-02-15 devnull return -1;
225 941e1713 2006-02-15 devnull if(z->nextbox && z->nextbox->mark)
226 941e1713 2006-02-15 devnull z->nextbox = nil;
227 941e1713 2006-02-15 devnull for(r=boxes, w=boxes, e=boxes+nboxes; r<e; r++){
228 941e1713 2006-02-15 devnull if((*r)->mark)
229 941e1713 2006-02-15 devnull {fprint(2, "*** free box %s %s\n", (*r)->name, (*r)->imapname);
230 941e1713 2006-02-15 devnull boxfree(*r);
231 941e1713 2006-02-15 devnull }
232 941e1713 2006-02-15 devnull else
233 941e1713 2006-02-15 devnull *w++ = *r;
234 941e1713 2006-02-15 devnull }
235 941e1713 2006-02-15 devnull nboxes = w - boxes;
236 941e1713 2006-02-15 devnull return 0;
237 941e1713 2006-02-15 devnull }
238 941e1713 2006-02-15 devnull
239 941e1713 2006-02-15 devnull static int
240 941e1713 2006-02-15 devnull getbox(Imap *z, Box *b)
241 941e1713 2006-02-15 devnull {
242 941e1713 2006-02-15 devnull int i;
243 941e1713 2006-02-15 devnull Msg **r, **w, **e;
244 941e1713 2006-02-15 devnull
245 941e1713 2006-02-15 devnull if(b == nil)
246 941e1713 2006-02-15 devnull return 0;
247 941e1713 2006-02-15 devnull
248 941e1713 2006-02-15 devnull for(i=0; i<b->nmsg; i++)
249 941e1713 2006-02-15 devnull b->msg[i]->imapid = 0;
250 941e1713 2006-02-15 devnull if(imapcmd(z, b, "UID FETCH 1:* FLAGS") < 0)
251 941e1713 2006-02-15 devnull return -1;
252 941e1713 2006-02-15 devnull for(r=b->msg, w=b->msg, e=b->msg+b->nmsg; r<e; r++){
253 941e1713 2006-02-15 devnull if((*r)->imapid == 0)
254 941e1713 2006-02-15 devnull msgfree(*r);
255 941e1713 2006-02-15 devnull else{
256 941e1713 2006-02-15 devnull (*r)->ix = w-b->msg;
257 941e1713 2006-02-15 devnull *w++ = *r;
258 941e1713 2006-02-15 devnull }
259 941e1713 2006-02-15 devnull }
260 941e1713 2006-02-15 devnull b->nmsg = w - b->msg;
261 941e1713 2006-02-15 devnull b->imapinit = 1;
262 941e1713 2006-02-15 devnull checkbox(z, b);
263 941e1713 2006-02-15 devnull return 0;
264 941e1713 2006-02-15 devnull }
265 941e1713 2006-02-15 devnull
266 941e1713 2006-02-15 devnull static void
267 941e1713 2006-02-15 devnull freeup(UserPasswd *up)
268 941e1713 2006-02-15 devnull {
269 941e1713 2006-02-15 devnull memset(up->user, 0, strlen(up->user));
270 941e1713 2006-02-15 devnull memset(up->passwd, 0, strlen(up->passwd));
271 941e1713 2006-02-15 devnull free(up);
272 941e1713 2006-02-15 devnull }
273 941e1713 2006-02-15 devnull
274 941e1713 2006-02-15 devnull static void
275 941e1713 2006-02-15 devnull imaptimerproc(void *v)
276 941e1713 2006-02-15 devnull {
277 941e1713 2006-02-15 devnull Imap *z;
278 941e1713 2006-02-15 devnull
279 941e1713 2006-02-15 devnull z = v;
280 941e1713 2006-02-15 devnull for(;;){
281 941e1713 2006-02-15 devnull sleep(60*1000);
282 941e1713 2006-02-15 devnull qlock(z->r.l);
283 941e1713 2006-02-15 devnull rwakeup(&z->r);
284 941e1713 2006-02-15 devnull qunlock(z->r.l);
285 941e1713 2006-02-15 devnull }
286 941e1713 2006-02-15 devnull }
287 941e1713 2006-02-15 devnull
288 941e1713 2006-02-15 devnull static void
289 941e1713 2006-02-15 devnull checkbox(Imap *z, Box *b)
290 941e1713 2006-02-15 devnull {
291 941e1713 2006-02-15 devnull if(imapcmd(z, b, "NOOP") >= 0){
292 941e1713 2006-02-15 devnull if(!b->imapinit)
293 941e1713 2006-02-15 devnull getbox(z, b);
294 941e1713 2006-02-15 devnull if(!b->imapinit)
295 941e1713 2006-02-15 devnull return;
296 941e1713 2006-02-15 devnull if(b==z->box && b->exists > b->maxseen){
297 941e1713 2006-02-15 devnull imapcmd(z, b, "UID FETCH %d:* FULL",
298 941e1713 2006-02-15 devnull b->uidnext);
299 941e1713 2006-02-15 devnull }
300 941e1713 2006-02-15 devnull }
301 941e1713 2006-02-15 devnull }
302 941e1713 2006-02-15 devnull
303 941e1713 2006-02-15 devnull static void
304 941e1713 2006-02-15 devnull imaprefreshthread(void *v)
305 941e1713 2006-02-15 devnull {
306 941e1713 2006-02-15 devnull Imap *z;
307 941e1713 2006-02-15 devnull
308 941e1713 2006-02-15 devnull z = v;
309 941e1713 2006-02-15 devnull for(;;){
310 941e1713 2006-02-15 devnull qlock(z->r.l);
311 941e1713 2006-02-15 devnull rsleep(&z->r);
312 941e1713 2006-02-15 devnull qunlock(z->r.l);
313 941e1713 2006-02-15 devnull
314 941e1713 2006-02-15 devnull qlock(&z->lk);
315 941e1713 2006-02-15 devnull if(z->inbox)
316 941e1713 2006-02-15 devnull checkbox(z, z->inbox);
317 941e1713 2006-02-15 devnull qunlock(&z->lk);
318 941e1713 2006-02-15 devnull }
319 941e1713 2006-02-15 devnull }
320 941e1713 2006-02-15 devnull
321 941e1713 2006-02-15 devnull /*
322 941e1713 2006-02-15 devnull * Run a single command and return the Sx. Does NOT redial.
323 941e1713 2006-02-15 devnull */
324 941e1713 2006-02-15 devnull static Sx*
325 941e1713 2006-02-15 devnull imapvcmdsx0(Imap *z, char *fmt, va_list arg)
326 941e1713 2006-02-15 devnull {
327 941e1713 2006-02-15 devnull char *s;
328 941e1713 2006-02-15 devnull Fmt f;
329 941e1713 2006-02-15 devnull int prefix, len;
330 941e1713 2006-02-15 devnull Sx *sx;
331 941e1713 2006-02-15 devnull
332 941e1713 2006-02-15 devnull if(canqlock(&z->lk))
333 941e1713 2006-02-15 devnull abort();
334 941e1713 2006-02-15 devnull
335 941e1713 2006-02-15 devnull if(z->fd < 0 || !z->connected)
336 941e1713 2006-02-15 devnull return nil;
337 941e1713 2006-02-15 devnull
338 941e1713 2006-02-15 devnull prefix = strlen(tag)+1;
339 941e1713 2006-02-15 devnull fmtstrinit(&f);
340 941e1713 2006-02-15 devnull fmtprint(&f, "%s ", tag);
341 941e1713 2006-02-15 devnull fmtvprint(&f, fmt, arg);
342 941e1713 2006-02-15 devnull fmtprint(&f, "\r\n");
343 941e1713 2006-02-15 devnull s = fmtstrflush(&f);
344 941e1713 2006-02-15 devnull len = strlen(s);
345 941e1713 2006-02-15 devnull s[len-2] = 0;
346 941e1713 2006-02-15 devnull if(chattyimap)
347 941e1713 2006-02-15 devnull fprint(2, "I> %s\n", s);
348 941e1713 2006-02-15 devnull s[len-2] = '\r';
349 941e1713 2006-02-15 devnull if(iowrite(z->io, z->fd, s, len) < 0){
350 941e1713 2006-02-15 devnull z->connected = 0;
351 941e1713 2006-02-15 devnull free(s);
352 941e1713 2006-02-15 devnull return nil;
353 941e1713 2006-02-15 devnull }
354 941e1713 2006-02-15 devnull sx = imapwaitsx(z);
355 941e1713 2006-02-15 devnull free(s);
356 941e1713 2006-02-15 devnull return sx;
357 941e1713 2006-02-15 devnull }
358 941e1713 2006-02-15 devnull
359 941e1713 2006-02-15 devnull static Sx*
360 941e1713 2006-02-15 devnull imapcmdsx0(Imap *z, char *fmt, ...)
361 941e1713 2006-02-15 devnull {
362 941e1713 2006-02-15 devnull va_list arg;
363 941e1713 2006-02-15 devnull Sx *sx;
364 941e1713 2006-02-15 devnull
365 941e1713 2006-02-15 devnull va_start(arg, fmt);
366 941e1713 2006-02-15 devnull sx = imapvcmdsx0(z, fmt, arg);
367 941e1713 2006-02-15 devnull va_end(arg);
368 941e1713 2006-02-15 devnull return sx;
369 941e1713 2006-02-15 devnull }
370 941e1713 2006-02-15 devnull
371 941e1713 2006-02-15 devnull /*
372 941e1713 2006-02-15 devnull * Run a single command on box b. Does redial.
373 941e1713 2006-02-15 devnull */
374 941e1713 2006-02-15 devnull static Sx*
375 941e1713 2006-02-15 devnull imapvcmdsx(Imap *z, Box *b, char *fmt, va_list arg)
376 941e1713 2006-02-15 devnull {
377 941e1713 2006-02-15 devnull int tries;
378 941e1713 2006-02-15 devnull Sx *sx;
379 941e1713 2006-02-15 devnull
380 941e1713 2006-02-15 devnull tries = 0;
381 941e1713 2006-02-15 devnull z->nextbox = b;
382 941e1713 2006-02-15 devnull
383 941e1713 2006-02-15 devnull if(z->fd < 0 || !z->connected){
384 941e1713 2006-02-15 devnull reconnect:
385 941e1713 2006-02-15 devnull if(!z->autoreconnect)
386 941e1713 2006-02-15 devnull return nil;
387 941e1713 2006-02-15 devnull if(imapreconnect(z) < 0)
388 941e1713 2006-02-15 devnull return nil;
389 941e1713 2006-02-15 devnull if(b && z->nextbox == nil) /* box disappeared on reconnect */
390 941e1713 2006-02-15 devnull return nil;
391 941e1713 2006-02-15 devnull }
392 941e1713 2006-02-15 devnull
393 941e1713 2006-02-15 devnull if(b && b != z->box){
394 941e1713 2006-02-15 devnull if(z->box)
395 941e1713 2006-02-15 devnull z->box->imapinit = 0;
396 941e1713 2006-02-15 devnull z->box = b;
397 941e1713 2006-02-15 devnull if((sx=imapcmdsx0(z, "SELECT %Z", b->imapname)) == nil){
398 941e1713 2006-02-15 devnull z->box = nil;
399 941e1713 2006-02-15 devnull if(tries++ == 0 && (z->fd < 0 || !z->connected))
400 941e1713 2006-02-15 devnull goto reconnect;
401 941e1713 2006-02-15 devnull return nil;
402 941e1713 2006-02-15 devnull }
403 941e1713 2006-02-15 devnull freesx(sx);
404 941e1713 2006-02-15 devnull }
405 941e1713 2006-02-15 devnull
406 941e1713 2006-02-15 devnull if((sx=imapvcmdsx0(z, fmt, arg)) == nil){
407 941e1713 2006-02-15 devnull if(tries++ == 0 && (z->fd < 0 || !z->connected))
408 941e1713 2006-02-15 devnull goto reconnect;
409 941e1713 2006-02-15 devnull return nil;
410 941e1713 2006-02-15 devnull }
411 941e1713 2006-02-15 devnull return sx;
412 941e1713 2006-02-15 devnull }
413 941e1713 2006-02-15 devnull
414 941e1713 2006-02-15 devnull static int
415 941e1713 2006-02-15 devnull imapcmd(Imap *z, Box *b, char *fmt, ...)
416 941e1713 2006-02-15 devnull {
417 941e1713 2006-02-15 devnull Sx *sx;
418 941e1713 2006-02-15 devnull va_list arg;
419 941e1713 2006-02-15 devnull
420 941e1713 2006-02-15 devnull va_start(arg, fmt);
421 941e1713 2006-02-15 devnull sx = imapvcmdsx(z, b, fmt, arg);
422 941e1713 2006-02-15 devnull va_end(arg);
423 941e1713 2006-02-15 devnull if(sx == nil)
424 941e1713 2006-02-15 devnull return -1;
425 941e1713 2006-02-15 devnull if(sx->nsx < 2 || !isatom(sx->sx[1], "OK")){
426 941e1713 2006-02-15 devnull werrstr("%$", sx);
427 941e1713 2006-02-15 devnull freesx(sx);
428 941e1713 2006-02-15 devnull return -1;
429 941e1713 2006-02-15 devnull }
430 941e1713 2006-02-15 devnull freesx(sx);
431 941e1713 2006-02-15 devnull return 0;
432 941e1713 2006-02-15 devnull }
433 941e1713 2006-02-15 devnull
434 941e1713 2006-02-15 devnull static Sx*
435 941e1713 2006-02-15 devnull imapcmdsx(Imap *z, Box *b, char *fmt, ...)
436 941e1713 2006-02-15 devnull {
437 941e1713 2006-02-15 devnull Sx *sx;
438 941e1713 2006-02-15 devnull va_list arg;
439 941e1713 2006-02-15 devnull
440 941e1713 2006-02-15 devnull va_start(arg, fmt);
441 941e1713 2006-02-15 devnull sx = imapvcmdsx(z, b, fmt, arg);
442 941e1713 2006-02-15 devnull va_end(arg);
443 941e1713 2006-02-15 devnull return sx;
444 941e1713 2006-02-15 devnull }
445 941e1713 2006-02-15 devnull
446 941e1713 2006-02-15 devnull static Sx*
447 941e1713 2006-02-15 devnull imapwaitsx(Imap *z)
448 941e1713 2006-02-15 devnull {
449 941e1713 2006-02-15 devnull Sx *sx;
450 941e1713 2006-02-15 devnull
451 941e1713 2006-02-15 devnull while((sx = zBrdsx(z)) != nil){
452 941e1713 2006-02-15 devnull if(chattyimap)
453 941e1713 2006-02-15 devnull fprint(2, "<| %#$\n", sx);
454 941e1713 2006-02-15 devnull if(sx->nsx >= 1 && sx->sx[0]->type == SxAtom && cistrcmp(sx->sx[0]->data, tag) == 0)
455 941e1713 2006-02-15 devnull return sx;
456 941e1713 2006-02-15 devnull if(sx->nsx >= 1 && sx->sx[0]->type == SxAtom && strcmp(sx->sx[0]->data, "*") == 0)
457 941e1713 2006-02-15 devnull unexpected(z, sx);
458 941e1713 2006-02-15 devnull if(sx->type == SxList && sx->nsx == 0){
459 941e1713 2006-02-15 devnull freesx(sx);
460 941e1713 2006-02-15 devnull break;
461 941e1713 2006-02-15 devnull }
462 941e1713 2006-02-15 devnull freesx(sx);
463 941e1713 2006-02-15 devnull }
464 941e1713 2006-02-15 devnull z->connected = 0;
465 941e1713 2006-02-15 devnull return nil;
466 941e1713 2006-02-15 devnull }
467 941e1713 2006-02-15 devnull
468 941e1713 2006-02-15 devnull /*
469 941e1713 2006-02-15 devnull * Imap interface to mail file system.
470 941e1713 2006-02-15 devnull */
471 941e1713 2006-02-15 devnull
472 941e1713 2006-02-15 devnull static void
473 941e1713 2006-02-15 devnull _bodyname(char *buf, char *ebuf, Part *p, char *extra)
474 941e1713 2006-02-15 devnull {
475 941e1713 2006-02-15 devnull if(buf >= ebuf){
476 941e1713 2006-02-15 devnull fprint(2, "***** BUFFER TOO SMALL\n");
477 941e1713 2006-02-15 devnull return;
478 941e1713 2006-02-15 devnull }
479 941e1713 2006-02-15 devnull *buf = 0;
480 941e1713 2006-02-15 devnull if(p->parent){
481 941e1713 2006-02-15 devnull _bodyname(buf, ebuf, p->parent, "");
482 941e1713 2006-02-15 devnull buf += strlen(buf);
483 941e1713 2006-02-15 devnull seprint(buf, ebuf, ".%d", p->pix+1);
484 941e1713 2006-02-15 devnull }
485 941e1713 2006-02-15 devnull buf += strlen(buf);
486 941e1713 2006-02-15 devnull seprint(buf, ebuf, "%s", extra);
487 941e1713 2006-02-15 devnull }
488 941e1713 2006-02-15 devnull
489 941e1713 2006-02-15 devnull static char*
490 941e1713 2006-02-15 devnull bodyname(Part *p, char *extra)
491 941e1713 2006-02-15 devnull {
492 941e1713 2006-02-15 devnull static char buf[256];
493 941e1713 2006-02-15 devnull memset(buf, 0, sizeof buf); /* can't see why this is necessary, but it is */
494 941e1713 2006-02-15 devnull _bodyname(buf, buf+sizeof buf, p, extra);
495 941e1713 2006-02-15 devnull return buf+1; /* buf[0] == '.' */
496 941e1713 2006-02-15 devnull }
497 941e1713 2006-02-15 devnull
498 941e1713 2006-02-15 devnull static void
499 941e1713 2006-02-15 devnull fetch1(Imap *z, Part *p, char *s)
500 941e1713 2006-02-15 devnull {
501 941e1713 2006-02-15 devnull qlock(&z->lk);
502 941e1713 2006-02-15 devnull imapcmd(z, p->msg->box, "UID FETCH %d BODY[%s]",
503 941e1713 2006-02-15 devnull p->msg->imapuid, bodyname(p, s));
504 941e1713 2006-02-15 devnull qunlock(&z->lk);
505 941e1713 2006-02-15 devnull }
506 941e1713 2006-02-15 devnull
507 941e1713 2006-02-15 devnull void
508 941e1713 2006-02-15 devnull imapfetchrawheader(Imap *z, Part *p)
509 941e1713 2006-02-15 devnull {
510 941e1713 2006-02-15 devnull fetch1(z, p, ".HEADER");
511 941e1713 2006-02-15 devnull }
512 941e1713 2006-02-15 devnull
513 941e1713 2006-02-15 devnull void
514 941e1713 2006-02-15 devnull imapfetchrawmime(Imap *z, Part *p)
515 941e1713 2006-02-15 devnull {
516 941e1713 2006-02-15 devnull fetch1(z, p, ".MIME");
517 941e1713 2006-02-15 devnull }
518 941e1713 2006-02-15 devnull
519 941e1713 2006-02-15 devnull void
520 941e1713 2006-02-15 devnull imapfetchrawbody(Imap *z, Part *p)
521 941e1713 2006-02-15 devnull {
522 941e1713 2006-02-15 devnull fetch1(z, p, ".TEXT");
523 941e1713 2006-02-15 devnull }
524 941e1713 2006-02-15 devnull
525 941e1713 2006-02-15 devnull void
526 941e1713 2006-02-15 devnull imapfetchraw(Imap *z, Part *p)
527 941e1713 2006-02-15 devnull {
528 941e1713 2006-02-15 devnull fetch1(z, p, "");
529 941e1713 2006-02-15 devnull }
530 941e1713 2006-02-15 devnull
531 941e1713 2006-02-15 devnull static int
532 941e1713 2006-02-15 devnull imaplistcmd(Imap *z, Box *box, char *before, Msg **m, uint nm, char *after)
533 941e1713 2006-02-15 devnull {
534 941e1713 2006-02-15 devnull int i, r;
535 941e1713 2006-02-15 devnull char *cmd;
536 941e1713 2006-02-15 devnull Fmt fmt;
537 941e1713 2006-02-15 devnull
538 941e1713 2006-02-15 devnull if(nm == 0)
539 941e1713 2006-02-15 devnull return 0;
540 941e1713 2006-02-15 devnull
541 941e1713 2006-02-15 devnull fmtstrinit(&fmt);
542 941e1713 2006-02-15 devnull fmtprint(&fmt, "%s ", before);
543 941e1713 2006-02-15 devnull for(i=0; i<nm; i++){
544 941e1713 2006-02-15 devnull if(i > 0)
545 941e1713 2006-02-15 devnull fmtrune(&fmt, ',');
546 941e1713 2006-02-15 devnull fmtprint(&fmt, "%ud", m[i]->imapuid);
547 941e1713 2006-02-15 devnull }
548 941e1713 2006-02-15 devnull fmtprint(&fmt, " %s", after);
549 941e1713 2006-02-15 devnull cmd = fmtstrflush(&fmt);
550 941e1713 2006-02-15 devnull
551 941e1713 2006-02-15 devnull r = 0;
552 941e1713 2006-02-15 devnull if(imapcmd(z, box, "%s", cmd) < 0)
553 941e1713 2006-02-15 devnull r = -1;
554 941e1713 2006-02-15 devnull free(cmd);
555 941e1713 2006-02-15 devnull return r;
556 941e1713 2006-02-15 devnull }
557 941e1713 2006-02-15 devnull
558 941e1713 2006-02-15 devnull int
559 941e1713 2006-02-15 devnull imapcopylist(Imap *z, char *nbox, Msg **m, uint nm)
560 941e1713 2006-02-15 devnull {
561 941e1713 2006-02-15 devnull int rv;
562 941e1713 2006-02-15 devnull char *name;
563 941e1713 2006-02-15 devnull
564 941e1713 2006-02-15 devnull if(nm == 0)
565 941e1713 2006-02-15 devnull return 0;
566 941e1713 2006-02-15 devnull
567 941e1713 2006-02-15 devnull qlock(&z->lk);
568 941e1713 2006-02-15 devnull name = esmprint("%Z", nbox);
569 941e1713 2006-02-15 devnull rv = imaplistcmd(z, m[0]->box, "UID COPY", m, nm, name);
570 941e1713 2006-02-15 devnull free(name);
571 941e1713 2006-02-15 devnull qunlock(&z->lk);
572 941e1713 2006-02-15 devnull return rv;
573 941e1713 2006-02-15 devnull }
574 941e1713 2006-02-15 devnull
575 941e1713 2006-02-15 devnull int
576 941e1713 2006-02-15 devnull imapremovelist(Imap *z, Msg **m, uint nm)
577 941e1713 2006-02-15 devnull {
578 941e1713 2006-02-15 devnull int rv;
579 941e1713 2006-02-15 devnull
580 941e1713 2006-02-15 devnull if(nm == 0)
581 941e1713 2006-02-15 devnull return 0;
582 941e1713 2006-02-15 devnull
583 941e1713 2006-02-15 devnull qlock(&z->lk);
584 941e1713 2006-02-15 devnull rv = imaplistcmd(z, m[0]->box, "UID STORE", m, nm, "+FLAGS.SILENT (\\Deleted)");
585 941e1713 2006-02-15 devnull /* careful - box might be gone; use z->box instead */
586 941e1713 2006-02-15 devnull if(rv == 0 && z->box)
587 941e1713 2006-02-15 devnull rv = imapcmd(z, z->box, "EXPUNGE");
588 941e1713 2006-02-15 devnull qunlock(&z->lk);
589 941e1713 2006-02-15 devnull return rv;
590 941e1713 2006-02-15 devnull }
591 941e1713 2006-02-15 devnull
592 941e1713 2006-02-15 devnull int
593 941e1713 2006-02-15 devnull imapflaglist(Imap *z, int op, int flag, Msg **m, uint nm)
594 941e1713 2006-02-15 devnull {
595 941e1713 2006-02-15 devnull char *mod, *s, *sep;
596 941e1713 2006-02-15 devnull int i, rv;
597 941e1713 2006-02-15 devnull Fmt fmt;
598 941e1713 2006-02-15 devnull
599 941e1713 2006-02-15 devnull if(op > 0)
600 941e1713 2006-02-15 devnull mod = "+";
601 941e1713 2006-02-15 devnull else if(op == 0)
602 941e1713 2006-02-15 devnull mod = "";
603 941e1713 2006-02-15 devnull else
604 941e1713 2006-02-15 devnull mod = "-";
605 941e1713 2006-02-15 devnull
606 941e1713 2006-02-15 devnull fmtstrinit(&fmt);
607 941e1713 2006-02-15 devnull fmtprint(&fmt, "%sFLAGS (", mod);
608 941e1713 2006-02-15 devnull sep = "";
609 941e1713 2006-02-15 devnull for(i=0; i<nelem(flagstab); i++){
610 941e1713 2006-02-15 devnull if(flagstab[i].flag & flag){
611 941e1713 2006-02-15 devnull fmtprint(&fmt, "%s%s", sep, flagstab[i].name);
612 941e1713 2006-02-15 devnull sep = " ";
613 941e1713 2006-02-15 devnull }
614 941e1713 2006-02-15 devnull }
615 941e1713 2006-02-15 devnull fmtprint(&fmt, ")");
616 941e1713 2006-02-15 devnull s = fmtstrflush(&fmt);
617 941e1713 2006-02-15 devnull
618 941e1713 2006-02-15 devnull qlock(&z->lk);
619 941e1713 2006-02-15 devnull rv = imaplistcmd(z, m[0]->box, "UID STORE", m, nm, s);
620 941e1713 2006-02-15 devnull qunlock(&z->lk);
621 941e1713 2006-02-15 devnull free(s);
622 941e1713 2006-02-15 devnull return rv;
623 941e1713 2006-02-15 devnull }
624 941e1713 2006-02-15 devnull
625 941e1713 2006-02-15 devnull int
626 941e1713 2006-02-15 devnull imapsearchbox(Imap *z, Box *b, char *search, Msg ***mm)
627 941e1713 2006-02-15 devnull {
628 941e1713 2006-02-15 devnull uint *uid;
629 941e1713 2006-02-15 devnull int i, nuid;
630 941e1713 2006-02-15 devnull Msg **m;
631 941e1713 2006-02-15 devnull int nm;
632 941e1713 2006-02-15 devnull
633 941e1713 2006-02-15 devnull qlock(&z->lk);
634 941e1713 2006-02-15 devnull if(imapcmd(z, b, "UID SEARCH CHARSET UTF-8 TEXT %Z", search) < 0){
635 941e1713 2006-02-15 devnull qunlock(&z->lk);
636 941e1713 2006-02-15 devnull return -1;
637 941e1713 2006-02-15 devnull }
638 941e1713 2006-02-15 devnull
639 941e1713 2006-02-15 devnull uid = z->uid;
640 941e1713 2006-02-15 devnull nuid = z->nuid;
641 941e1713 2006-02-15 devnull z->uid = nil;
642 941e1713 2006-02-15 devnull z->nuid = 0;
643 941e1713 2006-02-15 devnull qunlock(&z->lk);
644 941e1713 2006-02-15 devnull
645 941e1713 2006-02-15 devnull m = emalloc(nuid*sizeof m[0]);
646 941e1713 2006-02-15 devnull nm = 0;
647 941e1713 2006-02-15 devnull for(i=0; i<nuid; i++)
648 941e1713 2006-02-15 devnull if((m[nm] = msgbyimapuid(b, uid[i], 0)) != nil)
649 941e1713 2006-02-15 devnull nm++;
650 941e1713 2006-02-15 devnull *mm = m;
651 941e1713 2006-02-15 devnull free(uid);
652 941e1713 2006-02-15 devnull return nm;
653 941e1713 2006-02-15 devnull }
654 941e1713 2006-02-15 devnull
655 941e1713 2006-02-15 devnull void
656 941e1713 2006-02-15 devnull imapcheckbox(Imap *z, Box *b)
657 941e1713 2006-02-15 devnull {
658 941e1713 2006-02-15 devnull if(b == nil)
659 941e1713 2006-02-15 devnull return;
660 941e1713 2006-02-15 devnull qlock(&z->lk);
661 941e1713 2006-02-15 devnull checkbox(z, b);
662 941e1713 2006-02-15 devnull qunlock(&z->lk);
663 941e1713 2006-02-15 devnull }
664 941e1713 2006-02-15 devnull
665 941e1713 2006-02-15 devnull /*
666 941e1713 2006-02-15 devnull * Imap utility routines
667 941e1713 2006-02-15 devnull */
668 941e1713 2006-02-15 devnull static long
669 941e1713 2006-02-15 devnull _ioimapdial(va_list *arg)
670 941e1713 2006-02-15 devnull {
671 941e1713 2006-02-15 devnull char *server;
672 941e1713 2006-02-15 devnull int mode;
673 941e1713 2006-02-15 devnull
674 941e1713 2006-02-15 devnull server = va_arg(*arg, char*);
675 941e1713 2006-02-15 devnull mode = va_arg(*arg, int);
676 941e1713 2006-02-15 devnull return imapdial(server, mode);
677 941e1713 2006-02-15 devnull }
678 941e1713 2006-02-15 devnull static int
679 941e1713 2006-02-15 devnull ioimapdial(Ioproc *io, char *server, int mode)
680 941e1713 2006-02-15 devnull {
681 941e1713 2006-02-15 devnull return iocall(io, _ioimapdial, server, mode);
682 941e1713 2006-02-15 devnull }
683 941e1713 2006-02-15 devnull
684 941e1713 2006-02-15 devnull static long
685 941e1713 2006-02-15 devnull _ioBrdsx(va_list *arg)
686 941e1713 2006-02-15 devnull {
687 941e1713 2006-02-15 devnull Biobuf *b;
688 941e1713 2006-02-15 devnull Sx **sx;
689 941e1713 2006-02-15 devnull
690 941e1713 2006-02-15 devnull b = va_arg(*arg, Biobuf*);
691 941e1713 2006-02-15 devnull sx = va_arg(*arg, Sx**);
692 941e1713 2006-02-15 devnull *sx = Brdsx(b);
693 941e1713 2006-02-15 devnull if((*sx) && (*sx)->type == SxList && (*sx)->nsx == 0){
694 941e1713 2006-02-15 devnull freesx(*sx);
695 941e1713 2006-02-15 devnull *sx = nil;
696 941e1713 2006-02-15 devnull }
697 941e1713 2006-02-15 devnull return 0;
698 941e1713 2006-02-15 devnull }
699 941e1713 2006-02-15 devnull static Sx*
700 941e1713 2006-02-15 devnull ioBrdsx(Ioproc *io, Biobuf *b)
701 941e1713 2006-02-15 devnull {
702 941e1713 2006-02-15 devnull Sx *sx;
703 941e1713 2006-02-15 devnull
704 941e1713 2006-02-15 devnull iocall(io, _ioBrdsx, b, &sx);
705 941e1713 2006-02-15 devnull return sx;
706 941e1713 2006-02-15 devnull }
707 941e1713 2006-02-15 devnull
708 941e1713 2006-02-15 devnull static Sx*
709 941e1713 2006-02-15 devnull zBrdsx(Imap *z)
710 941e1713 2006-02-15 devnull {
711 941e1713 2006-02-15 devnull if(z->ticks && --z->ticks==0){
712 941e1713 2006-02-15 devnull close(z->fd);
713 941e1713 2006-02-15 devnull z->fd = -1;
714 941e1713 2006-02-15 devnull return nil;
715 941e1713 2006-02-15 devnull }
716 941e1713 2006-02-15 devnull return ioBrdsx(z->io, &z->b);
717 941e1713 2006-02-15 devnull }
718 941e1713 2006-02-15 devnull
719 941e1713 2006-02-15 devnull static int
720 941e1713 2006-02-15 devnull imapdial(char *server, int mode)
721 941e1713 2006-02-15 devnull {
722 941e1713 2006-02-15 devnull int p[2];
723 941e1713 2006-02-15 devnull int fd[3];
724 941e1713 2006-02-15 devnull char *tmp;
725 941e1713 2006-02-15 devnull
726 941e1713 2006-02-15 devnull switch(mode){
727 941e1713 2006-02-15 devnull default:
728 941e1713 2006-02-15 devnull case Unencrypted:
729 941e1713 2006-02-15 devnull return dial(netmkaddr(server, "tcp", "143"), nil, nil, nil);
730 941e1713 2006-02-15 devnull
731 941e1713 2006-02-15 devnull case Starttls:
732 941e1713 2006-02-15 devnull werrstr("starttls not supported");
733 941e1713 2006-02-15 devnull return -1;
734 941e1713 2006-02-15 devnull
735 941e1713 2006-02-15 devnull case Tls:
736 941e1713 2006-02-15 devnull if(pipe(p) < 0)
737 941e1713 2006-02-15 devnull return -1;
738 941e1713 2006-02-15 devnull fd[0] = dup(p[0], -1);
739 941e1713 2006-02-15 devnull fd[1] = dup(p[0], -1);
740 941e1713 2006-02-15 devnull fd[2] = dup(2, -1);
741 941e1713 2006-02-15 devnull tmp = esmprint("%s:993", server);
742 941e1713 2006-02-15 devnull if(threadspawnl(fd, "/usr/sbin/stunnel", "stunnel", "-c", "-r", tmp, nil) < 0){
743 941e1713 2006-02-15 devnull free(tmp);
744 941e1713 2006-02-15 devnull close(p[0]);
745 941e1713 2006-02-15 devnull close(p[1]);
746 941e1713 2006-02-15 devnull close(fd[0]);
747 941e1713 2006-02-15 devnull close(fd[1]);
748 941e1713 2006-02-15 devnull close(fd[2]);
749 941e1713 2006-02-15 devnull return -1;
750 941e1713 2006-02-15 devnull }
751 941e1713 2006-02-15 devnull free(tmp);
752 941e1713 2006-02-15 devnull close(p[0]);
753 941e1713 2006-02-15 devnull return p[1];
754 941e1713 2006-02-15 devnull
755 941e1713 2006-02-15 devnull case Cmd:
756 941e1713 2006-02-15 devnull if(pipe(p) < 0)
757 941e1713 2006-02-15 devnull return -1;
758 941e1713 2006-02-15 devnull fd[0] = dup(p[0], -1);
759 941e1713 2006-02-15 devnull fd[1] = dup(p[0], -1);
760 941e1713 2006-02-15 devnull fd[2] = dup(2, -1);
761 941e1713 2006-02-15 devnull if(threadspawnl(fd, "/usr/local/plan9/bin/rc", "rc", "-c", server, nil) < 0){
762 941e1713 2006-02-15 devnull close(p[0]);
763 941e1713 2006-02-15 devnull close(p[1]);
764 941e1713 2006-02-15 devnull close(fd[0]);
765 941e1713 2006-02-15 devnull close(fd[1]);
766 941e1713 2006-02-15 devnull close(fd[2]);
767 941e1713 2006-02-15 devnull return -1;
768 941e1713 2006-02-15 devnull }
769 941e1713 2006-02-15 devnull close(p[0]);
770 941e1713 2006-02-15 devnull return p[1];
771 941e1713 2006-02-15 devnull }
772 941e1713 2006-02-15 devnull }
773 941e1713 2006-02-15 devnull
774 941e1713 2006-02-15 devnull enum
775 941e1713 2006-02-15 devnull {
776 941e1713 2006-02-15 devnull Qok = 0,
777 941e1713 2006-02-15 devnull Qquote,
778 cbeb0b26 2006-04-01 devnull Qbackslash
779 941e1713 2006-02-15 devnull };
780 941e1713 2006-02-15 devnull
781 941e1713 2006-02-15 devnull static int
782 941e1713 2006-02-15 devnull needtoquote(Rune r)
783 941e1713 2006-02-15 devnull {
784 941e1713 2006-02-15 devnull if(r >= Runeself)
785 941e1713 2006-02-15 devnull return Qquote;
786 941e1713 2006-02-15 devnull if(r <= ' ')
787 941e1713 2006-02-15 devnull return Qquote;
788 941e1713 2006-02-15 devnull if(r=='\\' || r=='"')
789 941e1713 2006-02-15 devnull return Qbackslash;
790 941e1713 2006-02-15 devnull return Qok;
791 941e1713 2006-02-15 devnull }
792 941e1713 2006-02-15 devnull
793 941e1713 2006-02-15 devnull static int
794 941e1713 2006-02-15 devnull imapquote(Fmt *f)
795 941e1713 2006-02-15 devnull {
796 941e1713 2006-02-15 devnull char *s, *t;
797 941e1713 2006-02-15 devnull int w, quotes;
798 941e1713 2006-02-15 devnull Rune r;
799 941e1713 2006-02-15 devnull
800 941e1713 2006-02-15 devnull s = va_arg(f->args, char*);
801 941e1713 2006-02-15 devnull if(s == nil || *s == '\0')
802 941e1713 2006-02-15 devnull return fmtstrcpy(f, "\"\"");
803 941e1713 2006-02-15 devnull
804 941e1713 2006-02-15 devnull quotes = 0;
805 941e1713 2006-02-15 devnull if(f->flags&FmtSharp)
806 941e1713 2006-02-15 devnull quotes = 1;
807 941e1713 2006-02-15 devnull for(t=s; *t; t+=w){
808 941e1713 2006-02-15 devnull w = chartorune(&r, t);
809 941e1713 2006-02-15 devnull quotes |= needtoquote(r);
810 941e1713 2006-02-15 devnull }
811 941e1713 2006-02-15 devnull if(quotes == 0)
812 941e1713 2006-02-15 devnull return fmtstrcpy(f, s);
813 941e1713 2006-02-15 devnull
814 941e1713 2006-02-15 devnull fmtrune(f, '"');
815 941e1713 2006-02-15 devnull for(t=s; *t; t+=w){
816 941e1713 2006-02-15 devnull w = chartorune(&r, t);
817 941e1713 2006-02-15 devnull if(needtoquote(r) == Qbackslash)
818 941e1713 2006-02-15 devnull fmtrune(f, '\\');
819 941e1713 2006-02-15 devnull fmtrune(f, r);
820 941e1713 2006-02-15 devnull }
821 941e1713 2006-02-15 devnull return fmtrune(f, '"');
822 941e1713 2006-02-15 devnull }
823 941e1713 2006-02-15 devnull
824 941e1713 2006-02-15 devnull static int
825 941e1713 2006-02-15 devnull fmttype(char c)
826 941e1713 2006-02-15 devnull {
827 941e1713 2006-02-15 devnull switch(c){
828 941e1713 2006-02-15 devnull case 'A':
829 941e1713 2006-02-15 devnull return SxAtom;
830 941e1713 2006-02-15 devnull case 'L':
831 941e1713 2006-02-15 devnull return SxList;
832 941e1713 2006-02-15 devnull case 'N':
833 941e1713 2006-02-15 devnull return SxNumber;
834 941e1713 2006-02-15 devnull case 'S':
835 941e1713 2006-02-15 devnull return SxString;
836 941e1713 2006-02-15 devnull default:
837 941e1713 2006-02-15 devnull return -1;
838 941e1713 2006-02-15 devnull }
839 941e1713 2006-02-15 devnull }
840 941e1713 2006-02-15 devnull
841 941e1713 2006-02-15 devnull /*
842 941e1713 2006-02-15 devnull * Check S expression against format string.
843 941e1713 2006-02-15 devnull */
844 941e1713 2006-02-15 devnull static int
845 941e1713 2006-02-15 devnull sxmatch(Sx *sx, char *fmt)
846 941e1713 2006-02-15 devnull {
847 941e1713 2006-02-15 devnull int i;
848 941e1713 2006-02-15 devnull
849 941e1713 2006-02-15 devnull for(i=0; fmt[i]; i++){
850 941e1713 2006-02-15 devnull if(fmt[i] == '*')
851 941e1713 2006-02-15 devnull fmt--; /* like i-- but better */
852 941e1713 2006-02-15 devnull if(i == sx->nsx && fmt[i+1] == '*')
853 941e1713 2006-02-15 devnull return 1;
854 941e1713 2006-02-15 devnull if(i >= sx->nsx)
855 941e1713 2006-02-15 devnull return 0;
856 941e1713 2006-02-15 devnull if(sx->sx[i] == nil)
857 941e1713 2006-02-15 devnull return 0;
858 941e1713 2006-02-15 devnull if(sx->sx[i]->type == SxAtom && strcmp(sx->sx[i]->data, "NIL") == 0){
859 941e1713 2006-02-15 devnull if(fmt[i] == 'L'){
860 941e1713 2006-02-15 devnull free(sx->sx[i]->data);
861 941e1713 2006-02-15 devnull sx->sx[i]->data = nil;
862 941e1713 2006-02-15 devnull sx->sx[i]->type = SxList;
863 941e1713 2006-02-15 devnull sx->sx[i]->sx = nil;
864 941e1713 2006-02-15 devnull sx->sx[i]->nsx = 0;
865 941e1713 2006-02-15 devnull }
866 941e1713 2006-02-15 devnull else if(fmt[i] == 'S'){
867 941e1713 2006-02-15 devnull free(sx->sx[i]->data);
868 941e1713 2006-02-15 devnull sx->sx[i]->data = nil;
869 941e1713 2006-02-15 devnull sx->sx[i]->type = SxString;
870 941e1713 2006-02-15 devnull }
871 941e1713 2006-02-15 devnull }
872 941e1713 2006-02-15 devnull if(sx->sx[i]->type == SxAtom && fmt[i]=='S')
873 941e1713 2006-02-15 devnull sx->sx[i]->type = SxString;
874 941e1713 2006-02-15 devnull if(sx->sx[i]->type != fmttype(fmt[i])){
875 941e1713 2006-02-15 devnull fprint(2, "sxmatch: %$ not %c\n", sx->sx[i], fmt[i]);
876 941e1713 2006-02-15 devnull return 0;
877 941e1713 2006-02-15 devnull }
878 941e1713 2006-02-15 devnull }
879 941e1713 2006-02-15 devnull if(i != sx->nsx)
880 941e1713 2006-02-15 devnull return 0;
881 941e1713 2006-02-15 devnull return 1;
882 941e1713 2006-02-15 devnull }
883 941e1713 2006-02-15 devnull
884 941e1713 2006-02-15 devnull /*
885 941e1713 2006-02-15 devnull * Check string against format string.
886 941e1713 2006-02-15 devnull */
887 941e1713 2006-02-15 devnull static int
888 941e1713 2006-02-15 devnull stringmatch(char *fmt, char *s)
889 941e1713 2006-02-15 devnull {
890 941e1713 2006-02-15 devnull for(; *fmt && *s; fmt++, s++){
891 941e1713 2006-02-15 devnull switch(*fmt){
892 941e1713 2006-02-15 devnull case '0':
893 941e1713 2006-02-15 devnull if(*s == ' ')
894 941e1713 2006-02-15 devnull break;
895 941e1713 2006-02-15 devnull /* fall through */
896 941e1713 2006-02-15 devnull case '1':
897 941e1713 2006-02-15 devnull if(*s < '0' || *s > '9')
898 941e1713 2006-02-15 devnull return 0;
899 941e1713 2006-02-15 devnull break;
900 941e1713 2006-02-15 devnull case 'A':
901 941e1713 2006-02-15 devnull if(*s < 'A' || *s > 'Z')
902 941e1713 2006-02-15 devnull return 0;
903 941e1713 2006-02-15 devnull break;
904 941e1713 2006-02-15 devnull case 'a':
905 941e1713 2006-02-15 devnull if(*s < 'a' || *s > 'z')
906 941e1713 2006-02-15 devnull return 0;
907 941e1713 2006-02-15 devnull break;
908 941e1713 2006-02-15 devnull case '+':
909 941e1713 2006-02-15 devnull if(*s != '-' && *s != '+')
910 941e1713 2006-02-15 devnull return 0;
911 941e1713 2006-02-15 devnull break;
912 941e1713 2006-02-15 devnull default:
913 941e1713 2006-02-15 devnull if(*s != *fmt)
914 941e1713 2006-02-15 devnull return 0;
915 941e1713 2006-02-15 devnull break;
916 941e1713 2006-02-15 devnull }
917 941e1713 2006-02-15 devnull }
918 941e1713 2006-02-15 devnull if(*fmt || *s)
919 941e1713 2006-02-15 devnull return 0;
920 941e1713 2006-02-15 devnull return 1;
921 941e1713 2006-02-15 devnull }
922 941e1713 2006-02-15 devnull
923 941e1713 2006-02-15 devnull /*
924 941e1713 2006-02-15 devnull * Parse simple S expressions and IMAP elements.
925 941e1713 2006-02-15 devnull */
926 941e1713 2006-02-15 devnull static int
927 941e1713 2006-02-15 devnull isatom(Sx *v, char *name)
928 941e1713 2006-02-15 devnull {
929 941e1713 2006-02-15 devnull int n;
930 941e1713 2006-02-15 devnull
931 941e1713 2006-02-15 devnull if(v == nil || v->type != SxAtom)
932 941e1713 2006-02-15 devnull return 0;
933 941e1713 2006-02-15 devnull n = strlen(name);
934 941e1713 2006-02-15 devnull if(cistrncmp(v->data, name, n) == 0)
935 941e1713 2006-02-15 devnull if(v->data[n] == 0 || (n>0 && v->data[n-1] == '['))
936 941e1713 2006-02-15 devnull return 1;
937 941e1713 2006-02-15 devnull return 0;
938 941e1713 2006-02-15 devnull }
939 941e1713 2006-02-15 devnull
940 941e1713 2006-02-15 devnull static int
941 941e1713 2006-02-15 devnull isstring(Sx *sx)
942 941e1713 2006-02-15 devnull {
943 941e1713 2006-02-15 devnull if(sx->type == SxAtom)
944 941e1713 2006-02-15 devnull sx->type = SxString;
945 941e1713 2006-02-15 devnull return sx->type == SxString;
946 941e1713 2006-02-15 devnull }
947 941e1713 2006-02-15 devnull
948 941e1713 2006-02-15 devnull static int
949 941e1713 2006-02-15 devnull isnumber(Sx *sx)
950 941e1713 2006-02-15 devnull {
951 941e1713 2006-02-15 devnull return sx->type == SxNumber;
952 941e1713 2006-02-15 devnull }
953 941e1713 2006-02-15 devnull
954 941e1713 2006-02-15 devnull static int
955 941e1713 2006-02-15 devnull isnil(Sx *v)
956 941e1713 2006-02-15 devnull {
957 941e1713 2006-02-15 devnull return v == nil ||
958 941e1713 2006-02-15 devnull (v->type==SxList && v->nsx == 0) ||
959 941e1713 2006-02-15 devnull (v->type==SxAtom && strcmp(v->data, "NIL") == 0);
960 941e1713 2006-02-15 devnull }
961 941e1713 2006-02-15 devnull
962 941e1713 2006-02-15 devnull static int
963 941e1713 2006-02-15 devnull islist(Sx *v)
964 941e1713 2006-02-15 devnull {
965 941e1713 2006-02-15 devnull return isnil(v) || v->type==SxList;
966 941e1713 2006-02-15 devnull }
967 941e1713 2006-02-15 devnull
968 941e1713 2006-02-15 devnull static uint
969 941e1713 2006-02-15 devnull parseflags(Sx *v)
970 941e1713 2006-02-15 devnull {
971 941e1713 2006-02-15 devnull int f, i, j;
972 941e1713 2006-02-15 devnull
973 941e1713 2006-02-15 devnull if(v->type != SxList){
974 941e1713 2006-02-15 devnull warn("malformed flags: %$", v);
975 941e1713 2006-02-15 devnull return 0;
976 941e1713 2006-02-15 devnull }
977 941e1713 2006-02-15 devnull f = 0;
978 941e1713 2006-02-15 devnull for(i=0; i<v->nsx; i++){
979 941e1713 2006-02-15 devnull if(v->sx[i]->type != SxAtom)
980 941e1713 2006-02-15 devnull continue;
981 941e1713 2006-02-15 devnull for(j=0; j<nelem(flagstab); j++)
982 941e1713 2006-02-15 devnull if(cistrcmp(v->sx[i]->data, flagstab[j].name) == 0)
983 941e1713 2006-02-15 devnull f |= flagstab[j].flag;
984 941e1713 2006-02-15 devnull }
985 941e1713 2006-02-15 devnull return f;
986 941e1713 2006-02-15 devnull }
987 941e1713 2006-02-15 devnull
988 941e1713 2006-02-15 devnull static char months[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
989 941e1713 2006-02-15 devnull static int
990 941e1713 2006-02-15 devnull parsemon(char *s)
991 941e1713 2006-02-15 devnull {
992 941e1713 2006-02-15 devnull int i;
993 941e1713 2006-02-15 devnull
994 941e1713 2006-02-15 devnull for(i=0; months[i]; i+=3)
995 941e1713 2006-02-15 devnull if(memcmp(s, months+i, 3) == 0)
996 941e1713 2006-02-15 devnull return i/3;
997 941e1713 2006-02-15 devnull return -1;
998 941e1713 2006-02-15 devnull }
999 941e1713 2006-02-15 devnull
1000 941e1713 2006-02-15 devnull static uint
1001 941e1713 2006-02-15 devnull parsedate(Sx *v)
1002 941e1713 2006-02-15 devnull {
1003 941e1713 2006-02-15 devnull Tm tm;
1004 941e1713 2006-02-15 devnull uint t;
1005 941e1713 2006-02-15 devnull int delta;
1006 941e1713 2006-02-15 devnull char *p;
1007 941e1713 2006-02-15 devnull
1008 941e1713 2006-02-15 devnull if(v->type != SxString || !stringmatch("01-Aaa-1111 01:11:11 +1111", v->data)){
1009 941e1713 2006-02-15 devnull bad:
1010 941e1713 2006-02-15 devnull warn("bad date: %$", v);
1011 941e1713 2006-02-15 devnull return 0;
1012 941e1713 2006-02-15 devnull }
1013 95456b21 2006-02-18 devnull
1014 95456b21 2006-02-18 devnull /* cannot use atoi because 09 is malformed octal! */
1015 941e1713 2006-02-15 devnull memset(&tm, 0, sizeof tm);
1016 941e1713 2006-02-15 devnull p = v->data;
1017 95456b21 2006-02-18 devnull tm.mday = strtol(p, 0, 10);
1018 941e1713 2006-02-15 devnull tm.mon = parsemon(p+3);
1019 941e1713 2006-02-15 devnull if(tm.mon == -1)
1020 941e1713 2006-02-15 devnull goto bad;
1021 95456b21 2006-02-18 devnull tm.year = strtol(p+7, 0, 10) - 1900;
1022 95456b21 2006-02-18 devnull tm.hour = strtol(p+12, 0, 10);
1023 95456b21 2006-02-18 devnull tm.min = strtol(p+15, 0, 10);
1024 95456b21 2006-02-18 devnull tm.sec = strtol(p+18, 0, 10);
1025 941e1713 2006-02-15 devnull strcpy(tm.zone, "GMT");
1026 941e1713 2006-02-15 devnull
1027 941e1713 2006-02-15 devnull t = tm2sec(&tm);
1028 941e1713 2006-02-15 devnull delta = ((p[22]-'0')*10+p[23]-'0')*3600 + ((p[24]-'0')*10+p[25]-'0')*60;
1029 941e1713 2006-02-15 devnull if(p[21] == '-')
1030 941e1713 2006-02-15 devnull delta = -delta;
1031 941e1713 2006-02-15 devnull
1032 941e1713 2006-02-15 devnull t -= delta;
1033 941e1713 2006-02-15 devnull return t;
1034 941e1713 2006-02-15 devnull }
1035 941e1713 2006-02-15 devnull
1036 941e1713 2006-02-15 devnull static uint
1037 941e1713 2006-02-15 devnull parsenumber(Sx *v)
1038 941e1713 2006-02-15 devnull {
1039 941e1713 2006-02-15 devnull if(v->type != SxNumber)
1040 941e1713 2006-02-15 devnull return 0;
1041 941e1713 2006-02-15 devnull return v->number;
1042 941e1713 2006-02-15 devnull }
1043 941e1713 2006-02-15 devnull
1044 941e1713 2006-02-15 devnull static void
1045 941e1713 2006-02-15 devnull hash(DigestState *ds, char *tag, char *val)
1046 941e1713 2006-02-15 devnull {
1047 941e1713 2006-02-15 devnull if(val == nil)
1048 941e1713 2006-02-15 devnull val = "";
1049 941e1713 2006-02-15 devnull md5((uchar*)tag, strlen(tag)+1, nil, ds);
1050 941e1713 2006-02-15 devnull md5((uchar*)val, strlen(val)+1, nil, ds);
1051 941e1713 2006-02-15 devnull }
1052 941e1713 2006-02-15 devnull
1053 941e1713 2006-02-15 devnull static Hdr*
1054 941e1713 2006-02-15 devnull parseenvelope(Sx *v)
1055 941e1713 2006-02-15 devnull {
1056 941e1713 2006-02-15 devnull Hdr *hdr;
1057 941e1713 2006-02-15 devnull uchar digest[16];
1058 941e1713 2006-02-15 devnull DigestState ds;
1059 941e1713 2006-02-15 devnull
1060 941e1713 2006-02-15 devnull if(v->type != SxList || !sxmatch(v, "SSLLLLLLSS")){
1061 941e1713 2006-02-15 devnull warn("bad envelope: %$", v);
1062 941e1713 2006-02-15 devnull return nil;
1063 941e1713 2006-02-15 devnull }
1064 941e1713 2006-02-15 devnull
1065 941e1713 2006-02-15 devnull hdr = emalloc(sizeof *hdr);
1066 941e1713 2006-02-15 devnull hdr->date = nstring(v->sx[0]);
1067 941e1713 2006-02-15 devnull hdr->subject = unrfc2047(nstring(v->sx[1]));
1068 941e1713 2006-02-15 devnull hdr->from = copyaddrs(v->sx[2]);
1069 941e1713 2006-02-15 devnull hdr->sender = copyaddrs(v->sx[3]);
1070 941e1713 2006-02-15 devnull hdr->replyto = copyaddrs(v->sx[4]);
1071 941e1713 2006-02-15 devnull hdr->to = copyaddrs(v->sx[5]);
1072 941e1713 2006-02-15 devnull hdr->cc = copyaddrs(v->sx[6]);
1073 941e1713 2006-02-15 devnull hdr->bcc = copyaddrs(v->sx[7]);
1074 941e1713 2006-02-15 devnull hdr->inreplyto = unrfc2047(nstring(v->sx[8]));
1075 941e1713 2006-02-15 devnull hdr->messageid = unrfc2047(nstring(v->sx[9]));
1076 941e1713 2006-02-15 devnull
1077 941e1713 2006-02-15 devnull memset(&ds, 0, sizeof ds);
1078 941e1713 2006-02-15 devnull hash(&ds, "date", hdr->date);
1079 941e1713 2006-02-15 devnull hash(&ds, "subject", hdr->subject);
1080 941e1713 2006-02-15 devnull hash(&ds, "from", hdr->from);
1081 941e1713 2006-02-15 devnull hash(&ds, "sender", hdr->sender);
1082 941e1713 2006-02-15 devnull hash(&ds, "replyto", hdr->replyto);
1083 941e1713 2006-02-15 devnull hash(&ds, "to", hdr->to);
1084 941e1713 2006-02-15 devnull hash(&ds, "cc", hdr->cc);
1085 941e1713 2006-02-15 devnull hash(&ds, "bcc", hdr->bcc);
1086 941e1713 2006-02-15 devnull hash(&ds, "inreplyto", hdr->inreplyto);
1087 941e1713 2006-02-15 devnull hash(&ds, "messageid", hdr->messageid);
1088 941e1713 2006-02-15 devnull md5(0, 0, digest, &ds);
1089 941e1713 2006-02-15 devnull hdr->digest = esmprint("%.16H", digest);
1090 941e1713 2006-02-15 devnull
1091 941e1713 2006-02-15 devnull return hdr;
1092 941e1713 2006-02-15 devnull }
1093 941e1713 2006-02-15 devnull
1094 941e1713 2006-02-15 devnull static void
1095 941e1713 2006-02-15 devnull strlwr(char *s)
1096 941e1713 2006-02-15 devnull {
1097 941e1713 2006-02-15 devnull char *t;
1098 941e1713 2006-02-15 devnull
1099 941e1713 2006-02-15 devnull if(s == nil)
1100 941e1713 2006-02-15 devnull return;
1101 941e1713 2006-02-15 devnull for(t=s; *t; t++)
1102 941e1713 2006-02-15 devnull if('A' <= *t && *t <= 'Z')
1103 941e1713 2006-02-15 devnull *t += 'a' - 'A';
1104 941e1713 2006-02-15 devnull }
1105 941e1713 2006-02-15 devnull
1106 941e1713 2006-02-15 devnull static void
1107 941e1713 2006-02-15 devnull nocr(char *s)
1108 941e1713 2006-02-15 devnull {
1109 941e1713 2006-02-15 devnull char *r, *w;
1110 941e1713 2006-02-15 devnull
1111 941e1713 2006-02-15 devnull if(s == nil)
1112 941e1713 2006-02-15 devnull return;
1113 941e1713 2006-02-15 devnull for(r=w=s; *r; r++)
1114 941e1713 2006-02-15 devnull if(*r != '\r')
1115 941e1713 2006-02-15 devnull *w++ = *r;
1116 941e1713 2006-02-15 devnull *w = 0;
1117 941e1713 2006-02-15 devnull }
1118 941e1713 2006-02-15 devnull
1119 941e1713 2006-02-15 devnull /*
1120 941e1713 2006-02-15 devnull * substitute all occurrences of a with b in s.
1121 941e1713 2006-02-15 devnull */
1122 941e1713 2006-02-15 devnull static char*
1123 941e1713 2006-02-15 devnull gsub(char *s, char *a, char *b)
1124 941e1713 2006-02-15 devnull {
1125 941e1713 2006-02-15 devnull char *p, *t, *w, *last;
1126 941e1713 2006-02-15 devnull int n;
1127 941e1713 2006-02-15 devnull
1128 941e1713 2006-02-15 devnull n = 0;
1129 941e1713 2006-02-15 devnull for(p=s; (p=strstr(p, a)) != nil; p+=strlen(a))
1130 941e1713 2006-02-15 devnull n++;
1131 941e1713 2006-02-15 devnull if(n == 0)
1132 941e1713 2006-02-15 devnull return s;
1133 941e1713 2006-02-15 devnull t = emalloc(strlen(s)+n*strlen(b)+1);
1134 941e1713 2006-02-15 devnull w = t;
1135 941e1713 2006-02-15 devnull for(p=s; last=p, (p=strstr(p, a)) != nil; p+=strlen(a)){
1136 941e1713 2006-02-15 devnull memmove(w, last, p-last);
1137 941e1713 2006-02-15 devnull w += p-last;
1138 941e1713 2006-02-15 devnull memmove(w, b, strlen(b));
1139 941e1713 2006-02-15 devnull w += strlen(b);
1140 941e1713 2006-02-15 devnull }
1141 941e1713 2006-02-15 devnull strcpy(w, last);
1142 941e1713 2006-02-15 devnull free(s);
1143 941e1713 2006-02-15 devnull return t;
1144 941e1713 2006-02-15 devnull }
1145 941e1713 2006-02-15 devnull
1146 941e1713 2006-02-15 devnull /*
1147 941e1713 2006-02-15 devnull * Table-driven IMAP "unexpected response" parser.
1148 941e1713 2006-02-15 devnull * All the interesting data is in the unexpected responses.
1149 941e1713 2006-02-15 devnull */
1150 941e1713 2006-02-15 devnull static void xlist(Imap*, Sx*);
1151 941e1713 2006-02-15 devnull static void xrecent(Imap*, Sx*);
1152 941e1713 2006-02-15 devnull static void xexists(Imap*, Sx*);
1153 941e1713 2006-02-15 devnull static void xok(Imap*, Sx*);
1154 941e1713 2006-02-15 devnull static void xflags(Imap*, Sx*);
1155 941e1713 2006-02-15 devnull static void xfetch(Imap*, Sx*);
1156 941e1713 2006-02-15 devnull static void xexpunge(Imap*, Sx*);
1157 941e1713 2006-02-15 devnull static void xbye(Imap*, Sx*);
1158 941e1713 2006-02-15 devnull static void xsearch(Imap*, Sx*);
1159 941e1713 2006-02-15 devnull
1160 941e1713 2006-02-15 devnull static struct {
1161 941e1713 2006-02-15 devnull int num;
1162 941e1713 2006-02-15 devnull char *name;
1163 941e1713 2006-02-15 devnull char *fmt;
1164 941e1713 2006-02-15 devnull void (*fn)(Imap*, Sx*);
1165 941e1713 2006-02-15 devnull } unextab[] = {
1166 941e1713 2006-02-15 devnull 0, "BYE", nil, xbye,
1167 941e1713 2006-02-15 devnull 0, "FLAGS", "AAL", xflags,
1168 941e1713 2006-02-15 devnull 0, "LIST", "AALSS", xlist,
1169 941e1713 2006-02-15 devnull 0, "OK", nil, xok,
1170 941e1713 2006-02-15 devnull 0, "SEARCH", "AAN*", xsearch,
1171 941e1713 2006-02-15 devnull
1172 941e1713 2006-02-15 devnull 1, "EXISTS", "ANA", xexists,
1173 941e1713 2006-02-15 devnull 1, "EXPUNGE", "ANA", xexpunge,
1174 941e1713 2006-02-15 devnull 1, "FETCH", "ANAL", xfetch,
1175 cbeb0b26 2006-04-01 devnull 1, "RECENT", "ANA", xrecent
1176 941e1713 2006-02-15 devnull };
1177 941e1713 2006-02-15 devnull
1178 941e1713 2006-02-15 devnull static void
1179 941e1713 2006-02-15 devnull unexpected(Imap *z, Sx *sx)
1180 941e1713 2006-02-15 devnull {
1181 941e1713 2006-02-15 devnull int i, num;
1182 941e1713 2006-02-15 devnull char *name;
1183 941e1713 2006-02-15 devnull
1184 941e1713 2006-02-15 devnull if(sx->nsx >= 3 && sx->sx[1]->type == SxNumber && sx->sx[2]->type == SxAtom){
1185 941e1713 2006-02-15 devnull num = 1;
1186 941e1713 2006-02-15 devnull name = sx->sx[2]->data;
1187 941e1713 2006-02-15 devnull }else if(sx->nsx >= 2 && sx->sx[1]->type == SxAtom){
1188 941e1713 2006-02-15 devnull num = 0;
1189 941e1713 2006-02-15 devnull name = sx->sx[1]->data;
1190 941e1713 2006-02-15 devnull }else
1191 941e1713 2006-02-15 devnull return;
1192 941e1713 2006-02-15 devnull
1193 941e1713 2006-02-15 devnull for(i=0; i<nelem(unextab); i++){
1194 941e1713 2006-02-15 devnull if(unextab[i].num == num && cistrcmp(unextab[i].name, name) == 0){
1195 941e1713 2006-02-15 devnull if(unextab[i].fmt && !sxmatch(sx, unextab[i].fmt)){
1196 941e1713 2006-02-15 devnull warn("malformed %s: %$", name, sx);
1197 941e1713 2006-02-15 devnull continue;
1198 941e1713 2006-02-15 devnull }
1199 941e1713 2006-02-15 devnull unextab[i].fn(z, sx);
1200 941e1713 2006-02-15 devnull }
1201 941e1713 2006-02-15 devnull }
1202 941e1713 2006-02-15 devnull }
1203 941e1713 2006-02-15 devnull
1204 bb70a84b 2007-06-23 devnull static int
1205 bb70a84b 2007-06-23 devnull alldollars(char *s)
1206 bb70a84b 2007-06-23 devnull {
1207 bb70a84b 2007-06-23 devnull for(; *s; s++)
1208 bb70a84b 2007-06-23 devnull if(*s != '$')
1209 bb70a84b 2007-06-23 devnull return 0;
1210 bb70a84b 2007-06-23 devnull return 1;
1211 bb70a84b 2007-06-23 devnull }
1212 941e1713 2006-02-15 devnull
1213 941e1713 2006-02-15 devnull static void
1214 941e1713 2006-02-15 devnull xlist(Imap *z, Sx *sx)
1215 941e1713 2006-02-15 devnull {
1216 941e1713 2006-02-15 devnull int inbox;
1217 941e1713 2006-02-15 devnull char *s, *t;
1218 941e1713 2006-02-15 devnull Box *box;
1219 941e1713 2006-02-15 devnull
1220 941e1713 2006-02-15 devnull s = estrdup(sx->sx[4]->data);
1221 941e1713 2006-02-15 devnull if(sx->sx[3]->data && strcmp(sx->sx[3]->data, "/") != 0){
1222 941e1713 2006-02-15 devnull s = gsub(s, "/", "_");
1223 941e1713 2006-02-15 devnull s = gsub(s, sx->sx[3]->data, "/");
1224 941e1713 2006-02-15 devnull }
1225 941e1713 2006-02-15 devnull
1226 941e1713 2006-02-15 devnull /*
1227 941e1713 2006-02-15 devnull * Plan 9 calls the main mailbox mbox.
1228 941e1713 2006-02-15 devnull * Rename any existing mbox by appending a $.
1229 941e1713 2006-02-15 devnull */
1230 941e1713 2006-02-15 devnull inbox = 0;
1231 bb70a84b 2007-06-23 devnull if(strncmp(s, "mbox", 4) == 0 && alldollars(s+4)){
1232 941e1713 2006-02-15 devnull t = emalloc(strlen(s)+2);
1233 941e1713 2006-02-15 devnull strcpy(t, s);
1234 941e1713 2006-02-15 devnull strcat(t, "$");
1235 941e1713 2006-02-15 devnull free(s);
1236 941e1713 2006-02-15 devnull s = t;
1237 941e1713 2006-02-15 devnull }else if(cistrcmp(s, "INBOX") == 0){
1238 941e1713 2006-02-15 devnull inbox = 1;
1239 941e1713 2006-02-15 devnull free(s);
1240 941e1713 2006-02-15 devnull s = estrdup("mbox");
1241 941e1713 2006-02-15 devnull }
1242 941e1713 2006-02-15 devnull
1243 941e1713 2006-02-15 devnull box = boxcreate(s);
1244 941e1713 2006-02-15 devnull if(box == nil)
1245 941e1713 2006-02-15 devnull return;
1246 941e1713 2006-02-15 devnull box->imapname = estrdup(sx->sx[4]->data);
1247 941e1713 2006-02-15 devnull if(inbox)
1248 941e1713 2006-02-15 devnull z->inbox = box;
1249 941e1713 2006-02-15 devnull box->mark = 0;
1250 941e1713 2006-02-15 devnull box->flags = parseflags(sx->sx[2]);
1251 941e1713 2006-02-15 devnull }
1252 941e1713 2006-02-15 devnull
1253 941e1713 2006-02-15 devnull static void
1254 941e1713 2006-02-15 devnull xrecent(Imap *z, Sx *sx)
1255 941e1713 2006-02-15 devnull {
1256 941e1713 2006-02-15 devnull if(z->box)
1257 941e1713 2006-02-15 devnull z->box->recent = sx->sx[1]->number;
1258 941e1713 2006-02-15 devnull }
1259 941e1713 2006-02-15 devnull
1260 941e1713 2006-02-15 devnull static void
1261 941e1713 2006-02-15 devnull xexists(Imap *z, Sx *sx)
1262 941e1713 2006-02-15 devnull {
1263 941e1713 2006-02-15 devnull if(z->box){
1264 941e1713 2006-02-15 devnull z->box->exists = sx->sx[1]->number;
1265 941e1713 2006-02-15 devnull if(z->box->exists < z->box->maxseen)
1266 941e1713 2006-02-15 devnull z->box->maxseen = z->box->exists;
1267 941e1713 2006-02-15 devnull }
1268 941e1713 2006-02-15 devnull }
1269 941e1713 2006-02-15 devnull
1270 941e1713 2006-02-15 devnull static void
1271 941e1713 2006-02-15 devnull xflags(Imap *z, Sx *sx)
1272 941e1713 2006-02-15 devnull {
1273 6b0a42ed 2007-08-22 rsc /*
1274 6b0a42ed 2007-08-22 rsc * This response contains in sx->sx[2] the list of flags
1275 6b0a42ed 2007-08-22 rsc * that can be validly attached to messages in z->box.
1276 6b0a42ed 2007-08-22 rsc * We don't have any use for this list, since we
1277 6b0a42ed 2007-08-22 rsc * use only the standard flags.
1278 6b0a42ed 2007-08-22 rsc */
1279 941e1713 2006-02-15 devnull }
1280 941e1713 2006-02-15 devnull
1281 941e1713 2006-02-15 devnull static void
1282 941e1713 2006-02-15 devnull xbye(Imap *z, Sx *sx)
1283 941e1713 2006-02-15 devnull {
1284 941e1713 2006-02-15 devnull close(z->fd);
1285 941e1713 2006-02-15 devnull z->fd = -1;
1286 941e1713 2006-02-15 devnull z->connected = 0;
1287 941e1713 2006-02-15 devnull }
1288 941e1713 2006-02-15 devnull
1289 941e1713 2006-02-15 devnull static void
1290 941e1713 2006-02-15 devnull xexpunge(Imap *z, Sx *sx)
1291 941e1713 2006-02-15 devnull {
1292 941e1713 2006-02-15 devnull int i, n;
1293 941e1713 2006-02-15 devnull Box *b;
1294 941e1713 2006-02-15 devnull
1295 941e1713 2006-02-15 devnull if((b=z->box) == nil)
1296 941e1713 2006-02-15 devnull return;
1297 941e1713 2006-02-15 devnull n = sx->sx[1]->number;
1298 941e1713 2006-02-15 devnull for(i=0; i<b->nmsg; i++){
1299 941e1713 2006-02-15 devnull if(b->msg[i]->imapid == n){
1300 941e1713 2006-02-15 devnull msgplumb(b->msg[i], 1);
1301 941e1713 2006-02-15 devnull msgfree(b->msg[i]);
1302 941e1713 2006-02-15 devnull b->nmsg--;
1303 941e1713 2006-02-15 devnull memmove(b->msg+i, b->msg+i+1, (b->nmsg-i)*sizeof b->msg[0]);
1304 941e1713 2006-02-15 devnull i--;
1305 941e1713 2006-02-15 devnull b->maxseen--;
1306 941e1713 2006-02-15 devnull b->exists--;
1307 941e1713 2006-02-15 devnull continue;
1308 941e1713 2006-02-15 devnull }
1309 941e1713 2006-02-15 devnull if(b->msg[i]->imapid > n)
1310 941e1713 2006-02-15 devnull b->msg[i]->imapid--;
1311 941e1713 2006-02-15 devnull b->msg[i]->ix = i;
1312 941e1713 2006-02-15 devnull }
1313 941e1713 2006-02-15 devnull }
1314 941e1713 2006-02-15 devnull
1315 941e1713 2006-02-15 devnull static void
1316 941e1713 2006-02-15 devnull xsearch(Imap *z, Sx *sx)
1317 941e1713 2006-02-15 devnull {
1318 941e1713 2006-02-15 devnull int i;
1319 941e1713 2006-02-15 devnull
1320 941e1713 2006-02-15 devnull free(z->uid);
1321 941e1713 2006-02-15 devnull z->uid = emalloc((sx->nsx-2)*sizeof z->uid[0]);
1322 941e1713 2006-02-15 devnull z->nuid = sx->nsx-2;
1323 941e1713 2006-02-15 devnull for(i=0; i<z->nuid; i++)
1324 941e1713 2006-02-15 devnull z->uid[i] = sx->sx[i+2]->number;
1325 941e1713 2006-02-15 devnull }
1326 941e1713 2006-02-15 devnull
1327 941e1713 2006-02-15 devnull /*
1328 941e1713 2006-02-15 devnull * Table-driven FETCH message info parser.
1329 941e1713 2006-02-15 devnull */
1330 941e1713 2006-02-15 devnull static void xmsgflags(Msg*, Sx*, Sx*);
1331 941e1713 2006-02-15 devnull static void xmsgdate(Msg*, Sx*, Sx*);
1332 941e1713 2006-02-15 devnull static void xmsgrfc822size(Msg*, Sx*, Sx*);
1333 941e1713 2006-02-15 devnull static void xmsgenvelope(Msg*, Sx*, Sx*);
1334 941e1713 2006-02-15 devnull static void xmsgbody(Msg*, Sx*, Sx*);
1335 941e1713 2006-02-15 devnull static void xmsgbodydata(Msg*, Sx*, Sx*);
1336 941e1713 2006-02-15 devnull
1337 941e1713 2006-02-15 devnull static struct {
1338 941e1713 2006-02-15 devnull char *name;
1339 941e1713 2006-02-15 devnull void (*fn)(Msg*, Sx*, Sx*);
1340 941e1713 2006-02-15 devnull } msgtab[] = {
1341 941e1713 2006-02-15 devnull "FLAGS", xmsgflags,
1342 941e1713 2006-02-15 devnull "INTERNALDATE", xmsgdate,
1343 941e1713 2006-02-15 devnull "RFC822.SIZE", xmsgrfc822size,
1344 941e1713 2006-02-15 devnull "ENVELOPE", xmsgenvelope,
1345 941e1713 2006-02-15 devnull "BODY", xmsgbody,
1346 cbeb0b26 2006-04-01 devnull "BODY[", xmsgbodydata
1347 941e1713 2006-02-15 devnull };
1348 941e1713 2006-02-15 devnull
1349 941e1713 2006-02-15 devnull static void
1350 941e1713 2006-02-15 devnull xfetch(Imap *z, Sx *sx)
1351 941e1713 2006-02-15 devnull {
1352 941e1713 2006-02-15 devnull int i, j, n, uid;
1353 941e1713 2006-02-15 devnull Msg *msg;
1354 941e1713 2006-02-15 devnull
1355 941e1713 2006-02-15 devnull if(z->box == nil){
1356 941e1713 2006-02-15 devnull warn("FETCH but no open box: %$", sx);
1357 941e1713 2006-02-15 devnull return;
1358 941e1713 2006-02-15 devnull }
1359 941e1713 2006-02-15 devnull
1360 941e1713 2006-02-15 devnull /* * 152 FETCH (UID 185 FLAGS () ...) */
1361 941e1713 2006-02-15 devnull if(sx->sx[3]->nsx%2){
1362 941e1713 2006-02-15 devnull warn("malformed FETCH: %$", sx);
1363 941e1713 2006-02-15 devnull return;
1364 941e1713 2006-02-15 devnull }
1365 941e1713 2006-02-15 devnull
1366 941e1713 2006-02-15 devnull n = sx->sx[1]->number;
1367 941e1713 2006-02-15 devnull sx = sx->sx[3];
1368 941e1713 2006-02-15 devnull for(i=0; i<sx->nsx; i+=2){
1369 941e1713 2006-02-15 devnull if(isatom(sx->sx[i], "UID")){
1370 941e1713 2006-02-15 devnull if(sx->sx[i+1]->type == SxNumber){
1371 941e1713 2006-02-15 devnull uid = sx->sx[i+1]->number;
1372 941e1713 2006-02-15 devnull goto haveuid;
1373 941e1713 2006-02-15 devnull }
1374 941e1713 2006-02-15 devnull }
1375 941e1713 2006-02-15 devnull }
1376 e12bc7cd 2007-06-23 devnull /* This happens: too bad.
1377 941e1713 2006-02-15 devnull warn("FETCH without UID: %$", sx);
1378 e12bc7cd 2007-06-23 devnull */
1379 941e1713 2006-02-15 devnull return;
1380 941e1713 2006-02-15 devnull
1381 941e1713 2006-02-15 devnull haveuid:
1382 941e1713 2006-02-15 devnull msg = msgbyimapuid(z->box, uid, 1);
1383 941e1713 2006-02-15 devnull if(msg->imapid && msg->imapid != n)
1384 941e1713 2006-02-15 devnull warn("msg id mismatch: want %d have %d", msg->id, n);
1385 941e1713 2006-02-15 devnull msg->imapid = n;
1386 941e1713 2006-02-15 devnull for(i=0; i<sx->nsx; i+=2){
1387 941e1713 2006-02-15 devnull for(j=0; j<nelem(msgtab); j++)
1388 941e1713 2006-02-15 devnull if(isatom(sx->sx[i], msgtab[j].name))
1389 941e1713 2006-02-15 devnull msgtab[j].fn(msg, sx->sx[i], sx->sx[i+1]);
1390 941e1713 2006-02-15 devnull }
1391 941e1713 2006-02-15 devnull }
1392 941e1713 2006-02-15 devnull
1393 941e1713 2006-02-15 devnull static void
1394 941e1713 2006-02-15 devnull xmsgflags(Msg *msg, Sx *k, Sx *v)
1395 941e1713 2006-02-15 devnull {
1396 941e1713 2006-02-15 devnull USED(k);
1397 941e1713 2006-02-15 devnull msg->flags = parseflags(v);
1398 941e1713 2006-02-15 devnull }
1399 941e1713 2006-02-15 devnull
1400 941e1713 2006-02-15 devnull static void
1401 941e1713 2006-02-15 devnull xmsgdate(Msg *msg, Sx *k, Sx *v)
1402 941e1713 2006-02-15 devnull {
1403 941e1713 2006-02-15 devnull USED(k);
1404 941e1713 2006-02-15 devnull msg->date = parsedate(v);
1405 941e1713 2006-02-15 devnull }
1406 941e1713 2006-02-15 devnull
1407 941e1713 2006-02-15 devnull static void
1408 941e1713 2006-02-15 devnull xmsgrfc822size(Msg *msg, Sx *k, Sx *v)
1409 941e1713 2006-02-15 devnull {
1410 941e1713 2006-02-15 devnull USED(k);
1411 941e1713 2006-02-15 devnull msg->size = parsenumber(v);
1412 941e1713 2006-02-15 devnull }
1413 941e1713 2006-02-15 devnull
1414 941e1713 2006-02-15 devnull static char*
1415 941e1713 2006-02-15 devnull nstring(Sx *v)
1416 941e1713 2006-02-15 devnull {
1417 941e1713 2006-02-15 devnull char *p;
1418 941e1713 2006-02-15 devnull
1419 941e1713 2006-02-15 devnull p = v->data;
1420 941e1713 2006-02-15 devnull v->data = nil;
1421 941e1713 2006-02-15 devnull return p;
1422 941e1713 2006-02-15 devnull }
1423 941e1713 2006-02-15 devnull
1424 941e1713 2006-02-15 devnull static char*
1425 941e1713 2006-02-15 devnull copyaddrs(Sx *v)
1426 941e1713 2006-02-15 devnull {
1427 941e1713 2006-02-15 devnull char *s, *sep;
1428 941e1713 2006-02-15 devnull char *name, *email, *host, *mbox;
1429 941e1713 2006-02-15 devnull int i;
1430 941e1713 2006-02-15 devnull Fmt fmt;
1431 941e1713 2006-02-15 devnull
1432 941e1713 2006-02-15 devnull if(v->nsx == 0)
1433 941e1713 2006-02-15 devnull return nil;
1434 941e1713 2006-02-15 devnull
1435 941e1713 2006-02-15 devnull fmtstrinit(&fmt);
1436 941e1713 2006-02-15 devnull sep = "";
1437 941e1713 2006-02-15 devnull for(i=0; i<v->nsx; i++){
1438 941e1713 2006-02-15 devnull if(!sxmatch(v->sx[i], "SSSS"))
1439 941e1713 2006-02-15 devnull warn("bad address: %$", v->sx[i]);
1440 941e1713 2006-02-15 devnull name = unrfc2047(nstring(v->sx[i]->sx[0]));
1441 941e1713 2006-02-15 devnull /* ignore sx[1] - route */
1442 941e1713 2006-02-15 devnull mbox = unrfc2047(nstring(v->sx[i]->sx[2]));
1443 941e1713 2006-02-15 devnull host = unrfc2047(nstring(v->sx[i]->sx[3]));
1444 941e1713 2006-02-15 devnull if(mbox == nil || host == nil){ /* rfc822 group syntax */
1445 941e1713 2006-02-15 devnull free(name);
1446 941e1713 2006-02-15 devnull free(mbox);
1447 941e1713 2006-02-15 devnull free(host);
1448 941e1713 2006-02-15 devnull continue;
1449 941e1713 2006-02-15 devnull }
1450 941e1713 2006-02-15 devnull email = esmprint("%s@%s", mbox, host);
1451 941e1713 2006-02-15 devnull free(mbox);
1452 941e1713 2006-02-15 devnull free(host);
1453 941e1713 2006-02-15 devnull fmtprint(&fmt, "%s%q %q", sep, name ? name : "", email ? email : "");
1454 941e1713 2006-02-15 devnull free(name);
1455 941e1713 2006-02-15 devnull free(email);
1456 941e1713 2006-02-15 devnull sep = " ";
1457 941e1713 2006-02-15 devnull }
1458 941e1713 2006-02-15 devnull s = fmtstrflush(&fmt);
1459 941e1713 2006-02-15 devnull if(s == nil)
1460 941e1713 2006-02-15 devnull sysfatal("out of memory");
1461 941e1713 2006-02-15 devnull return s;
1462 941e1713 2006-02-15 devnull }
1463 941e1713 2006-02-15 devnull
1464 941e1713 2006-02-15 devnull static void
1465 941e1713 2006-02-15 devnull xmsgenvelope(Msg *msg, Sx *k, Sx *v)
1466 941e1713 2006-02-15 devnull {
1467 941e1713 2006-02-15 devnull hdrfree(msg->part[0]->hdr);
1468 941e1713 2006-02-15 devnull msg->part[0]->hdr = parseenvelope(v);
1469 941e1713 2006-02-15 devnull }
1470 941e1713 2006-02-15 devnull
1471 941e1713 2006-02-15 devnull static struct {
1472 941e1713 2006-02-15 devnull char *name;
1473 941e1713 2006-02-15 devnull int offset;
1474 941e1713 2006-02-15 devnull } paramtab[] = {
1475 141d6009 2006-06-30 devnull "charset", offsetof(Part, charset),
1476 141d6009 2006-06-30 devnull "name", offsetof(Part, filename)
1477 941e1713 2006-02-15 devnull };
1478 941e1713 2006-02-15 devnull
1479 941e1713 2006-02-15 devnull static void
1480 941e1713 2006-02-15 devnull parseparams(Part *part, Sx *v)
1481 941e1713 2006-02-15 devnull {
1482 941e1713 2006-02-15 devnull int i, j;
1483 941e1713 2006-02-15 devnull char *s, *t, **p;
1484 941e1713 2006-02-15 devnull
1485 941e1713 2006-02-15 devnull if(isnil(v))
1486 941e1713 2006-02-15 devnull return;
1487 941e1713 2006-02-15 devnull if(v->nsx%2){
1488 941e1713 2006-02-15 devnull warn("bad message params: %$", v);
1489 941e1713 2006-02-15 devnull return;
1490 941e1713 2006-02-15 devnull }
1491 941e1713 2006-02-15 devnull for(i=0; i<v->nsx; i+=2){
1492 941e1713 2006-02-15 devnull s = nstring(v->sx[i]);
1493 941e1713 2006-02-15 devnull t = nstring(v->sx[i+1]);
1494 941e1713 2006-02-15 devnull for(j=0; j<nelem(paramtab); j++){
1495 941e1713 2006-02-15 devnull if(cistrcmp(paramtab[j].name, s) == 0){
1496 941e1713 2006-02-15 devnull p = (char**)((char*)part+paramtab[j].offset);
1497 941e1713 2006-02-15 devnull free(*p);
1498 941e1713 2006-02-15 devnull *p = t;
1499 941e1713 2006-02-15 devnull t = nil;
1500 941e1713 2006-02-15 devnull break;
1501 941e1713 2006-02-15 devnull }
1502 941e1713 2006-02-15 devnull }
1503 941e1713 2006-02-15 devnull free(s);
1504 941e1713 2006-02-15 devnull free(t);
1505 941e1713 2006-02-15 devnull }
1506 941e1713 2006-02-15 devnull }
1507 941e1713 2006-02-15 devnull
1508 941e1713 2006-02-15 devnull static void
1509 941e1713 2006-02-15 devnull parsestructure(Part *part, Sx *v)
1510 941e1713 2006-02-15 devnull {
1511 941e1713 2006-02-15 devnull int i;
1512 941e1713 2006-02-15 devnull char *s, *t;
1513 941e1713 2006-02-15 devnull
1514 941e1713 2006-02-15 devnull if(isnil(v))
1515 941e1713 2006-02-15 devnull return;
1516 941e1713 2006-02-15 devnull if(v->type != SxList){
1517 941e1713 2006-02-15 devnull bad:
1518 941e1713 2006-02-15 devnull warn("bad structure: %$", v);
1519 941e1713 2006-02-15 devnull return;
1520 941e1713 2006-02-15 devnull }
1521 941e1713 2006-02-15 devnull if(islist(v->sx[0])){
1522 941e1713 2006-02-15 devnull /* multipart */
1523 941e1713 2006-02-15 devnull for(i=0; i<v->nsx && islist(v->sx[i]); i++)
1524 941e1713 2006-02-15 devnull parsestructure(partcreate(part->msg, part), v->sx[i]);
1525 941e1713 2006-02-15 devnull free(part->type);
1526 941e1713 2006-02-15 devnull if(i != v->nsx-1 || !isstring(v->sx[i])){
1527 941e1713 2006-02-15 devnull warn("bad multipart structure: %$", v);
1528 941e1713 2006-02-15 devnull part->type = estrdup("multipart/mixed");
1529 941e1713 2006-02-15 devnull return;
1530 941e1713 2006-02-15 devnull }
1531 941e1713 2006-02-15 devnull s = nstring(v->sx[i]);
1532 941e1713 2006-02-15 devnull strlwr(s);
1533 941e1713 2006-02-15 devnull part->type = esmprint("multipart/%s", s);
1534 941e1713 2006-02-15 devnull free(s);
1535 941e1713 2006-02-15 devnull return;
1536 941e1713 2006-02-15 devnull }
1537 941e1713 2006-02-15 devnull /* single part */
1538 941e1713 2006-02-15 devnull if(!isstring(v->sx[0]) || v->nsx < 2)
1539 941e1713 2006-02-15 devnull goto bad;
1540 941e1713 2006-02-15 devnull s = nstring(v->sx[0]);
1541 941e1713 2006-02-15 devnull t = nstring(v->sx[1]);
1542 941e1713 2006-02-15 devnull strlwr(s);
1543 941e1713 2006-02-15 devnull strlwr(t);
1544 941e1713 2006-02-15 devnull free(part->type);
1545 941e1713 2006-02-15 devnull part->type = esmprint("%s/%s", s, t);
1546 941e1713 2006-02-15 devnull if(v->nsx < 7 || !islist(v->sx[2]) || !isstring(v->sx[3])
1547 941e1713 2006-02-15 devnull || !isstring(v->sx[4]) || !isstring(v->sx[5]) || !isnumber(v->sx[6]))
1548 941e1713 2006-02-15 devnull goto bad;
1549 941e1713 2006-02-15 devnull parseparams(part, v->sx[2]);
1550 941e1713 2006-02-15 devnull part->idstr = nstring(v->sx[3]);
1551 941e1713 2006-02-15 devnull part->desc = nstring(v->sx[4]);
1552 941e1713 2006-02-15 devnull part->encoding = nstring(v->sx[5]);
1553 941e1713 2006-02-15 devnull part->size = v->sx[6]->number;
1554 941e1713 2006-02-15 devnull if(strcmp(s, "message") == 0 && strcmp(t, "rfc822") == 0){
1555 941e1713 2006-02-15 devnull if(v->nsx < 10 || !islist(v->sx[7]) || !islist(v->sx[8]) || !isnumber(v->sx[9]))
1556 941e1713 2006-02-15 devnull goto bad;
1557 941e1713 2006-02-15 devnull part->hdr = parseenvelope(v->sx[7]);
1558 941e1713 2006-02-15 devnull parsestructure(partcreate(part->msg, part), v->sx[8]);
1559 941e1713 2006-02-15 devnull part->lines = v->sx[9]->number;
1560 941e1713 2006-02-15 devnull }
1561 941e1713 2006-02-15 devnull if(strcmp(s, "text") == 0){
1562 941e1713 2006-02-15 devnull if(v->nsx < 8 || !isnumber(v->sx[7]))
1563 941e1713 2006-02-15 devnull goto bad;
1564 941e1713 2006-02-15 devnull part->lines = v->sx[7]->number;
1565 941e1713 2006-02-15 devnull }
1566 941e1713 2006-02-15 devnull }
1567 941e1713 2006-02-15 devnull
1568 941e1713 2006-02-15 devnull static void
1569 941e1713 2006-02-15 devnull xmsgbody(Msg *msg, Sx *k, Sx *v)
1570 941e1713 2006-02-15 devnull {
1571 941e1713 2006-02-15 devnull if(v->type != SxList){
1572 941e1713 2006-02-15 devnull warn("bad body: %$", v);
1573 941e1713 2006-02-15 devnull return;
1574 941e1713 2006-02-15 devnull }
1575 941e1713 2006-02-15 devnull /*
1576 941e1713 2006-02-15 devnull * To follow the structure exactly we should
1577 941e1713 2006-02-15 devnull * be doing this to partcreate(msg, msg->part[0]),
1578 941e1713 2006-02-15 devnull * and we should leave msg->part[0] with type message/rfc822,
1579 941e1713 2006-02-15 devnull * but the extra layer is redundant - what else would be in a mailbox?
1580 941e1713 2006-02-15 devnull */
1581 941e1713 2006-02-15 devnull parsestructure(msg->part[0], v);
1582 941e1713 2006-02-15 devnull if(msg->box->maxseen < msg->imapid)
1583 941e1713 2006-02-15 devnull msg->box->maxseen = msg->imapid;
1584 941e1713 2006-02-15 devnull if(msg->imapuid >= msg->box->uidnext)
1585 941e1713 2006-02-15 devnull msg->box->uidnext = msg->imapuid+1;
1586 941e1713 2006-02-15 devnull msgplumb(msg, 0);
1587 941e1713 2006-02-15 devnull }
1588 941e1713 2006-02-15 devnull
1589 941e1713 2006-02-15 devnull static void
1590 941e1713 2006-02-15 devnull xmsgbodydata(Msg *msg, Sx *k, Sx *v)
1591 941e1713 2006-02-15 devnull {
1592 941e1713 2006-02-15 devnull int i;
1593 941e1713 2006-02-15 devnull char *name, *p;
1594 941e1713 2006-02-15 devnull Part *part;
1595 941e1713 2006-02-15 devnull
1596 941e1713 2006-02-15 devnull name = k->data;
1597 941e1713 2006-02-15 devnull name += 5; /* body[ */
1598 941e1713 2006-02-15 devnull p = strchr(name, ']');
1599 941e1713 2006-02-15 devnull if(p)
1600 941e1713 2006-02-15 devnull *p = 0;
1601 941e1713 2006-02-15 devnull
1602 941e1713 2006-02-15 devnull /* now name is something like 1 or 3.2.MIME - walk down parts from root */
1603 941e1713 2006-02-15 devnull part = msg->part[0];
1604 941e1713 2006-02-15 devnull
1605 bb70a84b 2007-06-23 devnull
1606 941e1713 2006-02-15 devnull while('1' <= name[0] && name[0] <= '9'){
1607 941e1713 2006-02-15 devnull i = strtol(name, &p, 10);
1608 941e1713 2006-02-15 devnull if(*p == '.')
1609 941e1713 2006-02-15 devnull p++;
1610 941e1713 2006-02-15 devnull else if(*p != 0){
1611 941e1713 2006-02-15 devnull warn("bad body name: %$", k);
1612 941e1713 2006-02-15 devnull return;
1613 941e1713 2006-02-15 devnull }
1614 941e1713 2006-02-15 devnull if((part = subpart(part, i-1)) == nil){
1615 941e1713 2006-02-15 devnull warn("unknown body part: %$", k);
1616 941e1713 2006-02-15 devnull return;
1617 941e1713 2006-02-15 devnull }
1618 941e1713 2006-02-15 devnull name = p;
1619 941e1713 2006-02-15 devnull }
1620 941e1713 2006-02-15 devnull
1621 bb70a84b 2007-06-23 devnull
1622 941e1713 2006-02-15 devnull if(cistrcmp(name, "") == 0){
1623 941e1713 2006-02-15 devnull free(part->raw);
1624 941e1713 2006-02-15 devnull part->raw = nstring(v);
1625 941e1713 2006-02-15 devnull nocr(part->raw);
1626 941e1713 2006-02-15 devnull }else if(cistrcmp(name, "HEADER") == 0){
1627 941e1713 2006-02-15 devnull free(part->rawheader);
1628 941e1713 2006-02-15 devnull part->rawheader = nstring(v);
1629 941e1713 2006-02-15 devnull nocr(part->rawheader);
1630 941e1713 2006-02-15 devnull }else if(cistrcmp(name, "MIME") == 0){
1631 941e1713 2006-02-15 devnull free(part->mimeheader);
1632 941e1713 2006-02-15 devnull part->mimeheader = nstring(v);
1633 941e1713 2006-02-15 devnull nocr(part->mimeheader);
1634 941e1713 2006-02-15 devnull }else if(cistrcmp(name, "TEXT") == 0){
1635 941e1713 2006-02-15 devnull free(part->rawbody);
1636 941e1713 2006-02-15 devnull part->rawbody = nstring(v);
1637 941e1713 2006-02-15 devnull nocr(part->rawbody);
1638 941e1713 2006-02-15 devnull }
1639 941e1713 2006-02-15 devnull }
1640 941e1713 2006-02-15 devnull
1641 941e1713 2006-02-15 devnull /*
1642 941e1713 2006-02-15 devnull * Table-driven OK info parser.
1643 941e1713 2006-02-15 devnull */
1644 941e1713 2006-02-15 devnull static void xokuidvalidity(Imap*, Sx*);
1645 941e1713 2006-02-15 devnull static void xokpermflags(Imap*, Sx*);
1646 941e1713 2006-02-15 devnull static void xokunseen(Imap*, Sx*);
1647 941e1713 2006-02-15 devnull static void xokreadwrite(Imap*, Sx*);
1648 941e1713 2006-02-15 devnull static void xokreadonly(Imap*, Sx*);
1649 941e1713 2006-02-15 devnull
1650 941e1713 2006-02-15 devnull struct {
1651 941e1713 2006-02-15 devnull char *name;
1652 941e1713 2006-02-15 devnull char fmt;
1653 941e1713 2006-02-15 devnull void (*fn)(Imap*, Sx*);
1654 941e1713 2006-02-15 devnull } oktab[] = {
1655 941e1713 2006-02-15 devnull "UIDVALIDITY", 'N', xokuidvalidity,
1656 941e1713 2006-02-15 devnull "PERMANENTFLAGS", 'L', xokpermflags,
1657 941e1713 2006-02-15 devnull "UNSEEN", 'N', xokunseen,
1658 941e1713 2006-02-15 devnull "READ-WRITE", 0, xokreadwrite,
1659 cbeb0b26 2006-04-01 devnull "READ-ONLY", 0, xokreadonly
1660 941e1713 2006-02-15 devnull };
1661 941e1713 2006-02-15 devnull
1662 941e1713 2006-02-15 devnull static void
1663 941e1713 2006-02-15 devnull xok(Imap *z, Sx *sx)
1664 941e1713 2006-02-15 devnull {
1665 941e1713 2006-02-15 devnull int i;
1666 941e1713 2006-02-15 devnull char *name;
1667 941e1713 2006-02-15 devnull Sx *arg;
1668 941e1713 2006-02-15 devnull
1669 941e1713 2006-02-15 devnull if(sx->nsx >= 4 && sx->sx[2]->type == SxAtom && sx->sx[2]->data[0] == '['){
1670 941e1713 2006-02-15 devnull if(sx->sx[3]->type == SxAtom && sx->sx[3]->data[0] == ']')
1671 941e1713 2006-02-15 devnull arg = nil;
1672 941e1713 2006-02-15 devnull else if(sx->sx[4]->type == SxAtom && sx->sx[4]->data[0] == ']')
1673 941e1713 2006-02-15 devnull arg = sx->sx[3];
1674 941e1713 2006-02-15 devnull else{
1675 941e1713 2006-02-15 devnull warn("cannot parse OK: %$", sx);
1676 941e1713 2006-02-15 devnull return;
1677 941e1713 2006-02-15 devnull }
1678 941e1713 2006-02-15 devnull name = sx->sx[2]->data+1;
1679 941e1713 2006-02-15 devnull for(i=0; i<nelem(oktab); i++){
1680 941e1713 2006-02-15 devnull if(cistrcmp(name, oktab[i].name) == 0){
1681 941e1713 2006-02-15 devnull if(oktab[i].fmt && (arg==nil || arg->type != fmttype(oktab[i].fmt))){
1682 941e1713 2006-02-15 devnull warn("malformed %s: %$", name, arg);
1683 941e1713 2006-02-15 devnull continue;
1684 941e1713 2006-02-15 devnull }
1685 941e1713 2006-02-15 devnull oktab[i].fn(z, arg);
1686 941e1713 2006-02-15 devnull }
1687 941e1713 2006-02-15 devnull }
1688 941e1713 2006-02-15 devnull }
1689 941e1713 2006-02-15 devnull }
1690 941e1713 2006-02-15 devnull
1691 941e1713 2006-02-15 devnull static void
1692 941e1713 2006-02-15 devnull xokuidvalidity(Imap *z, Sx *sx)
1693 941e1713 2006-02-15 devnull {
1694 941e1713 2006-02-15 devnull int i;
1695 941e1713 2006-02-15 devnull Box *b;
1696 941e1713 2006-02-15 devnull
1697 941e1713 2006-02-15 devnull if((b=z->box) == nil)
1698 941e1713 2006-02-15 devnull return;
1699 941e1713 2006-02-15 devnull if(b->validity != sx->number){
1700 941e1713 2006-02-15 devnull b->validity = sx->number;
1701 941e1713 2006-02-15 devnull b->uidnext = 1;
1702 941e1713 2006-02-15 devnull for(i=0; i<b->nmsg; i++)
1703 941e1713 2006-02-15 devnull msgfree(b->msg[i]);
1704 941e1713 2006-02-15 devnull free(b->msg);
1705 941e1713 2006-02-15 devnull b->msg = nil;
1706 941e1713 2006-02-15 devnull b->nmsg = 0;
1707 941e1713 2006-02-15 devnull }
1708 941e1713 2006-02-15 devnull }
1709 941e1713 2006-02-15 devnull
1710 941e1713 2006-02-15 devnull static void
1711 941e1713 2006-02-15 devnull xokpermflags(Imap *z, Sx *sx)
1712 941e1713 2006-02-15 devnull {
1713 cbeb0b26 2006-04-01 devnull /* z->permflags = parseflags(sx); */
1714 941e1713 2006-02-15 devnull }
1715 941e1713 2006-02-15 devnull
1716 941e1713 2006-02-15 devnull static void
1717 941e1713 2006-02-15 devnull xokunseen(Imap *z, Sx *sx)
1718 941e1713 2006-02-15 devnull {
1719 cbeb0b26 2006-04-01 devnull /* z->unseen = sx->number; */
1720 941e1713 2006-02-15 devnull }
1721 941e1713 2006-02-15 devnull
1722 941e1713 2006-02-15 devnull static void
1723 941e1713 2006-02-15 devnull xokreadwrite(Imap *z, Sx *sx)
1724 941e1713 2006-02-15 devnull {
1725 cbeb0b26 2006-04-01 devnull /* z->boxmode = ORDWR; */
1726 941e1713 2006-02-15 devnull }
1727 941e1713 2006-02-15 devnull
1728 941e1713 2006-02-15 devnull static void
1729 941e1713 2006-02-15 devnull xokreadonly(Imap *z, Sx *sx)
1730 941e1713 2006-02-15 devnull {
1731 cbeb0b26 2006-04-01 devnull /* z->boxmode = OREAD; */
1732 941e1713 2006-02-15 devnull }
1733 941e1713 2006-02-15 devnull