Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 847 lines (662 sloc) 19.227 kB
5d4ed5e @lefcha Initial commit.
authored
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <strings.h>
5 #include <ctype.h>
6 #include <regex.h>
7
8 #include "imapfilter.h"
9 #include "session.h"
10 #include "buffer.h"
11 #include "regexp.h"
12
13
14 extern options opts;
15
16 buffer ibuf; /* Input buffer. */
17 enum { /* Server data responses to be parsed;
18 * regular expressions index. */
19 DATA_RESPONSE_TAGGED,
20 DATA_RESPONSE_CAPABILITY,
21 DATA_RESPONSE_AUTHENTICATE,
22 DATA_RESPONSE_NAMESPACE,
23 DATA_RESPONSE_STATUS,
24 DATA_RESPONSE_STATUS_MESSAGES,
25 DATA_RESPONSE_STATUS_RECENT,
26 DATA_RESPONSE_STATUS_UNSEEN,
27 DATA_RESPONSE_STATUS_UIDNEXT,
28 DATA_RESPONSE_EXAMINE_EXISTS,
29 DATA_RESPONSE_EXAMINE_RECENT,
30 DATA_RESPONSE_LIST,
31 DATA_RESPONSE_SEARCH,
32 DATA_RESPONSE_FETCH,
33 DATA_RESPONSE_FETCH_FLAGS,
34 DATA_RESPONSE_FETCH_DATE,
35 DATA_RESPONSE_FETCH_SIZE,
36 DATA_RESPONSE_FETCH_STRUCTURE,
37 DATA_RESPONSE_FETCH_BODY,
38 DATA_RESPONSE_IDLE,
39 };
40 regexp responses[] = { /* Server data responses to be parsed;
41 * regular expressions patterns. */
dae82ff @lefcha Fix matching problems in the regular expressions
authored
42 { "([[:xdigit:]]{4,4}) (OK|NO|BAD) [^[:cntrl:]]*\r\n", NULL, 0, NULL },
43 { "\\* CAPABILITY ([[:print:]]*)\r\n", NULL, 0, NULL },
44 { "\\+ ([[:graph:]]*)\r\n", NULL, 0, NULL },
45 { "\\* NAMESPACE (NIL|\\(\\(\"([[:graph:]]*)\" \"([[:print:]])\"\\)"
46 "[[:print:]]*\\)) (NIL|\\([[:print:]]*\\)) (NIL|\\([[:print:]]*\\))"
47 "\r\n", NULL, 0, NULL },
48 { "\\* STATUS [[:print:]]* \\(([[:alnum:] ]*)\\) *\r\n", NULL, 0, NULL },
49 { "MESSAGES ([[:digit:]]+)", NULL, 0, NULL },
50 { "RECENT ([[:digit:]]+)", NULL, 0, NULL },
51 { "UNSEEN ([[:digit:]]+)", NULL, 0, NULL },
52 { "UIDNEXT ([[:digit:]]+)", NULL, 0, NULL },
53 { "\\* ([[:digit:]]+) EXISTS\r\n", NULL, 0, NULL },
54 { "\\* ([[:digit:]]+) RECENT\r\n", NULL, 0, NULL },
55 { "\\* (LIST|LSUB) \\(([[:print:]]*)\\) (\"[[:print:]]\"|NIL) "
56 "(\"([[:print:]]+)\"|([[:print:]]+)|\\{([[:digit:]]+)\\}\r\n"
57 "([[:print:]]*))\r\n", NULL, 0, NULL },
58 { "\\* SEARCH ?([[:digit:] ]*)\r\n", NULL, 0, NULL },
59 { "\\* [[:digit:]]+ FETCH \\(([[:print:]]*)\\)\r\n", NULL, 0, NULL },
60 { "FLAGS \\(([[:print:]]*)\\)", NULL, 0, NULL },
61 { "INTERNALDATE \"([[:print:]]*)\"", NULL, 0, NULL },
62 { "RFC822.SIZE ([[:digit:]]+)", NULL, 0, NULL },
63 { "BODYSTRUCTURE (\\([[:print:]]+\\))", NULL, 0, NULL },
64 { "\\* [[:digit:]]+ FETCH \\([[:print:]]*BODY\\[[[:print:]]*\\] "
65 "(\\{([[:digit:]]+)\\}\r\n|\"([[:print:]]*)\")", NULL, 0, NULL },
66 { "\\* [[:digit:]]+ (RECENT|EXISTS)\r\n", NULL, 0, NULL },
5d4ed5e @lefcha Initial commit.
authored
67 { NULL, NULL, 0, NULL }
68 };
69
70
71 int receive_response(session *ssn, char *buf, long timeout, int timeoutfail);
72
73 int check_tag(char *buf, session *ssn, int tag);
74 int check_bye(char *buf);
75 int check_continuation(char *buf);
76 int check_trycreate(char *buf);
77
78
79 /*
80 * Read data the server sent.
81 */
82 int
83 receive_response(session *ssn, char *buf, long timeout, int timeoutfail)
84 {
85 ssize_t n;
86
87 if ((n = socket_read(ssn, buf, INPUT_BUF, timeout ? timeout :
88 (long)(get_option_number("timeout")), timeoutfail)) == -1)
89 return -1;
90
91
5c1f83f @lefcha Change debug option to take filename as argument
authored
92 if (opts.debug) {
5d4ed5e @lefcha Initial commit.
authored
93 int i;
94
95 debug("getting response (%d):\n\n", ssn->socket);
96
97 for (i = 0; i < n; i++)
98 debugc(buf[i]);
99
100 debug("\n");
101 }
102
103 return n;
104 }
105
106
107 /*
108 * Search for tagged response in the data that the server sent.
109 */
110 int
111 check_tag(char *buf, session *ssn, int tag)
112 {
113 int r;
114 char t[4 + 1];
115 regexp *re;
116
117 r = STATUS_RESPONSE_NONE;
118
119 snprintf(t, sizeof(t), "%04X", tag);
120
121 re = &responses[DATA_RESPONSE_TAGGED];
122
123 if (!regexec(re->preg, buf, re->nmatch, re->pmatch, 0)) {
124 if (!strncasecmp(buf + re->pmatch[1].rm_so, t,
125 strlen(t))) {
126 if (!strncasecmp(buf + re->pmatch[2].rm_so,
127 "OK", strlen("OK")))
128 r = STATUS_RESPONSE_OK;
129 else if (!strncasecmp(buf + re->pmatch[2].rm_so,
130 "NO", strlen("NO")))
131 r = STATUS_RESPONSE_NO;
132 else if (!strncasecmp(buf + re->pmatch[2].rm_so,
133 "BAD", strlen("BAD")))
134 r = STATUS_RESPONSE_BAD;
135 }
136 }
137
138 if (r != STATUS_RESPONSE_NONE)
139 verbose("S (%d): %s", ssn->socket, buf + re->pmatch[0].rm_so);
140
141 if (r == STATUS_RESPONSE_NO || r == STATUS_RESPONSE_BAD)
142 error("IMAP (%d): %s", ssn->socket, buf + re->pmatch[0].rm_so);
143
144 return r;
145 }
146
147
148 /*
149 * Check if server sent a BYE response (connection is closed immediately).
150 */
151 int
152 check_bye(char *buf)
153 {
154
155 if (xstrcasestr(buf, "* BYE") &&
156 !xstrcasestr(buf, " LOGOUT "))
157 return 1;
158 else
159 return 0;
160 }
161
162
163 /*
164 * Check if server sent a PREAUTH response (connection already authenticated
165 * by external means).
166 */
167 int
168 check_preauth(char *buf)
169 {
170
171 if (xstrcasestr(ibuf.data, "* PREAUTH"))
172 return 1;
173 else
174 return 0;
175 }
176
177
178 /*
179 * Check if the server sent a continuation request.
180 */
181 int
182 check_continuation(char *buf)
183 {
184
185 if ((buf[0] == '+' && buf[1] == ' ') || xstrcasestr(buf, "\r\n+ "))
186 return 1;
187 else
188 return 0;
189 }
190
191
192 /*
193 * Check if the server sent a TRYCREATE response.
194 */
195 int
196 check_trycreate(char *buf)
197 {
198
199 if (xstrcasestr(buf, "[TRYCREATE]"))
200 return 1;
201 else
202 return 0;
203 }
204
205
206 /*
207 * Get server data and make sure there is a tagged response inside them.
208 */
209 int
210 response_generic(session *ssn, int tag)
211 {
212 int r;
213 ssize_t n;
214
215 if (tag == -1)
216 return -1;
217
218 buffer_reset(&ibuf);
219
220 do {
221 buffer_check(&ibuf, ibuf.len + INPUT_BUF);
222 if ((n = receive_response(ssn, ibuf.data + ibuf.len, 0, 1)) == -1)
223 return -1;
224 ibuf.len += n;
225
226 if (check_bye(ibuf.data))
227 return -1;
228 } while ((r = check_tag(ibuf.data, ssn, tag)) == STATUS_RESPONSE_NONE);
229
230 if (r == STATUS_RESPONSE_NO &&
231 (check_trycreate(ibuf.data) || get_option_boolean("create")))
232 return STATUS_RESPONSE_TRYCREATE;
233
234 return r;
235 }
236
237
238 /*
239 * Get server data and make sure there is a continuation response inside them.
240 */
241 int
242 response_continuation(session *ssn)
243 {
244 ssize_t n;
245
246 buffer_reset(&ibuf);
247
248 do {
249 buffer_check(&ibuf, ibuf.len + INPUT_BUF);
250 if ((n = receive_response(ssn, ibuf.data + ibuf.len, 0, 1)) == -1)
251 return -1;
252 ibuf.len += n;
253
254 if (check_bye(ibuf.data))
255 return -1;
256 } while (!check_continuation(ibuf.data));
257
258 return STATUS_RESPONSE_CONTINUE;
259 }
260
261
262 /*
263 * Process the greeting that server sends during connection.
264 */
265 int
266 response_greeting(session *ssn)
267 {
268
269 buffer_reset(&ibuf);
270
271 if (receive_response(ssn, ibuf.data, 0, 1) == -1)
272 return -1;
273
274 verbose("S (%d): %s", ssn->socket, ibuf.data);
275
276 if (check_bye(ibuf.data))
277 return -1;
278
279 if (check_preauth(ibuf.data))
280 return STATUS_RESPONSE_PREAUTH;
281
282 return STATUS_RESPONSE_NONE;
283 }
284
285
286 /*
287 * Process the data that server sent due to IMAP CAPABILITY client request.
288 */
289 int
290 response_capability(session *ssn, int tag)
291 {
292 int r;
293 char *s;
294 regexp *re;
295
296 if ((r = response_generic(ssn, tag)) == -1)
297 return -1;
298
299 ssn->protocol = PROTOCOL_NONE;
300
301 re = &responses[DATA_RESPONSE_CAPABILITY];
302
303 if (!regexec(re->preg, ibuf.data, re->nmatch, re->pmatch, 0)) {
304 s = xstrndup(ibuf.data + re->pmatch[1].rm_so,
305 re->pmatch[1].rm_eo - re->pmatch[1].rm_so);
306
307 if (xstrcasestr(s, "IMAP4rev1"))
308 ssn->protocol = PROTOCOL_IMAP4REV1;
309 else if (xstrcasestr(s, "IMAP4"))
310 ssn->protocol = PROTOCOL_IMAP4;
311 else {
312 error("server supports neither the IMAP4rev1 nor the "
313 "IMAP4 protocol\n");
314 return -1;
315 }
316
317 ssn->capabilities = CAPABILITY_NONE;
318
319 if (xstrcasestr(s, "NAMESPACE"))
320 ssn->capabilities |= CAPABILITY_NAMESPACE;
321 #ifndef NO_CRAMMD5
322 if (xstrcasestr(s, "AUTH=CRAM-MD5"))
323 ssn->capabilities |= CAPABILITY_CRAMMD5;
324 #endif
325 #ifndef NO_SSLTLS
326 if (xstrcasestr(s, "STARTTLS"))
327 ssn->capabilities |= CAPABILITY_STARTTLS;
328 #endif
329 if (xstrcasestr(s, "CHILDREN"))
330 ssn->capabilities |= CAPABILITY_CHILDREN;
331
332 if (xstrcasestr(s, "IDLE"))
333 ssn->capabilities |= CAPABILITY_IDLE;
334
335 xfree(s);
336 }
337
338 return r;
339 }
340
341
342 #ifndef NO_CRAMMD5
343 /*
344 * Process the data that server sent due to IMAP AUTHENTICATE client request.
345 */
346 int
347 response_authenticate(session *ssn, int tag, unsigned char **cont)
348 {
349 int r;
350 regexp *re;
351
352 re = &responses[DATA_RESPONSE_AUTHENTICATE];
353
354 if ((r = response_continuation(ssn)) == STATUS_RESPONSE_CONTINUE &&
355 !regexec(re->preg, ibuf.data, re->nmatch, re->pmatch, 0))
356 *cont = (unsigned char *)xstrndup(ibuf.data + re->pmatch[1].rm_so,
357 re->pmatch[1].rm_eo - re->pmatch[1].rm_so);
358
359 return r;
360 }
361 #endif
362
363
364 /*
365 * Process the data that server sent due to IMAP NAMESPACE client request.
366 */
367 int
368 response_namespace(session *ssn, int tag)
369 {
370 int r, n;
371 regexp *re;
372
373 if ((r = response_generic(ssn, tag)) == -1)
374 return -1;
375
376 ssn->ns.prefix = NULL;
377 ssn->ns.delim = '\0';
378
379 re = &responses[DATA_RESPONSE_NAMESPACE];
380
381 if (!regexec(re->preg, ibuf.data, re->nmatch, re->pmatch, 0)) {
382 n = re->pmatch[2].rm_eo - re->pmatch[2].rm_so;
383 if (n > 0)
384 ssn->ns.prefix = xstrndup(ibuf.data +
385 re->pmatch[2].rm_so, n);
386 ssn->ns.delim = *(ibuf.data + re->pmatch[3].rm_so);
387 }
388 debug("namespace (%d): '%s' '%c'\n", ssn->socket,
389 (ssn->ns.prefix ? ssn->ns.prefix : ""), ssn->ns.delim);
390
391 return r;
392 }
393
394
395 /*
396 * Process the data that server sent due to IMAP STATUS client request.
397 */
398 int
399 response_status(session *ssn, int tag, unsigned int *exist,
400 unsigned int *recent, unsigned int *unseen, unsigned int *uidnext)
401 {
402 int r;
403 char *s;
404 regexp *re;
405
406 if ((r = response_generic(ssn, tag)) == -1)
407 return -1;
408
409 re = &responses[DATA_RESPONSE_STATUS];
410
411 if (!regexec(re->preg, ibuf.data, re->nmatch, re->pmatch, 0)) {
412 s = xstrndup(ibuf.data + re->pmatch[1].rm_so,
413 re->pmatch[1].rm_eo - re->pmatch[1].rm_so);
414
415 re = &responses[DATA_RESPONSE_STATUS_MESSAGES];
416 if (!regexec(re->preg, s, re->nmatch, re->pmatch, 0))
417 *exist = strtol(s + re->pmatch[1].rm_so, NULL, 10);
418
419 re = &responses[DATA_RESPONSE_STATUS_RECENT];
420 if (!regexec(re->preg, s, re->nmatch, re->pmatch, 0))
421 *recent = strtol(s + re->pmatch[1].rm_so, NULL, 10);
422
423 re = &responses[DATA_RESPONSE_STATUS_UNSEEN];
424 if (!regexec(re->preg, s, re->nmatch, re->pmatch, 0))
425 *unseen = strtol(s + re->pmatch[1].rm_so, NULL, 10);
426
427 re = &responses[DATA_RESPONSE_STATUS_UIDNEXT];
428 if (!regexec(re->preg, s, re->nmatch, re->pmatch, 0))
429 *uidnext = strtol(s + re->pmatch[1].rm_so, NULL, 10);
430
431 xfree(s);
432 }
433
434 return r;
435 }
436
437
438 /*
439 * Process the data that server sent due to IMAP EXAMINE client request.
440 */
441 int
442 response_examine(session *ssn, int tag, unsigned int *exist,
443 unsigned int *recent)
444 {
445 int r;
446 regexp *re;
447
448 if ((r = response_generic(ssn, tag)) == -1)
449 return -1;
450
451 re = &responses[DATA_RESPONSE_EXAMINE_EXISTS];
452 if (!regexec(re->preg, ibuf.data, re->nmatch, re->pmatch, 0))
453 *exist = strtol(ibuf.data + re->pmatch[1].rm_so, NULL, 10);
454
455 re = &responses[DATA_RESPONSE_EXAMINE_RECENT];
456 if (!regexec(re->preg, ibuf.data, re->nmatch, re->pmatch, 0))
457 *recent = strtol(ibuf.data + re->pmatch[1].rm_so, NULL, 10);
458
459 return r;
460 }
461
462
463 /*
464 * Process the data that server sent due to IMAP SELECT client request.
465 */
466 int
467 response_select(session *ssn, int tag)
468 {
469 int r;
470
471 if ((r = response_generic(ssn, tag)) == -1)
472 return -1;
473
474 if (xstrcasestr(ibuf.data, "[READ-ONLY]"))
475 return STATUS_RESPONSE_READONLY;
476
477 return r;
478 }
479
480
481 /*
482 * Process the data that server sent due to IMAP LIST or IMAP LSUB client
483 * request.
484 */
485 int
486 response_list(session *ssn, int tag, char **mboxs, char **folders)
487 {
488 int r, n;
489 char *b, *a, *s, *m, *f;
490 const char *v;
491 regexp *re;
492
493 if ((r = response_generic(ssn, tag)) == -1)
494 return -1;
495
496 m = *mboxs = (char *)xmalloc((ibuf.len + 1) * sizeof(char));
497 f = *folders = (char *)xmalloc((ibuf.len + 1) * sizeof(char));
498 *m = *f = '\0';
499
500 re = &responses[DATA_RESPONSE_LIST];
501
502 b = ibuf.data;
503 while (!regexec(re->preg, b, re->nmatch, re->pmatch, 0)) {
504 a = xstrndup(b + re->pmatch[2].rm_so,
505 re->pmatch[2].rm_eo - re->pmatch[2].rm_so);
506
507 if (re->pmatch[5].rm_so != -1 && re->pmatch[5].rm_so != -1)
508 s = xstrndup(b + re->pmatch[5].rm_so,
509 re->pmatch[5].rm_eo - re->pmatch[5].rm_so);
510 else if (re->pmatch[6].rm_so != -1 &&
511 re->pmatch[6].rm_so != -1)
512 s = xstrndup(b + re->pmatch[6].rm_so,
513 re->pmatch[6].rm_eo - re->pmatch[6].rm_so);
514 else
515 s = xstrndup(b + re->pmatch[8].rm_so, strtoul(b +
516 re->pmatch[7].rm_so, NULL, 10));
517
518 v = reverse_namespace(s, ssn->ns.prefix, ssn->ns.delim);
519 n = strlen(v);
520
521 if (!xstrcasestr(a, "\\NoSelect")) {
522 xstrncpy(m, v, ibuf.len - (m - *mboxs));
523 m += n;
524 xstrncpy(m, "\n", ibuf.len - (m - *mboxs));
525 m += strlen("\n");
526 }
527
528 if (!xstrcasestr(a, "\\NoInferiors") &&
529 (!(ssn->capabilities & CAPABILITY_CHILDREN) ||
530 ((ssn->capabilities & CAPABILITY_CHILDREN) &&
531 (xstrcasestr(a, "\\HasChildren")) &&
532 !xstrcasestr(a, "\\HasNoChildren")))) {
533 xstrncpy(f, v, ibuf.len - (f - *folders));
534 f += n;
535 xstrncpy(f, "\n", ibuf.len - (f - *folders));
536 f += strlen("\n");
537 }
538
539 b += re->pmatch[0].rm_eo;
540
541 xfree(a);
542 xfree(s);
543 }
544
545 return r;
546 }
547
548
549 /*
550 * Process the data that server sent due to IMAP SEARCH client request.
551 */
552 int
553 response_search(session *ssn, int tag, char **mesgs)
554 {
555 int r;
556 unsigned int min;
557 regexp *re;
558 char *b, *m;
559
560 if ((r = response_generic(ssn, tag)) == -1)
561 return -1;
562
563 re = &responses[DATA_RESPONSE_SEARCH];
564
565 b = ibuf.data;
566 m = NULL;
567 while (!regexec(re->preg, b, re->nmatch, re->pmatch, 0)) {
568 if (!*mesgs) {
569 m = *mesgs = (char *)xmalloc((ibuf.len + 1) *
570 sizeof(char));
571 *m = '\0';
572 }
573
574 min = (unsigned int)(re->pmatch[1].rm_eo - re->pmatch[1].rm_so) < ibuf.len ?
575 (unsigned int)(re->pmatch[1].rm_eo - re->pmatch[1].rm_so) :
576 ibuf.len;
577
578 xstrncpy(m, b + re->pmatch[1].rm_so, min);
579 m += min;
580 xstrncpy(m++, " ", ibuf.len - min);
581
582 b += re->pmatch[0].rm_eo;
583 }
584
585 return r;
586 }
587
588
589 /*
590 * Process the data that server sent due to IMAP FETCH FAST client request.
591 */
592 int
593 response_fetchfast(session *ssn, int tag, char **flags, char **date,
594 char **size)
595 {
596 int r;
597 char *s;
598 regexp *re;
599
600 if ((r = response_generic(ssn, tag)) == -1)
601 return -1;
602
603 re = &responses[DATA_RESPONSE_FETCH];
604 if (!regexec(re->preg, ibuf.data, re->nmatch, re->pmatch, 0)) {
605 s = xstrndup(ibuf.data + re->pmatch[1].rm_so,
606 re->pmatch[1].rm_eo - re->pmatch[1].rm_so);
607
608 re = &responses[DATA_RESPONSE_FETCH_FLAGS];
609 if (!regexec(re->preg, s, re->nmatch, re->pmatch, 0))
610 *flags = xstrndup(s + re->pmatch[1].rm_so,
611 re->pmatch[1].rm_eo - re->pmatch[1].rm_so);
612
613 re = &responses[DATA_RESPONSE_FETCH_DATE];
614 if (!regexec(re->preg, s, re->nmatch, re->pmatch, 0))
615 *date = xstrndup(s + re->pmatch[1].rm_so,
616 re->pmatch[1].rm_eo - re->pmatch[1].rm_so);
617
618 re = &responses[DATA_RESPONSE_FETCH_SIZE];
619 if (!regexec(re->preg, s, re->nmatch, re->pmatch, 0))
620 *size = xstrndup(s + re->pmatch[1].rm_so,
621 re->pmatch[1].rm_eo - re->pmatch[1].rm_so);
622
623 xfree(s);
624 }
625
626 return r;
627 }
628
629
630 /*
631 * Process the data that server sent due to IMAP FETCH FLAGS client request.
632 */
633 int
634 response_fetchflags(session *ssn, int tag, char **flags)
635 {
636 int r;
637 char *s;
638 regexp *re;
639
640 if ((r = response_generic(ssn, tag)) == -1)
641 return -1;
642
643 re = &responses[DATA_RESPONSE_FETCH];
644 if (!regexec(re->preg, ibuf.data, re->nmatch, re->pmatch, 0)) {
645 s = xstrndup(ibuf.data + re->pmatch[1].rm_so,
646 re->pmatch[1].rm_eo - re->pmatch[1].rm_so);
647
648 re = &responses[DATA_RESPONSE_FETCH_FLAGS];
649 if (!regexec(re->preg, s, re->nmatch, re->pmatch, 0))
650 *flags = xstrndup(s + re->pmatch[1].rm_so,
651 re->pmatch[1].rm_eo - re->pmatch[1].rm_so);
652
653 xfree(s);
654 }
655
656 return r;
657 }
658
659
660 /*
661 * Process the data that server sent due to IMAP FETCH INTERNALDATE client
662 * request.
663 */
664 int
665 response_fetchdate(session *ssn, int tag, char **date)
666 {
667 int r;
668 char *s;
669 regexp *re;
670
671 if ((r = response_generic(ssn, tag)) == -1)
672 return -1;
673
674 re = &responses[DATA_RESPONSE_FETCH];
675 if (!regexec(re->preg, ibuf.data, re->nmatch, re->pmatch, 0)) {
676 s = xstrndup(ibuf.data + re->pmatch[1].rm_so,
677 re->pmatch[1].rm_eo - re->pmatch[1].rm_so);
678
679 re = &responses[DATA_RESPONSE_FETCH_DATE];
680 if (!regexec(re->preg, s, re->nmatch, re->pmatch, 0))
681 *date = xstrndup(s + re->pmatch[1].rm_so,
682 re->pmatch[1].rm_eo - re->pmatch[1].rm_so);
683
684 xfree(s);
685 }
686
687 return r;
688 }
689
690
691 /*
692 * Process the data that server sent due to IMAP FETCH RFC822.SIZE client
693 * request.
694 */
695 int
696 response_fetchsize(session *ssn, int tag, char **size)
697 {
698 int r;
699 char *s;
700 regexp *re;
701
702 if ((r = response_generic(ssn, tag)) == -1)
703 return -1;
704
705 re = &responses[DATA_RESPONSE_FETCH];
706 if (!regexec(re->preg, ibuf.data, re->nmatch, re->pmatch, 0)) {
707 s = xstrndup(ibuf.data + re->pmatch[1].rm_so,
708 re->pmatch[1].rm_eo - re->pmatch[1].rm_so);
709
710 re = &responses[DATA_RESPONSE_FETCH_SIZE];
711 if (!regexec(re->preg, s, re->nmatch, re->pmatch, 0))
712 *size = xstrndup(s + re->pmatch[1].rm_so,
713 re->pmatch[1].rm_eo - re->pmatch[1].rm_so);
714
715 xfree(s);
716 }
717
718 return r;
719 }
720
721
722 /*
723 * Process the data that server sent due to IMAP FETCH BODYSTRUCTURE client
724 * request.
725 */
726 int
727 response_fetchstructure(session *ssn, int tag, char **structure)
728 {
729 int r;
730 char *s;
731 regexp *re;
732
733 if ((r = response_generic(ssn, tag)) == -1)
734 return -1;
735
736 re = &responses[DATA_RESPONSE_FETCH];
737 if (!regexec(re->preg, ibuf.data, re->nmatch, re->pmatch, 0)) {
738 s = xstrndup(ibuf.data + re->pmatch[1].rm_so,
739 re->pmatch[1].rm_eo - re->pmatch[1].rm_so);
740
741 re = &responses[DATA_RESPONSE_FETCH_STRUCTURE];
742 if (!regexec(re->preg, s, re->nmatch, re->pmatch, 0)) {
743 *structure = xstrndup(s + re->pmatch[1].rm_so,
744 re->pmatch[1].rm_eo - re->pmatch[1].rm_so);
745 }
746 xfree(s);
747 }
748
749 return r;
750 }
751
752
753 /*
754 * Process the data that server sent due to IMAP FETCH BODY[] client request,
755 * ie. FETCH BODY[HEADER], FETCH BODY[TEXT], FETCH BODY[HEADER.FIELDS
756 * (<fields>)], FETCH BODY[<part>].
757 */
758 int
759 response_fetchbody(session *ssn, int tag, char **body, size_t *len)
760 {
761 int r, match;
762 unsigned int offset;
763 ssize_t n;
764 regexp *re;
765
766 if (tag == -1)
767 return -1;
768
769 buffer_reset(&ibuf);
770
771 match = -1;
772 offset = 0;
773
774 re = &responses[DATA_RESPONSE_FETCH_BODY];
775
776 do {
777 buffer_check(&ibuf, ibuf.len + INPUT_BUF);
778 if ((n = receive_response(ssn, ibuf.data + ibuf.len, 0, 1)) == -1)
779 return -1;
780 ibuf.len += n;
781
782 if (match != 0) {
783 match = regexec(re->preg, ibuf.data, re->nmatch,
784 re->pmatch, 0);
785
786 if (match == 0 && re->pmatch[2].rm_so != -1 &&
787 re->pmatch[2].rm_eo != -1) {
788 *len = strtoul(ibuf.data + re->pmatch[2].rm_so,
789 NULL, 10);
790 offset = re->pmatch[0].rm_eo + *len;
791 }
792 }
793
794 if (offset != 0 && ibuf.len >= offset) {
795 if (check_bye(ibuf.data + offset))
796 return -1;
797 }
798 } while (ibuf.len < offset || (r = check_tag(ibuf.data + offset, ssn,
799 tag)) == STATUS_RESPONSE_NONE);
800
801 if (match == 0) {
802 if (re->pmatch[2].rm_so != -1 &&
803 re->pmatch[2].rm_eo != -1) {
804 *body = ibuf.data + re->pmatch[0].rm_eo;
805 } else {
806 *body = ibuf.data + re->pmatch[3].rm_so;
807 *len = re->pmatch[3].rm_eo - re->pmatch[3].rm_so;
808 }
809 }
810
811 return r;
812 }
813
814
815 /*
816 * Process the data that server sent due to IMAP IDLE client request.
817 */
818 int
819 response_idle(session *ssn, int tag)
820 {
821 regexp *re;
822
823 re = &responses[DATA_RESPONSE_IDLE];
824
825 do {
826 buffer_reset(&ibuf);
827
828 switch (receive_response(ssn, ibuf.data,
829 get_option_number("keepalive") * 60, 0)) {
830 case -1:
831 return -1;
832 break; /* NOTREACHED */
833 case 0:
834 return STATUS_RESPONSE_TIMEOUT;
835 break; /* NOTREACHED */
836 }
837
838 verbose("S (%d): %s", ssn->socket, ibuf.data);
839
840 if (check_bye(ibuf.data))
841 return -1;
842
843 } while (regexec(re->preg, ibuf.data, re->nmatch, re->pmatch, 0));
844
845 return STATUS_RESPONSE_UNTAGGED;
846 }
Something went wrong with that request. Please try again.