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

Contents of /imapfilter/response.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.33 - (show annotations)
Sat Feb 22 16:06:41 2003 UTC (21 years, 1 month ago) by lefcha
Branch: MAIN
Changes since 1.32: +310 -283 lines
File MIME type: text/plain
Coding style to KNF and some code cleanup.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26