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