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

Contents of /imapfilter/response.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.37 - (show annotations)
Sun Jul 27 10:08:42 2003 UTC (20 years, 8 months ago) by lefcha
Branch: MAIN
Changes since 1.36: +7 -0 lines
File MIME type: text/plain
Added STARTTLS support.

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 #ifdef CRAM_MD5
133 if (strcasestr(ibuf, "AUTH=CRAM-MD5"))
134 *caps |= CAPABILITY_AUTH_CRAM_MD5;
135 #endif
136 #ifdef SSL_TLS
137 if (strcasestr(ibuf, "STARTTLS"))
138 *caps |= CAPABILITY_STARTTLS;
139 #endif
140
141
142 return analyze_response(sock, ibuf);
143 }
144
145
146 #ifdef CRAM_MD5
147 /*
148 * Process the data that server sent due to IMAP AUTHENTICATE client request.
149 */
150 int
151 authenticate_response(int *sock, unsigned int tag, unsigned char **cont)
152 {
153 int i;
154 char *c;
155
156 reset_ibuf();
157
158 do {
159 check_ibuf();
160 receive_response(sock, ibuf + strlen(ibuf));
161 bye_response(ibuf);
162 } while (strlen(ibuf) == RESPONSE_BUF &&
163 !strcasestr(ibuf, ultostr(tag, 16)));
164
165 if (cont != NULL && ibuf[0] == '+' && ibuf[1] == ' ') {
166 c = *cont = (unsigned char *)xmalloc(strlen(ibuf) + 1);
167
168 for (i = 2; ibuf[i] != '\r'; i++)
169 *c++ = ibuf[i];
170
171 *c = '\0';
172 }
173 return analyze_response(sock, ibuf);
174 }
175
176 #endif
177
178
179 /*
180 * Process the data that server sent due to IMAP NAMESPACE client request.
181 */
182 int
183 namespace_response(int *sock, unsigned int tag, namesp_t * nsp)
184 {
185 char *c, *d;
186
187 reset_ibuf();
188
189 do {
190 check_ibuf();
191 receive_response(sock, ibuf + strlen(ibuf));
192 bye_response(ibuf);
193 } while (!strcasestr(ibuf, ultostr(tag, 16)));
194
195 if ((c = strcasestr(ibuf, "* NAMESPACE"))) {
196 c += 12;
197 if (strncasecmp(c, "NIL", 3)) {
198 c = strchr(c, '"') + 1;
199 d = strchr(c, '"') + 1;
200
201 strncat(nsp->prefix, c, d - c - 1);
202 nsp->delim = *(strchr(d, '"') + 1);
203 }
204 }
205 #ifdef DEBUG
206 fprintf(stderr, "debug: namespace (%s): '%s' '%c'\n",
207 (sock == &sockpri ? "primary" : "auxiliary"), nsp->prefix,
208 nsp->delim);
209 #endif
210 return analyze_response(sock, ibuf);
211 }
212
213
214 /*
215 * Process the data that server sent due to IMAP STATUS client request.
216 */
217 int
218 status_response(int *sock, unsigned int tag, char *mbox)
219 {
220 int r;
221 unsigned int exist, recent, unseen;
222 char *c;
223
224 exist = recent = unseen = 0;
225
226 reset_ibuf();
227
228 do {
229 check_ibuf();
230 receive_response(sock, ibuf + strlen(ibuf));
231 bye_response(ibuf);
232 } while (!strcasestr(ibuf, ultostr(tag, 16)));
233
234 r = analyze_response(sock, ibuf);
235
236 if (r == RESPONSE_NO)
237 return -2;
238
239 if ((c = strcasestr(ibuf, "MESSAGES"))) {
240 c += 9;
241 exist = strtoul(c, NULL, 10);
242 }
243 if ((c = strcasestr(ibuf, "RECENT"))) {
244 c += 7;
245 recent = strtoul(c, NULL, 10);
246 }
247 if ((c = strcasestr(ibuf, "UNSEEN"))) {
248 c += 7;
249 unseen = strtoul(c, NULL, 10);
250 }
251 if (exist == 0) {
252 info("No messages in mailbox \"%s\".\n", mbox);
253 return -2;
254 }
255 info("%d message%s, %d recent, %d unseen, in mailbox \"%s\".\n", exist,
256 plural(exist), recent, unseen, mbox);
257
258 return r;
259 }
260
261
262 /*
263 * Process the data that server sent due to IMAP SELECT client request.
264 */
265 int
266 select_response(int *sock, unsigned int tag)
267 {
268 reset_ibuf();
269
270 do {
271 check_ibuf();
272 receive_response(sock, ibuf + strlen(ibuf));
273 bye_response(ibuf);
274 } while (!strcasestr(ibuf, ultostr(tag, 16)));
275
276 if (strcasestr(ibuf, "[READ-ONLY]"))
277 return RESPONSE_READONLY;
278
279 return analyze_response(sock, ibuf);
280 }
281
282
283 /*
284 * Process the data that server sent due to IMAP SEARCH client request.
285 */
286 int
287 search_response(int *sock, unsigned int tag, char **mesgs)
288 {
289 char *c, *m;
290 unsigned int blen;
291
292 reset_ibuf();
293
294 do {
295 check_ibuf();
296 receive_response(sock, ibuf + strlen(ibuf));
297 bye_response(ibuf);
298 } while (!strcasestr(ibuf, ultostr(tag, 16)));
299
300 if ((c = strcasestr(ibuf, "* SEARCH "))) {
301 blen = strlen(ibuf);
302
303 m = *mesgs = (char *)xmalloc(blen + 1);
304
305 c += 9;
306
307 while (*c != '\0' && (isdigit(*c) || *c == ' '))
308 *(m++) = *(c++);
309
310 *m = 0;
311 }
312 return analyze_response(sock, ibuf);
313 }
314
315
316 /*
317 * Process the data that server sent due to IMAP FETCH client request.
318 */
319 int
320 fetch_response(int *sock, unsigned int tag, int reset, char *fetch)
321 {
322 unsigned int i;
323 static unsigned int s;
324 char *b;
325
326 if (reset) {
327 s = 0;
328 return 0;
329 }
330 i = 0;
331
332 reset_ibuf();
333
334 do {
335 check_ibuf();
336 receive_response(sock, ibuf + strlen(ibuf));
337 bye_response(ibuf);
338 } while (strlen(ibuf) < RESPONSE_BUF &&
339 !strcasestr(ibuf, ultostr(tag, 16)));
340
341 b = ibuf;
342
343 if (s == 0) {
344 if ((b = strstr(b, "}\r\n"))) {
345 while (b - ibuf > 0)
346 if (*--b == '{')
347 break;
348 s = atoi(++b) - 2;
349 b = strchr(b, '}');
350 b += 3;
351 } else {
352 return RESPONSE_NULLBODY; /* Null body. */
353 }
354 }
355 while (*b != '\0' && s-- != 0)
356 fetch[i++] = *(b++);
357
358 fetch[i] = '\0';
359
360 return analyze_response(sock, ibuf);
361 }
362
363
364 /*
365 * Process the data that server sent due to IMAP FETCH RFC822.SIZE client
366 * request.
367 */
368 int
369 fetchsize_response(int *sock, unsigned int *size, unsigned int tag)
370 {
371 char *c;
372
373 *size = 0;
374
375 reset_ibuf();
376
377 do {
378 check_ibuf();
379 receive_response(sock, ibuf + strlen(ibuf));
380 bye_response(ibuf);
381 } while (!strcasestr(ibuf, ultostr(tag, 16)));
382
383 if ((c = strcasestr(ibuf, "FETCH (RFC822.SIZE "))) {
384 c += 19;
385 *size = strtoul(c, NULL, 10);
386 }
387 return analyze_response(sock, ibuf);
388 }
389
390
391 /*
392 * Process the data that server sent due to IMAP APPEND client request.
393 */
394 int
395 append_response(int *sock, unsigned int tag)
396 {
397 int r;
398
399 r = RESPONSE_OK;
400
401 reset_ibuf();
402
403 do {
404 check_ibuf();
405 receive_response(sock, ibuf + strlen(ibuf));
406 bye_response(ibuf);
407 } while (!strcasestr(ibuf, ultostr(tag, 16)));
408
409 if ((r = analyze_response(sock, ibuf)) == RESPONSE_NO &&
410 strcasestr(ibuf, "[TRYCREATE]"))
411 return RESPONSE_TRYCREATE;
412
413 return r;
414 }
415
416
417 /*
418 * Process the data that server sent due to IMAP COPY client request.
419 */
420 int
421 copy_response(int *sock, unsigned int tag)
422 {
423 int r;
424
425 r = RESPONSE_OK;
426
427 reset_ibuf();
428
429 do {
430 check_ibuf();
431 receive_response(sock, ibuf + strlen(ibuf));
432 bye_response(ibuf);
433 } while (!strcasestr(ibuf, ultostr(tag, 16)));
434
435 if ((r = analyze_response(sock, ibuf)) == RESPONSE_NO &&
436 strcasestr(ibuf, "[TRYCREATE]"))
437 return RESPONSE_TRYCREATE;
438
439 return r;
440 }
441
442
443 /*
444 * Check if response of server to client's request was succesfully
445 * delivered or there was some kind of error.
446 */
447 int
448 analyze_response(int *sock, char *buf)
449 {
450 int r;
451 regex_t creg;
452 regmatch_t match[3];
453 const char *reg;
454 char result[RESULT_BUF];
455
456 r = RESPONSE_OK;
457 reg = "[[:xdigit:]]{6,6} ((OK|NO|BAD)[[:print:]]*)\r\n";
458 result[0] = '\0';
459
460 regcomp(&creg, reg, REG_EXTENDED | REG_ICASE);
461
462 if (!regexec(&creg, buf, 3, match, 0)) {
463 strncat(result, buf + match[1].rm_so,
464 min(match[1].rm_eo - match[1].rm_so, RESULT_BUF - 1));
465
466 if (!strncasecmp(buf + match[2].rm_so, "NO", 2))
467 r = RESPONSE_NO;
468 else if (!strncasecmp(buf + match[2].rm_so, "BAD", 3))
469 r = RESPONSE_BAD;
470
471 verbose("%s: %s", (sock == &sockpri ? "S" : "s"),
472 buf + match[0].rm_so);
473 } else
474 r = RESPONSE_NONE;
475
476 regfree(&creg);
477
478 return r;
479 }
480
481
482 /*
483 * Initialize input buffer.
484 */
485 void
486 init_ibuf(void)
487 {
488 ibuf = xmalloc(INPUT_BUF + 1);
489 *ibuf = '\0';
490 ibufs = INPUT_BUF + 1;
491 }
492
493
494 /*
495 * Reset input buffer.
496 */
497 void
498 reset_ibuf(void)
499 {
500 *ibuf = '\0';
501 }
502
503
504 /*
505 * Check if input buffer is full and make it bigger.
506 */
507 void
508 check_ibuf(void)
509 {
510 if (strlen(ibuf) + INPUT_BUF >= ibufs) {
511 ibufs += INPUT_BUF;
512 ibuf = xrealloc(ibuf, ibufs);
513 }
514 }

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26