Blame


1 5cdb1798 2005-10-29 devnull #include "common.h"
2 5cdb1798 2005-10-29 devnull #include <ctype.h>
3 5cdb1798 2005-10-29 devnull #include <plumb.h>
4 5cdb1798 2005-10-29 devnull #include <libsec.h>
5 5cdb1798 2005-10-29 devnull #include <auth.h>
6 5cdb1798 2005-10-29 devnull #include "dat.h"
7 5cdb1798 2005-10-29 devnull
8 5cdb1798 2005-10-29 devnull #pragma varargck argpos imap4cmd 2
9 5cdb1798 2005-10-29 devnull #pragma varargck type "Z" char*
10 5cdb1798 2005-10-29 devnull
11 5cdb1798 2005-10-29 devnull int doublequote(Fmt*);
12 5cdb1798 2005-10-29 devnull int pipeline = 1;
13 5cdb1798 2005-10-29 devnull
14 5cdb1798 2005-10-29 devnull /* static char Eio[] = "i/o error"; jpc */
15 5cdb1798 2005-10-29 devnull
16 5cdb1798 2005-10-29 devnull typedef struct Imap Imap;
17 5cdb1798 2005-10-29 devnull struct Imap {
18 cbeb0b26 2006-04-01 devnull char *freep; /* free this to free the strings below */
19 5cdb1798 2005-10-29 devnull
20 5cdb1798 2005-10-29 devnull char *host;
21 5cdb1798 2005-10-29 devnull char *user;
22 5cdb1798 2005-10-29 devnull char *mbox;
23 5cdb1798 2005-10-29 devnull
24 5cdb1798 2005-10-29 devnull int mustssl;
25 5cdb1798 2005-10-29 devnull int refreshtime;
26 5cdb1798 2005-10-29 devnull int debug;
27 5cdb1798 2005-10-29 devnull
28 5cdb1798 2005-10-29 devnull ulong tag;
29 5cdb1798 2005-10-29 devnull ulong validity;
30 5cdb1798 2005-10-29 devnull int nmsg;
31 5cdb1798 2005-10-29 devnull int size;
32 5cdb1798 2005-10-29 devnull char *base;
33 5cdb1798 2005-10-29 devnull char *data;
34 5cdb1798 2005-10-29 devnull
35 5cdb1798 2005-10-29 devnull vlong *uid;
36 5cdb1798 2005-10-29 devnull int nuid;
37 5cdb1798 2005-10-29 devnull int muid;
38 5cdb1798 2005-10-29 devnull
39 5cdb1798 2005-10-29 devnull Thumbprint *thumb;
40 5cdb1798 2005-10-29 devnull
41 cbeb0b26 2006-04-01 devnull /* open network connection */
42 5cdb1798 2005-10-29 devnull Biobuf bin;
43 5cdb1798 2005-10-29 devnull Biobuf bout;
44 5cdb1798 2005-10-29 devnull int fd;
45 5cdb1798 2005-10-29 devnull };
46 5cdb1798 2005-10-29 devnull
47 5cdb1798 2005-10-29 devnull static char*
48 5cdb1798 2005-10-29 devnull removecr(char *s)
49 5cdb1798 2005-10-29 devnull {
50 5cdb1798 2005-10-29 devnull char *r, *w;
51 5cdb1798 2005-10-29 devnull
52 5cdb1798 2005-10-29 devnull for(r=w=s; *r; r++)
53 5cdb1798 2005-10-29 devnull if(*r != '\r')
54 5cdb1798 2005-10-29 devnull *w++ = *r;
55 5cdb1798 2005-10-29 devnull *w = '\0';
56 5cdb1798 2005-10-29 devnull return s;
57 5cdb1798 2005-10-29 devnull }
58 5cdb1798 2005-10-29 devnull
59 cbeb0b26 2006-04-01 devnull /* */
60 cbeb0b26 2006-04-01 devnull /* send imap4 command */
61 cbeb0b26 2006-04-01 devnull /* */
62 5cdb1798 2005-10-29 devnull static void
63 5cdb1798 2005-10-29 devnull imap4cmd(Imap *imap, char *fmt, ...)
64 5cdb1798 2005-10-29 devnull {
65 5cdb1798 2005-10-29 devnull char buf[128], *p;
66 5cdb1798 2005-10-29 devnull va_list va;
67 5cdb1798 2005-10-29 devnull
68 5cdb1798 2005-10-29 devnull va_start(va, fmt);
69 5cdb1798 2005-10-29 devnull p = buf+sprint(buf, "9X%lud ", imap->tag);
70 5cdb1798 2005-10-29 devnull vseprint(p, buf+sizeof(buf), fmt, va);
71 5cdb1798 2005-10-29 devnull va_end(va);
72 5cdb1798 2005-10-29 devnull
73 5cdb1798 2005-10-29 devnull p = buf+strlen(buf);
74 5cdb1798 2005-10-29 devnull if(p > (buf+sizeof(buf)-3))
75 5cdb1798 2005-10-29 devnull sysfatal("imap4 command too long");
76 5cdb1798 2005-10-29 devnull
77 5cdb1798 2005-10-29 devnull if(imap->debug)
78 5cdb1798 2005-10-29 devnull fprint(2, "-> %s\n", buf);
79 5cdb1798 2005-10-29 devnull strcpy(p, "\r\n");
80 5cdb1798 2005-10-29 devnull Bwrite(&imap->bout, buf, strlen(buf));
81 5cdb1798 2005-10-29 devnull Bflush(&imap->bout);
82 5cdb1798 2005-10-29 devnull }
83 5cdb1798 2005-10-29 devnull
84 5cdb1798 2005-10-29 devnull enum {
85 5cdb1798 2005-10-29 devnull OK,
86 5cdb1798 2005-10-29 devnull NO,
87 5cdb1798 2005-10-29 devnull BAD,
88 5cdb1798 2005-10-29 devnull BYE,
89 5cdb1798 2005-10-29 devnull EXISTS,
90 5cdb1798 2005-10-29 devnull STATUS,
91 5cdb1798 2005-10-29 devnull FETCH,
92 cbeb0b26 2006-04-01 devnull UNKNOWN
93 5cdb1798 2005-10-29 devnull };
94 5cdb1798 2005-10-29 devnull
95 5cdb1798 2005-10-29 devnull static char *verblist[] = {
96 5cdb1798 2005-10-29 devnull [OK] "OK",
97 5cdb1798 2005-10-29 devnull [NO] "NO",
98 5cdb1798 2005-10-29 devnull [BAD] "BAD",
99 5cdb1798 2005-10-29 devnull [BYE] "BYE",
100 5cdb1798 2005-10-29 devnull [EXISTS] "EXISTS",
101 5cdb1798 2005-10-29 devnull [STATUS] "STATUS",
102 cbeb0b26 2006-04-01 devnull [FETCH] "FETCH"
103 5cdb1798 2005-10-29 devnull };
104 5cdb1798 2005-10-29 devnull
105 5cdb1798 2005-10-29 devnull static int
106 5cdb1798 2005-10-29 devnull verbcode(char *verb)
107 5cdb1798 2005-10-29 devnull {
108 5cdb1798 2005-10-29 devnull int i;
109 5cdb1798 2005-10-29 devnull char *q;
110 5cdb1798 2005-10-29 devnull
111 5cdb1798 2005-10-29 devnull if(q = strchr(verb, ' '))
112 5cdb1798 2005-10-29 devnull *q = '\0';
113 5cdb1798 2005-10-29 devnull
114 5cdb1798 2005-10-29 devnull for(i=0; i<nelem(verblist); i++)
115 5cdb1798 2005-10-29 devnull if(verblist[i] && strcmp(verblist[i], verb)==0){
116 5cdb1798 2005-10-29 devnull if(q)
117 5cdb1798 2005-10-29 devnull *q = ' ';
118 5cdb1798 2005-10-29 devnull return i;
119 5cdb1798 2005-10-29 devnull }
120 5cdb1798 2005-10-29 devnull if(q)
121 5cdb1798 2005-10-29 devnull *q = ' ';
122 5cdb1798 2005-10-29 devnull return UNKNOWN;
123 5cdb1798 2005-10-29 devnull }
124 5cdb1798 2005-10-29 devnull
125 5cdb1798 2005-10-29 devnull static void
126 5cdb1798 2005-10-29 devnull strupr(char *s)
127 5cdb1798 2005-10-29 devnull {
128 5cdb1798 2005-10-29 devnull for(; *s; s++)
129 5cdb1798 2005-10-29 devnull if('a' <= *s && *s <= 'z')
130 5cdb1798 2005-10-29 devnull *s += 'A'-'a';
131 5cdb1798 2005-10-29 devnull }
132 5cdb1798 2005-10-29 devnull
133 5cdb1798 2005-10-29 devnull static void
134 5cdb1798 2005-10-29 devnull imapgrow(Imap *imap, int n)
135 5cdb1798 2005-10-29 devnull {
136 5cdb1798 2005-10-29 devnull int i;
137 5cdb1798 2005-10-29 devnull
138 5cdb1798 2005-10-29 devnull if(imap->data == nil){
139 5cdb1798 2005-10-29 devnull imap->base = emalloc(n+1);
140 5cdb1798 2005-10-29 devnull imap->data = imap->base;
141 5cdb1798 2005-10-29 devnull imap->size = n+1;
142 5cdb1798 2005-10-29 devnull }
143 5cdb1798 2005-10-29 devnull if(n >= imap->size){
144 cbeb0b26 2006-04-01 devnull /* friggin microsoft - reallocate */
145 5cdb1798 2005-10-29 devnull i = imap->data - imap->base;
146 5cdb1798 2005-10-29 devnull imap->base = erealloc(imap->base, i+n+1);
147 5cdb1798 2005-10-29 devnull imap->data = imap->base + i;
148 5cdb1798 2005-10-29 devnull imap->size = n+1;
149 5cdb1798 2005-10-29 devnull }
150 5cdb1798 2005-10-29 devnull }
151 5cdb1798 2005-10-29 devnull
152 5cdb1798 2005-10-29 devnull
153 cbeb0b26 2006-04-01 devnull /* */
154 cbeb0b26 2006-04-01 devnull /* get imap4 response line. there might be various */
155 cbeb0b26 2006-04-01 devnull /* data or other informational lines mixed in. */
156 cbeb0b26 2006-04-01 devnull /* */
157 5cdb1798 2005-10-29 devnull static char*
158 5cdb1798 2005-10-29 devnull imap4resp(Imap *imap)
159 5cdb1798 2005-10-29 devnull {
160 5cdb1798 2005-10-29 devnull char *line, *p, *ep, *op, *q, *r, *en, *verb;
161 5cdb1798 2005-10-29 devnull int i, n;
162 5cdb1798 2005-10-29 devnull static char error[256];
163 5cdb1798 2005-10-29 devnull
164 5cdb1798 2005-10-29 devnull while(p = Brdline(&imap->bin, '\n')){
165 5cdb1798 2005-10-29 devnull ep = p+Blinelen(&imap->bin);
166 5cdb1798 2005-10-29 devnull while(ep > p && (ep[-1]=='\n' || ep[-1]=='\r'))
167 5cdb1798 2005-10-29 devnull *--ep = '\0';
168 5cdb1798 2005-10-29 devnull
169 5cdb1798 2005-10-29 devnull if(imap->debug)
170 5cdb1798 2005-10-29 devnull fprint(2, "<- %s\n", p);
171 5cdb1798 2005-10-29 devnull strupr(p);
172 5cdb1798 2005-10-29 devnull
173 5cdb1798 2005-10-29 devnull switch(p[0]){
174 5cdb1798 2005-10-29 devnull case '+':
175 5cdb1798 2005-10-29 devnull if(imap->tag == 0)
176 5cdb1798 2005-10-29 devnull fprint(2, "unexpected: %s\n", p);
177 5cdb1798 2005-10-29 devnull break;
178 5cdb1798 2005-10-29 devnull
179 cbeb0b26 2006-04-01 devnull /* ``unsolicited'' information; everything happens here. */
180 5cdb1798 2005-10-29 devnull case '*':
181 5cdb1798 2005-10-29 devnull if(p[1]!=' ')
182 5cdb1798 2005-10-29 devnull continue;
183 5cdb1798 2005-10-29 devnull p += 2;
184 5cdb1798 2005-10-29 devnull line = p;
185 5cdb1798 2005-10-29 devnull n = strtol(p, &p, 10);
186 5cdb1798 2005-10-29 devnull if(*p==' ')
187 5cdb1798 2005-10-29 devnull p++;
188 5cdb1798 2005-10-29 devnull verb = p;
189 5cdb1798 2005-10-29 devnull
190 5cdb1798 2005-10-29 devnull if(p = strchr(verb, ' '))
191 5cdb1798 2005-10-29 devnull p++;
192 5cdb1798 2005-10-29 devnull else
193 5cdb1798 2005-10-29 devnull p = verb+strlen(verb);
194 5cdb1798 2005-10-29 devnull
195 5cdb1798 2005-10-29 devnull switch(verbcode(verb)){
196 5cdb1798 2005-10-29 devnull case OK:
197 5cdb1798 2005-10-29 devnull case NO:
198 5cdb1798 2005-10-29 devnull case BAD:
199 cbeb0b26 2006-04-01 devnull /* human readable text at p; */
200 5cdb1798 2005-10-29 devnull break;
201 5cdb1798 2005-10-29 devnull case BYE:
202 cbeb0b26 2006-04-01 devnull /* early disconnect */
203 cbeb0b26 2006-04-01 devnull /* human readable text at p; */
204 5cdb1798 2005-10-29 devnull break;
205 5cdb1798 2005-10-29 devnull
206 cbeb0b26 2006-04-01 devnull /* * 32 EXISTS */
207 5cdb1798 2005-10-29 devnull case EXISTS:
208 5cdb1798 2005-10-29 devnull imap->nmsg = n;
209 5cdb1798 2005-10-29 devnull break;
210 5cdb1798 2005-10-29 devnull
211 cbeb0b26 2006-04-01 devnull /* * STATUS Inbox (MESSAGES 2 UIDVALIDITY 960164964) */
212 5cdb1798 2005-10-29 devnull case STATUS:
213 5cdb1798 2005-10-29 devnull if(q = strstr(p, "MESSAGES"))
214 5cdb1798 2005-10-29 devnull imap->nmsg = atoi(q+8);
215 5cdb1798 2005-10-29 devnull if(q = strstr(p, "UIDVALIDITY"))
216 5cdb1798 2005-10-29 devnull imap->validity = strtoul(q+11, 0, 10);
217 5cdb1798 2005-10-29 devnull break;
218 5cdb1798 2005-10-29 devnull
219 5cdb1798 2005-10-29 devnull case FETCH:
220 cbeb0b26 2006-04-01 devnull /* * 1 FETCH (uid 8889 RFC822.SIZE 3031 body[] {3031} */
221 cbeb0b26 2006-04-01 devnull /* <3031 bytes of data> */
222 cbeb0b26 2006-04-01 devnull /* ) */
223 5cdb1798 2005-10-29 devnull if(strstr(p, "RFC822.SIZE") && strstr(p, "BODY[]")){
224 5cdb1798 2005-10-29 devnull if((q = strchr(p, '{'))
225 5cdb1798 2005-10-29 devnull && (n=strtol(q+1, &en, 0), *en=='}')){
226 5cdb1798 2005-10-29 devnull if(imap->data == nil || n >= imap->size)
227 5cdb1798 2005-10-29 devnull imapgrow(imap, n);
228 5cdb1798 2005-10-29 devnull if((i = Bread(&imap->bin, imap->data, n)) != n){
229 5cdb1798 2005-10-29 devnull snprint(error, sizeof error,
230 5cdb1798 2005-10-29 devnull "short read %d != %d: %r\n",
231 5cdb1798 2005-10-29 devnull i, n);
232 5cdb1798 2005-10-29 devnull return error;
233 5cdb1798 2005-10-29 devnull }
234 5cdb1798 2005-10-29 devnull if(imap->debug)
235 5cdb1798 2005-10-29 devnull fprint(2, "<- read %d bytes\n", n);
236 5cdb1798 2005-10-29 devnull imap->data[n] = '\0';
237 5cdb1798 2005-10-29 devnull if(imap->debug)
238 5cdb1798 2005-10-29 devnull fprint(2, "<- %s\n", imap->data);
239 5cdb1798 2005-10-29 devnull imap->data += n;
240 5cdb1798 2005-10-29 devnull imap->size -= n;
241 5cdb1798 2005-10-29 devnull p = Brdline(&imap->bin, '\n');
242 5cdb1798 2005-10-29 devnull if(imap->debug)
243 5cdb1798 2005-10-29 devnull fprint(2, "<- ignoring %.*s\n",
244 5cdb1798 2005-10-29 devnull Blinelen(&imap->bin), p);
245 5cdb1798 2005-10-29 devnull }else if((q = strchr(p, '"')) && (r = strchr(q+1, '"'))){
246 5cdb1798 2005-10-29 devnull *r = '\0';
247 5cdb1798 2005-10-29 devnull q++;
248 5cdb1798 2005-10-29 devnull n = r-q;
249 5cdb1798 2005-10-29 devnull if(imap->data == nil || n >= imap->size)
250 5cdb1798 2005-10-29 devnull imapgrow(imap, n);
251 5cdb1798 2005-10-29 devnull memmove(imap->data, q, n);
252 5cdb1798 2005-10-29 devnull imap->data[n] = '\0';
253 5cdb1798 2005-10-29 devnull imap->data += n;
254 5cdb1798 2005-10-29 devnull imap->size -= n;
255 5cdb1798 2005-10-29 devnull }else
256 5cdb1798 2005-10-29 devnull return "confused about FETCH response";
257 5cdb1798 2005-10-29 devnull break;
258 5cdb1798 2005-10-29 devnull }
259 5cdb1798 2005-10-29 devnull
260 cbeb0b26 2006-04-01 devnull /* * 1 FETCH (UID 1 RFC822.SIZE 511) */
261 5cdb1798 2005-10-29 devnull if(q=strstr(p, "RFC822.SIZE")){
262 5cdb1798 2005-10-29 devnull imap->size = atoi(q+11);
263 5cdb1798 2005-10-29 devnull break;
264 5cdb1798 2005-10-29 devnull }
265 5cdb1798 2005-10-29 devnull
266 cbeb0b26 2006-04-01 devnull /* * 1 FETCH (UID 1 RFC822.HEADER {496} */
267 cbeb0b26 2006-04-01 devnull /* <496 bytes of data> */
268 cbeb0b26 2006-04-01 devnull /* ) */
269 cbeb0b26 2006-04-01 devnull /* * 1 FETCH (UID 1 RFC822.HEADER "data") */
270 5cdb1798 2005-10-29 devnull if(strstr(p, "RFC822.HEADER") || strstr(p, "RFC822.TEXT")){
271 5cdb1798 2005-10-29 devnull if((q = strchr(p, '{'))
272 5cdb1798 2005-10-29 devnull && (n=strtol(q+1, &en, 0), *en=='}')){
273 5cdb1798 2005-10-29 devnull if(imap->data == nil || n >= imap->size)
274 5cdb1798 2005-10-29 devnull imapgrow(imap, n);
275 5cdb1798 2005-10-29 devnull if((i = Bread(&imap->bin, imap->data, n)) != n){
276 5cdb1798 2005-10-29 devnull snprint(error, sizeof error,
277 5cdb1798 2005-10-29 devnull "short read %d != %d: %r\n",
278 5cdb1798 2005-10-29 devnull i, n);
279 5cdb1798 2005-10-29 devnull return error;
280 5cdb1798 2005-10-29 devnull }
281 5cdb1798 2005-10-29 devnull if(imap->debug)
282 5cdb1798 2005-10-29 devnull fprint(2, "<- read %d bytes\n", n);
283 5cdb1798 2005-10-29 devnull imap->data[n] = '\0';
284 5cdb1798 2005-10-29 devnull if(imap->debug)
285 5cdb1798 2005-10-29 devnull fprint(2, "<- %s\n", imap->data);
286 5cdb1798 2005-10-29 devnull imap->data += n;
287 5cdb1798 2005-10-29 devnull imap->size -= n;
288 5cdb1798 2005-10-29 devnull p = Brdline(&imap->bin, '\n');
289 5cdb1798 2005-10-29 devnull if(imap->debug)
290 5cdb1798 2005-10-29 devnull fprint(2, "<- ignoring %.*s\n",
291 5cdb1798 2005-10-29 devnull Blinelen(&imap->bin), p);
292 5cdb1798 2005-10-29 devnull }else if((q = strchr(p, '"')) && (r = strchr(q+1, '"'))){
293 5cdb1798 2005-10-29 devnull *r = '\0';
294 5cdb1798 2005-10-29 devnull q++;
295 5cdb1798 2005-10-29 devnull n = r-q;
296 5cdb1798 2005-10-29 devnull if(imap->data == nil || n >= imap->size)
297 5cdb1798 2005-10-29 devnull imapgrow(imap, n);
298 5cdb1798 2005-10-29 devnull memmove(imap->data, q, n);
299 5cdb1798 2005-10-29 devnull imap->data[n] = '\0';
300 5cdb1798 2005-10-29 devnull imap->data += n;
301 5cdb1798 2005-10-29 devnull imap->size -= n;
302 5cdb1798 2005-10-29 devnull }else
303 5cdb1798 2005-10-29 devnull return "confused about FETCH response";
304 5cdb1798 2005-10-29 devnull break;
305 5cdb1798 2005-10-29 devnull }
306 5cdb1798 2005-10-29 devnull
307 cbeb0b26 2006-04-01 devnull /* * 1 FETCH (UID 1) */
308 cbeb0b26 2006-04-01 devnull /* * 2 FETCH (UID 6) */
309 5cdb1798 2005-10-29 devnull if(q = strstr(p, "UID")){
310 5cdb1798 2005-10-29 devnull if(imap->nuid < imap->muid)
311 5cdb1798 2005-10-29 devnull imap->uid[imap->nuid++] = ((vlong)imap->validity<<32)|strtoul(q+3, nil, 10);
312 5cdb1798 2005-10-29 devnull break;
313 5cdb1798 2005-10-29 devnull }
314 5cdb1798 2005-10-29 devnull }
315 5cdb1798 2005-10-29 devnull
316 5cdb1798 2005-10-29 devnull if(imap->tag == 0)
317 5cdb1798 2005-10-29 devnull return line;
318 5cdb1798 2005-10-29 devnull break;
319 5cdb1798 2005-10-29 devnull
320 cbeb0b26 2006-04-01 devnull case '9': /* response to our message */
321 5cdb1798 2005-10-29 devnull op = p;
322 5cdb1798 2005-10-29 devnull if(p[1]=='X' && strtoul(p+2, &p, 10)==imap->tag){
323 5cdb1798 2005-10-29 devnull while(*p==' ')
324 5cdb1798 2005-10-29 devnull p++;
325 5cdb1798 2005-10-29 devnull imap->tag++;
326 5cdb1798 2005-10-29 devnull return p;
327 5cdb1798 2005-10-29 devnull }
328 5cdb1798 2005-10-29 devnull fprint(2, "expected %lud; got %s\n", imap->tag, op);
329 5cdb1798 2005-10-29 devnull break;
330 5cdb1798 2005-10-29 devnull
331 5cdb1798 2005-10-29 devnull default:
332 5cdb1798 2005-10-29 devnull if(imap->debug || *p)
333 5cdb1798 2005-10-29 devnull fprint(2, "unexpected line: %s\n", p);
334 5cdb1798 2005-10-29 devnull }
335 5cdb1798 2005-10-29 devnull }
336 5cdb1798 2005-10-29 devnull snprint(error, sizeof error, "i/o error: %r\n");
337 5cdb1798 2005-10-29 devnull return error;
338 5cdb1798 2005-10-29 devnull }
339 5cdb1798 2005-10-29 devnull
340 5cdb1798 2005-10-29 devnull static int
341 5cdb1798 2005-10-29 devnull isokay(char *resp)
342 5cdb1798 2005-10-29 devnull {
343 5cdb1798 2005-10-29 devnull return strncmp(resp, "OK", 2)==0;
344 5cdb1798 2005-10-29 devnull }
345 5cdb1798 2005-10-29 devnull
346 cbeb0b26 2006-04-01 devnull /* */
347 cbeb0b26 2006-04-01 devnull /* log in to IMAP4 server, select mailbox, no SSL at the moment */
348 cbeb0b26 2006-04-01 devnull /* */
349 5cdb1798 2005-10-29 devnull static char*
350 5cdb1798 2005-10-29 devnull imap4login(Imap *imap)
351 5cdb1798 2005-10-29 devnull {
352 5cdb1798 2005-10-29 devnull char *s;
353 5cdb1798 2005-10-29 devnull UserPasswd *up;
354 5cdb1798 2005-10-29 devnull
355 5cdb1798 2005-10-29 devnull imap->tag = 0;
356 5cdb1798 2005-10-29 devnull s = imap4resp(imap);
357 5cdb1798 2005-10-29 devnull if(!isokay(s))
358 5cdb1798 2005-10-29 devnull return "error in initial IMAP handshake";
359 5cdb1798 2005-10-29 devnull
360 5cdb1798 2005-10-29 devnull if(imap->user != nil)
361 efea318b 2005-11-28 devnull up = auth_getuserpasswd(auth_getkey, "proto=pass role=client service=imap server=%q user=%q", imap->host, imap->user);
362 5cdb1798 2005-10-29 devnull else
363 efea318b 2005-11-28 devnull up = auth_getuserpasswd(auth_getkey, "proto=pass role=client service=imap server=%q", imap->host);
364 5cdb1798 2005-10-29 devnull if(up == nil)
365 5cdb1798 2005-10-29 devnull return "cannot find IMAP password";
366 5cdb1798 2005-10-29 devnull
367 5cdb1798 2005-10-29 devnull imap->tag = 1;
368 5cdb1798 2005-10-29 devnull imap4cmd(imap, "LOGIN %Z %Z", up->user, up->passwd);
369 5cdb1798 2005-10-29 devnull free(up);
370 5cdb1798 2005-10-29 devnull if(!isokay(s = imap4resp(imap)))
371 5cdb1798 2005-10-29 devnull return s;
372 5cdb1798 2005-10-29 devnull
373 5cdb1798 2005-10-29 devnull imap4cmd(imap, "SELECT %Z", imap->mbox);
374 5cdb1798 2005-10-29 devnull if(!isokay(s = imap4resp(imap)))
375 5cdb1798 2005-10-29 devnull return s;
376 5cdb1798 2005-10-29 devnull
377 5cdb1798 2005-10-29 devnull return nil;
378 5cdb1798 2005-10-29 devnull }
379 5cdb1798 2005-10-29 devnull
380 cbeb0b26 2006-04-01 devnull /* */
381 cbeb0b26 2006-04-01 devnull /* push tls onto a connection */
382 cbeb0b26 2006-04-01 devnull /* */
383 5cdb1798 2005-10-29 devnull int
384 5cdb1798 2005-10-29 devnull mypushtls(int fd)
385 5cdb1798 2005-10-29 devnull {
386 5cdb1798 2005-10-29 devnull int p[2];
387 5cdb1798 2005-10-29 devnull char buf[10];
388 5cdb1798 2005-10-29 devnull
389 5cdb1798 2005-10-29 devnull if(pipe(p) < 0)
390 5cdb1798 2005-10-29 devnull return -1;
391 5cdb1798 2005-10-29 devnull
392 5cdb1798 2005-10-29 devnull switch(fork()){
393 5cdb1798 2005-10-29 devnull case -1:
394 5cdb1798 2005-10-29 devnull close(p[0]);
395 5cdb1798 2005-10-29 devnull close(p[1]);
396 5cdb1798 2005-10-29 devnull return -1;
397 5cdb1798 2005-10-29 devnull case 0:
398 5cdb1798 2005-10-29 devnull close(p[1]);
399 5cdb1798 2005-10-29 devnull dup(p[0], 0);
400 5cdb1798 2005-10-29 devnull dup(p[0], 1);
401 5cdb1798 2005-10-29 devnull sprint(buf, "/fd/%d", fd);
402 5cdb1798 2005-10-29 devnull execl("/bin/tlsrelay", "tlsrelay", "-f", buf, nil);
403 5cdb1798 2005-10-29 devnull _exits(nil);
404 5cdb1798 2005-10-29 devnull default:
405 5cdb1798 2005-10-29 devnull break;
406 5cdb1798 2005-10-29 devnull }
407 5cdb1798 2005-10-29 devnull close(fd);
408 5cdb1798 2005-10-29 devnull close(p[0]);
409 5cdb1798 2005-10-29 devnull return p[1];
410 5cdb1798 2005-10-29 devnull }
411 5cdb1798 2005-10-29 devnull
412 cbeb0b26 2006-04-01 devnull /* */
413 cbeb0b26 2006-04-01 devnull /* dial and handshake with the imap server */
414 cbeb0b26 2006-04-01 devnull /* */
415 5cdb1798 2005-10-29 devnull static char*
416 5cdb1798 2005-10-29 devnull imap4dial(Imap *imap)
417 5cdb1798 2005-10-29 devnull {
418 5cdb1798 2005-10-29 devnull char *err, *port;
419 5cdb1798 2005-10-29 devnull uchar digest[SHA1dlen];
420 5cdb1798 2005-10-29 devnull int sfd;
421 5cdb1798 2005-10-29 devnull TLSconn conn;
422 5cdb1798 2005-10-29 devnull
423 5cdb1798 2005-10-29 devnull if(imap->fd >= 0){
424 5cdb1798 2005-10-29 devnull imap4cmd(imap, "noop");
425 5cdb1798 2005-10-29 devnull if(isokay(imap4resp(imap)))
426 5cdb1798 2005-10-29 devnull return nil;
427 5cdb1798 2005-10-29 devnull close(imap->fd);
428 5cdb1798 2005-10-29 devnull imap->fd = -1;
429 5cdb1798 2005-10-29 devnull }
430 5cdb1798 2005-10-29 devnull
431 5cdb1798 2005-10-29 devnull if(imap->mustssl)
432 5cdb1798 2005-10-29 devnull port = "imaps";
433 5cdb1798 2005-10-29 devnull else
434 4bd43ca9 2005-11-28 devnull port = "imap";
435 5cdb1798 2005-10-29 devnull
436 5cdb1798 2005-10-29 devnull if((imap->fd = dial(netmkaddr(imap->host, "net", port), 0, 0, 0)) < 0)
437 5cdb1798 2005-10-29 devnull return geterrstr();
438 5cdb1798 2005-10-29 devnull
439 5cdb1798 2005-10-29 devnull if(imap->mustssl){
440 5cdb1798 2005-10-29 devnull memset(&conn, 0, sizeof conn);
441 5cdb1798 2005-10-29 devnull sfd = tlsClient(imap->fd, &conn);
442 5cdb1798 2005-10-29 devnull if(sfd < 0)
443 5cdb1798 2005-10-29 devnull sysfatal("tlsClient: %r");
444 5cdb1798 2005-10-29 devnull if(conn.cert==nil || conn.certlen <= 0)
445 5cdb1798 2005-10-29 devnull sysfatal("server did not provide TLS certificate");
446 5cdb1798 2005-10-29 devnull sha1(conn.cert, conn.certlen, digest, nil);
447 5cdb1798 2005-10-29 devnull if(!imap->thumb || !okThumbprint(digest, imap->thumb)){
448 5cdb1798 2005-10-29 devnull fmtinstall('H', encodefmt);
449 5cdb1798 2005-10-29 devnull sysfatal("server certificate %.*H not recognized", SHA1dlen, digest);
450 5cdb1798 2005-10-29 devnull }
451 5cdb1798 2005-10-29 devnull free(conn.cert);
452 5cdb1798 2005-10-29 devnull close(imap->fd);
453 5cdb1798 2005-10-29 devnull imap->fd = sfd;
454 5cdb1798 2005-10-29 devnull
455 5cdb1798 2005-10-29 devnull if(imap->debug){
456 5cdb1798 2005-10-29 devnull char fn[128];
457 5cdb1798 2005-10-29 devnull int fd;
458 5cdb1798 2005-10-29 devnull
459 5cdb1798 2005-10-29 devnull snprint(fn, sizeof fn, "%s/ctl", conn.dir);
460 5cdb1798 2005-10-29 devnull fd = open(fn, ORDWR);
461 5cdb1798 2005-10-29 devnull if(fd < 0)
462 5cdb1798 2005-10-29 devnull fprint(2, "opening ctl: %r\n");
463 5cdb1798 2005-10-29 devnull if(fprint(fd, "debug") < 0)
464 5cdb1798 2005-10-29 devnull fprint(2, "writing ctl: %r\n");
465 5cdb1798 2005-10-29 devnull close(fd);
466 5cdb1798 2005-10-29 devnull }
467 5cdb1798 2005-10-29 devnull }
468 5cdb1798 2005-10-29 devnull Binit(&imap->bin, imap->fd, OREAD);
469 5cdb1798 2005-10-29 devnull Binit(&imap->bout, imap->fd, OWRITE);
470 5cdb1798 2005-10-29 devnull
471 5cdb1798 2005-10-29 devnull if(err = imap4login(imap)) {
472 5cdb1798 2005-10-29 devnull close(imap->fd);
473 5cdb1798 2005-10-29 devnull return err;
474 5cdb1798 2005-10-29 devnull }
475 5cdb1798 2005-10-29 devnull
476 5cdb1798 2005-10-29 devnull return nil;
477 5cdb1798 2005-10-29 devnull }
478 5cdb1798 2005-10-29 devnull
479 cbeb0b26 2006-04-01 devnull /* */
480 cbeb0b26 2006-04-01 devnull /* close connection */
481 cbeb0b26 2006-04-01 devnull /* */
482 5cdb1798 2005-10-29 devnull #if 0 /* jpc */
483 5cdb1798 2005-10-29 devnull static void
484 5cdb1798 2005-10-29 devnull imap4hangup(Imap *imap)
485 5cdb1798 2005-10-29 devnull {
486 5cdb1798 2005-10-29 devnull imap4cmd(imap, "LOGOUT");
487 5cdb1798 2005-10-29 devnull imap4resp(imap);
488 5cdb1798 2005-10-29 devnull close(imap->fd);
489 5cdb1798 2005-10-29 devnull }
490 5cdb1798 2005-10-29 devnull #endif
491 5cdb1798 2005-10-29 devnull
492 cbeb0b26 2006-04-01 devnull /* */
493 cbeb0b26 2006-04-01 devnull /* download a single message */
494 cbeb0b26 2006-04-01 devnull /* */
495 5cdb1798 2005-10-29 devnull static char*
496 5cdb1798 2005-10-29 devnull imap4fetch(Mailbox *mb, Message *m)
497 5cdb1798 2005-10-29 devnull {
498 5cdb1798 2005-10-29 devnull int i;
499 5cdb1798 2005-10-29 devnull char *p, *s, sdigest[2*SHA1dlen+1];
500 5cdb1798 2005-10-29 devnull Imap *imap;
501 5cdb1798 2005-10-29 devnull
502 5cdb1798 2005-10-29 devnull imap = mb->aux;
503 5cdb1798 2005-10-29 devnull
504 5cdb1798 2005-10-29 devnull imap->size = 0;
505 5cdb1798 2005-10-29 devnull
506 5cdb1798 2005-10-29 devnull if(!isokay(s = imap4resp(imap)))
507 5cdb1798 2005-10-29 devnull return s;
508 5cdb1798 2005-10-29 devnull
509 5cdb1798 2005-10-29 devnull p = imap->base;
510 5cdb1798 2005-10-29 devnull if(p == nil)
511 5cdb1798 2005-10-29 devnull return "did not get message body";
512 5cdb1798 2005-10-29 devnull
513 5cdb1798 2005-10-29 devnull removecr(p);
514 5cdb1798 2005-10-29 devnull free(m->start);
515 5cdb1798 2005-10-29 devnull m->start = p;
516 5cdb1798 2005-10-29 devnull m->end = p+strlen(p);
517 5cdb1798 2005-10-29 devnull m->bend = m->rbend = m->end;
518 5cdb1798 2005-10-29 devnull m->header = m->start;
519 5cdb1798 2005-10-29 devnull
520 5cdb1798 2005-10-29 devnull imap->base = nil;
521 5cdb1798 2005-10-29 devnull imap->data = nil;
522 5cdb1798 2005-10-29 devnull
523 5cdb1798 2005-10-29 devnull parse(m, 0, mb, 1);
524 5cdb1798 2005-10-29 devnull
525 cbeb0b26 2006-04-01 devnull /* digest headers */
526 5cdb1798 2005-10-29 devnull sha1((uchar*)m->start, m->end - m->start, m->digest, nil);
527 5cdb1798 2005-10-29 devnull for(i = 0; i < SHA1dlen; i++)
528 5cdb1798 2005-10-29 devnull sprint(sdigest+2*i, "%2.2ux", m->digest[i]);
529 5cdb1798 2005-10-29 devnull m->sdigest = s_copy(sdigest);
530 5cdb1798 2005-10-29 devnull
531 5cdb1798 2005-10-29 devnull return nil;
532 5cdb1798 2005-10-29 devnull }
533 5cdb1798 2005-10-29 devnull
534 cbeb0b26 2006-04-01 devnull /* */
535 cbeb0b26 2006-04-01 devnull /* check for new messages on imap4 server */
536 cbeb0b26 2006-04-01 devnull /* download new messages, mark deleted messages */
537 cbeb0b26 2006-04-01 devnull /* */
538 5cdb1798 2005-10-29 devnull static char*
539 5cdb1798 2005-10-29 devnull imap4read(Imap *imap, Mailbox *mb, int doplumb)
540 5cdb1798 2005-10-29 devnull {
541 5cdb1798 2005-10-29 devnull char *s;
542 5cdb1798 2005-10-29 devnull int i, ignore, nnew, t;
543 5cdb1798 2005-10-29 devnull Message *m, *next, **l;
544 5cdb1798 2005-10-29 devnull
545 5cdb1798 2005-10-29 devnull imap4cmd(imap, "STATUS %Z (MESSAGES UIDVALIDITY)", imap->mbox);
546 5cdb1798 2005-10-29 devnull if(!isokay(s = imap4resp(imap)))
547 5cdb1798 2005-10-29 devnull return s;
548 5cdb1798 2005-10-29 devnull
549 5cdb1798 2005-10-29 devnull imap->nuid = 0;
550 5cdb1798 2005-10-29 devnull imap->uid = erealloc(imap->uid, imap->nmsg*sizeof(imap->uid[0]));
551 5cdb1798 2005-10-29 devnull imap->muid = imap->nmsg;
552 5cdb1798 2005-10-29 devnull
553 5cdb1798 2005-10-29 devnull if(imap->nmsg > 0){
554 5cdb1798 2005-10-29 devnull imap4cmd(imap, "UID FETCH 1:* UID");
555 5cdb1798 2005-10-29 devnull if(!isokay(s = imap4resp(imap)))
556 5cdb1798 2005-10-29 devnull return s;
557 5cdb1798 2005-10-29 devnull }
558 5cdb1798 2005-10-29 devnull
559 5cdb1798 2005-10-29 devnull l = &mb->root->part;
560 5cdb1798 2005-10-29 devnull for(i=0; i<imap->nuid; i++){
561 5cdb1798 2005-10-29 devnull ignore = 0;
562 5cdb1798 2005-10-29 devnull while(*l != nil){
563 5cdb1798 2005-10-29 devnull if((*l)->imapuid == imap->uid[i]){
564 5cdb1798 2005-10-29 devnull ignore = 1;
565 5cdb1798 2005-10-29 devnull l = &(*l)->next;
566 5cdb1798 2005-10-29 devnull break;
567 5cdb1798 2005-10-29 devnull }else{
568 cbeb0b26 2006-04-01 devnull /* old mail, we don't have it anymore */
569 5cdb1798 2005-10-29 devnull if(doplumb)
570 5cdb1798 2005-10-29 devnull mailplumb(mb, *l, 1);
571 5cdb1798 2005-10-29 devnull (*l)->inmbox = 0;
572 5cdb1798 2005-10-29 devnull (*l)->deleted = 1;
573 5cdb1798 2005-10-29 devnull l = &(*l)->next;
574 5cdb1798 2005-10-29 devnull }
575 5cdb1798 2005-10-29 devnull }
576 5cdb1798 2005-10-29 devnull if(ignore)
577 5cdb1798 2005-10-29 devnull continue;
578 5cdb1798 2005-10-29 devnull
579 cbeb0b26 2006-04-01 devnull /* new message */
580 5cdb1798 2005-10-29 devnull m = newmessage(mb->root);
581 5cdb1798 2005-10-29 devnull m->mallocd = 1;
582 5cdb1798 2005-10-29 devnull m->inmbox = 1;
583 5cdb1798 2005-10-29 devnull m->imapuid = imap->uid[i];
584 5cdb1798 2005-10-29 devnull
585 cbeb0b26 2006-04-01 devnull /* add to chain, will download soon */
586 5cdb1798 2005-10-29 devnull *l = m;
587 5cdb1798 2005-10-29 devnull l = &m->next;
588 5cdb1798 2005-10-29 devnull }
589 5cdb1798 2005-10-29 devnull
590 cbeb0b26 2006-04-01 devnull /* whatever is left at the end of the chain is gone */
591 5cdb1798 2005-10-29 devnull while(*l != nil){
592 5cdb1798 2005-10-29 devnull if(doplumb)
593 5cdb1798 2005-10-29 devnull mailplumb(mb, *l, 1);
594 5cdb1798 2005-10-29 devnull (*l)->inmbox = 0;
595 5cdb1798 2005-10-29 devnull (*l)->deleted = 1;
596 5cdb1798 2005-10-29 devnull l = &(*l)->next;
597 5cdb1798 2005-10-29 devnull }
598 5cdb1798 2005-10-29 devnull
599 cbeb0b26 2006-04-01 devnull /* download new messages */
600 5cdb1798 2005-10-29 devnull t = imap->tag;
601 5cdb1798 2005-10-29 devnull if(pipeline)
602 5cdb1798 2005-10-29 devnull switch(rfork(RFPROC|RFMEM)){
603 5cdb1798 2005-10-29 devnull case -1:
604 5cdb1798 2005-10-29 devnull sysfatal("rfork: %r");
605 5cdb1798 2005-10-29 devnull default:
606 5cdb1798 2005-10-29 devnull break;
607 5cdb1798 2005-10-29 devnull case 0:
608 5cdb1798 2005-10-29 devnull for(m = mb->root->part; m != nil; m = m->next){
609 5cdb1798 2005-10-29 devnull if(m->start != nil)
610 5cdb1798 2005-10-29 devnull continue;
611 5cdb1798 2005-10-29 devnull if(imap->debug)
612 5cdb1798 2005-10-29 devnull fprint(2, "9X%d UID FETCH %lud (UID RFC822.SIZE BODY[])\r\n",
613 5cdb1798 2005-10-29 devnull t, (ulong)m->imapuid);
614 5cdb1798 2005-10-29 devnull Bprint(&imap->bout, "9X%d UID FETCH %lud (UID RFC822.SIZE BODY[])\r\n",
615 5cdb1798 2005-10-29 devnull t++, (ulong)m->imapuid);
616 5cdb1798 2005-10-29 devnull }
617 5cdb1798 2005-10-29 devnull Bflush(&imap->bout);
618 5cdb1798 2005-10-29 devnull _exits(nil);
619 5cdb1798 2005-10-29 devnull }
620 5cdb1798 2005-10-29 devnull
621 5cdb1798 2005-10-29 devnull nnew = 0;
622 5cdb1798 2005-10-29 devnull for(m=mb->root->part; m!=nil; m=next){
623 5cdb1798 2005-10-29 devnull next = m->next;
624 5cdb1798 2005-10-29 devnull if(m->start != nil)
625 5cdb1798 2005-10-29 devnull continue;
626 5cdb1798 2005-10-29 devnull
627 5cdb1798 2005-10-29 devnull if(!pipeline){
628 5cdb1798 2005-10-29 devnull Bprint(&imap->bout, "9X%lud UID FETCH %lud (UID RFC822.SIZE BODY[])\r\n",
629 5cdb1798 2005-10-29 devnull (ulong)imap->tag, (ulong)m->imapuid);
630 5cdb1798 2005-10-29 devnull Bflush(&imap->bout);
631 5cdb1798 2005-10-29 devnull }
632 5cdb1798 2005-10-29 devnull
633 5cdb1798 2005-10-29 devnull if(s = imap4fetch(mb, m)){
634 cbeb0b26 2006-04-01 devnull /* message disappeared? unchain */
635 5cdb1798 2005-10-29 devnull fprint(2, "download %lud: %s\n", (ulong)m->imapuid, s);
636 5cdb1798 2005-10-29 devnull delmessage(mb, m);
637 5cdb1798 2005-10-29 devnull mb->root->subname--;
638 5cdb1798 2005-10-29 devnull continue;
639 5cdb1798 2005-10-29 devnull }
640 5cdb1798 2005-10-29 devnull nnew++;
641 5cdb1798 2005-10-29 devnull if(doplumb)
642 5cdb1798 2005-10-29 devnull mailplumb(mb, m, 0);
643 5cdb1798 2005-10-29 devnull }
644 5cdb1798 2005-10-29 devnull if(pipeline)
645 5cdb1798 2005-10-29 devnull waitpid();
646 5cdb1798 2005-10-29 devnull
647 5cdb1798 2005-10-29 devnull if(nnew || mb->vers == 0){
648 5cdb1798 2005-10-29 devnull mb->vers++;
649 5cdb1798 2005-10-29 devnull henter(PATH(0, Qtop), mb->name,
650 5cdb1798 2005-10-29 devnull (Qid){PATH(mb->id, Qmbox), mb->vers, QTDIR}, nil, mb);
651 5cdb1798 2005-10-29 devnull }
652 5cdb1798 2005-10-29 devnull return nil;
653 5cdb1798 2005-10-29 devnull }
654 5cdb1798 2005-10-29 devnull
655 cbeb0b26 2006-04-01 devnull /* */
656 cbeb0b26 2006-04-01 devnull /* sync mailbox */
657 cbeb0b26 2006-04-01 devnull /* */
658 5cdb1798 2005-10-29 devnull static void
659 5cdb1798 2005-10-29 devnull imap4purge(Imap *imap, Mailbox *mb)
660 5cdb1798 2005-10-29 devnull {
661 5cdb1798 2005-10-29 devnull int ndel;
662 5cdb1798 2005-10-29 devnull Message *m, *next;
663 5cdb1798 2005-10-29 devnull
664 5cdb1798 2005-10-29 devnull ndel = 0;
665 5cdb1798 2005-10-29 devnull for(m=mb->root->part; m!=nil; m=next){
666 5cdb1798 2005-10-29 devnull next = m->next;
667 5cdb1798 2005-10-29 devnull if(m->deleted && m->refs==0){
668 5cdb1798 2005-10-29 devnull if(m->inmbox && (ulong)(m->imapuid>>32)==imap->validity){
669 5cdb1798 2005-10-29 devnull imap4cmd(imap, "UID STORE %lud +FLAGS (\\Deleted)", (ulong)m->imapuid);
670 5cdb1798 2005-10-29 devnull if(isokay(imap4resp(imap))){
671 5cdb1798 2005-10-29 devnull ndel++;
672 5cdb1798 2005-10-29 devnull delmessage(mb, m);
673 5cdb1798 2005-10-29 devnull }
674 5cdb1798 2005-10-29 devnull }else
675 5cdb1798 2005-10-29 devnull delmessage(mb, m);
676 5cdb1798 2005-10-29 devnull }
677 5cdb1798 2005-10-29 devnull }
678 5cdb1798 2005-10-29 devnull
679 5cdb1798 2005-10-29 devnull if(ndel){
680 5cdb1798 2005-10-29 devnull imap4cmd(imap, "EXPUNGE");
681 5cdb1798 2005-10-29 devnull imap4resp(imap);
682 5cdb1798 2005-10-29 devnull }
683 5cdb1798 2005-10-29 devnull }
684 5cdb1798 2005-10-29 devnull
685 cbeb0b26 2006-04-01 devnull /* */
686 cbeb0b26 2006-04-01 devnull /* connect to imap4 server, sync mailbox */
687 cbeb0b26 2006-04-01 devnull /* */
688 5cdb1798 2005-10-29 devnull static char*
689 5cdb1798 2005-10-29 devnull imap4sync(Mailbox *mb, int doplumb)
690 5cdb1798 2005-10-29 devnull {
691 5cdb1798 2005-10-29 devnull char *err;
692 5cdb1798 2005-10-29 devnull Imap *imap;
693 5cdb1798 2005-10-29 devnull
694 5cdb1798 2005-10-29 devnull imap = mb->aux;
695 5cdb1798 2005-10-29 devnull
696 5cdb1798 2005-10-29 devnull if(err = imap4dial(imap)){
697 5cdb1798 2005-10-29 devnull mb->waketime = time(0) + imap->refreshtime;
698 5cdb1798 2005-10-29 devnull return err;
699 5cdb1798 2005-10-29 devnull }
700 5cdb1798 2005-10-29 devnull
701 5cdb1798 2005-10-29 devnull if((err = imap4read(imap, mb, doplumb)) == nil){
702 5cdb1798 2005-10-29 devnull imap4purge(imap, mb);
703 5cdb1798 2005-10-29 devnull mb->d->atime = mb->d->mtime = time(0);
704 5cdb1798 2005-10-29 devnull }
705 5cdb1798 2005-10-29 devnull /*
706 5cdb1798 2005-10-29 devnull * don't hang up; leave connection open for next time.
707 5cdb1798 2005-10-29 devnull */
708 cbeb0b26 2006-04-01 devnull /* imap4hangup(imap); */
709 5cdb1798 2005-10-29 devnull mb->waketime = time(0) + imap->refreshtime;
710 5cdb1798 2005-10-29 devnull return err;
711 5cdb1798 2005-10-29 devnull }
712 5cdb1798 2005-10-29 devnull
713 5cdb1798 2005-10-29 devnull static char Eimap4ctl[] = "bad imap4 control message";
714 5cdb1798 2005-10-29 devnull
715 5cdb1798 2005-10-29 devnull static char*
716 5cdb1798 2005-10-29 devnull imap4ctl(Mailbox *mb, int argc, char **argv)
717 5cdb1798 2005-10-29 devnull {
718 5cdb1798 2005-10-29 devnull int n;
719 5cdb1798 2005-10-29 devnull Imap *imap;
720 5cdb1798 2005-10-29 devnull
721 5cdb1798 2005-10-29 devnull imap = mb->aux;
722 5cdb1798 2005-10-29 devnull if(argc < 1)
723 5cdb1798 2005-10-29 devnull return Eimap4ctl;
724 5cdb1798 2005-10-29 devnull
725 5cdb1798 2005-10-29 devnull if(argc==1 && strcmp(argv[0], "debug")==0){
726 5cdb1798 2005-10-29 devnull imap->debug = 1;
727 5cdb1798 2005-10-29 devnull return nil;
728 5cdb1798 2005-10-29 devnull }
729 5cdb1798 2005-10-29 devnull
730 5cdb1798 2005-10-29 devnull if(argc==1 && strcmp(argv[0], "nodebug")==0){
731 5cdb1798 2005-10-29 devnull imap->debug = 0;
732 5cdb1798 2005-10-29 devnull return nil;
733 5cdb1798 2005-10-29 devnull }
734 5cdb1798 2005-10-29 devnull
735 5cdb1798 2005-10-29 devnull if(argc==1 && strcmp(argv[0], "thumbprint")==0){
736 5cdb1798 2005-10-29 devnull if(imap->thumb)
737 5cdb1798 2005-10-29 devnull freeThumbprints(imap->thumb);
738 5cdb1798 2005-10-29 devnull imap->thumb = initThumbprints("/sys/lib/tls/mail", "/sys/lib/tls/mail.exclude");
739 5cdb1798 2005-10-29 devnull }
740 5cdb1798 2005-10-29 devnull if(strcmp(argv[0], "refresh")==0){
741 5cdb1798 2005-10-29 devnull if(argc==1){
742 5cdb1798 2005-10-29 devnull imap->refreshtime = 60;
743 5cdb1798 2005-10-29 devnull return nil;
744 5cdb1798 2005-10-29 devnull }
745 5cdb1798 2005-10-29 devnull if(argc==2){
746 5cdb1798 2005-10-29 devnull n = atoi(argv[1]);
747 5cdb1798 2005-10-29 devnull if(n < 15)
748 5cdb1798 2005-10-29 devnull return Eimap4ctl;
749 5cdb1798 2005-10-29 devnull imap->refreshtime = n;
750 5cdb1798 2005-10-29 devnull return nil;
751 5cdb1798 2005-10-29 devnull }
752 5cdb1798 2005-10-29 devnull }
753 5cdb1798 2005-10-29 devnull
754 5cdb1798 2005-10-29 devnull return Eimap4ctl;
755 5cdb1798 2005-10-29 devnull }
756 5cdb1798 2005-10-29 devnull
757 cbeb0b26 2006-04-01 devnull /* */
758 cbeb0b26 2006-04-01 devnull /* free extra memory associated with mb */
759 cbeb0b26 2006-04-01 devnull /* */
760 5cdb1798 2005-10-29 devnull static void
761 5cdb1798 2005-10-29 devnull imap4close(Mailbox *mb)
762 5cdb1798 2005-10-29 devnull {
763 5cdb1798 2005-10-29 devnull Imap *imap;
764 5cdb1798 2005-10-29 devnull
765 5cdb1798 2005-10-29 devnull imap = mb->aux;
766 5cdb1798 2005-10-29 devnull free(imap->freep);
767 5cdb1798 2005-10-29 devnull free(imap->base);
768 5cdb1798 2005-10-29 devnull free(imap->uid);
769 5cdb1798 2005-10-29 devnull if(imap->fd >= 0)
770 5cdb1798 2005-10-29 devnull close(imap->fd);
771 5cdb1798 2005-10-29 devnull free(imap);
772 5cdb1798 2005-10-29 devnull }
773 5cdb1798 2005-10-29 devnull
774 cbeb0b26 2006-04-01 devnull /* */
775 cbeb0b26 2006-04-01 devnull /* open mailboxes of the form /imap/host/user */
776 cbeb0b26 2006-04-01 devnull /* */
777 5cdb1798 2005-10-29 devnull char*
778 5cdb1798 2005-10-29 devnull imap4mbox(Mailbox *mb, char *path)
779 5cdb1798 2005-10-29 devnull {
780 5cdb1798 2005-10-29 devnull char *f[10];
781 5cdb1798 2005-10-29 devnull int mustssl, nf;
782 5cdb1798 2005-10-29 devnull Imap *imap;
783 5cdb1798 2005-10-29 devnull
784 5cdb1798 2005-10-29 devnull quotefmtinstall();
785 5cdb1798 2005-10-29 devnull fmtinstall('Z', doublequote);
786 5cdb1798 2005-10-29 devnull if(strncmp(path, "/imap/", 6) != 0 && strncmp(path, "/imaps/", 7) != 0)
787 5cdb1798 2005-10-29 devnull return Enotme;
788 5cdb1798 2005-10-29 devnull mustssl = (strncmp(path, "/imaps/", 7) == 0);
789 5cdb1798 2005-10-29 devnull
790 5cdb1798 2005-10-29 devnull path = strdup(path);
791 5cdb1798 2005-10-29 devnull if(path == nil)
792 5cdb1798 2005-10-29 devnull return "out of memory";
793 5cdb1798 2005-10-29 devnull
794 5cdb1798 2005-10-29 devnull nf = getfields(path, f, 5, 0, "/");
795 5cdb1798 2005-10-29 devnull if(nf < 3){
796 5cdb1798 2005-10-29 devnull free(path);
797 5cdb1798 2005-10-29 devnull return "bad imap path syntax /imap[s]/system[/user[/mailbox]]";
798 5cdb1798 2005-10-29 devnull }
799 5cdb1798 2005-10-29 devnull
800 5cdb1798 2005-10-29 devnull imap = emalloc(sizeof(*imap));
801 5cdb1798 2005-10-29 devnull imap->fd = -1;
802 5cdb1798 2005-10-29 devnull imap->debug = debug;
803 5cdb1798 2005-10-29 devnull imap->freep = path;
804 5cdb1798 2005-10-29 devnull imap->mustssl = mustssl;
805 5cdb1798 2005-10-29 devnull imap->host = f[2];
806 5cdb1798 2005-10-29 devnull if(nf < 4)
807 5cdb1798 2005-10-29 devnull imap->user = nil;
808 5cdb1798 2005-10-29 devnull else
809 5cdb1798 2005-10-29 devnull imap->user = f[3];
810 5cdb1798 2005-10-29 devnull if(nf < 5)
811 5cdb1798 2005-10-29 devnull imap->mbox = "Inbox";
812 5cdb1798 2005-10-29 devnull else
813 5cdb1798 2005-10-29 devnull imap->mbox = f[4];
814 5cdb1798 2005-10-29 devnull imap->thumb = initThumbprints("/sys/lib/tls/mail", "/sys/lib/tls/mail.exclude");
815 5cdb1798 2005-10-29 devnull
816 5cdb1798 2005-10-29 devnull mb->aux = imap;
817 5cdb1798 2005-10-29 devnull mb->sync = imap4sync;
818 5cdb1798 2005-10-29 devnull mb->close = imap4close;
819 5cdb1798 2005-10-29 devnull mb->ctl = imap4ctl;
820 5cdb1798 2005-10-29 devnull mb->d = emalloc(sizeof(*mb->d));
821 cbeb0b26 2006-04-01 devnull /*mb->fetch = imap4fetch; */
822 5cdb1798 2005-10-29 devnull
823 5cdb1798 2005-10-29 devnull return nil;
824 5cdb1798 2005-10-29 devnull }
825 5cdb1798 2005-10-29 devnull
826 cbeb0b26 2006-04-01 devnull /* */
827 cbeb0b26 2006-04-01 devnull /* Formatter for %" */
828 cbeb0b26 2006-04-01 devnull /* Use double quotes to protect white space, frogs, \ and " */
829 cbeb0b26 2006-04-01 devnull /* */
830 5cdb1798 2005-10-29 devnull enum
831 5cdb1798 2005-10-29 devnull {
832 5cdb1798 2005-10-29 devnull Qok = 0,
833 5cdb1798 2005-10-29 devnull Qquote,
834 cbeb0b26 2006-04-01 devnull Qbackslash
835 5cdb1798 2005-10-29 devnull };
836 5cdb1798 2005-10-29 devnull
837 5cdb1798 2005-10-29 devnull static int
838 5cdb1798 2005-10-29 devnull needtoquote(Rune r)
839 5cdb1798 2005-10-29 devnull {
840 5cdb1798 2005-10-29 devnull if(r >= Runeself)
841 5cdb1798 2005-10-29 devnull return Qquote;
842 5cdb1798 2005-10-29 devnull if(r <= ' ')
843 5cdb1798 2005-10-29 devnull return Qquote;
844 5cdb1798 2005-10-29 devnull if(r=='\\' || r=='"')
845 5cdb1798 2005-10-29 devnull return Qbackslash;
846 5cdb1798 2005-10-29 devnull return Qok;
847 5cdb1798 2005-10-29 devnull }
848 5cdb1798 2005-10-29 devnull
849 5cdb1798 2005-10-29 devnull int
850 5cdb1798 2005-10-29 devnull doublequote(Fmt *f)
851 5cdb1798 2005-10-29 devnull {
852 5cdb1798 2005-10-29 devnull char *s, *t;
853 5cdb1798 2005-10-29 devnull int w, quotes;
854 5cdb1798 2005-10-29 devnull Rune r;
855 5cdb1798 2005-10-29 devnull
856 5cdb1798 2005-10-29 devnull s = va_arg(f->args, char*);
857 5cdb1798 2005-10-29 devnull if(s == nil || *s == '\0')
858 5cdb1798 2005-10-29 devnull return fmtstrcpy(f, "\"\"");
859 5cdb1798 2005-10-29 devnull
860 5cdb1798 2005-10-29 devnull quotes = 0;
861 5cdb1798 2005-10-29 devnull for(t=s; *t; t+=w){
862 5cdb1798 2005-10-29 devnull w = chartorune(&r, t);
863 5cdb1798 2005-10-29 devnull quotes |= needtoquote(r);
864 5cdb1798 2005-10-29 devnull }
865 5cdb1798 2005-10-29 devnull if(quotes == 0)
866 5cdb1798 2005-10-29 devnull return fmtstrcpy(f, s);
867 5cdb1798 2005-10-29 devnull
868 5cdb1798 2005-10-29 devnull fmtrune(f, '"');
869 5cdb1798 2005-10-29 devnull for(t=s; *t; t+=w){
870 5cdb1798 2005-10-29 devnull w = chartorune(&r, t);
871 5cdb1798 2005-10-29 devnull if(needtoquote(r) == Qbackslash)
872 5cdb1798 2005-10-29 devnull fmtrune(f, '\\');
873 5cdb1798 2005-10-29 devnull fmtrune(f, r);
874 5cdb1798 2005-10-29 devnull }
875 5cdb1798 2005-10-29 devnull return fmtrune(f, '"');
876 5cdb1798 2005-10-29 devnull }