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

Annotation of /imapfilter/action.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.4 - (hide annotations)
Fri Sep 12 09:58:20 2003 UTC (20 years, 6 months ago) by lefcha
Branch: MAIN
Changes since 1.3: +1 -0 lines
File MIME type: text/plain
Fix so that default_variables() is called during rcopy/rmove.

1 lefcha 1.1 #include <stdio.h>
2 lefcha 1.2 #include <stdlib.h>
3 lefcha 1.1 #include <string.h>
4 lefcha 1.3 #include <sys/types.h>
5 lefcha 1.1 #include <time.h>
6    
7     #include "config.h"
8     #include "imapfilter.h"
9    
10    
11     extern conn_t connpri, connaux;
12     extern unsigned int options;
13    
14    
15     int action_delete(char *mesgs, char *args);
16     int action_copy(char *mbox, char *mesgs, char *destmbox, char *args);
17     int action_move(char *mbox, char *mesgs, char *destmbox, char *args);
18     int action_rcopy(char *mbox, char *mesgs, account_t * destacc, char *destmbox, char *args);
19     int action_rmove(char *mbox, char *mesgs, account_t * destacc, char *destmbox, char *args);
20     int action_flag(char *mesgs, unsigned int *type, unsigned int *msgflags, char *args);
21     int action_list(char *mesgs, char *args);
22    
23     unsigned int count_messages(char *mesgs);
24     char *convert_messages(char *mesgs);
25     int substitute_date(char *str);
26     void current_date(char *destmbox);
27     void message_date(char *mesg, char *destmbox);
28     void default_variables(char *mbox, char *destmbox);
29    
30    
31     /*
32     * Apply the appropriate action.
33     */
34     int
35     apply_action(char *mbox, char *mesgs, unsigned int *type, account_t * raccount,
36     char *destmbox, unsigned int *msgflags, char *args)
37     {
38     unsigned int cnt;
39    
40     if (*mesgs == '\0')
41     return 0;
42    
43     log_info(LOG_ACTION, type);
44     log_info(LOG_DESTINATION_ACCOUNT, raccount->key);
45     log_info(LOG_DESTINATION_MAILBOX, destmbox);
46    
47     cnt = count_messages(mesgs);
48    
49     switch (*type) {
50     case FILTER_ACTION_DELETE:
51     info("%d message%s deleted.\n", cnt, plural(cnt));
52     action_delete(mesgs, args);
53     break;
54     case FILTER_ACTION_COPY:
55     info("%d message%s copied from \"%s\" to mailbox \"%s\".\n",
56     cnt, plural(cnt), mbox, destmbox);
57     action_copy(mbox, mesgs, apply_namespace(destmbox,
58     connpri.nsp.prefix, connpri.nsp.delim), args);
59     break;
60     case FILTER_ACTION_MOVE:
61     info("%d message%s moved from \"%s\" to mailbox \"%s\".\n",
62     cnt, plural(cnt), mbox, destmbox);
63     action_move(mbox, mesgs, apply_namespace(destmbox,
64     connpri.nsp.prefix, connpri.nsp.delim), args);
65     break;
66     case FILTER_ACTION_RCOPY:
67     info("%d message%s copied from \"%s\" to mailbox "
68     "\"%s\" at account %s.\n", cnt, plural(cnt),
69     mbox, destmbox, raccount->key);
70     action_rcopy(mbox, mesgs, raccount, destmbox, args);
71     break;
72     case FILTER_ACTION_RMOVE:
73     info("%d message%s moved from \"%s\" to mailbox "
74     "\"%s\" at account %s.\n", cnt, plural(cnt),
75     mbox, destmbox, raccount->key);
76     action_rmove(mbox, mesgs, raccount, destmbox, args);
77     break;
78     case FILTER_ACTION_FLAG_REPLACE:
79     case FILTER_ACTION_FLAG_ADD:
80     case FILTER_ACTION_FLAG_REMOVE:
81     info("%d message%s flagged.\n", cnt, plural(cnt));
82     action_flag(mesgs, type, msgflags, args);
83     break;
84     case FILTER_ACTION_LIST:
85     info("%d message%s listed.\n", cnt, plural(cnt));
86     action_list(mesgs, args);
87     break;
88     }
89    
90     if (*args == '\0')
91     log_info(LOG_PREAMBLE, NULL);
92    
93     return 0;
94     }
95    
96    
97     /*
98     * Delete messages and optionally list some of their headers.
99     */
100     int
101     action_delete(char *mesgs, char *args)
102     {
103     char *tok, *m, *mcp;
104    
105     action_list(mesgs, args);
106    
107     m = mcp = convert_messages(mesgs);
108    
109     tok = strtok_r(m, " ", &m);
110     while (tok) {
111     server_response(&connpri, imap_store(&connpri, tok,
112     STORE_FLAG_ADD, "\\Deleted"));
113    
114     tok = strtok_r(NULL, " ", &m);
115     }
116    
117     if (options & OPTION_EXPUNGE)
118     server_response(&connpri, imap_expunge(&connpri));
119    
120     xfree(mcp);
121    
122     return 0;
123     }
124    
125    
126     /*
127     * Copy messages to specified mailbox.
128     */
129     int
130     action_copy(char *mbox, char *mesgs, char *destmbox, char *args)
131     {
132     int r;
133     char *tok, *mcp, *m;
134     char dm[2][MBOX_NAME_LEN];
135    
136     r = 0;
137     tok = NULL;
138    
139     action_list(mesgs, args);
140    
141     if (strchr(destmbox, '@'))
142     m = mcp = xstrdup(mesgs);
143     else
144     m = mcp = convert_messages(mesgs);
145    
146     xstrncpy(dm[0], destmbox, MBOX_NAME_LEN - 1);
147     default_variables(mbox, dm[0]);
148     current_date(dm[0]);
149     tok = strtok_r(m, " ", &m);
150     while (tok != NULL) {
151     xstrncpy(dm[1], dm[0], MBOX_NAME_LEN - 1);
152     message_date(tok, dm[1]);
153    
154     if ((r = copy_response(&connpri, imap_copy(&connpri, tok,
155     dm[1]))) == RESPONSE_TRYCREATE)
156     if (!server_response(&connpri, imap_create(&connpri,
157     dm[1]))) {
158     if ((options & OPTION_SUBSCRIBE))
159     server_response(&connpri,
160     imap_subscribe(&connpri, dm[1]));
161     r = copy_response(&connpri,
162     imap_copy(&connpri, tok, dm[1]));
163     }
164     tok = strtok_r(NULL, " ", &m);
165     }
166    
167     xfree(mcp);
168    
169     return r;
170     }
171    
172    
173     /*
174     * Move messages to specified mailbox.
175     */
176     int
177     action_move(char *mbox, char *mesgs, char *destmbox, char *args)
178     {
179     if (!action_copy(mbox, mesgs, destmbox, args))
180     action_delete(mesgs, "\0");
181    
182     return 0;
183     }
184    
185    
186     /*
187     * Copy messages to the specified mailbox of another mail server.
188     */
189     int
190     action_rcopy(char *mbox, char *mesgs, account_t * destacc, char *destmbox,
191     char *args)
192     {
193     int r, ta, tf;
194     char *tok, *m, *mcp, *ndm;
195     unsigned int n;
196     char buf[RESPONSE_BUF * 2 + 1];
197     char dm[3][MBOX_NAME_LEN];
198    
199     *dm[0] = *dm[1] = *dm[2] = '\0';
200    
201     if (init_connection(&connaux, destacc->server, destacc->port,
202     destacc->ssl))
203     return ERROR_NETWORK;
204    
205     r = greeting_response(&connaux);
206    
207     #ifdef DEBUG
208     test(&connaux);
209     #endif
210    
211     if (r == RESPONSE_BYE || check_capabilities(&connaux))
212     return ERROR_NETWORK;
213    
214     #ifdef SSL_TLS
215     if (destacc->ssl == SSL_DISABLED && connaux.caps & CAPABILITY_STARTTLS)
216     if (negotiate_tls(&connaux) == RESPONSE_OK)
217     check_capabilities(&connaux);
218     #endif
219    
220     if (r != RESPONSE_PREAUTH) {
221     if (destacc->passwdattr == PASSWORD_NONE) {
222     printf("Enter password for %s@%s: ", destacc->username,
223     destacc->server);
224     get_password(destacc->password, PASSWORD_LEN);
225     destacc->passwdattr = PASSWORD_PLAIN;
226     }
227     #ifdef CRAM_MD5
228     if (connaux.caps & CAPABILITY_AUTH_CRAM_MD5)
229     r = auth_cram_md5(&connaux, destacc->username,
230     destacc->password);
231     else
232     #endif
233     r = login(&connaux, destacc->username,
234     destacc->password);
235    
236     if (r == RESPONSE_NO) {
237     error("username %s or password rejected at %s\n",
238     destacc->username, destacc->server);
239     return ERROR_NETWORK;
240     }
241     }
242     check_namespace(&connaux);
243    
244     m = mcp = xstrdup(mesgs);
245    
246     xstrncpy(dm[1], destmbox, MBOX_NAME_LEN - 1);
247 lefcha 1.4 default_variables(mbox, dm[1]);
248 lefcha 1.1 current_date(dm[1]);
249    
250     tok = strtok_r(m, " ", &m);
251     while (tok != NULL) {
252     xstrncpy(dm[2], dm[1], MBOX_NAME_LEN - 1);
253     message_date(tok, dm[2]);
254    
255     /* apply_namespace() returns a pointer to a static buffer. */
256     ndm = apply_namespace(dm[2], connaux.nsp.prefix,
257     connaux.nsp.delim);
258    
259     /* Check only if mailbox name is different from last one. */
260     if (strncmp(dm[0], dm[2], strlen(dm[2]))) {
261     r = check_mailbox(&connaux, ndm);
262     if (r == RESPONSE_NO) {
263     server_response(&connaux,
264     imap_create(&connaux, ndm));
265     if ((options & OPTION_SUBSCRIBE))
266     server_response(&connaux,
267     imap_subscribe(&connaux, ndm));
268     }
269     }
270     xstrncpy(dm[0], dm[2], MBOX_NAME_LEN - 1);
271    
272     fetchsize_response(&connpri, &n,
273     imap_fetch(&connpri, tok, "RFC822.SIZE"));
274    
275     ta = imap_append(&connaux, ndm, n);
276    
277     fetch_response(&connpri, 0, 1, NULL);
278     tf = imap_fetch(&connpri, tok, "RFC822.HEADER");
279     do {
280     r = fetch_response(&connpri, tf, 0, buf);
281     socket_write(&connaux, buf);
282     } while (r == RESPONSE_NONE);
283    
284     socket_write(&connaux, "\r\n");
285    
286     fetch_response(&connpri, 0, 1, NULL);
287     tf = imap_fetch(&connpri, tok, "BODY[TEXT]");
288     do {
289     r = fetch_response(&connpri, tf, 0, buf);
290     if (r != RESPONSE_NULLBODY)
291     socket_write(&connaux, buf);
292     } while (r == RESPONSE_NONE);
293    
294     if (r != RESPONSE_NULLBODY)
295     socket_write(&connaux, "\r\n\r\n");
296     else
297     socket_write(&connaux, "\r\n");
298    
299     append_response(&connaux, ta);
300    
301     tok = strtok_r(NULL, " ", &m);
302     }
303    
304     logout(&connaux);
305    
306     action_list(mesgs, args);
307    
308     xfree(mcp);
309    
310     return 0;
311     }
312    
313    
314     /*
315     * Move messages to the specified mailbox of another mail server.
316     */
317     int
318     action_rmove(char *mbox, char *mesgs, account_t * destacc, char *destmbox,
319     char *args)
320     {
321     if (!action_rcopy(mbox, mesgs, destacc, destmbox, args))
322     action_delete(mesgs, "\0");
323    
324     return 0;
325     }
326    
327    
328     /*
329     * Flag messages by replacing, adding or removing specified flags.
330     */
331     int
332     action_flag(char *mesgs, unsigned int *type, unsigned int *msgflags,
333     char *args)
334     {
335     unsigned int t;
336     char s[STORE_FLAGS_BUF];
337     char *tok, *m, *mcp;
338    
339     *s = 0;
340    
341     switch (*type) {
342     case FILTER_ACTION_FLAG_ADD:
343     t = STORE_FLAG_ADD;
344     break;
345     case FILTER_ACTION_FLAG_REMOVE:
346     t = STORE_FLAG_REMOVE;
347     break;
348     default:
349     t = STORE_FLAG_REPLACE;
350     }
351    
352     if ((*msgflags != MESSAGE_FLAG_NONE)) {
353     if ((*msgflags & MESSAGE_FLAG_SEEN))
354     strncat(s, "\\Seen ", STORE_FLAGS_BUF - strlen(s) - 1);
355     if ((*msgflags & MESSAGE_FLAG_ANSWERED))
356     strncat(s, "\\Answered ",
357     STORE_FLAGS_BUF - strlen(s) - 1);
358     if ((*msgflags & MESSAGE_FLAG_FLAGGED))
359     strncat(s, "\\Flagged ",
360     STORE_FLAGS_BUF - strlen(s) - 1);
361     if ((*msgflags & MESSAGE_FLAG_DELETED))
362     strncat(s, "\\Deleted ",
363     STORE_FLAGS_BUF - strlen(s) - 1);
364     if ((*msgflags & MESSAGE_FLAG_DRAFT))
365     strncat(s, "\\Draft", STORE_FLAGS_BUF - strlen(s) - 1);
366     if ((s[strlen(s) - 1] == ' '))
367     s[strlen(s) - 1] = 0;
368     }
369     action_list(mesgs, args);
370    
371     m = mcp = convert_messages(mesgs);
372    
373     tok = strtok_r(m, " ", &m);
374     while (tok != NULL) {
375     server_response(&connpri, imap_store(&connpri, tok, t, s));
376    
377     tok = strtok_r(NULL, " ", &m);
378     }
379    
380     if (options & OPTION_EXPUNGE)
381     server_response(&connpri, imap_expunge(&connpri));
382    
383     xfree(mcp);
384    
385     return 0;
386     }
387    
388     /*
389     * List user selected headers of messages.
390     */
391     int
392     action_list(char *mesgs, char *args)
393     {
394     int r, t;
395     char *tok, *mcp, *m;
396     char s[ARGS_LEN + 27];
397     char hdrs[RESPONSE_BUF * 2 + 1];
398    
399     if (*args == '\0')
400     return 0;
401    
402     m = mcp = xstrdup(mesgs);
403    
404     snprintf(s, ARGS_LEN + 27 - 1, "BODY.PEEK[HEADER.FIELDS (%s)]", args);
405    
406     tok = strtok_r(m, " ", &m);
407     while (tok != NULL) {
408     /* Reset internal fetch counter. */
409     fetch_response(&connpri, 0, 1, NULL);
410     t = imap_fetch(&connpri, tok, s);
411    
412     log_info(LOG_PREAMBLE, NULL);
413     do {
414     r = fetch_response(&connpri, t, 0, hdrs);
415    
416     if (*hdrs != '\0') {
417     if (options & OPTION_HEADERS)
418     info("%s\n", hdrs);
419     log_info(LOG_HEADER, hdrs);
420     }
421     } while (r == RESPONSE_NONE);
422    
423     tok = strtok_r(NULL, " ", &m);
424     }
425    
426     xfree(mcp);
427    
428     return 0;
429     }
430    
431    
432     /*
433     * Count how many messages matched the filter.
434     */
435     unsigned int
436     count_messages(char *mesgs)
437     {
438     unsigned int cnt;
439     char *c;
440    
441     cnt = 0;
442     c = mesgs;
443    
444     while ((c = strchr(c, ' '))) {
445     cnt++;
446     c++;
447     }
448    
449     return ++cnt;
450     }
451    
452    
453     /*
454     * Convert messages with contiguous sequence number to the corresponding
455     * number range, eg. 1 2 3 5 7 8 --> 1:3 5 7:8 and return a newly allocated
456     * buffer with the results.
457     */
458     char *
459     convert_messages(char *mesgs)
460     {
461     int maxlen;
462     unsigned int start, end, tmp;
463     char *c, *cp, *tail;
464    
465     start = end = tmp = 0;
466     maxlen = strlen(mesgs) + 1;
467     tail = NULL;
468    
469     c = cp = xstrdup(mesgs);
470    
471     start = (unsigned int)strtoul(mesgs, &tail, 10);
472     end = start;
473    
474     do {
475     if (tail != NULL) {
476     tmp = (unsigned int)strtoul(tail, &tail, 10);
477     if (tmp == 0)
478     tail = NULL;
479     }
480     if (tmp == end + 1)
481     end++;
482     else {
483     if (start == end) {
484     xstrncpy(c, ultostr(start, 10), maxlen);
485     c += strlen(c);
486     } else {
487     xstrncpy(c, ultostr(start, 10), maxlen - 1);
488     c += strlen(c);
489     *c = ':';
490     *++c = 0;
491     xstrncpy(c, ultostr(end, 10), maxlen);
492     c += strlen(c);
493     }
494    
495     if (tail != NULL && c - cp < maxlen) {
496     *c = ' ';
497     *++c = 0;
498     }
499     start = end = tmp;
500     }
501     } while (tmp != 0);
502    
503     return cp;
504     }
505    
506    
507     /*
508     * Substitute all occurences of the '@' character with the '%' character,
509     * and any double '@' characters with a signle '@' character, returning the
510     * number of replacements.
511     */
512     int
513     substitute_date(char *str)
514     {
515     int n;
516     char *r, *w, *s;
517    
518     n = 0;
519    
520     s = xstrdup(str);
521    
522     for (r = s, w = str; *r != '\0'; r++, w++) {
523     if (*r == '%') {
524     *w++ = '%';
525     *w = '%';
526     } else if (*r == '@') {
527     if (*(r + 1) == '@') {
528     *w = *r++;
529     } else {
530     *w = '%';
531     n++;
532     }
533     } else {
534     *w = *r;
535     }
536     }
537     *w = '\0';
538    
539     xfree(s);
540    
541     return n;
542     }
543    
544    
545     /*
546     * Format the destination mailbox according to the current date conversion
547     * specifiers.
548     */
549     void
550     current_date(char *destmbox)
551     {
552     char s[MBOX_NAME_LEN];
553     time_t te;
554     struct tm *tl;
555    
556     if (!strchr(destmbox, '%'))
557     return;
558    
559     te = time(NULL);
560     tl = localtime(&te);
561    
562     if (strftime(s, MBOX_NAME_LEN - 1, destmbox, tl))
563     xstrncpy(destmbox, s, MBOX_NAME_LEN - 1);
564     }
565    
566    
567     /*
568     * Format the destination mailbox according to the message date conversion
569     * specifiers.
570     */
571     void
572     message_date(char *mesg, char *destmbox)
573     {
574     unsigned int t;
575     char s[MBOX_NAME_LEN];
576     struct tm tl;
577     char dbuf[RESPONSE_BUF + 1];
578    
579     if (!strchr(destmbox, '@'))
580     return;
581    
582     substitute_date(destmbox);
583    
584     fetch_response(&connpri, 0, 1, NULL);
585     t = imap_fetch(&connpri, mesg, "BODY.PEEK[HEADER.FIELDS (DATE)]");
586    
587     while (fetch_response(&connpri, t, 0, dbuf) == RESPONSE_NONE);
588    
589     if (strptime(dbuf, "Date: %a, %d %b %Y %H:%M:%S", &tl) &&
590     strftime(s, MBOX_NAME_LEN - 1, destmbox, &tl))
591     xstrncpy(destmbox, s, MBOX_NAME_LEN - 1);
592     }
593    
594    
595     /*
596     * Format the destination mailbox according to "default variables" specifiers.
597     */
598     void
599     default_variables(char *mbox, char *destmbox)
600     {
601     char *m, *r, *w, *s;
602    
603     if (!strchr(destmbox, '$'))
604     return;
605    
606     s = xstrdup(destmbox);
607    
608     for (r = s, w = destmbox; *r != '\0';) {
609     if (w - destmbox >= MBOX_NAME_LEN - 1)
610     break;
611     if (*r == '$') {
612     switch (*(r + 1)) {
613     case '_':
614     if (w + strlen(mbox) - destmbox >
615     MBOX_NAME_LEN - 1) {
616     r += 2;
617     break;
618     }
619     for (m = mbox; *m != '\0'; m++, w++)
620     *w = *m;
621     r += 2;
622     break;
623     case '$':
624     *w++ = '$';
625     r += 2;
626     break;
627     default:
628     *w++ = *r++;
629     break;
630     }
631     } else {
632     *w++ = *r++;
633     }
634     }
635     *w = '\0';
636    
637     xfree(s);
638     }

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26