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

Annotation of /imapfilter/response.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.38 - (hide annotations)
Sun Jul 27 15:54:49 2003 UTC (20 years, 8 months ago) by lefcha
Branch: MAIN
Changes since 1.37: +99 -135 lines
File MIME type: text/plain
Use new *_buffer() routines for input/output buffers.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26