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

Contents of /imapfilter/request.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.52 - (show annotations)
Sun Jul 27 15:56:05 2003 UTC (20 years, 8 months ago) by lefcha
Branch: MAIN
Changes since 1.51: +0 -1 lines
File MIME type: text/plain
Removed unused variable.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26