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

Annotation of /imapfilter/action.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.11 - (hide annotations)
Mon Feb 9 22:03:33 2004 UTC (20 years, 1 month ago) by lefcha
Branch: MAIN
Changes since 1.10: +3 -6 lines
File MIME type: text/plain
Indenting.

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 lefcha 1.11 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 lefcha 1.1 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 lefcha 1.7 char *flags, *date;
196     unsigned int size;
197 lefcha 1.1 char buf[RESPONSE_BUF * 2 + 1];
198     char dm[3][MBOX_NAME_LEN];
199    
200     *dm[0] = *dm[1] = *dm[2] = '\0';
201 lefcha 1.7 flags = date = NULL;
202 lefcha 1.1
203     if (init_connection(&connaux, destacc->server, destacc->port,
204     destacc->ssl))
205     return ERROR_NETWORK;
206    
207     r = greeting_response(&connaux);
208    
209 lefcha 1.9 if (options & OPTION_DEBUG)
210     test(&connaux);
211 lefcha 1.1
212     if (r == RESPONSE_BYE || check_capabilities(&connaux))
213     return ERROR_NETWORK;
214    
215     #ifdef SSL_TLS
216     if (destacc->ssl == SSL_DISABLED && connaux.caps & CAPABILITY_STARTTLS)
217     if (negotiate_tls(&connaux) == RESPONSE_OK)
218     check_capabilities(&connaux);
219     #endif
220    
221     if (r != RESPONSE_PREAUTH) {
222     if (destacc->passwdattr == PASSWORD_NONE) {
223     printf("Enter password for %s@%s: ", destacc->username,
224     destacc->server);
225     get_password(destacc->password, PASSWORD_LEN);
226     destacc->passwdattr = PASSWORD_PLAIN;
227     }
228     #ifdef CRAM_MD5
229     if (connaux.caps & CAPABILITY_AUTH_CRAM_MD5)
230     r = auth_cram_md5(&connaux, destacc->username,
231     destacc->password);
232     else
233     #endif
234     r = login(&connaux, destacc->username,
235     destacc->password);
236    
237     if (r == RESPONSE_NO) {
238     error("username %s or password rejected at %s\n",
239     destacc->username, destacc->server);
240     return ERROR_NETWORK;
241     }
242     }
243     check_namespace(&connaux);
244    
245     m = mcp = xstrdup(mesgs);
246    
247     xstrncpy(dm[1], destmbox, MBOX_NAME_LEN - 1);
248 lefcha 1.4 default_variables(mbox, dm[1]);
249 lefcha 1.1 current_date(dm[1]);
250    
251     tok = strtok_r(m, " ", &m);
252     while (tok != NULL) {
253     xstrncpy(dm[2], dm[1], MBOX_NAME_LEN - 1);
254     message_date(tok, dm[2]);
255    
256     /* apply_namespace() returns a pointer to a static buffer. */
257     ndm = apply_namespace(dm[2], connaux.nsp.prefix,
258     connaux.nsp.delim);
259    
260     /* Check only if mailbox name is different from last one. */
261     if (strncmp(dm[0], dm[2], strlen(dm[2]))) {
262     r = check_mailbox(&connaux, ndm);
263     if (r == RESPONSE_NO) {
264     server_response(&connaux,
265     imap_create(&connaux, ndm));
266     if ((options & OPTION_SUBSCRIBE))
267     server_response(&connaux,
268     imap_subscribe(&connaux, ndm));
269     }
270     }
271     xstrncpy(dm[0], dm[2], MBOX_NAME_LEN - 1);
272    
273 lefcha 1.7 fetchfast_response(&connpri, &flags, &date, &size,
274     imap_fetch(&connpri, tok, "FAST"));
275 lefcha 1.1
276 lefcha 1.7 ta = imap_append(&connaux, ndm, flags, date, size);
277    
278     xfree(flags);
279     xfree(date);
280 lefcha 1.1
281     fetch_response(&connpri, 0, 1, NULL);
282 lefcha 1.5 tf = imap_fetch(&connpri, tok, options & OPTION_PEEK ?
283     "BODY.PEEK[HEADER]" : "BODY[HEADER]");
284 lefcha 1.1 do {
285     r = fetch_response(&connpri, tf, 0, buf);
286     socket_write(&connaux, buf);
287     } while (r == RESPONSE_NONE);
288    
289     socket_write(&connaux, "\r\n");
290    
291     fetch_response(&connpri, 0, 1, NULL);
292 lefcha 1.5 tf = imap_fetch(&connpri, tok, options & OPTION_PEEK ?
293     "BODY.PEEK[TEXT]" : "BODY[TEXT]");
294 lefcha 1.1 do {
295     r = fetch_response(&connpri, tf, 0, buf);
296     if (r != RESPONSE_NULLBODY)
297     socket_write(&connaux, buf);
298     } while (r == RESPONSE_NONE);
299    
300     if (r != RESPONSE_NULLBODY)
301     socket_write(&connaux, "\r\n\r\n");
302     else
303     socket_write(&connaux, "\r\n");
304    
305     append_response(&connaux, ta);
306    
307     tok = strtok_r(NULL, " ", &m);
308     }
309    
310     logout(&connaux);
311    
312     action_list(mesgs, args);
313    
314     xfree(mcp);
315    
316     return 0;
317     }
318    
319    
320     /*
321     * Move messages to the specified mailbox of another mail server.
322     */
323     int
324     action_rmove(char *mbox, char *mesgs, account_t * destacc, char *destmbox,
325     char *args)
326     {
327     if (!action_rcopy(mbox, mesgs, destacc, destmbox, args))
328     action_delete(mesgs, "\0");
329    
330     return 0;
331     }
332    
333    
334     /*
335     * Flag messages by replacing, adding or removing specified flags.
336     */
337     int
338     action_flag(char *mesgs, unsigned int *type, unsigned int *msgflags,
339     char *args)
340     {
341     unsigned int t;
342     char s[STORE_FLAGS_BUF];
343     char *tok, *m, *mcp;
344    
345     *s = 0;
346    
347     switch (*type) {
348     case FILTER_ACTION_FLAG_ADD:
349     t = STORE_FLAG_ADD;
350     break;
351     case FILTER_ACTION_FLAG_REMOVE:
352     t = STORE_FLAG_REMOVE;
353     break;
354     default:
355     t = STORE_FLAG_REPLACE;
356     }
357    
358     if ((*msgflags != MESSAGE_FLAG_NONE)) {
359     if ((*msgflags & MESSAGE_FLAG_SEEN))
360     strncat(s, "\\Seen ", STORE_FLAGS_BUF - strlen(s) - 1);
361     if ((*msgflags & MESSAGE_FLAG_ANSWERED))
362     strncat(s, "\\Answered ",
363     STORE_FLAGS_BUF - strlen(s) - 1);
364     if ((*msgflags & MESSAGE_FLAG_FLAGGED))
365     strncat(s, "\\Flagged ",
366     STORE_FLAGS_BUF - strlen(s) - 1);
367     if ((*msgflags & MESSAGE_FLAG_DELETED))
368     strncat(s, "\\Deleted ",
369     STORE_FLAGS_BUF - strlen(s) - 1);
370     if ((*msgflags & MESSAGE_FLAG_DRAFT))
371     strncat(s, "\\Draft", STORE_FLAGS_BUF - strlen(s) - 1);
372     if ((s[strlen(s) - 1] == ' '))
373     s[strlen(s) - 1] = 0;
374     }
375     action_list(mesgs, args);
376    
377     m = mcp = convert_messages(mesgs);
378    
379     tok = strtok_r(m, " ", &m);
380     while (tok != NULL) {
381     server_response(&connpri, imap_store(&connpri, tok, t, s));
382    
383     tok = strtok_r(NULL, " ", &m);
384     }
385    
386     if (options & OPTION_EXPUNGE)
387     server_response(&connpri, imap_expunge(&connpri));
388    
389     xfree(mcp);
390    
391     return 0;
392     }
393    
394     /*
395     * List user selected headers of messages.
396     */
397     int
398     action_list(char *mesgs, char *args)
399     {
400     int r, t;
401     char *tok, *mcp, *m;
402     char s[ARGS_LEN + 27];
403     char hdrs[RESPONSE_BUF * 2 + 1];
404    
405     if (*args == '\0')
406     return 0;
407    
408     m = mcp = xstrdup(mesgs);
409    
410 lefcha 1.5 snprintf(s, ARGS_LEN + 27 - 1, options & OPTION_PEEK ?
411     "BODY.PEEK[HEADER.FIELDS (%s)]" :
412 lefcha 1.6 "BODY[HEADER.FIELDS (%s)]", args);
413 lefcha 1.1
414     tok = strtok_r(m, " ", &m);
415     while (tok != NULL) {
416     /* Reset internal fetch counter. */
417     fetch_response(&connpri, 0, 1, NULL);
418     t = imap_fetch(&connpri, tok, s);
419    
420     log_info(LOG_PREAMBLE, NULL);
421     do {
422     r = fetch_response(&connpri, t, 0, hdrs);
423    
424     if (*hdrs != '\0') {
425     if (options & OPTION_HEADERS)
426     info("%s\n", hdrs);
427     log_info(LOG_HEADER, hdrs);
428     }
429     } while (r == RESPONSE_NONE);
430    
431     tok = strtok_r(NULL, " ", &m);
432     }
433    
434     xfree(mcp);
435    
436     return 0;
437     }
438    
439    
440     /*
441     * Count how many messages matched the filter.
442     */
443     unsigned int
444     count_messages(char *mesgs)
445     {
446     unsigned int cnt;
447     char *c;
448    
449     cnt = 0;
450     c = mesgs;
451    
452     while ((c = strchr(c, ' '))) {
453     cnt++;
454     c++;
455     }
456    
457     return ++cnt;
458     }
459    
460    
461     /*
462     * Convert messages with contiguous sequence number to the corresponding
463     * number range, eg. 1 2 3 5 7 8 --> 1:3 5 7:8 and return a newly allocated
464     * buffer with the results.
465     */
466     char *
467     convert_messages(char *mesgs)
468     {
469     int maxlen;
470     unsigned int start, end, tmp;
471     char *c, *cp, *tail;
472    
473     start = end = tmp = 0;
474     maxlen = strlen(mesgs) + 1;
475     tail = NULL;
476    
477     c = cp = xstrdup(mesgs);
478    
479     start = (unsigned int)strtoul(mesgs, &tail, 10);
480     end = start;
481    
482     do {
483     if (tail != NULL) {
484     tmp = (unsigned int)strtoul(tail, &tail, 10);
485     if (tmp == 0)
486     tail = NULL;
487     }
488     if (tmp == end + 1)
489     end++;
490     else {
491     if (start == end) {
492     xstrncpy(c, ultostr(start, 10), maxlen);
493     c += strlen(c);
494     } else {
495     xstrncpy(c, ultostr(start, 10), maxlen - 1);
496     c += strlen(c);
497     *c = ':';
498     *++c = 0;
499     xstrncpy(c, ultostr(end, 10), maxlen);
500     c += strlen(c);
501     }
502    
503     if (tail != NULL && c - cp < maxlen) {
504     *c = ' ';
505     *++c = 0;
506     }
507     start = end = tmp;
508     }
509     } while (tmp != 0);
510    
511     return cp;
512     }
513    
514    
515     /*
516     * Substitute all occurences of the '@' character with the '%' character,
517     * and any double '@' characters with a signle '@' character, returning the
518     * number of replacements.
519     */
520     int
521     substitute_date(char *str)
522     {
523     int n;
524     char *r, *w, *s;
525    
526     n = 0;
527    
528     s = xstrdup(str);
529    
530     for (r = s, w = str; *r != '\0'; r++, w++) {
531     if (*r == '%') {
532     *w++ = '%';
533     *w = '%';
534     } else if (*r == '@') {
535     if (*(r + 1) == '@') {
536     *w = *r++;
537     } else {
538     *w = '%';
539     n++;
540     }
541     } else {
542     *w = *r;
543     }
544     }
545     *w = '\0';
546    
547     xfree(s);
548    
549     return n;
550     }
551    
552    
553     /*
554     * Format the destination mailbox according to the current date conversion
555     * specifiers.
556     */
557     void
558     current_date(char *destmbox)
559     {
560     char s[MBOX_NAME_LEN];
561     time_t te;
562     struct tm *tl;
563    
564     if (!strchr(destmbox, '%'))
565     return;
566    
567     te = time(NULL);
568     tl = localtime(&te);
569    
570     if (strftime(s, MBOX_NAME_LEN - 1, destmbox, tl))
571     xstrncpy(destmbox, s, MBOX_NAME_LEN - 1);
572     }
573    
574    
575     /*
576     * Format the destination mailbox according to the message date conversion
577     * specifiers.
578     */
579     void
580     message_date(char *mesg, char *destmbox)
581     {
582     unsigned int t;
583     char s[MBOX_NAME_LEN];
584     struct tm tl;
585     char dbuf[RESPONSE_BUF + 1];
586    
587     if (!strchr(destmbox, '@'))
588     return;
589    
590     substitute_date(destmbox);
591    
592     fetch_response(&connpri, 0, 1, NULL);
593 lefcha 1.5 t = imap_fetch(&connpri, mesg, options & OPTION_PEEK ?
594     "BODY.PEEK[HEADER.FIELDS (DATE)]" :
595     "BODY[HEADER.FIELDS (DATE)]");
596 lefcha 1.1
597     while (fetch_response(&connpri, t, 0, dbuf) == RESPONSE_NONE);
598    
599 lefcha 1.8 if (((strptime(dbuf, "Date: %a, %d %b %Y %H:%M:%S", &tl) ||
600     strptime(dbuf, "Date: %d %b %Y %H:%M:%S", &tl)) &&
601     strftime(s, MBOX_NAME_LEN - 1, destmbox, &tl)))
602 lefcha 1.1 xstrncpy(destmbox, s, MBOX_NAME_LEN - 1);
603     }
604    
605    
606     /*
607     * Format the destination mailbox according to "default variables" specifiers.
608     */
609     void
610     default_variables(char *mbox, char *destmbox)
611     {
612     char *m, *r, *w, *s;
613    
614     if (!strchr(destmbox, '$'))
615     return;
616    
617     s = xstrdup(destmbox);
618    
619     for (r = s, w = destmbox; *r != '\0';) {
620     if (w - destmbox >= MBOX_NAME_LEN - 1)
621     break;
622     if (*r == '$') {
623     switch (*(r + 1)) {
624     case '_':
625     if (w + strlen(mbox) - destmbox >
626     MBOX_NAME_LEN - 1) {
627     r += 2;
628     break;
629     }
630     for (m = mbox; *m != '\0'; m++, w++)
631     *w = *m;
632     r += 2;
633     break;
634     case '$':
635     *w++ = '$';
636     r += 2;
637     break;
638     default:
639     *w++ = *r++;
640     break;
641     }
642     } else {
643     *w++ = *r++;
644     }
645     }
646     *w = '\0';
647    
648     xfree(s);
649     }

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26