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

Contents of /imapfilter/response.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.49 - (show annotations)
Fri Feb 13 13:18:38 2004 UTC (20 years, 2 months ago) by lefcha
Branch: MAIN
Changes since 1.48: +7 -0 lines
File MIME type: text/plain
Insert an empty line if the function has no local variables.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26