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

Contents of /imapfilter/response.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.34 - (show annotations)
Sat Mar 15 18:39:55 2003 UTC (21 years ago) by lefcha
Branch: MAIN
Changes since 1.33: +4 -2 lines
File MIME type: text/plain
More informational debug messages for interaction with the server.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26