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

Annotation of /imapfilter/action.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1 - (hide annotations)
Thu Jul 31 15:46:02 2003 UTC (20 years, 8 months ago) by lefcha
Branch: MAIN
File MIME type: text/plain
Broke up program files and created some new header files.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26