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

Annotation of /imapfilter/response.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.49 - (hide annotations)
Fri Feb 13 13:18:38 2004 UTC (20 years, 2 months ago) by lefcha
Branch: MAIN
Changes since 1.48: +7 -0 lines
File MIME type: text/plain
Insert an empty line if the function has no local variables.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26