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

Contents of /imapfilter/response.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.41.2.5 - (show annotations)
Mon Jan 26 21:37:58 2004 UTC (20 years, 2 months ago) by lefcha
Branch: release-0_9-patches
Changes since 1.41.2.4: +2 -5 lines
File MIME type: text/plain
Indentation applied.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26