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

Contents of /imapfilter/response.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.47 - (show annotations)
Mon Feb 9 17:34:56 2004 UTC (20 years, 1 month ago) by lefcha
Branch: MAIN
Changes since 1.46: +2 -6 lines
File MIME type: text/plain
Move DEBUG from compilation #define variable to runtime command line option.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26