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

Contents of /imapfilter/response.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.40 - (show annotations)
Thu Jul 31 15:53:19 2003 UTC (20 years, 8 months ago) by lefcha
Branch: MAIN
Changes since 1.39: +7 -9 lines
File MIME type: text/plain
Broke up program files and created some new header files.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26