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

Contents of /imapfilter/response.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.53 - (show annotations)
Sun Feb 15 15:31:54 2004 UTC (16 years, 8 months ago) by lefcha
Branch: MAIN
CVS Tags: HEAD
Changes since 1.52: +3 -3 lines
File MIME type: text/plain
Renamed variable.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26