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

Annotation of /imapfilter/response.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.47 - (hide annotations)
Mon Feb 9 17:34:56 2004 UTC (20 years, 1 month ago) by lefcha
Branch: MAIN
Changes since 1.46: +2 -6 lines
File MIME type: text/plain
Move DEBUG from compilation #define variable to runtime command line option.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26