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

Annotation of /imapfilter/action.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.17 - (hide annotations)
Sun Feb 15 15:32:38 2004 UTC (20 years, 1 month ago) by lefcha
Branch: MAIN
CVS Tags: HEAD
Changes since 1.16: +122 -9 lines
File MIME type: text/plain
Added message headers' variables for From: header.

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 lefcha 1.13 #include "filter.h"
10 lefcha 1.1
11    
12 lefcha 1.13 extern connection_t connpri, connaux;
13     extern options_t opts;
14 lefcha 1.1
15    
16     int action_delete(char *mesgs, char *args);
17     int action_copy(char *mbox, char *mesgs, char *destmbox, char *args);
18     int action_move(char *mbox, char *mesgs, char *destmbox, char *args);
19 lefcha 1.15 int action_rcopy(char *mbox, char *mesgs, account_t * destacct, char *destmbox, char *args);
20     int action_rmove(char *mbox, char *mesgs, account_t * destacct, char *destmbox, char *args);
21 lefcha 1.11 int action_flag(char *mesgs, unsigned int *type, unsigned int *msgflags, char *args);
22 lefcha 1.1 int action_list(char *mesgs, char *args);
23    
24     unsigned int count_messages(char *mesgs);
25     char *convert_messages(char *mesgs);
26     int substitute_date(char *str);
27 lefcha 1.17 void system_date(char *destmbox);
28 lefcha 1.1 void message_date(char *mesg, char *destmbox);
29     void default_variables(char *mbox, char *destmbox);
30 lefcha 1.17 void headers_variables(char *mesg, char *destmbox);
31 lefcha 1.1
32    
33     /*
34     * Apply the appropriate action.
35     */
36     int
37 lefcha 1.15 apply_action(char *mbox, char *mesgs, unsigned int *type, account_t * destacct,
38 lefcha 1.1 char *destmbox, unsigned int *msgflags, char *args)
39     {
40     unsigned int cnt;
41    
42     if (*mesgs == '\0')
43     return 0;
44    
45     log_info(LOG_ACTION, type);
46 lefcha 1.15 log_info(LOG_DEST_ACCOUNT, destacct->key);
47 lefcha 1.13 log_info(LOG_DEST_MBOX, destmbox);
48 lefcha 1.1
49     cnt = count_messages(mesgs);
50    
51     switch (*type) {
52 lefcha 1.13 case ACTION_DELETE:
53 lefcha 1.1 info("%d message%s deleted.\n", cnt, plural(cnt));
54     action_delete(mesgs, args);
55     break;
56 lefcha 1.13 case ACTION_COPY:
57 lefcha 1.1 info("%d message%s copied from \"%s\" to mailbox \"%s\".\n",
58     cnt, plural(cnt), mbox, destmbox);
59     action_copy(mbox, mesgs, apply_namespace(destmbox,
60 lefcha 1.15 connpri.ns.prefix, connpri.ns.delim), args);
61 lefcha 1.1 break;
62 lefcha 1.13 case ACTION_MOVE:
63 lefcha 1.1 info("%d message%s moved from \"%s\" to mailbox \"%s\".\n",
64     cnt, plural(cnt), mbox, destmbox);
65     action_move(mbox, mesgs, apply_namespace(destmbox,
66 lefcha 1.15 connpri.ns.prefix, connpri.ns.delim), args);
67 lefcha 1.1 break;
68 lefcha 1.13 case ACTION_RCOPY:
69 lefcha 1.1 info("%d message%s copied from \"%s\" to mailbox "
70 lefcha 1.15 "\"%s\" at account %s.\n", cnt, plural(cnt), mbox,
71     destmbox, destacct->key);
72     action_rcopy(mbox, mesgs, destacct, destmbox, args);
73 lefcha 1.1 break;
74 lefcha 1.13 case ACTION_RMOVE:
75 lefcha 1.1 info("%d message%s moved from \"%s\" to mailbox "
76 lefcha 1.15 "\"%s\" at account %s.\n", cnt, plural(cnt), mbox,
77     destmbox, destacct->key);
78     action_rmove(mbox, mesgs, destacct, destmbox, args);
79 lefcha 1.1 break;
80 lefcha 1.13 case ACTION_FLAG_REPLACE:
81     case ACTION_FLAG_ADD:
82     case ACTION_FLAG_REMOVE:
83 lefcha 1.1 info("%d message%s flagged.\n", cnt, plural(cnt));
84     action_flag(mesgs, type, msgflags, args);
85     break;
86 lefcha 1.13 case ACTION_LIST:
87 lefcha 1.1 info("%d message%s listed.\n", cnt, plural(cnt));
88     action_list(mesgs, args);
89     break;
90     }
91    
92     if (*args == '\0')
93     log_info(LOG_PREAMBLE, NULL);
94    
95     return 0;
96     }
97    
98    
99     /*
100     * Delete messages and optionally list some of their headers.
101     */
102     int
103     action_delete(char *mesgs, char *args)
104     {
105     char *tok, *m, *mcp;
106    
107     action_list(mesgs, args);
108    
109     m = mcp = convert_messages(mesgs);
110    
111     tok = strtok_r(m, " ", &m);
112     while (tok) {
113 lefcha 1.13 response_generic(&connpri, imap_store(&connpri, tok,
114 lefcha 1.15 ACTION_FLAG_ADD, "\\Deleted"));
115 lefcha 1.1
116     tok = strtok_r(NULL, " ", &m);
117     }
118    
119 lefcha 1.12 if (opts.expunge)
120 lefcha 1.13 response_generic(&connpri, imap_expunge(&connpri));
121 lefcha 1.1
122     xfree(mcp);
123    
124     return 0;
125     }
126    
127    
128     /*
129     * Copy messages to specified mailbox.
130     */
131     int
132     action_copy(char *mbox, char *mesgs, char *destmbox, char *args)
133     {
134     int r;
135     char *tok, *mcp, *m;
136 lefcha 1.13 char dm[2][MBOX_LEN];
137 lefcha 1.1
138     r = 0;
139     tok = NULL;
140 lefcha 1.17 *dm[0] = *dm[1] = '\0';
141 lefcha 1.1
142     action_list(mesgs, args);
143    
144 lefcha 1.17 if (strchr(destmbox, '@') || strchr(destmbox, '&'))
145 lefcha 1.1 m = mcp = xstrdup(mesgs);
146     else
147     m = mcp = convert_messages(mesgs);
148    
149 lefcha 1.13 xstrncpy(dm[0], destmbox, MBOX_LEN - 1);
150 lefcha 1.1 default_variables(mbox, dm[0]);
151 lefcha 1.17 system_date(dm[0]);
152 lefcha 1.1 tok = strtok_r(m, " ", &m);
153     while (tok != NULL) {
154 lefcha 1.13 xstrncpy(dm[1], dm[0], MBOX_LEN - 1);
155 lefcha 1.1 message_date(tok, dm[1]);
156 lefcha 1.17 headers_variables(tok, dm[1]);
157 lefcha 1.1
158 lefcha 1.13 if ((r = response_copy(&connpri, imap_copy(&connpri, tok,
159 lefcha 1.15 dm[1]))) == RESPONSE_TRYCREATE)
160 lefcha 1.13 if (!response_generic(&connpri, imap_create(&connpri,
161 lefcha 1.15 dm[1]))) {
162 lefcha 1.12 if (opts.subscribe)
163 lefcha 1.13 response_generic(&connpri,
164 lefcha 1.1 imap_subscribe(&connpri, dm[1]));
165 lefcha 1.13 r = response_copy(&connpri,
166 lefcha 1.1 imap_copy(&connpri, tok, dm[1]));
167     }
168     tok = strtok_r(NULL, " ", &m);
169     }
170    
171     xfree(mcp);
172    
173     return r;
174     }
175    
176    
177     /*
178     * Move messages to specified mailbox.
179     */
180     int
181     action_move(char *mbox, char *mesgs, char *destmbox, char *args)
182     {
183 lefcha 1.14
184 lefcha 1.1 if (!action_copy(mbox, mesgs, destmbox, args))
185     action_delete(mesgs, "\0");
186    
187     return 0;
188     }
189    
190    
191     /*
192     * Copy messages to the specified mailbox of another mail server.
193     */
194     int
195 lefcha 1.15 action_rcopy(char *mbox, char *mesgs, account_t * destacct, char *destmbox,
196 lefcha 1.1 char *args)
197     {
198     int r, ta, tf;
199     char *tok, *m, *mcp, *ndm;
200 lefcha 1.7 char *flags, *date;
201     unsigned int size;
202 lefcha 1.1 char buf[RESPONSE_BUF * 2 + 1];
203 lefcha 1.13 char dm[3][MBOX_LEN];
204 lefcha 1.1
205     *dm[0] = *dm[1] = *dm[2] = '\0';
206 lefcha 1.7 flags = date = NULL;
207 lefcha 1.1
208 lefcha 1.15 if (init_connection(&connaux, destacct->server, destacct->port,
209     destacct->ssl))
210 lefcha 1.1 return ERROR_NETWORK;
211    
212 lefcha 1.13 r = response_greeting(&connaux);
213 lefcha 1.1
214 lefcha 1.12 if (opts.debug)
215 lefcha 1.9 test(&connaux);
216 lefcha 1.1
217     if (r == RESPONSE_BYE || check_capabilities(&connaux))
218     return ERROR_NETWORK;
219    
220     #ifdef SSL_TLS
221 lefcha 1.16 if (destacct->ssl == SSL_DISABLED && connaux.caps & CAPABILITY_STARTTLS)
222 lefcha 1.1 if (negotiate_tls(&connaux) == RESPONSE_OK)
223     check_capabilities(&connaux);
224     #endif
225    
226     if (r != RESPONSE_PREAUTH) {
227 lefcha 1.15 if (destacct->pass_attr == PASS_ATTR_NONE) {
228     printf("Enter password for %s@%s: ", destacct->user,
229     destacct->server);
230     get_password(destacct->pass, PASS_LEN);
231     destacct->pass_attr = PASS_ATTR_PLAIN;
232 lefcha 1.1 }
233     #ifdef CRAM_MD5
234 lefcha 1.16 if (connaux.caps & CAPABILITY_CRAMMD5)
235 lefcha 1.15 r = auth_cram_md5(&connaux, destacct->user,
236     destacct->pass);
237 lefcha 1.1 else
238     #endif
239 lefcha 1.15 r = login(&connaux, destacct->user, destacct->pass);
240 lefcha 1.1
241     if (r == RESPONSE_NO) {
242     error("username %s or password rejected at %s\n",
243 lefcha 1.15 destacct->user, destacct->server);
244 lefcha 1.1 return ERROR_NETWORK;
245     }
246     }
247     check_namespace(&connaux);
248    
249     m = mcp = xstrdup(mesgs);
250    
251 lefcha 1.13 xstrncpy(dm[1], destmbox, MBOX_LEN - 1);
252 lefcha 1.4 default_variables(mbox, dm[1]);
253 lefcha 1.17 system_date(dm[1]);
254 lefcha 1.1
255     tok = strtok_r(m, " ", &m);
256     while (tok != NULL) {
257 lefcha 1.13 xstrncpy(dm[2], dm[1], MBOX_LEN - 1);
258 lefcha 1.1 message_date(tok, dm[2]);
259 lefcha 1.17 headers_variables(tok, dm[2]);
260 lefcha 1.1
261     /* apply_namespace() returns a pointer to a static buffer. */
262 lefcha 1.13 ndm = apply_namespace(dm[2], connaux.ns.prefix,
263     connaux.ns.delim);
264 lefcha 1.1
265     /* Check only if mailbox name is different from last one. */
266     if (strncmp(dm[0], dm[2], strlen(dm[2]))) {
267     r = check_mailbox(&connaux, ndm);
268     if (r == RESPONSE_NO) {
269 lefcha 1.13 response_generic(&connaux,
270 lefcha 1.1 imap_create(&connaux, ndm));
271 lefcha 1.12 if (opts.subscribe)
272 lefcha 1.13 response_generic(&connaux,
273 lefcha 1.1 imap_subscribe(&connaux, ndm));
274     }
275     }
276 lefcha 1.13 xstrncpy(dm[0], dm[2], MBOX_LEN - 1);
277 lefcha 1.1
278 lefcha 1.13 response_fetchfast(&connpri, &flags, &date, &size,
279 lefcha 1.7 imap_fetch(&connpri, tok, "FAST"));
280 lefcha 1.1
281 lefcha 1.7 ta = imap_append(&connaux, ndm, flags, date, size);
282    
283     xfree(flags);
284     xfree(date);
285 lefcha 1.1
286 lefcha 1.13 response_fetch(&connpri, 0, 1, NULL);
287 lefcha 1.12 tf = imap_fetch(&connpri, tok, opts.peek ?
288 lefcha 1.5 "BODY.PEEK[HEADER]" : "BODY[HEADER]");
289 lefcha 1.1 do {
290 lefcha 1.13 r = response_fetch(&connpri, tf, 0, buf);
291 lefcha 1.1 socket_write(&connaux, buf);
292     } while (r == RESPONSE_NONE);
293    
294     socket_write(&connaux, "\r\n");
295    
296 lefcha 1.13 response_fetch(&connpri, 0, 1, NULL);
297 lefcha 1.12 tf = imap_fetch(&connpri, tok, opts.peek ?
298 lefcha 1.5 "BODY.PEEK[TEXT]" : "BODY[TEXT]");
299 lefcha 1.1 do {
300 lefcha 1.13 r = response_fetch(&connpri, tf, 0, buf);
301 lefcha 1.1 if (r != RESPONSE_NULLBODY)
302     socket_write(&connaux, buf);
303     } while (r == RESPONSE_NONE);
304    
305     if (r != RESPONSE_NULLBODY)
306     socket_write(&connaux, "\r\n\r\n");
307     else
308     socket_write(&connaux, "\r\n");
309    
310 lefcha 1.13 response_append(&connaux, ta);
311 lefcha 1.1
312     tok = strtok_r(NULL, " ", &m);
313     }
314    
315     logout(&connaux);
316    
317     action_list(mesgs, args);
318    
319     xfree(mcp);
320    
321     return 0;
322     }
323    
324    
325     /*
326     * Move messages to the specified mailbox of another mail server.
327     */
328     int
329 lefcha 1.15 action_rmove(char *mbox, char *mesgs, account_t * destacct, char *destmbox,
330 lefcha 1.1 char *args)
331     {
332 lefcha 1.14
333 lefcha 1.15 if (!action_rcopy(mbox, mesgs, destacct, destmbox, args))
334 lefcha 1.1 action_delete(mesgs, "\0");
335    
336     return 0;
337     }
338    
339    
340     /*
341     * Flag messages by replacing, adding or removing specified flags.
342     */
343     int
344     action_flag(char *mesgs, unsigned int *type, unsigned int *msgflags,
345     char *args)
346     {
347     char s[STORE_FLAGS_BUF];
348     char *tok, *m, *mcp;
349    
350     *s = 0;
351    
352 lefcha 1.13 if ((*msgflags != MSG_FLAG_NONE)) {
353     if ((*msgflags & MSG_FLAG_SEEN))
354 lefcha 1.1 strncat(s, "\\Seen ", STORE_FLAGS_BUF - strlen(s) - 1);
355 lefcha 1.13 if ((*msgflags & MSG_FLAG_ANSWERED))
356 lefcha 1.1 strncat(s, "\\Answered ",
357     STORE_FLAGS_BUF - strlen(s) - 1);
358 lefcha 1.13 if ((*msgflags & MSG_FLAG_FLAGGED))
359 lefcha 1.1 strncat(s, "\\Flagged ",
360     STORE_FLAGS_BUF - strlen(s) - 1);
361 lefcha 1.13 if ((*msgflags & MSG_FLAG_DELETED))
362 lefcha 1.1 strncat(s, "\\Deleted ",
363     STORE_FLAGS_BUF - strlen(s) - 1);
364 lefcha 1.13 if ((*msgflags & MSG_FLAG_DRAFT))
365 lefcha 1.1 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 lefcha 1.13 response_generic(&connpri, imap_store(&connpri, tok, *type, s));
376 lefcha 1.1 tok = strtok_r(NULL, " ", &m);
377     }
378    
379 lefcha 1.12 if (opts.expunge)
380 lefcha 1.13 response_generic(&connpri, imap_expunge(&connpri));
381 lefcha 1.1
382     xfree(mcp);
383    
384     return 0;
385     }
386    
387     /*
388     * List user selected headers of messages.
389     */
390     int
391     action_list(char *mesgs, char *args)
392     {
393     int r, t;
394     char *tok, *mcp, *m;
395     char s[ARGS_LEN + 27];
396     char hdrs[RESPONSE_BUF * 2 + 1];
397    
398     if (*args == '\0')
399     return 0;
400    
401     m = mcp = xstrdup(mesgs);
402    
403 lefcha 1.12 snprintf(s, ARGS_LEN + 27 - 1, opts.peek ?
404 lefcha 1.5 "BODY.PEEK[HEADER.FIELDS (%s)]" :
405 lefcha 1.6 "BODY[HEADER.FIELDS (%s)]", args);
406 lefcha 1.1
407     tok = strtok_r(m, " ", &m);
408     while (tok != NULL) {
409     /* Reset internal fetch counter. */
410 lefcha 1.13 response_fetch(&connpri, 0, 1, NULL);
411 lefcha 1.1 t = imap_fetch(&connpri, tok, s);
412    
413     log_info(LOG_PREAMBLE, NULL);
414     do {
415 lefcha 1.13 r = response_fetch(&connpri, t, 0, hdrs);
416 lefcha 1.1
417     if (*hdrs != '\0') {
418 lefcha 1.12 if (opts.headers)
419 lefcha 1.1 info("%s\n", hdrs);
420     log_info(LOG_HEADER, hdrs);
421     }
422     } while (r == RESPONSE_NONE);
423    
424     tok = strtok_r(NULL, " ", &m);
425     }
426    
427     xfree(mcp);
428    
429     return 0;
430     }
431    
432    
433     /*
434     * Count how many messages matched the filter.
435     */
436     unsigned int
437     count_messages(char *mesgs)
438     {
439     unsigned int cnt;
440     char *c;
441    
442     cnt = 0;
443     c = mesgs;
444    
445     while ((c = strchr(c, ' '))) {
446     cnt++;
447     c++;
448     }
449    
450     return ++cnt;
451     }
452    
453    
454     /*
455 lefcha 1.15 * Convert messages with contiguous sequence number to the corresponding number
456     * range, eg. 1 2 3 5 7 8 --> 1:3 5 7:8 and return a newly allocated buffer
457     * with the results.
458 lefcha 1.1 */
459     char *
460     convert_messages(char *mesgs)
461     {
462     int maxlen;
463     unsigned int start, end, tmp;
464     char *c, *cp, *tail;
465    
466     start = end = tmp = 0;
467     maxlen = strlen(mesgs) + 1;
468     tail = NULL;
469    
470     c = cp = xstrdup(mesgs);
471    
472     start = (unsigned int)strtoul(mesgs, &tail, 10);
473     end = start;
474    
475     do {
476     if (tail != NULL) {
477     tmp = (unsigned int)strtoul(tail, &tail, 10);
478     if (tmp == 0)
479     tail = NULL;
480     }
481     if (tmp == end + 1)
482     end++;
483     else {
484     if (start == end) {
485     xstrncpy(c, ultostr(start, 10), maxlen);
486     c += strlen(c);
487     } else {
488     xstrncpy(c, ultostr(start, 10), maxlen - 1);
489     c += strlen(c);
490     *c = ':';
491     *++c = 0;
492     xstrncpy(c, ultostr(end, 10), maxlen);
493     c += strlen(c);
494     }
495    
496     if (tail != NULL && c - cp < maxlen) {
497     *c = ' ';
498     *++c = 0;
499     }
500     start = end = tmp;
501     }
502     } while (tmp != 0);
503    
504     return cp;
505     }
506    
507    
508     /*
509 lefcha 1.15 * Substitute all occurences of the '@' character with the '%' character, and
510     * any double '@' characters with a signle '@' character, returning the number
511     * of replacements.
512 lefcha 1.1 */
513     int
514     substitute_date(char *str)
515     {
516     int n;
517     char *r, *w, *s;
518    
519     n = 0;
520    
521     s = xstrdup(str);
522    
523     for (r = s, w = str; *r != '\0'; r++, w++) {
524     if (*r == '%') {
525     *w++ = '%';
526     *w = '%';
527     } else if (*r == '@') {
528     if (*(r + 1) == '@') {
529     *w = *r++;
530     } else {
531     *w = '%';
532     n++;
533     }
534     } else {
535     *w = *r;
536     }
537     }
538     *w = '\0';
539    
540     xfree(s);
541    
542     return n;
543     }
544    
545    
546     /*
547     * Format the destination mailbox according to the current date conversion
548     * specifiers.
549     */
550     void
551 lefcha 1.17 system_date(char *destmbox)
552 lefcha 1.1 {
553 lefcha 1.13 char s[MBOX_LEN];
554 lefcha 1.1 time_t te;
555     struct tm *tl;
556    
557     if (!strchr(destmbox, '%'))
558     return;
559    
560     te = time(NULL);
561     tl = localtime(&te);
562    
563 lefcha 1.13 if (strftime(s, MBOX_LEN - 1, destmbox, tl))
564     xstrncpy(destmbox, s, MBOX_LEN - 1);
565 lefcha 1.1 }
566    
567    
568     /*
569     * Format the destination mailbox according to the message date conversion
570     * specifiers.
571     */
572     void
573     message_date(char *mesg, char *destmbox)
574     {
575     unsigned int t;
576 lefcha 1.13 char s[MBOX_LEN];
577 lefcha 1.1 struct tm tl;
578 lefcha 1.17 char buf[RESPONSE_BUF + 1];
579 lefcha 1.1
580     if (!strchr(destmbox, '@'))
581     return;
582    
583     substitute_date(destmbox);
584    
585 lefcha 1.13 response_fetch(&connpri, 0, 1, NULL);
586 lefcha 1.12 t = imap_fetch(&connpri, mesg, opts.peek ?
587 lefcha 1.5 "BODY.PEEK[HEADER.FIELDS (DATE)]" :
588     "BODY[HEADER.FIELDS (DATE)]");
589 lefcha 1.1
590 lefcha 1.17 while (response_fetch(&connpri, t, 0, buf) == RESPONSE_NONE);
591 lefcha 1.1
592 lefcha 1.17 if (((strptime(buf, "Date: %a, %d %b %Y %H:%M:%S", &tl) ||
593     strptime(buf, "Date: %d %b %Y %H:%M:%S", &tl)) &&
594 lefcha 1.15 strftime(s, MBOX_LEN - 1, destmbox, &tl)))
595 lefcha 1.13 xstrncpy(destmbox, s, MBOX_LEN - 1);
596 lefcha 1.1 }
597    
598    
599     /*
600     * Format the destination mailbox according to "default variables" specifiers.
601     */
602     void
603     default_variables(char *mbox, char *destmbox)
604     {
605     char *m, *r, *w, *s;
606    
607     if (!strchr(destmbox, '$'))
608     return;
609    
610     s = xstrdup(destmbox);
611    
612     for (r = s, w = destmbox; *r != '\0';) {
613 lefcha 1.13 if (w - destmbox >= MBOX_LEN - 1)
614 lefcha 1.1 break;
615     if (*r == '$') {
616     switch (*(r + 1)) {
617     case '_':
618     if (w + strlen(mbox) - destmbox >
619 lefcha 1.13 MBOX_LEN - 1) {
620 lefcha 1.1 r += 2;
621     break;
622     }
623     for (m = mbox; *m != '\0'; m++, w++)
624     *w = *m;
625     r += 2;
626     break;
627     case '$':
628     *w++ = '$';
629     r += 2;
630     break;
631     default:
632     *w++ = *r++;
633     break;
634     }
635     } else {
636     *w++ = *r++;
637     }
638     }
639     *w = '\0';
640    
641     xfree(s);
642     }
643 lefcha 1.17
644    
645     /*
646     * Format the destination mailbox according to "headers variables" specifiers.
647     */
648     void
649     headers_variables(char *mesg, char *destmbox)
650     {
651     int i;
652     unsigned int t;
653     char *c, *r, *w, *s;
654     regex_t creg[2];
655     regmatch_t match[3];
656     char buf[RESPONSE_BUF + 1];
657     struct {
658     char *s;
659     char *e;
660     } user, domain;
661     const char *reg[2] = {
662     "From:[[:blank:]]+([[:graph:]]+)@([[:graph:]]+)"
663     "[[:blank:]]*\r\n",
664    
665     "From:[[:print:]]+<([[:graph:]]+)@([[:graph:]]+)>"
666     "[[:blank:]]*\r\n"
667     };
668    
669     if (!strchr(destmbox, '&'))
670     return;
671    
672     response_fetch(&connpri, 0, 1, NULL);
673     t = imap_fetch(&connpri, mesg, opts.peek ?
674     "BODY.PEEK[HEADER.FIELDS (FROM)]" :
675     "BODY[HEADER.FIELDS (FROM)]");
676     while (response_fetch(&connpri, t, 0, buf) == RESPONSE_NONE);
677    
678     for (i = 0; i < 2; i++)
679     regcomp(&creg[i], reg[i], REG_EXTENDED | REG_ICASE);
680    
681     if (!regexec(&creg[0], buf, 3, match, 0) ||
682     !regexec(&creg[1], buf, 3, match, 0)) {
683     user.s = buf + match[1].rm_so;
684     user.e = buf + match[1].rm_eo;
685     domain.s = buf + match[2].rm_so;
686     domain.e = buf + match[2].rm_eo;
687     } else {
688     for (i = 0; i < 2; i++)
689     regfree(&creg[i]);
690     return;
691     }
692    
693     s = xstrdup(destmbox);
694    
695     for (r = s, w = destmbox; *r != '\0';) {
696     if (w - destmbox >= MBOX_LEN - 1)
697     break;
698     if (*r == '&') {
699     switch (*(r + 1)) {
700     case 'f':
701     if (w + (user.e - user.s) +
702     (domain.s - domain.e) + 1 -
703     destmbox > MBOX_LEN) {
704     r += 2;
705     break;
706     }
707     for (c = user.s; c < user.e; c++, w++)
708     *w = *c;
709     *w++ = '@';
710     for (c = domain.s; c < domain.e; c++, w++)
711     *w = *c;
712     r += 2;
713     break;
714     case 'u':
715     if (w + (user.e - user.s) - destmbox >
716     MBOX_LEN - 1) {
717     r += 2;
718     break;
719     }
720     for (c = user.s; c < user.e; c++, w++)
721     *w = *c;
722     r += 2;
723     break;
724     case 'd':
725     if (w + (domain.e - domain.s) - destmbox >
726     MBOX_LEN - 1) {
727     r += 2;
728     break;
729     }
730     for (c = domain.s; c < domain.e; c++, w++)
731     *w = *c;
732     r += 2;
733     break;
734     case '&':
735     *w++ = '&';
736     r += 2;
737     break;
738     default:
739     *w++ = *r++;
740     break;
741     }
742     } else {
743     *w++ = *r++;
744     }
745     }
746     *w = '\0';
747    
748     for (i = 0; i < 2; i++)
749     regfree(&creg[i]);
750     xfree(s);
751     }

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26