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

Contents of /imapfilter/request.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.53 - (show annotations)
Sun Jul 27 17:39:45 2003 UTC (20 years, 8 months ago) by lefcha
Branch: MAIN
Changes since 1.52: +81 -90 lines
File MIME type: text/plain
New structure to hold information about connection's socket, ssl socket, capabilities, namespace.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26