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

Contents of /imapfilter/response.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.32 - (show annotations)
Fri Feb 21 18:54:18 2003 UTC (21 years, 2 months ago) by lefcha
Branch: MAIN
Changes since 1.31: +2 -1 lines
File MIME type: text/plain
Fix network bug when server aborts connection.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26