Codebase list fdm / 25522f3
Make remove-header support a list. Nicholas Marriott 16 years ago
18 changed file(s) with 181 addition(s) and 103 deletion(s). Raw diff Collapse all Expand all
0 24 August 2007
1
2 * remove-header now accepts a list of headers in {}.
3
04 23 August 2007
15
26 * Yet another fetch reorganisation to try to make it clearer. Move tracking
2121 - better website
2222 - generic flags on account so that no-verify/no-apop don't have to be in the
2323 right order
24 - document mbox fetch
25 - remove-headers { ... }
2624 - pop3 over pipe
2725 - pop3/imap tests via pipe and coprocess
2826 - aio for fetch maildir
2927 - fetch from gzipped mbox
28 - document mbox fetch
29 - document remove-headers { ... }
6666 /*
6767 * Complete flag. Set when fetch code is finished. All fetching finished after
6868 * queues drain.
69 */
69 */
7070 int fetch_complete;
7171
7272 int
325325 if (n == last || n % conf.purge_after != 0)
326326 return (0);
327327 last = n;
328
328
329329 log_debug("%s: purging after %u mails", a->name, n);
330330 return (1);
331331 }
427427 ARRAY_ADD(&iol, pio);
428428 if (a->fetch->fill != NULL)
429429 a->fetch->fill(a, &iol);
430
430
431431 /* Poll for fetch data or privsep messages. */
432432 log_debug3("%s: queued %u; blocked %u; flags 0x%02x", a->name,
433433 fetch_queued, fetch_blocked, fctx.flags);
442442 log_warnx("%s: polling error. aborted", a->name);
443443 else
444444 log_warnx("%s: fetching error. aborted", a->name);
445
445
446446 aborted = 1;
447447
448448 finished:
453453
454454 xfree(fctx.lbuf);
455455 fetch_free();
456 ARRAY_FREE(&iol);
456 ARRAY_FREE(&iol);
457457
458458 /* Close caches. */
459459 TAILQ_FOREACH(cache, &conf.caches, entry) {
469469 n = fetch_dropped + fetch_kept;
470470 if (n > 0) {
471471 log_info("%s: %u messages processed (%u kept) in %.3f "
472 "seconds (average %.3f)", a->name, n, fetch_kept,
472 "seconds (average %.3f)", a->name, n, fetch_kept,
473473 tim, tim / n);
474474 } else {
475475 log_info("%s: 0 messages processed in %.3f seconds",
4040 struct deliver_remove_header_data *data = ti->data;
4141 char *ptr, *hdr;
4242 size_t len, off, wrap;
43 u_int i;
43 u_int i, j;
4444
45 hdr = replacestr(&data->hdr, m->tags, m, &m->rml);
46 if (hdr == NULL || *hdr == '\0') {
47 if (hdr != NULL)
48 xfree(hdr);
49 log_warnx("%s: empty header", a->name);
50 return (DELIVER_FAILURE);
51 }
52 log_debug2("%s: removing header: %s", a->name, hdr);
5345
54 ARRAY_FREE(&m->wrapped);
55 m->wrapchar = '\0';
56 fill_wrapped(m);
46 for (j = 0; j < ARRAY_LENGTH(data->hdrs); j++) {
47 hdr = replacestr(
48 &ARRAY_ITEM(data->hdrs, j), m->tags, m, &m->rml);
49 if (hdr == NULL || *hdr == '\0') {
50 if (hdr != NULL)
51 xfree(hdr);
52 log_warnx("%s: empty header", a->name);
53 return (DELIVER_FAILURE);
54 }
55 log_debug2("%s: removing header: %s", a->name, hdr);
5756
58 set_wrapped(m, ' ');
57 ARRAY_FREE(&m->wrapped);
58 m->wrapchar = '\0';
59 fill_wrapped(m);
5960
60 while ((ptr = match_header(m, hdr, &len, 0)) != NULL) {
61 log_debug3("%s: found header to remove: %.*s", a->name,
62 (int) len, ptr);
61 set_wrapped(m, ' ');
6362
64 /* Remove the header. */
65 memmove(ptr, ptr + len, m->size - len - (ptr - m->data));
66 m->size -= len;
67 m->body -= len;
63 while ((ptr = match_header(m, hdr, &len, 0)) != NULL) {
64 log_debug3("%s: found header to remove: %.*s", a->name,
65 (int) len, ptr);
6866
69 /* Fix up the wrapped array. */
70 off = ptr - m->data;
71 i = 0;
72 while (i < ARRAY_LENGTH(&m->wrapped)) {
73 wrap = ARRAY_ITEM(&m->wrapped, i);
74 if (wrap >= off + len) {
75 ARRAY_SET(&m->wrapped, i, wrap - len);
76 i++;
77 } else if (wrap >= off)
78 ARRAY_REMOVE(&m->wrapped, i);
79 else
80 i++;
67 /* Remove the header. */
68 memmove(
69 ptr, ptr + len, m->size - len - (ptr - m->data));
70 m->size -= len;
71 m->body -= len;
72
73 /* Fix up the wrapped array. */
74 off = ptr - m->data;
75 i = 0;
76 while (i < ARRAY_LENGTH(&m->wrapped)) {
77 wrap = ARRAY_ITEM(&m->wrapped, i);
78 if (wrap >= off + len) {
79 ARRAY_SET(&m->wrapped, i, wrap - len);
80 i++;
81 } else if (wrap >= off)
82 ARRAY_REMOVE(&m->wrapped, i);
83 else
84 i++;
85 }
8186 }
8287 }
8388
84 /* invalidate the match data since stuff may have moved */
89 /* Invalidate the match data since stuff may have moved. */
8590 m->rml.valid = 0;
8691
8792 set_wrapped(m, '\n');
9297 deliver_remove_header_desc(struct actitem *ti, char *buf, size_t len)
9398 {
9499 struct deliver_remove_header_data *data = ti->data;
100 char *hdrs;
95101
96 xsnprintf(buf, len, "remove-header \"%s\"", data->hdr.str);
102 hdrs = fmt_replstrs("remove-headers ", data->hdrs);
103 strlcpy(buf, hdrs, len);
104 xfree(hdrs);
97105 }
115115 error_cause:
116116 log_warnx("%s: %s: %s", a->name, s, cause);
117117 xfree(cause);
118
118
119119 error:
120120 if (cmd != NULL)
121121 cmd_free(cmd);
8787
8888 /* Deliver remove-header data. */
8989 struct deliver_remove_header_data {
90 struct replstr hdr;
90 struct replstrs *hdrs;
9191 };
9292
9393 /* Deliver write data. */
257257 struct fetch_mbox_data *data = a->data;
258258 struct fetch_mbox_mbox *fmbox;
259259 u_int i;
260
260
261261 for (i = 0; i < ARRAY_LENGTH(&data->fmboxes); i++) {
262262 fmbox = ARRAY_ITEM(&data->fmboxes, i);
263
263
264264 if (fmbox->base != NULL)
265265 munmap(fmbox->base, fmbox->size);
266266 if (fmbox->fd != -1)
278278 fetch_mbox_state_init(struct account *a, struct fetch_ctx *fctx)
279279 {
280280 struct fetch_mbox_data *data = a->data;
281
281
282282 if (fetch_mbox_make(a) != 0)
283283 return (FETCH_ERROR);
284284 if (ARRAY_EMPTY(&data->fmboxes)) {
328328 return (FETCH_ERROR);
329329 }
330330 fmbox->size = size;
331
331
332332 log_debug3("%s: opening mbox, size %ju", a->name, size);
333333 used = 0;
334334 do {
342342 goto error;
343343 }
344344 } while (fmbox->fd < 0);
345
345
346346 /* mmap the file. */
347347 fmbox->base = mmap(
348348 NULL, fmbox->size, PROT_READ|PROT_WRITE, MAP_SHARED, fmbox->fd, 0);
452452 data->off = fmbox->size;
453453 } else
454454 data->off += ptr - line + 1;
455
455
456456 /* Check if the line is "From ". */
457457 if (line > fmbox->base &&
458458 ptr - line >= 5 && strncmp(line, "From ", 5) == 0) {
469469 lptr++;
470470 llen--;
471471 }
472
472
473473 if (llen >= 5 && strncmp(lptr, "From ", 5) == 0)
474474 line++;
475475 }
496496 aux->size -= 2;
497497 m->size -= 2;
498498 }
499
499
500500 return (FETCH_MAIL);
501501 }
502502
511511 if (fetch_mbox_save(a, ARRAY_ITEM(&data->fmboxes, i)) != 0)
512512 return (FETCH_ERROR);
513513 }
514
515 fetch_mbox_abort(a);
514
515 fetch_mbox_abort(a);
516516 return (FETCH_EXIT);
517517 }
518518
5959 struct fetch fetch_nntp = {
6060 "nntp",
6161 fetch_nntp_state_connect,
62
62
6363 fetch_nntp_fill,
6464 NULL,
6565 fetch_nntp_abort,
116116 va_list ap;
117117 u_int i;
118118 int code;
119
119
120120 if (codep == NULL)
121121 codep = &code;
122122
318318 void
319319 fetch_nntp_fill(struct account *a, struct iolist *iol)
320320 {
321 struct fetch_nntp_data *data = a->data;
321 struct fetch_nntp_data *data = a->data;
322322
323323 if (data->io != NULL)
324324 ARRAY_ADD(iol, data->io);
428428 return (FETCH_BLOCK);
429429 }
430430 } while (ARRAY_ITEM(&data->groups, data->group)->ignore);
431
431
432432 fctx->state = fetch_nntp_state_group;
433433 return (FETCH_AGAIN);
434434 }
478478 struct fetch_nntp_group *group;
479479 char *line;
480480 u_int n;
481
481
482482 group = ARRAY_ITEM(&data->groups, data->group);
483483
484484 if (fetch_nntp_check(a, fctx, &line, NULL, 1, 211) != 0)
621621 fctx->state = fetch_nntp_state_line;
622622 return (FETCH_AGAIN);
623623 }
624
624
625625 /* Line state. */
626626 int
627627 fetch_nntp_state_line(struct account *a, struct fetch_ctx *fctx)
634634 line = io_readline2(data->io, &fctx->lbuf, &fctx->llen);
635635 if (line == NULL)
636636 return (FETCH_BLOCK);
637
637
638638 if (line[0] == '.') {
639639 if (line[1] == '\0')
640640 break;
641641 line++;
642642 }
643
643
644644 if (data->flushing)
645645 continue;
646
646
647647 if (append_line(m, line, strlen(line)) != 0) {
648648 log_warn("%s: failed to resize mail", a->name);
649649 return (FETCH_ERROR);
5555 int fetch_pop3_state_retr(struct account *, struct fetch_ctx *);
5656 int fetch_pop3_state_line(struct account *, struct fetch_ctx *);
5757 int fetch_pop3_state_quit(struct account *, struct fetch_ctx *);
58
58
5959 struct fetch fetch_pop3 = {
6060 "pop3",
6161 fetch_pop3_state_init,
223223 xasprintf(&src, "%s%s", line, data->pass);
224224 MD5(src, strlen(src), digest);
225225 xfree(src);
226
226
227227 for (i = 0; i < MD5_DIGEST_LENGTH; i++)
228228 xsnprintf(out + i * 2, 3, "%02hhx", digest[i]);
229229
316316 /* Handle dropped mail here. */
317317 if (!TAILQ_EMPTY(&data->dropped)) {
318318 aux = TAILQ_FIRST(&data->dropped);
319
319
320320 io_writeline(data->io, "DELE %u", aux->idx);
321321 fctx->state = fetch_pop3_state_delete;
322322 return (FETCH_BLOCK);
336336 if (data->cur <= data->num)
337337 data->cur++;
338338
339 /*
339 /*
340340 * If this is the last mail, wait until everything has been committed
341341 * back, then quit.
342342 */
535535 line = io_readline2(data->io, &fctx->lbuf, &fctx->llen);
536536 if (line == NULL)
537537 return (FETCH_BLOCK);
538
538
539539 if (line[0] == '.') {
540540 if (line[1] == '\0')
541541 break;
542542 line++;
543543 }
544
544
545545 if (data->flushing)
546546 continue;
547
547
548548 if (append_line(m, line, strlen(line)) != 0) {
549549 log_warn("%s: failed to resize mail", a->name);
550550 return (FETCH_ERROR);
563563 {
564564 struct fetch_pop3_data *data = a->data;
565565 char *line;
566
566
567567 line = io_readline2(data->io, &fctx->lbuf, &fctx->llen);
568568 if (line == NULL)
569569 return (FETCH_BLOCK);
127127 out:
128128 if (io != NULL)
129129 io_free(io);
130
130
131131 fctx->state = fetch_stdin_state_exit;
132132 return (FETCH_MAIL);
133133
3434 struct fetch_ctx {
3535 int (*state)(struct account *, struct fetch_ctx *);
3636 int flags;
37
37
3838 struct mail *mail;
3939
4040 size_t llen;
7474
7575 ARRAY_DECL(, struct fetch_mbox_mbox *) fmboxes;
7676 u_int index;
77
77
7878 size_t off;
7979
8080 TAILQ_HEAD(, fetch_mbox_mail) kept;
713713 return (FETCH_ERROR);
714714 if (line == NULL)
715715 return (FETCH_BLOCK);
716
716
717717 if (data->flushing)
718718 continue;
719719
722722 size = strlen(line);
723723 if (used + size + 2 > data->size)
724724 break;
725
725
726726 if (append_line(m, line, size) != 0) {
727727 log_warn("%s: failed to resize mail", a->name);
728728 return (FETCH_ERROR);
739739 return (imap_invalid(a, line));
740740 if (line[left] != ')' || line[left + 1] != '\0')
741741 return (imap_invalid(a, line));
742
742
743743 /* If there was data left, add it as a new line without trailing \n. */
744744 if (left > 0) {
745745 if (append_line(m, line, left) != 0) {
746746 log_warn("%s: failed to resize mail", a->name);
747747 return (FETCH_ERROR);
748 }
748 }
749749 data->lines++;
750
750
751751 /* Wipe out the trailing \n. */
752752 m->size--;
753753 }
142142 *rio = io;
143143 if (io == NULL)
144144 continue;
145
145
146146 switch (io_before_poll(io, &pfds[i])) {
147147 case 0:
148148 /* Found a closed io. */
187187 if (io_after_poll(io, &pfds[i]) == -1)
188188 goto error;
189189 }
190
190
191191 xfree(pfds);
192192 return (1);
193193
218218 pfd->events |= POLLIN;
219219 if (io->wr != NULL && (BUFFER_USED(io->wr) != 0 ||
220220 (io->flags & (IOF_NEEDFILL|IOF_NEEDPUSH|IOF_MUSTWR)) != 0))
221 pfd->events |= POLLOUT;
221 pfd->events |= POLLOUT;
222222
223223 return (1);
224224 }
119119 { "kilobyte", TOKKILOBYTES },
120120 { "kilobytes", TOKKILOBYTES },
121121 { "lock-file", TOKLOCKFILE },
122 { "lock-type", TOKLOCKTYPES },
122123 { "lock-types", TOKLOCKTYPES },
123124 { "m", TOKMEGABYTES },
124125 { "maildir", TOKMAILDIR },
153154 { "queue-high", TOKQUEUEHIGH },
154155 { "queue-low", TOKQUEUELOW },
155156 { "remove-header", TOKREMOVEHEADER },
157 { "remove-headers", TOKREMOVEHEADERS },
156158 { "returns", TOKRETURNS },
157159 { "rewrite", TOKREWRITE },
158160 { "second", TOKSECONDS },
329329 xfree(hdr);
330330 }
331331 }
332
332
333333 line_next(m, &ptr, len);
334334 }
335335 if (ptr == NULL)
405405 xfree(data->path.str);
406406 } else if (ti->deliver == &deliver_remove_header) {
407407 struct deliver_remove_header_data *data = ti->data;
408 xfree(data->hdr.str);
408 free_replstrs(data->hdrs);
409 ARRAY_FREEALL(data->hdrs);
409410 } else if (ti->deliver == &deliver_add_header) {
410411 struct deliver_add_header_data *data = ti->data;
411412 xfree(data->hdr.str);
125125 %token TOKMEGABYTES TOKGIGABYTES TOKBYTES TOKATTACHMENT TOKCOUNT TOKTOTALSIZE
126126 %token TOKANYTYPE TOKANYNAME TOKANYSIZE TOKEQ TOKNE TOKNNTP TOKNNTPS TOKCACHE
127127 %token TOKGROUP TOKGROUPS TOKPURGEAFTER TOKCOMPRESS TOKNORECEIVED TOKFILEUMASK
128 %token TOKFILEGROUP TOKVALUE TOKTIMEOUT TOKREMOVEHEADER TOKSTDOUT TOKNOVERIFY
129 %token TOKADDHEADER TOKQUEUEHIGH TOKQUEUELOW TOKVERIFYCERTS TOKEXPIRE
130 %token TOKTOCACHE TOKINCACHE TOKKEY TOKNOAPOP
128 %token TOKFILEGROUP TOKVALUE TOKTIMEOUT TOKREMOVEHEADER TOKREMOVEHEADERS
129 %token TOKSTDOUT TOKNOVERIFY TOKADDHEADER TOKQUEUEHIGH TOKQUEUELOW
130 %token TOKVERIFYCERTS TOKEXPIRE TOKTOCACHE TOKINCACHE TOKKEY TOKNOAPOP
131131 %token LCKFLOCK LCKFCNTL LCKDOTLOCK
132132
133133 %union
186186 %type <gid> gid
187187 %type <locks> lock locklist
188188 %type <number> size time numv retrc expire
189 %type <replstrs> actions actionslist
189 %type <replstrs> actions actionslist rmheaders rmheaderslist
190190 %type <rule> perform
191191 %type <server> server
192192 %type <string> port to folder xstrv strv replstrv retre replpathv val optval
230230 /** MBOXP */
231231 mboxp: TOKMBOX
232232 | TOKMBOXES
233 /** RMHEADERP */
234 rmheaderp: TOKREMOVEHEADER
235 | TOKREMOVEHEADERS
236 /** HEADERP */
237 headerp: TOKHEADER
238 | TOKHEADERS
239 /** DOMAINP */
240 domainp: TOKDOMAIN
241 | TOKDOMAINS
233242
234243 /** VAL: <string> (char *) */
235244 val: TOKVALUE strv
703712 }
704713
705714 /** DOMAINS: <strings> (struct strings *) */
706 domains: TOKDOMAIN replstrv
715 domains: domainp replstrv
707716 /** [$2: replstrv (char *)] */
708717 {
709718 char *cp;
717726 *cp = tolower((u_char) *cp);
718727 ARRAY_ADD($$, $2);
719728 }
720 | TOKDOMAINS '{' domainslist '}'
729 | domainp '{' domainslist '}'
721730 /** [$3: domainslist (struct strings *)] */
722731 {
723732 $$ = weed_strings($3);
753762 }
754763
755764 /** HEADERS: <strings> (struct strings *) */
756 headers: TOKHEADER replstrv
765 headers: headerp replstrv
757766 /** [$2: replstrv (char *)] */
758767 {
759768 char *cp;
767776 *cp = tolower((u_char) *cp);
768777 ARRAY_ADD($$, $2);
769778 }
770 | TOKHEADERS '{' headerslist '}'
779 | headerp '{' headerslist '}'
771780 /** [$3: headerslist (struct strings *)] */
772781 {
773782 $$ = weed_strings($3);
800809 for (cp = $1; *cp != '\0'; cp++)
801810 *cp = tolower((u_char) *cp);
802811 ARRAY_ADD($$, $1);
812 }
813
814 /** RMHEADERS: <replstrs> (struct replstrs *) */
815 rmheaders: rmheaderp strv
816 /** [$2: strv (char *)] */
817 {
818 if (*$2 == '\0')
819 yyerror("invalid header");
820
821 $$ = xmalloc(sizeof *$$);
822 ARRAY_INIT($$);
823 ARRAY_EXPAND($$, 1);
824 ARRAY_LAST($$).str = $2;
825 }
826 | rmheaderp '{' rmheaderslist '}'
827 /** [$3: rmheaderslist (struct replstrs *)] */
828 {
829 $$ = $3;
830 }
831
832 /** RMHEADERSLIST: <replstrs> (struct replstrs *) */
833 rmheaderslist: rmheaderslist strv
834 /** [$1: rmheaderslist (struct replstrs *)] [$2: strv (char *)] */
835 {
836 if (*$2 == '\0')
837 yyerror("invalid header");
838
839 $$ = $1;
840 ARRAY_EXPAND($$, 1);
841 ARRAY_LAST($$).str = $2;
842 }
843 | replstrv
844 /** [$1: replstrv (char *)] */
845 {
846 if (*$1 == '\0')
847 yyerror("invalid header");
848
849 $$ = xmalloc(sizeof *$$);
850 ARRAY_INIT($$);
851 ARRAY_EXPAND($$, 1);
852 ARRAY_LAST($$).str = $1;
803853 }
804854
805855 /** PATHSLIST: <strings> (struct strings *) */
11711221
11721222 data->path.str = $2;
11731223 }
1174 | TOKREMOVEHEADER strv
1175 /** [$2: strv (char *)] */
1224 | rmheaders
1225 /** [$1: rmheaders (struct replstrs *)] */
11761226 {
11771227 struct deliver_remove_header_data *data;
1178 char *cp;
1179
1180 if (*$2 == '\0')
1181 yyerror("invalid header");
11821228
11831229 $$ = xcalloc(1, sizeof *$$);
11841230 $$->deliver = &deliver_remove_header;
11861232 data = xcalloc(1, sizeof *data);
11871233 $$->data = data;
11881234
1189 for (cp = $2; *cp != '\0'; cp++)
1190 *cp = tolower((u_char) *cp);
1191 data->hdr.str = $2;
1235 data->hdrs = $1;
11921236 }
11931237 | TOKADDHEADER strv val
11941238 /** [$2: strv (char *)] [$3: val (char *)] */
22312275 /** FETCHTYPE: <fetch> (struct { ... } fetch) */
22322276 fetchtype: poptype server userpassnetrc apop verify
22332277 /** [$1: poptype (int)] [$2: server (struct { ... } server)] */
2234 /** [$3: userpassnetrc (struct { ... } userpass)] [$4: verify (int)] */
2235 /** [$5: apop (int)] */
2278 /** [$3: userpassnetrc (struct { ... } userpass)] [$4: apop (int)] */
2279 /** [$5: verify (int)] */
22362280 {
22372281 struct fetch_pop3_data *data;
22382282
0 #!/bin/sh
1 # $Id$
2
3 . ./test-deliver.subr && test_init
4
5 cat <<EOF|test_in
6 Header: Test
7 Header2: Test
8 Header: Test
9
10 EOF
11
12 cat <<EOF|test_out
13
14 EOF
15
16 cat <<EOF|test_run
17 match all action remove-headers { "Header" "Header2" } continue
18 EOF