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

Contents of /imapfilter/action.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.2.2.2 - (show annotations)
Fri Sep 12 09:58:52 2003 UTC (20 years, 7 months ago) by lefcha
Branch: release-0_9-patches
Changes since 1.2.2.1: +1 -0 lines
File MIME type: text/plain
Fix so that default_variables() is called during rcopy/rmove.

1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <sys/types.h>
5 #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 default_variables(mbox, dm[1]);
248 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