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

Contents of /imapfilter/response.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.28 - (show annotations)
Sat Nov 9 14:22:03 2002 UTC (21 years, 5 months ago) by lefcha
Branch: MAIN
Changes since 1.27: +16 -8 lines
File MIME type: text/plain
Fixed bug related to getting the octet count of FETCH responses.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26