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

Contents of /imapfilter/response.c

Parent Directory Parent Directory | Revision Log Revision Log


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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26