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

Contents of /imapfilter/request.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.50 - (show annotations)
Sat Jul 26 19:40:20 2003 UTC (20 years, 8 months ago) by lefcha
Branch: MAIN
Changes since 1.49: +19 -5 lines
File MIME type: text/plain
Added CRAM-MD5 support.

1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <errno.h>
5 #include <time.h>
6
7 #include "config.h"
8 #include "imapfilter.h"
9 #include "data.h"
10
11
12 extern int sockpri, sockaux;
13 extern unsigned int options;
14 extern char charset[CHARSET_LEN];
15 extern unsigned int capspri, capsaux;
16
17 namesp_t nsppri, nspaux; /* Primary and auxiliary namespace. */
18
19
20 #ifdef DEBUG
21 /*
22 * Test/ping server.
23 */
24 int
25 test(int *sock)
26 {
27 return server_response(sock, imap_noop(sock));
28 }
29
30 #endif
31
32
33 /*
34 * Check server's capabilities.
35 */
36 int
37 check_capabilities(int *sock)
38 {
39 if (sock == &sockpri)
40 capspri = CAPABILITY_NONE;
41 else
42 capsaux = CAPABILITY_NONE;
43
44 return capability_response(sock, imap_capability(sock));
45 }
46
47
48 /*
49 * Get namespace of mail server's mailboxes.
50 */
51 int
52 check_namespace(int *sock, namesp_t * nsp)
53 {
54 unsigned int *caps;
55
56 caps = (sock == &sockpri ? &capspri : &capsaux);
57 nsp->prefix[0] = nsp->delim = '\0';
58
59 if (!(options & OPTION_NAMESPACE) ||
60 !(*caps & CAPABILITY_NAMESPACE))
61 return 0;
62 else
63 return namespace_response(sock, imap_namespace(sock), nsp);
64 }
65
66
67 /*
68 * Login to server.
69 */
70 int
71 login(int *sock, char *user, char *pass)
72 {
73 return server_response(sock, imap_login(sock, user, pass));
74 }
75
76
77
78 /*
79 * Check if a mailbox exists.
80 */
81 int
82 check_mailbox(int *sock, char *mbox)
83 {
84 return server_response(sock, imap_status(sock, mbox, "MESSAGES"));
85 }
86
87
88 /*
89 * Open mailbox in read-write mode.
90 */
91 int
92 select_mailbox(int *sock, char *mbox, namesp_t * nsp)
93 {
94 int r;
95
96 if (mailbox_status(sock, mbox, nsp) == -2)
97 return -2; /* No messages exist. No filters need to be
98 * applied. */
99
100 r = select_response(sock, imap_select(sock,
101 apply_namespace(mbox, nsp->prefix,
102 nsp->delim)));
103
104 log_info(LOG_MAILBOX, mbox);
105
106 return r;
107 }
108
109
110 /*
111 * Get mailbox's status.
112 */
113 int
114 mailbox_status(int *sock, char *mbox, namesp_t * nsp)
115 {
116 return status_response(sock, imap_status(sock,
117 apply_namespace(mbox, nsp->prefix, nsp->delim),
118 "MESSAGES RECENT UNSEEN"), mbox);
119 }
120
121
122 /*
123 * Close examined/selected mailbox.
124 */
125 int
126 close_mailbox(int *sock)
127 {
128 return server_response(sock, imap_close(sock));
129 }
130
131
132 /*
133 * Logout from server.
134 */
135 int
136 logout(int *sock)
137 {
138 return logout_response(sock, imap_logout(sock));
139 }
140
141
142 /*
143 * Match and apply filters assigned to a mailbox.
144 */
145 int
146 apply_filters(char *mbox, filter_t ** filters)
147 {
148 int i;
149 char *mesgs;
150
151 for (i = 0; filters[i] != NULL; i++) {
152 mesgs = NULL;
153
154 if (match_filter(filters[i], &mesgs))
155 continue;
156
157 log_info(LOG_FILTER, filters[i]->key);
158
159 apply_action(mbox, mesgs, &(filters[i]->action.type),
160 filters[i]->action.raccount, filters[i]->action.destmbox,
161 &filters[i]->action.msgflags, filters[i]->action.args);
162
163 xfree(mesgs);
164 }
165
166 return 0;
167 }
168
169
170 /*
171 * Generate the search request by the masks of the filter and try to
172 * match the generated filter.
173 */
174 int
175 match_filter(filter_t * filter, char **mesgs)
176 {
177 char *search;
178
179 if (filter->mode == FILTER_MODE_OR)
180 search = generate_filter_or(filter->masks, filter->masknum,
181 filter->masklen);
182 else
183 search = generate_filter_and(filter->masks, filter->masknum,
184 filter->masklen);
185
186 search_response(&sockpri, imap_search(&sockpri, charset, search),
187 mesgs);
188
189 xfree(search);
190
191 if (*mesgs == '\0')
192 return 1;
193
194 return 0;
195 }
196
197
198 /*
199 * Empty the FIFO inventory.
200 */
201 void
202 empty_fifo(mask_t ** mfifo)
203 {
204 mfifo[0] = NULL;
205
206 queue_fifo(NULL, NULL);
207 dequeue_fifo(NULL);
208 }
209
210
211 /*
212 * Add item to FIFO inventory.
213 */
214 void
215 queue_fifo(mask_t ** mfifo, mask_t * mask)
216 {
217 static unsigned int i;
218
219 if (mfifo == NULL) {
220 i = 0;
221 return;
222 }
223 mfifo[i++] = mask;
224 mfifo[i] = NULL;
225 }
226
227
228 /*
229 * Get next item from FIFO inventory.
230 */
231 mask_t *
232 dequeue_fifo(mask_t ** mfifo)
233 {
234 static unsigned int j;
235
236 if (mfifo == NULL) {
237 j = 0;
238 return NULL;
239 }
240 return mfifo[j++];
241 }
242
243
244 /*
245 * Generate the filter search command from the masks, assuming that
246 * masks are AND-ed.
247 */
248 char *
249 generate_filter_and(mask_t * mask, unsigned int masknum,
250 unsigned int masklen)
251 {
252 const unsigned int searchbuf = masklen + masknum * 6 + 8;
253 unsigned int len;
254 char *search;
255 mask_t *tmp;
256
257 len = 0;
258
259 search = (char *)xmalloc(sizeof(char) * searchbuf);
260 search[0] = '\0';
261
262 tmp = mask;
263 if (tmp == NULL) {
264 strncat(search, "ALL ", searchbuf - len - 1);
265 len += 4;
266 } else
267 while ((tmp = tmp->next) != NULL) {
268 if (tmp->type != MASK_TYPE_OR) {
269 strncat(search, "ALL ", searchbuf - len - 1);
270 len += 4;
271 break;
272 }
273 }
274
275 tmp = NULL;
276 while (mask != NULL) {
277 tmp = mask;
278 mask = mask->next;
279
280 if (mask != NULL && mask->type == MASK_TYPE_OR) {
281 strncat(search, "OR (", searchbuf - len - 1);
282 len += 4;
283
284 strncat(search, tmp->body, searchbuf - len - 1);
285 len = strlen(search);
286 search[len] = ' ';
287 search[++len] = '\0';
288
289 search[len - 1] = ')';
290 search[len] = ' ';
291 search[++len] = '\0';
292
293 if (mask->next == NULL ||
294 mask->next->type != MASK_TYPE_OR) {
295 search[len] = '(';
296 search[++len] = '\0';
297 strncat(search, mask->body,
298 searchbuf - len - 1);
299 len = strlen(search);
300 search[len] = ')';
301 search[++len] = ' ';
302 search[++len] = '\0';
303 mask = mask->next;
304 }
305 } else {
306 strncat(search, tmp->body, searchbuf - len - 1);
307 len = strlen(search);
308 search[len] = ' ';
309 search[++len] = '\0';
310 }
311 }
312
313 search[len - 1] = '\0';
314
315 return search;
316 }
317
318
319 /*
320 * Generate the filter search command from the masks, assuming that
321 * masks are OR-ed.
322 */
323 char *
324 generate_filter_or(mask_t * mask, unsigned int masknum,
325 unsigned int masklen)
326 {
327 const unsigned int searchbuf = masklen + masknum * 6 + 8;
328 unsigned int len;
329 char *search;
330 mask_t **mfifo; /* Mailbox FIFO queue. */
331 mask_t *mf; /* Mask returned from FIFO. */
332
333 len = 0;
334
335 search = (char *)xmalloc(sizeof(char) * searchbuf);
336 mfifo = (mask_t **) xmalloc(sizeof(mask_t *) * (masknum + 1));
337
338 search[0] = '\0';
339 empty_fifo(mfifo);
340
341 strncat(search, "ALL ", searchbuf - len - 1);
342 len += 4;
343
344 while (mask != NULL) {
345 queue_fifo(mfifo, mask);
346 mask = mask->next;
347
348 while (mask != NULL && mask->type == MASK_TYPE_AND) {
349 queue_fifo(mfifo, mask);
350 mask = mask->next;
351 }
352
353 if (mask != NULL) {
354 if (len == 4 && search[0] == 'A') {
355 search[0] = '\0';
356 len = 0;
357 }
358 strncat(search, "OR ", searchbuf - len - 1);
359 len += 3;
360 }
361 if (search[0] != 'A') {
362 search[len] = '(';
363 search[++len] = '\0';
364 }
365 while ((mf = dequeue_fifo(mfifo)) != NULL) {
366 strncat(search, mf->body, searchbuf - len - 1);
367 len = strlen(search);
368 search[len] = ' ';
369 search[++len] = '\0';
370 }
371
372 if (strchr(search, '(')) {
373 search[len - 1] = ')';
374 search[len] = ' ';
375 search[++len] = '\0';
376 }
377 empty_fifo(mfifo);
378 }
379
380 search[len - 1] = '\0';
381
382 xfree(mfifo);
383
384 return search;
385 }
386
387
388 /*
389 * Apply the appropriate action.
390 */
391 int
392 apply_action(char *mbox, char *mesgs, unsigned int *type, account_t * raccount,
393 char *destmbox, unsigned int *msgflags, char *args)
394 {
395 unsigned int cnt;
396
397 if (*mesgs == '\0')
398 return 0;
399
400 log_info(LOG_ACTION, type);
401 log_info(LOG_DESTINATION_ACCOUNT, raccount->key);
402 log_info(LOG_DESTINATION_MAILBOX, destmbox);
403
404 cnt = count_messages(mesgs);
405
406 switch (*type) {
407 case FILTER_ACTION_DELETE:
408 info("%d message%s deleted.\n", cnt, plural(cnt));
409 action_delete(mesgs, args);
410 break;
411 case FILTER_ACTION_COPY:
412 info("%d message%s copied from \"%s\" to mailbox \"%s\".\n",
413 cnt, plural(cnt), mbox, destmbox);
414 action_copy(mbox, mesgs, apply_namespace(destmbox,
415 nsppri.prefix, nsppri.delim), args);
416 break;
417 case FILTER_ACTION_MOVE:
418 info("%d message%s moved from \"%s\" to mailbox \"%s\".\n",
419 cnt, plural(cnt), mbox, destmbox);
420 action_move(mbox, mesgs, apply_namespace(destmbox,
421 nsppri.prefix, nsppri.delim), args);
422 break;
423 case FILTER_ACTION_RCOPY:
424 info("%d message%s copied from \"%s\" to mailbox "
425 "\"%s\" at account %s.\n", cnt, plural(cnt),
426 mbox, destmbox, raccount->key);
427 action_rcopy(mbox, mesgs, raccount, destmbox, args);
428 break;
429 case FILTER_ACTION_RMOVE:
430 info("%d message%s moved from \"%s\" to mailbox "
431 "\"%s\" at account %s.\n", cnt, plural(cnt),
432 mbox, destmbox, raccount->key);
433 action_rmove(mbox, mesgs, raccount, destmbox, args);
434 break;
435 case FILTER_ACTION_FLAG_REPLACE:
436 case FILTER_ACTION_FLAG_ADD:
437 case FILTER_ACTION_FLAG_REMOVE:
438 info("%d message%s flagged.\n", cnt, plural(cnt));
439 action_flag(mesgs, type, msgflags, args);
440 break;
441 case FILTER_ACTION_LIST:
442 info("%d message%s listed.\n", cnt, plural(cnt));
443 action_list(mesgs, args);
444 break;
445 }
446
447 if (*args == '\0')
448 log_info(LOG_PREAMBLE, NULL);
449
450 return 0;
451 }
452
453
454 /*
455 * Delete messages and optionally list some of their headers.
456 */
457 int
458 action_delete(char *mesgs, char *args)
459 {
460 char *tok, *m, *mcp;
461
462 action_list(mesgs, args);
463
464 m = mcp = convert_messages(mesgs);
465
466 tok = strtok_r(m, " ", &m);
467 while (tok) {
468 server_response(&sockpri, imap_store(&sockpri, tok,
469 STORE_FLAG_ADD, "\\Deleted"));
470
471 tok = strtok_r(NULL, " ", &m);
472 }
473
474 if (options & OPTION_EXPUNGE)
475 server_response(&sockpri, imap_expunge(&sockpri));
476
477 xfree(mcp);
478
479 return 0;
480 }
481
482
483 /*
484 * Copy messages to specified mailbox.
485 */
486 int
487 action_copy(char *mbox, char *mesgs, char *destmbox, char *args)
488 {
489 int r;
490 char *tok, *mcp, *m;
491 char dm[2][MBOX_NAME_LEN];
492
493 r = 0;
494 tok = NULL;
495
496 action_list(mesgs, args);
497
498 if (strchr(destmbox, '@'))
499 m = mcp = xstrdup(mesgs);
500 else
501 m = mcp = convert_messages(mesgs);
502
503 xstrncpy(dm[0], destmbox, MBOX_NAME_LEN - 1);
504 default_variables(mbox, dm[0]);
505 current_date(dm[0]);
506 tok = strtok_r(m, " ", &m);
507 while (tok != NULL) {
508 xstrncpy(dm[1], dm[0], MBOX_NAME_LEN - 1);
509 message_date(tok, dm[1]);
510
511 if ((r = copy_response(&sockpri, imap_copy(&sockpri, tok,
512 dm[1]))) == RESPONSE_TRYCREATE)
513 if (!server_response(&sockpri, imap_create(&sockpri,
514 dm[1]))) {
515 if ((options & OPTION_SUBSCRIBE))
516 server_response(&sockpri,
517 imap_subscribe(&sockpri, dm[1]));
518 r = copy_response(&sockpri,
519 imap_copy(&sockpri, tok, dm[1]));
520 }
521 tok = strtok_r(NULL, " ", &m);
522 }
523
524 xfree(mcp);
525
526 return r;
527 }
528
529
530 /*
531 * Move messages to specified mailbox.
532 */
533 int
534 action_move(char *mbox, char *mesgs, char *destmbox, char *args)
535 {
536 if (!action_copy(mbox, mesgs, destmbox, args))
537 action_delete(mesgs, "\0");
538
539 return 0;
540 }
541
542
543 /*
544 * Copy messages to the specified mailbox of another mail server.
545 */
546 int
547 action_rcopy(char *mbox, char *mesgs, account_t * destacc, char *destmbox,
548 char *args)
549 {
550 int r, ta, tf;
551 char *tok, *m, *mcp, *ndm;
552 unsigned int n;
553 char buf[RESPONSE_BUF * 2 + 1];
554 char dm[3][MBOX_NAME_LEN];
555
556 *dm[0] = *dm[1] = *dm[2] = '\0';
557
558 if (init_connection(&sockaux, destacc->server, destacc->port,
559 destacc->ssl))
560 return ERROR_NETWORK;
561
562 r = greeting_response(&sockaux);
563
564 #ifdef DEBUG
565 test(&sockaux);
566 #endif
567
568 if (r == RESPONSE_BYE || check_capabilities(&sockaux))
569 return ERROR_NETWORK;
570
571 if (r != RESPONSE_PREAUTH) {
572 if (destacc->passwdattr == PASSWORD_NONE) {
573 printf("Enter password for %s@%s: ", destacc->username,
574 destacc->server);
575 get_password(destacc->password, PASSWORD_LEN);
576 destacc->passwdattr = PASSWORD_PLAIN;
577 }
578 #ifdef CRAM_MD5
579 if (capsaux & CAPABILITY_AUTH_CRAM_MD5)
580 r = imf_cram_md5(&sockaux, destacc->username,
581 destacc->password);
582 else
583 #endif
584 r = login(&sockaux, destacc->username,
585 destacc->password);
586
587 if (r == RESPONSE_NO) {
588 error("username %s or password rejected at %s\n",
589 destacc->username, destacc->server);
590 return ERROR_NETWORK;
591 }
592 }
593 check_namespace(&sockaux, &nspaux);
594
595 m = mcp = xstrdup(mesgs);
596
597 xstrncpy(dm[1], destmbox, MBOX_NAME_LEN - 1);
598 current_date(dm[1]);
599
600 tok = strtok_r(m, " ", &m);
601 while (tok != NULL) {
602 xstrncpy(dm[2], dm[1], MBOX_NAME_LEN - 1);
603 message_date(tok, dm[2]);
604
605 /* apply_namespace() returns a pointer to a static buffer. */
606 ndm = apply_namespace(dm[2], nspaux.prefix, nspaux.delim);
607
608 /* Check only if mailbox name is different from last one. */
609 if (strncmp(dm[0], dm[2], strlen(dm[2]))) {
610 r = check_mailbox(&sockaux, ndm);
611 if (r == RESPONSE_NO) {
612 server_response(&sockaux,
613 imap_create(&sockaux, ndm));
614 if ((options & OPTION_SUBSCRIBE))
615 server_response(&sockaux,
616 imap_subscribe(&sockaux, ndm));
617 }
618 }
619 xstrncpy(dm[0], dm[2], MBOX_NAME_LEN - 1);
620
621 fetchsize_response(&sockpri, &n,
622 imap_fetch(&sockpri, tok, "RFC822.SIZE"));
623
624 ta = imap_append(&sockaux, ndm, n);
625
626 fetch_response(&sockpri, 0, 1, NULL);
627 tf = imap_fetch(&sockpri, tok, "RFC822.HEADER");
628 do {
629 r = fetch_response(&sockpri, tf, 0, buf);
630 socket_write(&sockaux, buf);
631 } while (r == RESPONSE_NONE);
632
633 socket_write(&sockaux, "\r\n");
634
635 fetch_response(&sockpri, 0, 1, NULL);
636 tf = imap_fetch(&sockpri, tok, "BODY[TEXT]");
637 do {
638 r = fetch_response(&sockpri, tf, 0, buf);
639 if (r != RESPONSE_NULLBODY)
640 socket_write(&sockaux, buf);
641 } while (r == RESPONSE_NONE);
642
643 if (r != RESPONSE_NULLBODY)
644 socket_write(&sockaux, "\r\n\r\n");
645 else
646 socket_write(&sockaux, "\r\n");
647
648 append_response(&sockaux, ta);
649
650 tok = strtok_r(NULL, " ", &m);
651 }
652
653 logout(&sockaux);
654
655 action_list(mesgs, args);
656
657 xfree(mcp);
658
659 return 0;
660 }
661
662
663 /*
664 * Move messages to the specified mailbox of another mail server.
665 */
666 int
667 action_rmove(char *mbox, char *mesgs, account_t * destacc, char *destmbox,
668 char *args)
669 {
670 if (!action_rcopy(mbox, mesgs, destacc, destmbox, args))
671 action_delete(mesgs, "\0");
672
673 return 0;
674 }
675
676
677 /*
678 * Flag messages by replacing, adding or removing specified flags.
679 */
680 int
681 action_flag(char *mesgs, unsigned int *type, unsigned int *msgflags,
682 char *args)
683 {
684 unsigned int t;
685 char s[STORE_FLAGS_BUF];
686 char *tok, *m, *mcp;
687
688 *s = 0;
689
690 switch (*type) {
691 case FILTER_ACTION_FLAG_ADD:
692 t = STORE_FLAG_ADD;
693 break;
694 case FILTER_ACTION_FLAG_REMOVE:
695 t = STORE_FLAG_REMOVE;
696 break;
697 default:
698 t = STORE_FLAG_REPLACE;
699 }
700
701 if ((*msgflags != MESSAGE_FLAG_NONE)) {
702 if ((*msgflags & MESSAGE_FLAG_SEEN))
703 strncat(s, "\\Seen ", STORE_FLAGS_BUF - strlen(s) - 1);
704 if ((*msgflags & MESSAGE_FLAG_ANSWERED))
705 strncat(s, "\\Answered ",
706 STORE_FLAGS_BUF - strlen(s) - 1);
707 if ((*msgflags & MESSAGE_FLAG_FLAGGED))
708 strncat(s, "\\Flagged ",
709 STORE_FLAGS_BUF - strlen(s) - 1);
710 if ((*msgflags & MESSAGE_FLAG_DELETED))
711 strncat(s, "\\Deleted ",
712 STORE_FLAGS_BUF - strlen(s) - 1);
713 if ((*msgflags & MESSAGE_FLAG_DRAFT))
714 strncat(s, "\\Draft", STORE_FLAGS_BUF - strlen(s) - 1);
715 if ((s[strlen(s) - 1] == ' '))
716 s[strlen(s) - 1] = 0;
717 }
718 action_list(mesgs, args);
719
720 m = mcp = convert_messages(mesgs);
721
722 tok = strtok_r(m, " ", &m);
723 while (tok != NULL) {
724 server_response(&sockpri, imap_store(&sockpri, tok, t, s));
725
726 tok = strtok_r(NULL, " ", &m);
727 }
728
729 if (options & OPTION_EXPUNGE)
730 server_response(&sockpri, imap_expunge(&sockpri));
731
732 xfree(mcp);
733
734 return 0;
735 }
736
737 /*
738 * List user selected headers of messages.
739 */
740 int
741 action_list(char *mesgs, char *args)
742 {
743 int r, t;
744 char *tok, *mcp, *m;
745 char s[ARGS_LEN + 27];
746 char hdrs[RESPONSE_BUF * 2 + 1];
747
748 if (*args == '\0')
749 return 0;
750
751 m = mcp = xstrdup(mesgs);
752
753 snprintf(s, ARGS_LEN + 27 - 1, "BODY.PEEK[HEADER.FIELDS (%s)]", args);
754
755 tok = strtok_r(m, " ", &m);
756 while (tok != NULL) {
757 /* Reset internal fetch counter. */
758 fetch_response(&sockpri, 0, 1, NULL);
759 t = imap_fetch(&sockpri, tok, s);
760
761 log_info(LOG_PREAMBLE, NULL);
762 do {
763 r = fetch_response(&sockpri, t, 0, hdrs);
764
765 if (*hdrs != '\0') {
766 if (options & OPTION_HEADERS)
767 info("%s\n", hdrs);
768 log_info(LOG_HEADER, hdrs);
769 }
770 } while (r == RESPONSE_NONE);
771
772 tok = strtok_r(NULL, " ", &m);
773 }
774
775 xfree(mcp);
776
777 return 0;
778 }
779
780
781 /*
782 * Count how many messages matched the filter.
783 */
784 unsigned int
785 count_messages(char *mesgs)
786 {
787 unsigned int cnt;
788 char *c;
789
790 cnt = 0;
791 c = mesgs;
792
793 while ((c = strchr(c, ' '))) {
794 cnt++;
795 c++;
796 }
797
798 return ++cnt;
799 }
800
801
802 /*
803 * Convert messages with contiguous sequence number to the corresponding
804 * number range, eg. 1 2 3 5 7 8 --> 1:3 5 7:8 and return a newly allocated
805 * buffer with the results.
806 */
807 char *
808 convert_messages(char *mesgs)
809 {
810 int maxlen;
811 unsigned int start, end, tmp;
812 char *c, *cp, *tail;
813
814 start = end = tmp = 0;
815 maxlen = strlen(mesgs) + 1;
816 tail = NULL;
817
818 c = cp = xstrdup(mesgs);
819
820 start = (unsigned int)strtoul(mesgs, &tail, 10);
821 end = start;
822
823 do {
824 if (tail != NULL) {
825 tmp = (unsigned int)strtoul(tail, &tail, 10);
826 if (tmp == 0)
827 tail = NULL;
828 }
829 if (tmp == end + 1)
830 end++;
831 else {
832 if (start == end) {
833 xstrncpy(c, ultostr(start, 10), maxlen);
834 c += strlen(c);
835 } else {
836 xstrncpy(c, ultostr(start, 10), maxlen - 1);
837 c += strlen(c);
838 *c = ':';
839 *++c = 0;
840 xstrncpy(c, ultostr(end, 10), maxlen);
841 c += strlen(c);
842 }
843
844 if (tail != NULL && c - cp < maxlen) {
845 *c = ' ';
846 *++c = 0;
847 }
848 start = end = tmp;
849 }
850 } while (tmp != 0);
851
852 return cp;
853 }
854
855
856 /*
857 * Substitute all occurences of the '@' character with the '%' character,
858 * and any double '@' characters with a signle '@' character, returning the
859 * number of replacements.
860 */
861 int
862 substitute_date(char *str)
863 {
864 int n;
865 char *r, *w, *s;
866
867 n = 0;
868
869 s = xstrdup(str);
870
871 for (r = s, w = str; *r != '\0'; r++, w++) {
872 if (*r == '%') {
873 *w++ = '%';
874 *w = '%';
875 } else if (*r == '@') {
876 if (*(r + 1) == '@') {
877 *w = *r++;
878 } else {
879 *w = '%';
880 n++;
881 }
882 } else {
883 *w = *r;
884 }
885 }
886 *w = '\0';
887
888 xfree(s);
889
890 return n;
891 }
892
893
894 /*
895 * Format the destination mailbox according to the current date conversion
896 * specifiers.
897 */
898 void
899 current_date(char *destmbox)
900 {
901 char s[MBOX_NAME_LEN];
902 time_t te;
903 struct tm *tl;
904
905 if (!strchr(destmbox, '%'))
906 return;
907
908 te = time(NULL);
909 tl = localtime(&te);
910
911 if (strftime(s, MBOX_NAME_LEN - 1, destmbox, tl))
912 xstrncpy(destmbox, s, MBOX_NAME_LEN - 1);
913 }
914
915
916 /*
917 * Format the destination mailbox according to the message date conversion
918 * specifiers.
919 */
920 void
921 message_date(char *mesg, char *destmbox)
922 {
923 unsigned int t;
924 char s[MBOX_NAME_LEN];
925 struct tm tl;
926 char dbuf[RESPONSE_BUF + 1];
927
928 if (!strchr(destmbox, '@'))
929 return;
930
931 substitute_date(destmbox);
932
933 fetch_response(&sockpri, 0, 1, NULL);
934 t = imap_fetch(&sockpri, mesg, "BODY.PEEK[HEADER.FIELDS (DATE)]");
935
936 while (fetch_response(&sockpri, t, 0, dbuf) == RESPONSE_NONE);
937
938 if (strptime(dbuf, "Date: %a, %d %b %Y %H:%M:%S", &tl) &&
939 strftime(s, MBOX_NAME_LEN - 1, destmbox, &tl))
940 xstrncpy(destmbox, s, MBOX_NAME_LEN - 1);
941 }
942
943
944 /*
945 * Format the destination mailbox according to "default variables" specifiers.
946 */
947 void
948 default_variables(char *mbox, char *destmbox)
949 {
950 char *m, *r, *w, *s;
951
952 if (!strchr(destmbox, '$'))
953 return;
954
955 s = xstrdup(destmbox);
956
957 for (r = s, w = destmbox; *r != '\0';) {
958 if (w - destmbox >= MBOX_NAME_LEN - 1)
959 break;
960 if (*r == '$') {
961 switch (*(r + 1)) {
962 case '_':
963 if (w + strlen(mbox) - destmbox >
964 MBOX_NAME_LEN - 1) {
965 r += 2;
966 break;
967 }
968 for (m = mbox; *m != '\0'; m++, w++)
969 *w = *m;
970 r += 2;
971 break;
972 case '$':
973 *w++ = '$';
974 r += 2;
975 break;
976 default:
977 *w++ = *r++;
978 break;
979 }
980 } else {
981 *w++ = *r++;
982 }
983 }
984 *w = '\0';
985
986 xfree(s);
987 }

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26