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

Contents of /imapfilter/response.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.38 - (show annotations)
Sun Jul 27 15:54:49 2003 UTC (20 years, 8 months ago) by lefcha
Branch: MAIN
Changes since 1.37: +99 -135 lines
File MIME type: text/plain
Use new *_buffer() routines for input/output buffers.

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 capspri, capsaux;
18 extern jmp_buf acctloop;
19
20 buffer_t ibuf; /* Input buffer. */
21
22
23 /*
24 * Read one packet of data that the server sent.
25 */
26 void
27 receive_response(int *sock, char *buf)
28 {
29 if (socket_read(sock, buf) == ERROR_NETWORK)
30 longjmp(acctloop, -1);
31
32 #ifdef DEBUG
33 fprintf(stderr, "debug: getting response (%s):\n\n%s\n",
34 (sock == &sockpri ? "primary" : "auxiliary"), buf);
35 #endif
36
37 }
38
39
40 /*
41 * Get server response to client's request.
42 */
43 int
44 server_response(int *sock, unsigned int tag)
45 {
46 reset_buffer(&ibuf);
47
48 do {
49 check_buffer(&ibuf, strlen(ibuf.data) + RESPONSE_BUF);
50 receive_response(sock, ibuf.data + strlen(ibuf.data));
51 bye_response(ibuf.data);
52 } while (!strcasestr(ibuf.data, ultostr(tag, 16)));
53
54 return analyze_response(sock, 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(int *sock)
74 {
75 reset_buffer(&ibuf);
76
77 receive_response(sock, ibuf.data);
78
79 verbose("%s: %s", (sock == &sockpri ? "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(int *sock, unsigned int tag)
95 {
96 reset_buffer(&ibuf);
97
98 do {
99 check_buffer(&ibuf, strlen(ibuf.data) + RESPONSE_BUF);
100 receive_response(sock, ibuf.data + strlen(ibuf.data));
101 } while (!strcasestr(ibuf.data, ultostr(tag, 16)));
102
103 return analyze_response(sock, 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(int *sock, unsigned int tag)
112 {
113 unsigned int *caps;
114
115 caps = (sock == &sockpri ? &capspri : &capsaux);
116
117 reset_buffer(&ibuf);
118
119 do {
120 check_buffer(&ibuf, strlen(ibuf.data) + RESPONSE_BUF);
121 receive_response(sock, ibuf.data + strlen(ibuf.data));
122 bye_response(ibuf.data);
123 } while (!strcasestr(ibuf.data, ultostr(tag, 16)));
124
125 if (!strcasestr(ibuf.data, "IMAP4rev1")) {
126 error("server does not support IMAP4rev1 protocol\n");
127 return -2;
128 }
129 if (strcasestr(ibuf.data, "NAMESPACE"))
130 *caps |= CAPABILITY_NAMESPACE;
131 #ifdef CRAM_MD5
132 if (strcasestr(ibuf.data, "AUTH=CRAM-MD5"))
133 *caps |= CAPABILITY_AUTH_CRAM_MD5;
134 #endif
135 #ifdef SSL_TLS
136 if (strcasestr(ibuf.data, "STARTTLS"))
137 *caps |= CAPABILITY_STARTTLS;
138 #endif
139
140
141 return analyze_response(sock, ibuf.data);
142 }
143
144
145 #ifdef CRAM_MD5
146 /*
147 * Process the data that server sent due to IMAP AUTHENTICATE client request.
148 */
149 int
150 authenticate_response(int *sock, unsigned int tag, unsigned char **cont)
151 {
152 int i;
153 char *c;
154
155 reset_buffer(&ibuf);
156
157 do {
158 check_buffer(&ibuf, strlen(ibuf.data) + RESPONSE_BUF);
159 receive_response(sock, ibuf.data + strlen(ibuf.data));
160 bye_response(ibuf.data);
161 } while (strlen(ibuf.data) == RESPONSE_BUF &&
162 !strcasestr(ibuf.data, ultostr(tag, 16)));
163
164 if (cont != NULL && ibuf.data[0] == '+' && ibuf.data[1] == ' ') {
165 c = *cont = (unsigned char *)xmalloc(strlen(ibuf.data) + 1);
166
167 for (i = 2; ibuf.data[i] != '\r'; i++)
168 *c++ = ibuf.data[i];
169
170 *c = '\0';
171 }
172 return analyze_response(sock, ibuf.data);
173 }
174
175 #endif
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 *c, *d;
185
186 reset_buffer(&ibuf);
187
188 do {
189 check_buffer(&ibuf, strlen(ibuf.data) + RESPONSE_BUF);
190 receive_response(sock, ibuf.data + strlen(ibuf.data));
191 bye_response(ibuf.data);
192 } while (!strcasestr(ibuf.data, ultostr(tag, 16)));
193
194 if ((c = strcasestr(ibuf.data, "* NAMESPACE"))) {
195 c += 12;
196 if (strncasecmp(c, "NIL", 3)) {
197 c = strchr(c, '"') + 1;
198 d = strchr(c, '"') + 1;
199
200 strncat(nsp->prefix, c, d - c - 1);
201 nsp->delim = *(strchr(d, '"') + 1);
202 }
203 }
204 #ifdef DEBUG
205 fprintf(stderr, "debug: namespace (%s): '%s' '%c'\n",
206 (sock == &sockpri ? "primary" : "auxiliary"), nsp->prefix,
207 nsp->delim);
208 #endif
209 return analyze_response(sock, ibuf.data);
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 unsigned int exist, recent, unseen;
221 char *c;
222
223 exist = recent = unseen = 0;
224
225 reset_buffer(&ibuf);
226
227 do {
228 check_buffer(&ibuf, strlen(ibuf.data) + RESPONSE_BUF);
229 receive_response(sock, ibuf.data + strlen(ibuf.data));
230 bye_response(ibuf.data);
231 } while (!strcasestr(ibuf.data, ultostr(tag, 16)));
232
233 r = analyze_response(sock, ibuf.data);
234
235 if (r == RESPONSE_NO)
236 return -2;
237
238 if ((c = strcasestr(ibuf.data, "MESSAGES"))) {
239 c += 9;
240 exist = strtoul(c, NULL, 10);
241 }
242 if ((c = strcasestr(ibuf.data, "RECENT"))) {
243 c += 7;
244 recent = strtoul(c, NULL, 10);
245 }
246 if ((c = strcasestr(ibuf.data, "UNSEEN"))) {
247 c += 7;
248 unseen = strtoul(c, NULL, 10);
249 }
250 if (exist == 0) {
251 info("No messages in mailbox \"%s\".\n", mbox);
252 return -2;
253 }
254 info("%d message%s, %d recent, %d unseen, in mailbox \"%s\".\n", exist,
255 plural(exist), recent, unseen, mbox);
256
257 return r;
258 }
259
260
261 /*
262 * Process the data that server sent due to IMAP SELECT client request.
263 */
264 int
265 select_response(int *sock, unsigned int tag)
266 {
267 reset_buffer(&ibuf);
268
269 do {
270 check_buffer(&ibuf, strlen(ibuf.data) + RESPONSE_BUF);
271 receive_response(sock, ibuf.data + strlen(ibuf.data));
272 bye_response(ibuf.data);
273 } while (!strcasestr(ibuf.data, ultostr(tag, 16)));
274
275 if (strcasestr(ibuf.data, "[READ-ONLY]"))
276 return RESPONSE_READONLY;
277
278 return analyze_response(sock, ibuf.data);
279 }
280
281
282 /*
283 * Process the data that server sent due to IMAP SEARCH client request.
284 */
285 int
286 search_response(int *sock, unsigned int tag, char **mesgs)
287 {
288 char *c, *m;
289 unsigned int blen;
290
291 reset_buffer(&ibuf);
292
293 do {
294 check_buffer(&ibuf, strlen(ibuf.data) + RESPONSE_BUF);
295 receive_response(sock, ibuf.data + strlen(ibuf.data));
296 bye_response(ibuf.data);
297 } while (!strcasestr(ibuf.data, ultostr(tag, 16)));
298
299 if ((c = strcasestr(ibuf.data, "* SEARCH "))) {
300 blen = strlen(ibuf.data);
301
302 m = *mesgs = (char *)xmalloc(blen + 1);
303
304 c += 9;
305
306 while (*c != '\0' && (isdigit(*c) || *c == ' '))
307 *(m++) = *(c++);
308
309 *m = 0;
310 }
311 return analyze_response(sock, ibuf.data);
312 }
313
314
315 /*
316 * Process the data that server sent due to IMAP FETCH client request.
317 */
318 int
319 fetch_response(int *sock, unsigned int tag, int reset, char *fetch)
320 {
321 unsigned int i;
322 static unsigned int s;
323 char *b;
324
325 if (reset) {
326 s = 0;
327 return 0;
328 }
329 i = 0;
330
331 reset_buffer(&ibuf);
332
333 do {
334 check_buffer(&ibuf, strlen(ibuf.data) + RESPONSE_BUF);
335 receive_response(sock, ibuf.data + strlen(ibuf.data));
336 bye_response(ibuf.data);
337 } while (strlen(ibuf.data) < RESPONSE_BUF &&
338 !strcasestr(ibuf.data, ultostr(tag, 16)));
339
340 b = ibuf.data;
341
342 if (s == 0) {
343 if ((b = strstr(b, "}\r\n"))) {
344 while (b - ibuf.data > 0)
345 if (*--b == '{')
346 break;
347 s = atoi(++b) - 2;
348 b = strchr(b, '}');
349 b += 3;
350 } else {
351 return RESPONSE_NULLBODY; /* Null body. */
352 }
353 }
354 while (*b != '\0' && s-- != 0)
355 fetch[i++] = *(b++);
356
357 fetch[i] = '\0';
358
359 return analyze_response(sock, ibuf.data);
360 }
361
362
363 /*
364 * Process the data that server sent due to IMAP FETCH RFC822.SIZE client
365 * request.
366 */
367 int
368 fetchsize_response(int *sock, unsigned int *size, unsigned int tag)
369 {
370 char *c;
371
372 *size = 0;
373
374 reset_buffer(&ibuf);
375
376 do {
377 check_buffer(&ibuf, strlen(ibuf.data) + RESPONSE_BUF);
378 receive_response(sock, ibuf.data + strlen(ibuf.data));
379 bye_response(ibuf.data);
380 } while (!strcasestr(ibuf.data, ultostr(tag, 16)));
381
382 if ((c = strcasestr(ibuf.data, "FETCH (RFC822.SIZE "))) {
383 c += 19;
384 *size = strtoul(c, NULL, 10);
385 }
386 return analyze_response(sock, ibuf.data);
387 }
388
389
390 /*
391 * Process the data that server sent due to IMAP APPEND client request.
392 */
393 int
394 append_response(int *sock, unsigned int tag)
395 {
396 int r;
397
398 r = RESPONSE_OK;
399
400 reset_buffer(&ibuf);
401
402 do {
403 check_buffer(&ibuf, strlen(ibuf.data) + RESPONSE_BUF);
404 receive_response(sock, ibuf.data + strlen(ibuf.data));
405 bye_response(ibuf.data);
406 } while (!strcasestr(ibuf.data, ultostr(tag, 16)));
407
408 if ((r = analyze_response(sock, ibuf.data)) == RESPONSE_NO &&
409 strcasestr(ibuf.data, "[TRYCREATE]"))
410 return RESPONSE_TRYCREATE;
411
412 return r;
413 }
414
415
416 /*
417 * Process the data that server sent due to IMAP COPY client request.
418 */
419 int
420 copy_response(int *sock, unsigned int tag)
421 {
422 int r;
423
424 r = RESPONSE_OK;
425
426 reset_buffer(&ibuf);
427
428 do {
429 check_buffer(&ibuf, strlen(ibuf.data) + RESPONSE_BUF);
430 receive_response(sock, ibuf.data + strlen(ibuf.data));
431 bye_response(ibuf.data);
432 } while (!strcasestr(ibuf.data, ultostr(tag, 16)));
433
434 if ((r = analyze_response(sock, ibuf.data)) == RESPONSE_NO &&
435 strcasestr(ibuf.data, "[TRYCREATE]"))
436 return RESPONSE_TRYCREATE;
437
438 return r;
439 }
440
441
442 /*
443 * Check if response of server to client's request was succesfully
444 * delivered or there was some kind of error.
445 */
446 int
447 analyze_response(int *sock, char *buf)
448 {
449 int r;
450 regex_t creg;
451 regmatch_t match[3];
452 const char *reg;
453 char result[RESULT_BUF];
454
455 r = RESPONSE_OK;
456 reg = "[[:xdigit:]]{8,8} ((OK|NO|BAD)[[:print:]]*)\r\n";
457 result[0] = '\0';
458
459 regcomp(&creg, reg, REG_EXTENDED | REG_ICASE);
460
461 if (!regexec(&creg, buf, 3, match, 0)) {
462 strncat(result, buf + match[1].rm_so,
463 min(match[1].rm_eo - match[1].rm_so, RESULT_BUF - 1));
464
465 if (!strncasecmp(buf + match[2].rm_so, "NO", 2))
466 r = RESPONSE_NO;
467 else if (!strncasecmp(buf + match[2].rm_so, "BAD", 3))
468 r = RESPONSE_BAD;
469
470 verbose("%s: %s", (sock == &sockpri ? "S" : "s"),
471 buf + match[0].rm_so);
472 } else
473 r = RESPONSE_NONE;
474
475 regfree(&creg);
476
477 return r;
478 }

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26