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

Contents of /imapfilter/response.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.36 - (show annotations)
Sat Jul 26 19:42:13 2003 UTC (20 years, 8 months ago) by lefcha
Branch: MAIN
Changes since 1.35: +129 -155 lines
File MIME type: text/plain
Added CRAM-MD5 support and replaced virtual buffer with more clean input buffer.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26