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

Contents of /imapfilter/response.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.41 - (show annotations)
Sun Aug 3 16:01:53 2003 UTC (20 years, 8 months ago) by lefcha
Branch: MAIN
CVS Tags: release-0_9
Branch point for: release-0_9-patches
Changes since 1.40: +1 -0 lines
File MIME type: text/plain
Added missing stdlib.h header.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26