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

Annotation of /imapfilter/response.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.34 - (hide annotations)
Sat Mar 15 18:39:55 2003 UTC (21 years, 1 month ago) by lefcha
Branch: MAIN
Changes since 1.33: +4 -2 lines
File MIME type: text/plain
More informational debug messages for interaction with the server.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26