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

Contents of /imapfilter/action.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1 - (show 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 #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