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

Contents of /imapfilter/response.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.26 - (show annotations)
Thu Aug 29 19:51:24 2002 UTC (21 years, 7 months ago) by lefcha
Branch: MAIN
Changes since 1.25: +24 -3 lines
File MIME type: text/plain
Check for BYE response and proceed to next account if got one.

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, int reset, char *fetch, unsigned int tag)
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 receive_response(sock, buf);
288 bye_response(buf);
289
290 b = buf;
291
292 if (!s) {
293 b = strchr(b, '{');
294 b++;
295 s = atoi(b) - 2;
296 b = strchr(b, '}');
297 b += 3;
298 }
299 while (*b && s--)
300 fetch[i++] = *(b++);
301
302 fetch[i] = 0;
303
304 return analyze_response(buf);
305 }
306
307
308 /*
309 * Process the data that server sent due to IMAP FETCH RFC822.SIZE client
310 * request.
311 */
312 int fetchsize_response(int *sock, unsigned int *size, unsigned int tag)
313 {
314 char buf[RESPONSE_BUF];
315 char *c;
316
317 *size = 0;
318
319 reset_vbuf();
320
321 do {
322 receive_response(sock, buf);
323 bye_response(buf);
324 check_vbuf(strlen(buf));
325 strncat(vbuf, buf, vbufs - strlen(vbuf));
326 } while (!strcasestr(buf, ultostr(tag, 16)));
327
328 if ((c = strcasestr(vbuf, "FETCH (RFC822.SIZE "))) {
329 c += 19;
330 *size = strtoul(c, NULL, 10);
331 }
332 return analyze_response(buf);
333 }
334
335
336 /*
337 * Process the data that server sent due to IMAP APPEND client request.
338 */
339 int append_response(int *sock, unsigned int tag)
340 {
341 int r = RESPONSE_OK;
342 char buf[RESPONSE_BUF];
343
344 reset_vbuf();
345
346 do {
347 receive_response(sock, buf);
348 bye_response(buf);
349 check_vbuf(strlen(buf));
350 strncat(vbuf, buf, vbufs - strlen(vbuf));
351 } while (!strcasestr(buf, ultostr(tag, 16)));
352
353 if ((r = analyze_response(buf)) == RESPONSE_NO &&
354 strcasestr(vbuf, "[TRYCREATE]"))
355 return RESPONSE_TRYCREATE;
356
357 return r;
358 }
359
360
361 /*
362 * Process the data that server sent due to IMAP COPY client request.
363 */
364 int copy_response(int *sock, unsigned int tag)
365 {
366 int r = RESPONSE_OK;
367 char buf[RESPONSE_BUF];
368
369 reset_vbuf();
370
371 do {
372 receive_response(sock, buf);
373 bye_response(buf);
374 check_vbuf(strlen(buf));
375 strncat(vbuf, buf, vbufs - strlen(vbuf));
376 } while (!strcasestr(buf, ultostr(tag, 16)));
377
378 if ((r = analyze_response(buf)) == RESPONSE_NO &&
379 strcasestr(vbuf, "[TRYCREATE]"))
380 return RESPONSE_TRYCREATE;
381
382 return r;
383 }
384
385
386 /*
387 * Check if response of server to client's request was succesfully
388 * delivered or there was some kind of error.
389 */
390 int analyze_response(char *buf)
391 {
392 int r = RESPONSE_OK;
393 regex_t creg;
394 regmatch_t match[3];
395 const char *reg = "[[:xdigit:]]{6,6} ((OK|NO|BAD)[[:print:]]*)\r\n";
396 char result[RESULT_BUF];
397
398 result[0] = 0;
399
400 regcomp(&creg, reg, REG_EXTENDED | REG_ICASE);
401
402 if (!regexec(&creg, buf, 3, match, 0)) {
403 strncat(result, buf + match[1].rm_so,
404 min(match[1].rm_eo - match[1].rm_so, RESULT_BUF - 1));
405
406 if (!strncasecmp(buf + match[2].rm_so, "NO", 2))
407 r = RESPONSE_NO;
408 else if (!strncasecmp(buf + match[2].rm_so, "BAD", 3))
409 r = RESPONSE_BAD;
410
411 verbose("Server response: %s\n", result);
412 } else
413 r = RESPONSE_NONE;
414
415 regfree(&creg);
416
417 return r;
418 }
419
420
421 /*
422 * Initialize virtual buffer.
423 */
424 void init_vbuf(void)
425 {
426 vbuf = xmalloc(VIRTUAL_BUF);
427 *vbuf = 0;
428 vbufs = VIRTUAL_BUF;
429 }
430
431
432 /*
433 * Reset virtual buffer.
434 */
435 void reset_vbuf(void)
436 {
437 *vbuf = 0;
438 }
439
440
441 /*
442 * Check if virtual buffer is full and make it bigger.
443 */
444 void check_vbuf(size_t n)
445 {
446 if (n + strlen(vbuf) >= vbufs) {
447 vbufs += VIRTUAL_BUF;
448 vbuf = xrealloc(vbuf, vbufs);
449 }
450 }

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26