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

Annotation of /imapfilter/response.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.37 - (hide annotations)
Sun Jul 27 10:08:42 2003 UTC (20 years, 8 months ago) by lefcha
Branch: MAIN
Changes since 1.36: +7 -0 lines
File MIME type: text/plain
Added STARTTLS support.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26