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

Contents of /imapfilter/request.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.49 - (show annotations)
Sun Mar 30 15:40:28 2003 UTC (21 years ago) by lefcha
Branch: MAIN
Changes since 1.48: +10 -8 lines
File MIME type: text/plain
Print source mailbox if action is (r)copy/(r)move.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26