/[imapfilter]/imapfilter/response.c
ViewVC logotype

Annotation of /imapfilter/response.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.32 - (hide annotations)
Fri Feb 21 18:54:18 2003 UTC (21 years, 1 month ago) by lefcha
Branch: MAIN
Changes since 1.31: +2 -1 lines
File MIME type: text/plain
Fix network bug when server aborts connection.

1 lefcha 1.1 #include <stdio.h>
2     #include <unistd.h>
3     #include <stdlib.h>
4 lefcha 1.9 #include <ctype.h>
5 lefcha 1.4 #include <errno.h>
6 lefcha 1.1 #include <string.h>
7     #include <sys/time.h>
8     #include <sys/types.h>
9     #include <regex.h>
10 lefcha 1.26 #include <setjmp.h>
11 lefcha 1.1
12     #include "config.h"
13     #include "imapfilter.h"
14    
15    
16 lefcha 1.20 extern int sockpri;
17 lefcha 1.18 extern unsigned int capabilities;
18 lefcha 1.31 extern char authmech[AUTH_MECH_LEN];
19 lefcha 1.26 extern jmp_buf acctloop;
20 lefcha 1.1
21 lefcha 1.20 static char *vbuf = NULL; /* Virtual buffer. */
22     static size_t vbufs = 0; /* Virtual buffer size. */
23    
24 lefcha 1.1
25     /*
26 lefcha 1.14 * Read one packet of data that the server sent.
27 lefcha 1.1 */
28 lefcha 1.20 void receive_response(int *sock, char *buf)
29 lefcha 1.1 {
30 lefcha 1.32 if (socket_read(sock, buf) == ERROR_NETWORK)
31     longjmp(acctloop, -1);
32 lefcha 1.1
33     #ifdef DEBUG
34 lefcha 1.31 fprintf(stderr, "\n%s\n", buf);
35 lefcha 1.1 #endif
36 lefcha 1.11
37 lefcha 1.1 }
38    
39    
40     /*
41     * Get server response to client's request.
42     */
43 lefcha 1.20 int server_response(int *sock, unsigned int tag)
44 lefcha 1.1 {
45 lefcha 1.14 char buf[RESPONSE_BUF];
46 lefcha 1.6
47 lefcha 1.20 reset_vbuf();
48 lefcha 1.21
49 lefcha 1.20 do {
50     receive_response(sock, buf);
51 lefcha 1.26 bye_response(buf);
52 lefcha 1.20 check_vbuf(strlen(buf));
53     strncat(vbuf, buf, vbufs - strlen(vbuf));
54     } while (tag && !strcasestr(buf, ultostr(tag, 16)));
55 lefcha 1.6
56 lefcha 1.14 return analyze_response(buf);
57 lefcha 1.1 }
58    
59    
60     /*
61 lefcha 1.26 * Check if server sent a BYE response (connection is closed immediately).
62     */
63     void bye_response(char *buf)
64     {
65     if (strcasestr(buf, "* BYE"))
66     longjmp(acctloop, -1);
67     }
68    
69    
70     /*
71 lefcha 1.9 * Process the greeting that server sends during connection.
72     */
73 lefcha 1.20 int greeting_response(int *sock)
74 lefcha 1.9 {
75 lefcha 1.14 char buf[RESPONSE_BUF];
76 lefcha 1.9
77 lefcha 1.20 receive_response(sock, buf);
78 lefcha 1.26 bye_response(buf);
79 lefcha 1.9
80 lefcha 1.26 if (strcasestr(buf, "* PREAUTH"))
81 lefcha 1.14 return RESPONSE_PREAUTH;
82 lefcha 1.9
83     return RESPONSE_OK;
84     }
85    
86 lefcha 1.13
87 lefcha 1.9 /*
88 lefcha 1.25 * Process the data that server sent due to IMAP LOGOUT client request.
89     */
90     int logout_response(int *sock, unsigned int tag)
91     {
92     char buf[RESPONSE_BUF];
93    
94     reset_vbuf();
95    
96     do {
97     receive_response(sock, buf);
98     check_vbuf(strlen(buf));
99     strncat(vbuf, buf, vbufs - strlen(vbuf));
100     } while (!strcasestr(buf, ultostr(tag, 16)));
101    
102     return analyze_response(buf);
103     }
104    
105    
106     /*
107 lefcha 1.9 * Process the data that server sent due to IMAP CAPABILITY client request.
108     */
109 lefcha 1.20 int capability_response(int *sock, unsigned int tag)
110 lefcha 1.9 {
111 lefcha 1.14 char buf[RESPONSE_BUF];
112 lefcha 1.21
113 lefcha 1.20 reset_vbuf();
114 lefcha 1.9
115 lefcha 1.20 do {
116 lefcha 1.21 receive_response(sock, buf);
117 lefcha 1.26 bye_response(buf);
118 lefcha 1.20 check_vbuf(strlen(buf));
119     strncat(vbuf, buf, vbufs - strlen(vbuf));
120     } while (!strcasestr(buf, ultostr(tag, 16)));
121 lefcha 1.9
122 lefcha 1.20 if (!strcasestr(vbuf, "IMAP4rev1")) {
123 lefcha 1.9 error("imapfilter: server does not support IMAP4rev1 protocol\n");
124     return -2;
125     }
126 lefcha 1.20 if (strcasestr(vbuf, "NAMESPACE"))
127 lefcha 1.18 capabilities |= CAPABILITY_NAMESPACE;
128    
129 lefcha 1.31 auth_mechanisms();
130    
131 lefcha 1.18 return analyze_response(buf);
132     }
133    
134    
135     /*
136 lefcha 1.31 * Create the list of available authentication mechanisms.
137     */
138     void auth_mechanisms(void)
139     {
140     int len;
141     char *c, *cp, *tok;
142    
143     *authmech = 0;
144    
145     c = cp = xstrdup(vbuf);
146    
147     tok = strtok_r(c, " \r\n", &c);
148     while(tok) {
149     if (strcasestr(tok, "AUTH=")) {
150     strncat(authmech, tok + 5, AUTH_MECH_LEN - strlen(authmech) - 2);
151     len = strlen(authmech);
152     *(authmech + len) = ' ';
153     *(authmech + len + 1) = 0;
154     }
155     tok = strtok_r(NULL, " \r\n", &c);
156     }
157     if ((len = strlen(authmech)))
158     *(authmech + strlen(authmech) - 1) = 0;
159    
160     xfree(cp);
161    
162     #ifdef DEBUG
163     fprintf(stderr, "debug: authentication mechanisms: '%s'\n", authmech);
164     #endif
165    
166     }
167    
168    
169     /*
170 lefcha 1.18 * Process the data that server sent due to IMAP NAMESPACE client request.
171     */
172 lefcha 1.21 int namespace_response(int *sock, unsigned int tag, namesp_t * nsp)
173 lefcha 1.18 {
174     char buf[RESPONSE_BUF];
175     char *c, *d;
176    
177 lefcha 1.20 reset_vbuf();
178 lefcha 1.21
179 lefcha 1.20 do {
180 lefcha 1.24 receive_response(sock, buf);
181 lefcha 1.26 bye_response(buf);
182 lefcha 1.20 check_vbuf(strlen(buf));
183 lefcha 1.21 strncat(vbuf, buf, vbufs - strlen(vbuf));
184 lefcha 1.20 } while (!strcasestr(buf, ultostr(tag, 16)));
185 lefcha 1.18
186 lefcha 1.20 if ((c = strcasestr(vbuf, "* NAMESPACE"))) {
187 lefcha 1.18 c += 12;
188     if (strncasecmp(c, "NIL", 3)) {
189     c = strchr(c, '"') + 1;
190     d = strchr(c, '"') + 1;
191    
192 lefcha 1.20 strncat(nsp->prefix, c, d - c - 1);
193     nsp->delim = *(strchr(d, '"') + 1);
194 lefcha 1.18 }
195     }
196 lefcha 1.20 #ifdef DEBUG
197 lefcha 1.31 fprintf(stderr, "debug: namespace: '%s' '%c'\n", nsp->prefix, nsp->delim);
198 lefcha 1.20 #endif
199 lefcha 1.14 return analyze_response(buf);
200 lefcha 1.9 }
201    
202    
203     /*
204 lefcha 1.3 * Process the data that server sent due to IMAP STATUS client request.
205 lefcha 1.1 */
206 lefcha 1.20 int status_response(int *sock, unsigned int tag, char *mbox)
207 lefcha 1.1 {
208 lefcha 1.17 int r;
209 lefcha 1.14 char buf[RESPONSE_BUF];
210 lefcha 1.1 unsigned int exist, recent, unseen;
211 lefcha 1.9 char *c;
212 lefcha 1.1
213     exist = recent = unseen = 0;
214 lefcha 1.21
215 lefcha 1.20 reset_vbuf();
216 lefcha 1.1
217 lefcha 1.20 do {
218     receive_response(sock, buf);
219 lefcha 1.26 bye_response(buf);
220 lefcha 1.20 check_vbuf(strlen(buf));
221     strncat(vbuf, buf, vbufs - strlen(vbuf));
222     } while (!strcasestr(buf, ultostr(tag, 16)));
223 lefcha 1.13
224 lefcha 1.17 r = analyze_response(buf);
225    
226     if (r == RESPONSE_NO)
227     return -2;
228    
229 lefcha 1.20 if ((c = strcasestr(vbuf, "MESSAGES"))) {
230 lefcha 1.9 c += 9;
231     exist = strtoul(c, NULL, 10);
232     }
233 lefcha 1.20 if ((c = strcasestr(vbuf, "RECENT"))) {
234 lefcha 1.9 c += 7;
235     recent = strtoul(c, NULL, 10);
236     }
237 lefcha 1.20 if ((c = strcasestr(vbuf, "UNSEEN"))) {
238 lefcha 1.9 c += 7;
239     unseen = strtoul(c, NULL, 10);
240     }
241 lefcha 1.8 if (!exist) {
242 lefcha 1.19 info("No messages in mailbox \"%s\".\n", mbox);
243 lefcha 1.8 return -2;
244     }
245 lefcha 1.19 info("%d message%s, %d recent, %d unseen, in mailbox \"%s\".\n", exist,
246 lefcha 1.18 plural(exist), recent, unseen, mbox);
247 lefcha 1.9
248 lefcha 1.17 return r;
249 lefcha 1.9 }
250    
251    
252     /*
253     * Process the data that server sent due to IMAP SELECT client request.
254     */
255 lefcha 1.20 int select_response(int *sock, unsigned int tag)
256 lefcha 1.9 {
257 lefcha 1.14 char buf[RESPONSE_BUF];
258 lefcha 1.9
259 lefcha 1.20 reset_vbuf();
260 lefcha 1.21
261 lefcha 1.20 do {
262     receive_response(sock, buf);
263 lefcha 1.26 bye_response(buf);
264 lefcha 1.20 check_vbuf(strlen(buf));
265     strncat(vbuf, buf, vbufs - strlen(vbuf));
266     } while (!strcasestr(buf, ultostr(tag, 16)));
267 lefcha 1.9
268 lefcha 1.20 if (strcasestr(vbuf, "[READ-ONLY]"))
269 lefcha 1.9 return RESPONSE_READONLY;
270 lefcha 1.1
271 lefcha 1.14 return analyze_response(buf);
272 lefcha 1.1 }
273    
274    
275     /*
276 lefcha 1.3 * Process the data that server sent due to IMAP SEARCH client request.
277 lefcha 1.1 */
278 lefcha 1.20 int search_response(int *sock, unsigned int tag, char **mesgs)
279 lefcha 1.1 {
280 lefcha 1.14 char buf[RESPONSE_BUF];
281 lefcha 1.13 char *c, *m;
282 lefcha 1.20 unsigned int blen;
283 lefcha 1.13
284 lefcha 1.20 reset_vbuf();
285 lefcha 1.21
286 lefcha 1.20 do {
287     receive_response(sock, buf);
288 lefcha 1.26 bye_response(buf);
289 lefcha 1.20 check_vbuf(strlen(buf));
290     strncat(vbuf, buf, vbufs - strlen(vbuf));
291     } while (!strcasestr(buf, ultostr(tag, 16)));
292 lefcha 1.1
293 lefcha 1.20 if ((c = strcasestr(vbuf, "* SEARCH "))) {
294     blen = strlen(vbuf);
295 lefcha 1.21
296     m = *mesgs = (char *)xmalloc(blen + 1);
297    
298 lefcha 1.20 c += 9;
299 lefcha 1.21
300 lefcha 1.25 while (*c && (isdigit((unsigned char)(*c)) || *c == ' '))
301 lefcha 1.20 *(m++) = *(c++);
302 lefcha 1.14
303 lefcha 1.20 *m = 0;
304     }
305 lefcha 1.14 return analyze_response(buf);
306 lefcha 1.1 }
307    
308    
309     /*
310 lefcha 1.3 * Process the data that server sent due to IMAP FETCH client request.
311 lefcha 1.1 */
312 lefcha 1.28 int fetch_response(int *sock, unsigned int tag, int reset, char *fetch)
313 lefcha 1.1 {
314 lefcha 1.14 char buf[RESPONSE_BUF];
315 lefcha 1.20 unsigned int i;
316     static unsigned int s;
317 lefcha 1.15 char *b;
318 lefcha 1.14
319 lefcha 1.20 if (reset) {
320     s = 0;
321     return 0;
322     }
323     i = 0;
324    
325 lefcha 1.28 reset_vbuf();
326 lefcha 1.20
327 lefcha 1.28 do {
328     receive_response(sock, buf);
329     bye_response(buf);
330     check_vbuf(strlen(buf));
331     strncat(vbuf, buf, vbufs - strlen(vbuf));
332     } while (strlen(vbuf) < RESPONSE_BUF &&
333     !strcasestr(buf, ultostr(tag, 16)));
334 lefcha 1.21
335 lefcha 1.28 b = vbuf;
336    
337 lefcha 1.29 if (!s) {
338     if ((b = strstr(b, "}\r\n"))) {
339     while (b - vbuf > 0)
340     if (*--b == '{')
341     break;
342     s = atoi(++b) - 2;
343     b = strchr(b, '}');
344     b += 3;
345     } else {
346 lefcha 1.30 return RESPONSE_NULLBODY; /* Null body. */
347 lefcha 1.29 }
348 lefcha 1.20 }
349     while (*b && s--)
350     fetch[i++] = *(b++);
351    
352     fetch[i] = 0;
353 lefcha 1.21
354 lefcha 1.20 return analyze_response(buf);
355     }
356    
357 lefcha 1.6
358 lefcha 1.20 /*
359     * Process the data that server sent due to IMAP FETCH RFC822.SIZE client
360     * request.
361     */
362     int fetchsize_response(int *sock, unsigned int *size, unsigned int tag)
363     {
364     char buf[RESPONSE_BUF];
365     char *c;
366 lefcha 1.21
367 lefcha 1.20 *size = 0;
368 lefcha 1.21
369 lefcha 1.20 reset_vbuf();
370 lefcha 1.21
371 lefcha 1.13 do {
372 lefcha 1.20 receive_response(sock, buf);
373 lefcha 1.26 bye_response(buf);
374 lefcha 1.20 check_vbuf(strlen(buf));
375     strncat(vbuf, buf, vbufs - strlen(vbuf));
376     } while (!strcasestr(buf, ultostr(tag, 16)));
377 lefcha 1.21
378 lefcha 1.20 if ((c = strcasestr(vbuf, "FETCH (RFC822.SIZE "))) {
379     c += 19;
380     *size = strtoul(c, NULL, 10);
381     }
382     return analyze_response(buf);
383     }
384 lefcha 1.13
385 lefcha 1.6
386 lefcha 1.20 /*
387     * Process the data that server sent due to IMAP APPEND client request.
388     */
389     int append_response(int *sock, unsigned int tag)
390     {
391     int r = RESPONSE_OK;
392     char buf[RESPONSE_BUF];
393 lefcha 1.21
394 lefcha 1.20 reset_vbuf();
395 lefcha 1.21
396 lefcha 1.20 do {
397     receive_response(sock, buf);
398 lefcha 1.26 bye_response(buf);
399 lefcha 1.21 check_vbuf(strlen(buf));
400 lefcha 1.20 strncat(vbuf, buf, vbufs - strlen(vbuf));
401 lefcha 1.14 } while (!strcasestr(buf, ultostr(tag, 16)));
402 lefcha 1.21
403 lefcha 1.20 if ((r = analyze_response(buf)) == RESPONSE_NO &&
404     strcasestr(vbuf, "[TRYCREATE]"))
405     return RESPONSE_TRYCREATE;
406 lefcha 1.6
407 lefcha 1.20 return r;
408 lefcha 1.1 }
409    
410    
411     /*
412 lefcha 1.3 * Process the data that server sent due to IMAP COPY client request.
413 lefcha 1.1 */
414 lefcha 1.20 int copy_response(int *sock, unsigned int tag)
415 lefcha 1.1 {
416 lefcha 1.19 int r = RESPONSE_OK;
417 lefcha 1.20 char buf[RESPONSE_BUF];
418 lefcha 1.21
419 lefcha 1.20 reset_vbuf();
420 lefcha 1.1
421 lefcha 1.20 do {
422     receive_response(sock, buf);
423 lefcha 1.26 bye_response(buf);
424 lefcha 1.21 check_vbuf(strlen(buf));
425 lefcha 1.20 strncat(vbuf, buf, vbufs - strlen(vbuf));
426     } while (!strcasestr(buf, ultostr(tag, 16)));
427 lefcha 1.1
428 lefcha 1.19 if ((r = analyze_response(buf)) == RESPONSE_NO &&
429 lefcha 1.20 strcasestr(vbuf, "[TRYCREATE]"))
430 lefcha 1.9 return RESPONSE_TRYCREATE;
431 lefcha 1.1
432 lefcha 1.19 return r;
433 lefcha 1.1 }
434    
435    
436     /*
437 lefcha 1.3 * Check if response of server to client's request was succesfully
438 lefcha 1.1 * delivered or there was some kind of error.
439     */
440 lefcha 1.14 int analyze_response(char *buf)
441 lefcha 1.1 {
442 lefcha 1.9 int r = RESPONSE_OK;
443 lefcha 1.1 regex_t creg;
444     regmatch_t match[3];
445 lefcha 1.9 const char *reg = "[[:xdigit:]]{6,6} ((OK|NO|BAD)[[:print:]]*)\r\n";
446 lefcha 1.14 char result[RESULT_BUF];
447 lefcha 1.1
448 lefcha 1.4 result[0] = 0;
449    
450 lefcha 1.9 regcomp(&creg, reg, REG_EXTENDED | REG_ICASE);
451 lefcha 1.6
452 lefcha 1.14 if (!regexec(&creg, buf, 3, match, 0)) {
453     strncat(result, buf + match[1].rm_so,
454     min(match[1].rm_eo - match[1].rm_so, RESULT_BUF - 1));
455 lefcha 1.1
456 lefcha 1.22 if (!strncasecmp(buf + match[2].rm_so, "NO", 2))
457 lefcha 1.9 r = RESPONSE_NO;
458 lefcha 1.22 else if (!strncasecmp(buf + match[2].rm_so, "BAD", 3))
459 lefcha 1.9 r = RESPONSE_BAD;
460 lefcha 1.6
461 lefcha 1.1 verbose("Server response: %s\n", result);
462 lefcha 1.20 } else
463     r = RESPONSE_NONE;
464 lefcha 1.21
465 lefcha 1.6 regfree(&creg);
466 lefcha 1.1
467     return r;
468 lefcha 1.20 }
469    
470    
471     /*
472     * Initialize virtual buffer.
473     */
474     void init_vbuf(void)
475     {
476 lefcha 1.25 vbuf = xmalloc(VIRTUAL_BUF);
477 lefcha 1.20 *vbuf = 0;
478 lefcha 1.25 vbufs = VIRTUAL_BUF;
479 lefcha 1.20 }
480    
481    
482     /*
483     * Reset virtual buffer.
484     */
485     void reset_vbuf(void)
486     {
487     *vbuf = 0;
488     }
489    
490    
491     /*
492     * Check if virtual buffer is full and make it bigger.
493     */
494     void check_vbuf(size_t n)
495     {
496     if (n + strlen(vbuf) >= vbufs) {
497 lefcha 1.25 vbufs += VIRTUAL_BUF;
498 lefcha 1.20 vbuf = xrealloc(vbuf, vbufs);
499     }
500 lefcha 1.1 }

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26