8 |
#include "data.h" |
#include "data.h" |
9 |
|
|
10 |
|
|
11 |
|
extern int sockpri, sockaux; |
12 |
extern unsigned int options; |
extern unsigned int options; |
13 |
extern unsigned int capabilities; |
extern unsigned int capabilities; |
14 |
|
|
15 |
static struct { |
namesp_t nsppri, nspaux; /* Primary and auxiliary namespace. */ |
|
char prefix[NAMESPACE_PREFIX_LEN]; |
|
|
char delim; |
|
|
} namesp; |
|
16 |
|
|
17 |
|
|
18 |
#ifdef DEBUG |
#ifdef DEBUG |
19 |
/* |
/* |
20 |
* Test/ping server. |
* Test/ping server. |
21 |
*/ |
*/ |
22 |
int test(void) |
int test(int *sock) |
23 |
{ |
{ |
24 |
return server_response(imap_noop()); |
return server_response(sock, imap_noop(sock)); |
25 |
} |
} |
26 |
#endif |
#endif |
27 |
|
|
29 |
/* |
/* |
30 |
* Check server's capabilities. |
* Check server's capabilities. |
31 |
*/ |
*/ |
32 |
int check_capabilities(void) |
int check_capabilities(int *sock) |
33 |
{ |
{ |
34 |
capabilities = CAPABILITY_NONE; |
capabilities = CAPABILITY_NONE; |
35 |
|
|
36 |
return capability_response(imap_capability()); |
return capability_response(sock, imap_capability(sock)); |
37 |
} |
} |
38 |
|
|
39 |
|
|
40 |
/* |
/* |
41 |
* Get namespace of mail server's mailboxes. |
* Get namespace of mail server's mailboxes. |
42 |
*/ |
*/ |
43 |
int check_namespace(void) |
int check_namespace(int *sock, namesp_t *nsp) |
44 |
{ |
{ |
45 |
namesp.prefix[0] = namesp.delim = 0; |
nsp->prefix[0] = nsp->delim = 0; |
46 |
|
|
47 |
if (!(options & OPTION_NAMESPACE) || |
if (!(options & OPTION_NAMESPACE) || |
48 |
!(capabilities & CAPABILITY_NAMESPACE)) |
!(capabilities & CAPABILITY_NAMESPACE)) |
49 |
return 0; |
return 0; |
50 |
else |
else |
51 |
return namespace_response(imap_namespace(), |
return namespace_response(sock, imap_namespace(sock), nsp); |
|
namesp.prefix, namesp.delim); |
|
52 |
} |
} |
53 |
|
|
54 |
|
|
55 |
/* |
/* |
56 |
* Login to server. |
* Login to server. |
57 |
*/ |
*/ |
58 |
int login(char *user, char *pass) |
int login(int *sock, char *user, char *pass) |
59 |
{ |
{ |
60 |
log_info(LOG_USERNAME, user); |
log_info(LOG_USERNAME, user); |
61 |
|
|
62 |
return server_response(imap_login(user, pass)); |
return server_response(sock, imap_login(sock, user, pass)); |
63 |
|
} |
64 |
|
|
65 |
|
|
66 |
|
|
67 |
|
/* |
68 |
|
* Check if a mailbox exists. |
69 |
|
*/ |
70 |
|
int check_mailbox(int *sock, char *mbox, namesp_t *nsp) |
71 |
|
{ |
72 |
|
return server_response(sock, imap_examine(sock, |
73 |
|
apply_namespace(mbox, |
74 |
|
nsp->prefix, |
75 |
|
nsp->delim))); |
76 |
} |
} |
77 |
|
|
78 |
|
|
79 |
/* |
/* |
80 |
* Open mailbox in read-write mode. |
* Open mailbox in read-write mode. |
81 |
*/ |
*/ |
82 |
int select_mailbox(char *mbox) |
int select_mailbox(int *sock, char *mbox, namesp_t *nsp) |
83 |
{ |
{ |
84 |
int r; |
int r; |
85 |
|
|
86 |
if (mailbox_status(mbox) == -2) |
if (mailbox_status(sock, mbox, nsp) == -2) |
87 |
return -2; /* No messages exist. No filters need to |
return -2; /* No messages exist. No filters need to |
88 |
be applied. */ |
be applied. */ |
89 |
|
|
90 |
r = select_response(imap_select(apply_namespace(mbox, namesp.prefix, |
r = select_response(sock, imap_select(sock, |
91 |
namesp.delim))); |
apply_namespace(mbox, nsp->prefix, |
92 |
|
nsp->delim))); |
93 |
|
|
94 |
log_info(LOG_MAILBOX, mbox); |
log_info(LOG_MAILBOX, mbox); |
95 |
|
|
100 |
/* |
/* |
101 |
* Get mailbox's status. |
* Get mailbox's status. |
102 |
*/ |
*/ |
103 |
int mailbox_status(char *mbox) |
int mailbox_status(int *sock, char *mbox, namesp_t *nsp) |
104 |
{ |
{ |
105 |
return status_response(imap_status(apply_namespace(mbox, namesp.prefix, |
return status_response(sock, imap_status(sock, |
106 |
namesp.delim), |
apply_namespace(mbox, nsp->prefix, |
107 |
"MESSAGES RECENT UNSEEN"), mbox); |
nsp->delim), |
108 |
|
"MESSAGES RECENT UNSEEN"), mbox); |
109 |
} |
} |
110 |
|
|
111 |
|
|
112 |
/* |
/* |
113 |
* Close examined/selected mailbox. |
* Close examined/selected mailbox. |
114 |
*/ |
*/ |
115 |
int close_mailbox(void) |
int close_mailbox(int *sock) |
116 |
{ |
{ |
117 |
return server_response(imap_close()); |
return server_response(sock, imap_close(sock)); |
118 |
} |
} |
119 |
|
|
120 |
|
|
121 |
/* |
/* |
122 |
* Logout from server. |
* Logout from server. |
123 |
*/ |
*/ |
124 |
int logout(void) |
int logout(int *sock) |
125 |
{ |
{ |
126 |
return server_response(imap_logout()); |
return server_response(sock, imap_logout(sock)); |
127 |
} |
} |
128 |
|
|
129 |
|
|
144 |
log_info(LOG_FILTER, filters[i]->key); |
log_info(LOG_FILTER, filters[i]->key); |
145 |
|
|
146 |
apply_action(mesgs, &(filters[i]->action.type), |
apply_action(mesgs, &(filters[i]->action.type), |
147 |
filters[i]->action.destmbox, filters[i]->action.args); |
filters[i]->action.raccount, filters[i]->action.destmbox, |
148 |
|
filters[i]->action.args); |
149 |
|
|
150 |
xfree(mesgs); |
xfree(mesgs); |
151 |
} |
} |
169 |
search = generate_filter_and(filter->masks, filter->masknum, |
search = generate_filter_and(filter->masks, filter->masknum, |
170 |
filter->masklen); |
filter->masklen); |
171 |
|
|
172 |
search_response(imap_search(search), mesgs); |
search_response(&sockpri, imap_search(&sockpri, search), mesgs); |
173 |
|
|
174 |
xfree(search); |
xfree(search); |
175 |
|
|
362 |
/* |
/* |
363 |
* Apply the appropriate action. |
* Apply the appropriate action. |
364 |
*/ |
*/ |
365 |
int apply_action(char *mesgs, unsigned int *type, char *destmbox, |
int apply_action(char *mesgs, unsigned int *type, account_t *raccount, |
366 |
char *args) |
char *destmbox, char *args) |
367 |
{ |
{ |
368 |
unsigned int cnt; |
unsigned int cnt; |
369 |
|
|
370 |
if (!*mesgs) |
if (!*mesgs) |
371 |
return 0; |
return 0; |
372 |
|
|
373 |
log_info(LOG_ACTION, type); |
log_info(LOG_ACTION, type); |
374 |
log_info(LOG_DESTINATION_MAILBOX, destmbox); |
log_info(LOG_DESTINATION_MAILBOX, destmbox); |
375 |
|
|
376 |
cnt = convert_messages(mesgs); |
cnt = count_messages(mesgs); |
377 |
|
|
378 |
switch (*type) { |
switch (*type) { |
379 |
case FILTER_ACTION_DELETE: |
case FILTER_ACTION_DELETE: |
380 |
info("%d message%s deleted.\n", cnt, plural(cnt)); |
info("%d message%s deleted.\n", cnt, plural(cnt)); |
383 |
case FILTER_ACTION_COPY: |
case FILTER_ACTION_COPY: |
384 |
info("%d message%s copied to mailbox \"%s\".\n", cnt, plural(cnt), |
info("%d message%s copied to mailbox \"%s\".\n", cnt, plural(cnt), |
385 |
destmbox); |
destmbox); |
386 |
action_copy(mesgs, apply_namespace(destmbox, namesp.prefix, |
action_copy(mesgs, apply_namespace(destmbox, nsppri.prefix, |
387 |
namesp.delim), args); |
nsppri.delim), args); |
388 |
break; |
break; |
389 |
case FILTER_ACTION_MOVE: |
case FILTER_ACTION_MOVE: |
390 |
info("%d message%s moved to mailbox \"%s\".\n", cnt, plural(cnt), |
info("%d message%s moved to mailbox \"%s\".\n", cnt, plural(cnt), |
391 |
destmbox); |
destmbox); |
392 |
action_move(mesgs, apply_namespace(destmbox, namesp.prefix, |
action_move(mesgs, apply_namespace(destmbox, nsppri.prefix, |
393 |
namesp.delim), args); |
nsppri.delim), args); |
394 |
|
break; |
395 |
|
case FILTER_ACTION_RCOPY: |
396 |
|
info("%d message%s copied to mailbox \"%s\" at account %s\n", cnt, |
397 |
|
plural(cnt), destmbox, raccount->key); |
398 |
|
action_rcopy(mesgs, raccount, destmbox, args); |
399 |
|
break; |
400 |
|
case FILTER_ACTION_RMOVE: |
401 |
|
info("%d messages%s moved to mailbox \"%s\" at account %s\n", cnt, |
402 |
|
plural(cnt), destmbox, raccount->key); |
403 |
|
action_rmove(mesgs, raccount, destmbox, args); |
404 |
break; |
break; |
405 |
case FILTER_ACTION_LIST: |
case FILTER_ACTION_LIST: |
406 |
info("%d message%s listed.\n", cnt, plural(cnt)); |
info("%d message%s listed.\n", cnt, plural(cnt)); |
420 |
*/ |
*/ |
421 |
int action_delete(char *mesgs, char *args) |
int action_delete(char *mesgs, char *args) |
422 |
{ |
{ |
423 |
const char *delim = " "; |
char *tok, *mcp, *m; |
424 |
char *tok, *mcp, *m, *acp = NULL, *occur; |
|
425 |
|
action_list(mesgs, args); |
426 |
|
|
427 |
|
convert_messages(mesgs); |
428 |
|
|
429 |
m = mcp = xstrdup(mesgs); |
m = mcp = xstrdup(mesgs); |
430 |
|
|
431 |
if (*args) { |
while ((tok = strsep(&m, " "))) |
432 |
acp = xstrdup(args); |
server_response(&sockpri, imap_store(&sockpri, tok, "\\Deleted")); |
|
while ((occur = strchr(acp, ','))) |
|
|
*occur = ' '; |
|
|
} |
|
|
while ((tok = strsep(&m, delim))) { |
|
|
if (*args) |
|
|
fetch_response(imap_fetch(tok, acp, 0)); |
|
|
|
|
|
server_response(imap_store(tok, "\\Deleted")); |
|
|
} |
|
433 |
|
|
434 |
xfree(mcp); |
xfree(mcp); |
435 |
|
|
|
if (*args) |
|
|
xfree(acp); |
|
|
|
|
436 |
return 0; |
return 0; |
437 |
} |
} |
438 |
|
|
443 |
int action_copy(char *mesgs, char *destmbox, char *args) |
int action_copy(char *mesgs, char *destmbox, char *args) |
444 |
{ |
{ |
445 |
int r = 0; |
int r = 0; |
446 |
const char *delim = " "; |
char *tok = NULL, *mcp, *m; |
447 |
char *tok, *mcp, *m, *acp = NULL, *occur; |
|
448 |
|
action_list(mesgs, args); |
449 |
|
|
450 |
|
convert_messages(mesgs); |
451 |
|
|
452 |
m = mcp = xstrdup(mesgs); |
m = mcp = xstrdup(mesgs); |
453 |
|
|
454 |
if (*args) { |
if ((r = copy_response(&sockpri, imap_copy(&sockpri, tok, destmbox))) == |
455 |
acp = xstrdup(args); |
RESPONSE_TRYCREATE) |
456 |
|
if (!server_response(&sockpri, imap_create(&sockpri, destmbox))) { |
457 |
while ((occur = strchr(acp, ','))) |
server_response(&sockpri, imap_subscribe(&sockpri, destmbox)); |
458 |
*occur = ' '; |
r = copy_response(&sockpri, imap_copy(&sockpri, tok, destmbox)); |
459 |
} |
} |
460 |
while ((tok = strsep(&m, delim))) { |
|
|
if (*args) |
|
|
fetch_response(imap_fetch(tok, acp, 0)); |
|
|
|
|
|
if ((r = copy_response(imap_copy(tok, destmbox))) == RESPONSE_TRYCREATE) |
|
|
if (!server_response(imap_create(destmbox))) |
|
|
r = copy_response(imap_copy(tok, destmbox)); |
|
|
} |
|
|
|
|
461 |
xfree(mcp); |
xfree(mcp); |
462 |
|
|
|
if (*args) |
|
|
xfree(acp); |
|
|
|
|
463 |
return r; |
return r; |
464 |
} |
} |
465 |
|
|
480 |
|
|
481 |
|
|
482 |
/* |
/* |
483 |
|
* Copy messages to the specified mailbox of another mail server. |
484 |
|
*/ |
485 |
|
int action_rcopy(char *mesgs, account_t *destacc, char *destmbox, char *args) |
486 |
|
{ |
487 |
|
int r; |
488 |
|
char *tok, *m, *mcp, *ndm; |
489 |
|
unsigned int n, t = 0; |
490 |
|
char buf[RESPONSE_BUF]; |
491 |
|
|
492 |
|
if (init_connection(&sockaux, destacc->server, destacc->port, |
493 |
|
destacc->ssl)) |
494 |
|
return ERROR_NETWORK; |
495 |
|
|
496 |
|
r = greeting_response(&sockaux); |
497 |
|
|
498 |
|
if (r == RESPONSE_BYE || check_capabilities(&sockaux)) |
499 |
|
return ERROR_NETWORK; |
500 |
|
|
501 |
|
#ifdef DEBUG |
502 |
|
test(&sockaux); |
503 |
|
#endif |
504 |
|
|
505 |
|
if (r != RESPONSE_PREAUTH) { |
506 |
|
if (destacc->passwdattr == PASSWORD_NONE) { |
507 |
|
printf("Enter password for %s@%s: ", destacc->username, |
508 |
|
destacc->server); |
509 |
|
get_password(destacc->password, PASSWORD_LEN); |
510 |
|
destacc->passwdattr = PASSWORD_PLAIN; |
511 |
|
} |
512 |
|
if (login(&sockaux, destacc->username, |
513 |
|
destacc->password) == RESPONSE_NO) { |
514 |
|
error("imapfilter: username %s or password rejected at %s\n", |
515 |
|
destacc->username, destacc->server); |
516 |
|
return ERROR_NETWORK; |
517 |
|
} |
518 |
|
} |
519 |
|
check_namespace(&sockaux, &nspaux); |
520 |
|
|
521 |
|
/* apply_namespace() returns a pointer to a static buffer. */ |
522 |
|
ndm = apply_namespace(destmbox, nspaux.prefix, nspaux.delim); |
523 |
|
|
524 |
|
r = check_mailbox(&sockaux, ndm, &nspaux); |
525 |
|
|
526 |
|
if (r == RESPONSE_OK) |
527 |
|
close_mailbox(&sockaux); |
528 |
|
else if (r == RESPONSE_NO) { |
529 |
|
server_response(&sockaux, imap_create(&sockaux, ndm)); |
530 |
|
server_response(&sockaux, imap_subscribe(&sockaux, ndm)); |
531 |
|
} |
532 |
|
|
533 |
|
m = mcp = xstrdup(mesgs); |
534 |
|
|
535 |
|
while ((tok = strsep(&m, " "))) { |
536 |
|
fetchsize_response(&sockpri, &n, |
537 |
|
imap_fetch(&sockpri, tok, "RFC822.SIZE")); |
538 |
|
|
539 |
|
t = imap_append(&sockaux, ndm, n); |
540 |
|
|
541 |
|
do { |
542 |
|
r = fetch_response(&sockpri, 0, buf, imap_fetch(&sockpri, tok, |
543 |
|
"RFC822.HEADER")); |
544 |
|
|
545 |
|
socket_write(&sockaux, buf); |
546 |
|
} while (r == RESPONSE_NONE); |
547 |
|
|
548 |
|
socket_write(&sockaux, "\r\n"); |
549 |
|
|
550 |
|
fetch_response(&sockpri, 1, NULL, 0); |
551 |
|
do { |
552 |
|
r = fetch_response(&sockpri, 0, buf, imap_fetch(&sockpri, tok, |
553 |
|
"BODY[TEXT]")); |
554 |
|
|
555 |
|
socket_write(&sockaux, buf); |
556 |
|
} while (r == RESPONSE_NONE); |
557 |
|
} |
558 |
|
|
559 |
|
socket_write(&sockaux, "\r\n\r\n"); |
560 |
|
|
561 |
|
append_response(&sockaux, t); |
562 |
|
|
563 |
|
logout(&sockaux); |
564 |
|
|
565 |
|
action_list(mesgs, args); |
566 |
|
|
567 |
|
xfree(mcp); |
568 |
|
|
569 |
|
return 0; |
570 |
|
} |
571 |
|
|
572 |
|
|
573 |
|
/* |
574 |
|
* Move messages to the specified mailbox of another mail server. |
575 |
|
*/ |
576 |
|
int action_rmove(char *mesgs, account_t *destacc, char *destmbox, char *args) |
577 |
|
{ |
578 |
|
if (!action_rcopy(mesgs, destacc, destmbox, args)) |
579 |
|
action_delete(mesgs, "\0"); |
580 |
|
|
581 |
|
return 0; |
582 |
|
} |
583 |
|
|
584 |
|
|
585 |
|
/* |
586 |
* List user selected headers of messages. |
* List user selected headers of messages. |
587 |
*/ |
*/ |
588 |
int action_list(char *mesgs, char *args) |
int action_list(char *mesgs, char *args) |
589 |
{ |
{ |
590 |
const char *delim = " "; |
int r; |
591 |
char *tok, *mcp, *m, *acp, *occur; |
char *tok, *mcp, *m; |
592 |
|
char s[ARGS_LEN + 27]; |
593 |
|
char hdrs[RESPONSE_BUF]; |
594 |
|
|
595 |
if (!*args) |
if (!*args) |
596 |
return 0; |
return 0; |
597 |
|
|
598 |
m = mcp = xstrdup(mesgs); |
m = mcp = xstrdup(mesgs); |
|
acp = xstrdup(args); |
|
599 |
|
|
600 |
while ((occur = strchr(acp, ','))) |
snprintf(s, ARGS_LEN + 27 - 1, "BODY.PEEK[HEADER.FIELDS (%s)]", args); |
|
*occur = ' '; |
|
601 |
|
|
602 |
while ((tok = strsep(&m, delim))) |
while ((tok = strsep(&m, " "))) { |
603 |
fetch_response(imap_fetch(tok, acp, 1)); |
/* Reset internal fetch counter. */ |
604 |
|
fetch_response(&sockpri, 1, NULL, 0); |
605 |
|
|
606 |
|
do { |
607 |
|
r = fetch_response(&sockpri, 0, hdrs, imap_fetch(&sockpri, tok, s)); |
608 |
|
|
609 |
|
if (*hdrs) { |
610 |
|
if (options & OPTION_HEADERS) |
611 |
|
info("%s\n", hdrs); |
612 |
|
log_info(LOG_WRITE, hdrs); |
613 |
|
} else { |
614 |
|
log_info(LOG_WRITE, NULL); |
615 |
|
} |
616 |
|
} while (r == RESPONSE_NONE); |
617 |
|
} |
618 |
|
|
619 |
xfree(mcp); |
xfree(mcp); |
|
xfree(acp); |
|
620 |
|
|
621 |
return 0; |
return 0; |
622 |
} |
} |
623 |
|
|
624 |
|
|
625 |
/* |
/* |
626 |
|
* Count how many messages matched the filter. |
627 |
|
*/ |
628 |
|
unsigned int count_messages(char *mesgs) |
629 |
|
{ |
630 |
|
unsigned int cnt = 0; |
631 |
|
char *c = mesgs; |
632 |
|
|
633 |
|
while ((c = strchr(c, ' '))) { |
634 |
|
cnt++; |
635 |
|
c++; |
636 |
|
} |
637 |
|
|
638 |
|
return ++cnt; |
639 |
|
} |
640 |
|
|
641 |
|
|
642 |
|
/* |
643 |
* Convert messages with contiguous sequence number to the corresponding |
* Convert messages with contiguous sequence number to the corresponding |
644 |
* number range, eg. 1 2 3 5 7 8 --> 1:3 5 7:8 |
* number range, eg. 1 2 3 5 7 8 --> 1:3 5 7:8 |
645 |
*/ |
*/ |
646 |
unsigned int convert_messages(char *mesgs) |
void convert_messages(char *mesgs) |
647 |
{ |
{ |
648 |
unsigned int cnt, maxlen; |
unsigned int maxlen; |
649 |
unsigned int start, end, tmp; |
unsigned int start, end, tmp; |
650 |
char *cp, *tail, *m; |
char *cp, *tail, *m; |
651 |
|
|
652 |
cnt = start = end = tmp = 0; |
start = end = tmp = 0; |
653 |
maxlen = strlen(mesgs) + 1; |
maxlen = strlen(mesgs) + 1; |
654 |
tail = NULL; |
tail = NULL; |
655 |
|
|
657 |
m = mesgs; |
m = mesgs; |
658 |
|
|
659 |
start = (unsigned int) strtoul(cp, &tail, 10); |
start = (unsigned int) strtoul(cp, &tail, 10); |
|
cnt++; |
|
660 |
end = start; |
end = start; |
661 |
|
|
662 |
do { |
do { |
663 |
if (tail) { |
if (tail) { |
664 |
tmp = (unsigned int) strtoul(tail, &tail, 10); |
tmp = (unsigned int) strtoul(tail, &tail, 10); |
665 |
if (tmp) |
if (!tmp) |
|
cnt++; |
|
|
else |
|
666 |
tail = NULL; |
tail = NULL; |
667 |
} |
} |
668 |
if (tmp == end + 1) |
if (tmp == end + 1) |
689 |
} while (tmp); |
} while (tmp); |
690 |
|
|
691 |
xfree(cp); |
xfree(cp); |
|
|
|
|
return cnt; |
|
692 |
} |
} |