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

Annotation of /imapfilter/response.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.33 - (hide annotations)
Sat Feb 22 16:06:41 2003 UTC (21 years, 1 month ago) by lefcha
Branch: MAIN
Changes since 1.32: +310 -283 lines
File MIME type: text/plain
Coding style to KNF and some code cleanup.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26