wip - see failed-summary.log.list_match_value. Pretty much ok.
[exim.git] / src / src / filter.c
CommitLineData
059ec3d9
PH
1/*************************************************
2* Exim - an Internet mail transport agent *
3*************************************************/
4
f9ba5e22 5/* Copyright (c) University of Cambridge 1995 - 2018 */
1e1ddfac 6/* Copyright (c) The Exim Maintainers 2020 */
059ec3d9
PH
7/* See the file NOTICE for conditions of use and distribution. */
8
9
10/* Code for mail filtering functions. */
11
12#include "exim.h"
13
14
15/* Command arguments and left/right points in conditions can contain different
16types of data, depending on the particular command or condition. Originally,
17(void *) was used as "any old type", with casts, but this gives trouble and
18warnings in some environments. So now it is done "properly", with a union. We
19need to declare the structures first because some of them are recursive. */
20
21struct filter_cmd;
22struct condition_block;
23
24union argtypes {
25 struct string_item *a;
26 BOOL b;
27 struct condition_block *c;
28 struct filter_cmd *f;
29 int i;
30 uschar *u;
31};
32
33/* Local structures used in this module */
34
35typedef struct filter_cmd {
36 struct filter_cmd *next;
37 int command;
38 BOOL seen;
39 BOOL noerror;
40 union argtypes args[1];
41} filter_cmd;
42
43typedef struct condition_block {
44 struct condition_block *parent;
45 int type;
46 BOOL testfor;
47 union argtypes left;
48 union argtypes right;
49} condition_block;
50
51/* Miscellaneous other declarations */
52
53static uschar **error_pointer;
54static uschar *log_filename;
55static int filter_options;
56static int line_number;
57static int expect_endif;
58static int had_else_endif;
59static int log_fd;
60static int log_mode;
61static int output_indent;
62static BOOL filter_delivered;
63static BOOL finish_obeyed;
64static BOOL seen_force;
65static BOOL seen_value;
66static BOOL noerror_force;
67
68enum { had_neither, had_else, had_elif, had_endif };
69
70static BOOL read_command_list(uschar **, filter_cmd ***, BOOL);
71
72
73/* The string arguments for the mail command. The header line ones (that are
74permitted to include \n followed by white space) first, and then the body text
75one (it can have \n anywhere). Then the file names and once_repeat, which may
76not contain \n. */
77
1ba28e2b
PP
78static const char *mailargs[] = { /* "to" must be first, and */
79 "to", /* "cc" and "bcc" must follow */
059ec3d9
PH
80 "cc",
81 "bcc",
82 "from",
83 "reply_to",
84 "subject",
85 "extra_headers", /* miscellaneous added header lines */
86 "text",
87 "file",
88 "log",
89 "once",
90 "once_repeat"
91};
92
93/* The count of string arguments */
94
5903c6ff 95#define MAILARGS_STRING_COUNT (nelem(mailargs))
059ec3d9
PH
96
97/* The count of string arguments that are actually passed over as strings
98(once_repeat is converted to an int). */
99
100#define mailargs_string_passed (MAILARGS_STRING_COUNT - 1)
101
102/* This defines the offsets for the arguments; first the string ones, and
103then the non-string ones. The order must be as above. */
104
105enum { mailarg_index_to,
106 mailarg_index_cc,
107 mailarg_index_bcc,
108 mailarg_index_from,
109 mailarg_index_reply_to,
110 mailarg_index_subject,
111 mailarg_index_headers, /* misc headers must be last */
112 mailarg_index_text, /* text is first after headers */
113 mailarg_index_file, /* between text and expand are filenames */
114 mailarg_index_log,
115 mailarg_index_once,
116 mailarg_index_once_repeat, /* a time string */
117 mailarg_index_expand, /* first non-string argument */
118 mailarg_index_return,
119 mailargs_total /* total number of arguments */
120 };
121
122/* Offsets in the data structure for the string arguments (note that
123once_repeat isn't a string argument at this point.) */
124
125static int reply_offsets[] = { /* must be in same order as above */
126 offsetof(reply_item, to),
127 offsetof(reply_item, cc),
128 offsetof(reply_item, bcc),
129 offsetof(reply_item, from),
130 offsetof(reply_item, reply_to),
131 offsetof(reply_item, subject),
132 offsetof(reply_item, headers),
133 offsetof(reply_item, text),
134 offsetof(reply_item, file),
135 offsetof(reply_item, logfile),
136 offsetof(reply_item, oncelog),
137};
138
139/* Condition identities and names, with negated versions for some
140of them. */
141
142enum { cond_and, cond_or, cond_personal, cond_begins, cond_BEGINS,
143 cond_ends, cond_ENDS, cond_is, cond_IS, cond_matches,
144 cond_MATCHES, cond_contains, cond_CONTAINS, cond_delivered,
145 cond_above, cond_below, cond_errormsg, cond_firsttime,
146 cond_manualthaw, cond_foranyaddress };
147
1ba28e2b 148static const char *cond_names[] = {
059ec3d9
PH
149 "and", "or", "personal",
150 "begins", "BEGINS", "ends", "ENDS",
151 "is", "IS", "matches", "MATCHES", "contains",
152 "CONTAINS", "delivered", "above", "below", "error_message",
153 "first_delivery", "manually_thawed", "foranyaddress" };
154
1ba28e2b 155static const char *cond_not_names[] = {
059ec3d9
PH
156 "", "", "not personal",
157 "does not begin", "does not BEGIN",
158 "does not end", "does not END",
159 "is not", "IS not", "does not match",
160 "does not MATCH", "does not contain", "does not CONTAIN",
161 "not delivered", "not above", "not below", "not error_message",
162 "not first_delivery", "not manually_thawed", "not foranyaddress" };
163
164/* Tables of binary condition words and their corresponding types. Not easy
165to amalgamate with the above because of the different variants. */
166
1ba28e2b 167static const char *cond_words[] = {
059ec3d9
PH
168 "BEGIN",
169 "BEGINS",
170 "CONTAIN",
171 "CONTAINS",
172 "END",
173 "ENDS",
174 "IS",
175 "MATCH",
176 "MATCHES",
177 "above",
178 "begin",
179 "begins",
180 "below",
181 "contain",
182 "contains",
183 "end",
184 "ends",
185 "is",
186 "match",
187 "matches"};
188
5903c6ff 189static int cond_word_count = nelem(cond_words);
059ec3d9
PH
190
191static int cond_types[] = { cond_BEGINS, cond_BEGINS, cond_CONTAINS,
192 cond_CONTAINS, cond_ENDS, cond_ENDS, cond_IS, cond_MATCHES, cond_MATCHES,
193 cond_above, cond_begins, cond_begins, cond_below, cond_contains,
194 cond_contains, cond_ends, cond_ends, cond_is, cond_matches, cond_matches };
195
196/* Command identities: must be kept in step with the list of command words
197and the list of expanded argument counts which follow. */
198
199enum { add_command, defer_command, deliver_command, elif_command, else_command,
200 endif_command, finish_command, fail_command, freeze_command,
201 headers_command, if_command, logfile_command, logwrite_command,
202 mail_command, noerror_command, pipe_command, save_command, seen_command,
203 testprint_command, unseen_command, vacation_command };
204
1ba28e2b 205static const char *command_list[] = {
059ec3d9
PH
206 "add", "defer", "deliver", "elif", "else", "endif", "finish",
207 "fail", "freeze", "headers", "if", "logfile", "logwrite", "mail",
208 "noerror", "pipe", "save", "seen", "testprint", "unseen", "vacation"
209};
210
5903c6ff 211static int command_list_count = nelem(command_list);
059ec3d9
PH
212
213/* This table contains the number of expanded arguments in the bottom 4 bits.
214If the top bit is set, it means that the default for the command is "seen". */
215
216static uschar command_exparg_count[] = {
217 2, /* add */
218 1, /* defer */
219 128+2, /* deliver */
220 0, /* elif */
221 0, /* else */
222 0, /* endif */
223 0, /* finish */
224 1, /* fail */
225 1, /* freeze */
226 1, /* headers */
227 0, /* if */
228 1, /* logfile */
229 1, /* logwrite */
230 MAILARGS_STRING_COUNT, /* mail */
231 0, /* noerror */
232 128+0, /* pipe */
233 128+1, /* save */
234 0, /* seen */
235 1, /* testprint */
236 0, /* unseen */
237 MAILARGS_STRING_COUNT /* vacation */
238};
239
240
241
242/*************************************************
243* Find next significant uschar *
244*************************************************/
245
246/* Function to skip over white space and, optionally, comments.
247
248Arguments:
249 ptr pointer to next character
250 comment_allowed if TRUE, comments (# to \n) are skipped
251
252Returns: pointer to next non-whitespace character
253*/
254
255static uschar *
256nextsigchar(uschar *ptr, BOOL comment_allowed)
257{
258for (;;)
259 {
260 while (isspace(*ptr))
261 {
262 if (*ptr == '\n') line_number++;
263 ptr++;
264 }
265 if (comment_allowed && *ptr == '#')
266 {
267 while (*(++ptr) != '\n' && *ptr != 0);
268 continue;
269 }
270 else break;
271 }
272return ptr;
273}
274
275
276
277/*************************************************
278* Read one word *
279*************************************************/
280
281/* The terminator is white space unless bracket is TRUE, in which
282case ( and ) terminate.
283
284Arguments
285 ptr pointer to next character
286 buffer where to put the word
287 size size of buffer
288 bracket if TRUE, terminate on ( and ) as well as space
289
290Returns: pointer to the next significant character after the word
291*/
292
293static uschar *
294nextword(uschar *ptr, uschar *buffer, int size, BOOL bracket)
295{
296uschar *bp = buffer;
297while (*ptr != 0 && !isspace(*ptr) &&
298 (!bracket || (*ptr != '(' && *ptr != ')')))
299 {
300 if (bp - buffer < size - 1) *bp++ = *ptr++; else
301 {
302 *error_pointer = string_sprintf("word is too long in line %d of "
303 "filter file (max = %d chars)", line_number, size);
304 break;
305 }
306 }
307*bp = 0;
308return nextsigchar(ptr, TRUE);
309}
310
311
312
313/*************************************************
314* Read one item *
315*************************************************/
316
317/* Might be a word, or might be a quoted string; in the latter case
318do the escape stuff.
319
320Arguments:
321 ptr pointer to next character
322 buffer where to put the item
323 size size of buffer
324 bracket if TRUE, terminate non-quoted on ( and ) as well as space
325
326Returns: the next significant character after the item
327*/
328
329static uschar *
330nextitem(uschar *ptr, uschar *buffer, int size, BOOL bracket)
331{
332uschar *bp = buffer;
333if (*ptr != '\"') return nextword(ptr, buffer, size, bracket);
334
335while (*(++ptr) != 0 && *ptr != '\"' && *ptr != '\n')
336 {
337 if (bp - buffer >= size - 1)
338 {
339 *error_pointer = string_sprintf("string is too long in line %d of "
340 "filter file (max = %d chars)", line_number, size);
341 break;
342 }
343
344 if (*ptr != '\\') *bp++ = *ptr; else
345 {
346 if (isspace(ptr[1])) /* \<whitespace>NL<whitespace> ignored */
347 {
348 uschar *p = ptr + 1;
349 while (*p != '\n' && isspace(*p)) p++;
350 if (*p == '\n')
351 {
352 line_number++;
353 ptr = p;
354 while (ptr[1] != '\n' && isspace(ptr[1])) ptr++;
355 continue;
356 }
357 }
358
55414b25 359 *bp++ = string_interpret_escape(CUSS &ptr);
059ec3d9
PH
360 }
361 }
362
363if (*ptr == '\"') ptr++;
364 else if (*error_pointer == NULL)
365 *error_pointer = string_sprintf("quote missing at end of string "
366 "in line %d", line_number);
367
368*bp = 0;
369return nextsigchar(ptr, TRUE);
370}
371
372
373
374
375/*************************************************
376* Convert a string + K|M to a number *
377*************************************************/
378
379/*
380Arguments:
381 s points to text string
382 OK set TRUE if a valid number was read
383
384Returns: the number, or 0 on error (with *OK FALSE)
385*/
386
387static int
388get_number(uschar *s, BOOL *ok)
389{
390int value, count;
391*ok = FALSE;
392if (sscanf(CS s, "%i%n", &value, &count) != 1) return 0;
393if (tolower(s[count]) == 'k') { value *= 1024; count++; }
394if (tolower(s[count]) == 'm') { value *= 1024*1024; count++; }
395while (isspace((s[count]))) count++;
396if (s[count] != 0) return 0;
397*ok = TRUE;
398return value;
399}
400
401
402
403/*************************************************
404* Read one condition *
405*************************************************/
406
407/* A complete condition must be terminated by "then"; bracketed internal
408conditions must be terminated by a closing bracket. They are read by calling
409this function recursively.
410
411Arguments:
412 ptr points to start of condition
413 condition_block where to hang the created condition block
414 toplevel TRUE when called at the top level
415
416Returns: points to next character after "then"
417*/
418
419static uschar *
420read_condition(uschar *ptr, condition_block **cond, BOOL toplevel)
421{
422uschar buffer[1024];
423BOOL testfor = TRUE;
424condition_block *current_parent = NULL;
425condition_block **current = cond;
426
427*current = NULL;
428
429/* Loop to read next condition */
430
431for (;;)
432 {
433 condition_block *c;
434
435 /* reaching the end of the input is an error. */
436
437 if (*ptr == 0)
438 {
f3ebb786 439 *error_pointer = US"\"then\" missing at end of filter file";
059ec3d9
PH
440 break;
441 }
442
443 /* Opening bracket at the start of a condition introduces a nested
444 condition, which must be terminated by a closing bracket. */
445
446 if (*ptr == '(')
447 {
448 ptr = read_condition(nextsigchar(ptr+1, TRUE), &c, FALSE);
449 if (*error_pointer != NULL) break;
450 if (*ptr != ')')
451 {
452 *error_pointer = string_sprintf("expected \")\" in line %d of "
453 "filter file", line_number);
454 break;
455 }
456 if (!testfor)
457 {
458 c->testfor = !c->testfor;
459 testfor = TRUE;
460 }
461 ptr = nextsigchar(ptr+1, TRUE);
462 }
463
464
465 /* Closing bracket at the start of a condition is an error. Give an
466 explicit message, as otherwise "unknown condition" would be confusing. */
467
468 else if (*ptr == ')')
469 {
470 *error_pointer = string_sprintf("unexpected \")\" in line %d of "
471 "filter file", line_number);
472 break;
473 }
474
475 /* Otherwise we expect a word or a string. */
476
477 else
478 {
479 ptr = nextitem(ptr, buffer, sizeof(buffer), TRUE);
480 if (*error_pointer != NULL) break;
481
482 /* "Then" at the start of a condition is an error */
483
484 if (Ustrcmp(buffer, "then") == 0)
485 {
486 *error_pointer = string_sprintf("unexpected \"then\" near line %d of "
487 "filter file", line_number);
488 break;
489 }
490
491 /* "Not" at the start of a condition negates the testing condition. */
492
493 if (Ustrcmp(buffer, "not") == 0)
494 {
495 testfor = !testfor;
496 continue;
497 }
498
499 /* Build a condition block from the specific word. */
500
f3ebb786 501 c = store_get(sizeof(condition_block), FALSE);
059ec3d9
PH
502 c->left.u = c->right.u = NULL;
503 c->testfor = testfor;
504 testfor = TRUE;
505
506 /* Check for conditions that start with a keyword */
507
508 if (Ustrcmp(buffer, "delivered") == 0) c->type = cond_delivered;
509 else if (Ustrcmp(buffer, "error_message") == 0) c->type = cond_errormsg;
510 else if (Ustrcmp(buffer, "first_delivery") == 0) c->type = cond_firsttime;
511 else if (Ustrcmp(buffer, "manually_thawed") == 0) c->type = cond_manualthaw;
512
513 /* Personal can be followed by any number of aliases */
514
515 else if (Ustrcmp(buffer, "personal") == 0)
516 {
517 c->type = cond_personal;
518 for (;;)
519 {
520 string_item *aa;
521 uschar *saveptr = ptr;
522 ptr = nextword(ptr, buffer, sizeof(buffer), TRUE);
4dc2379a 523 if (*error_pointer) break;
059ec3d9
PH
524 if (Ustrcmp(buffer, "alias") != 0)
525 {
526 ptr = saveptr;
527 break;
528 }
529 ptr = nextitem(ptr, buffer, sizeof(buffer), TRUE);
4dc2379a 530 if (*error_pointer) break;
f3ebb786 531 aa = store_get(sizeof(string_item), FALSE);
059ec3d9
PH
532 aa->text = string_copy(buffer);
533 aa->next = c->left.a;
534 c->left.a = aa;
535 }
536 }
537
538 /* Foranyaddress must be followed by a string and a condition enclosed
539 in parentheses, which is handled as a subcondition. */
540
541 else if (Ustrcmp(buffer, "foranyaddress") == 0)
542 {
543 ptr = nextitem(ptr, buffer, sizeof(buffer), TRUE);
4dc2379a 544 if (*error_pointer) break;
059ec3d9
PH
545 if (*ptr != '(')
546 {
547 *error_pointer = string_sprintf("\"(\" expected after \"foranyaddress\" "
548 "near line %d of filter file", line_number);
549 break;
550 }
551
552 c->type = cond_foranyaddress;
553 c->left.u = string_copy(buffer);
554
555 ptr = read_condition(nextsigchar(ptr+1, TRUE), &(c->right.c), FALSE);
4dc2379a 556 if (*error_pointer) break;
059ec3d9
PH
557 if (*ptr != ')')
558 {
559 *error_pointer = string_sprintf("expected \")\" in line %d of "
560 "filter file", line_number);
561 break;
562 }
059ec3d9
PH
563 ptr = nextsigchar(ptr+1, TRUE);
564 }
565
566 /* If it's not a word we recognize, then it must be the lefthand
567 operand of one of the comparison words. */
568
569 else
570 {
571 int i;
572 uschar *isptr = NULL;
573
574 c->left.u = string_copy(buffer);
575 ptr = nextword(ptr, buffer, sizeof(buffer), TRUE);
4dc2379a 576 if (*error_pointer) break;
059ec3d9
PH
577
578 /* Handle "does|is [not]", preserving the pointer after "is" in
579 case it isn't that, but the form "is <string>". */
580
581 if (strcmpic(buffer, US"does") == 0 || strcmpic(buffer, US"is") == 0)
582 {
583 if (buffer[0] == 'i') { c->type = cond_is; isptr = ptr; }
584 if (buffer[0] == 'I') { c->type = cond_IS; isptr = ptr; }
585
586 ptr = nextword(ptr, buffer, sizeof(buffer), TRUE);
4dc2379a 587 if (*error_pointer) break;
059ec3d9
PH
588 if (strcmpic(buffer, US"not") == 0)
589 {
590 c->testfor = !c->testfor;
4dc2379a 591 if (isptr) isptr = ptr;
059ec3d9 592 ptr = nextword(ptr, buffer, sizeof(buffer), TRUE);
4dc2379a 593 if (*error_pointer) break;
059ec3d9
PH
594 }
595 }
596
597 for (i = 0; i < cond_word_count; i++)
598 {
599 if (Ustrcmp(buffer, cond_words[i]) == 0)
600 {
601 c->type = cond_types[i];
602 break;
603 }
604 }
605
606 /* If an unknown word follows "is" or "is not"
607 it's actually the argument. Reset to read it. */
608
609 if (i >= cond_word_count)
610 {
4dc2379a 611 if (!isptr)
059ec3d9
PH
612 {
613 *error_pointer = string_sprintf("unrecognized condition word \"%s\" "
614 "near line %d of filter file", buffer, line_number);
615 break;
616 }
4dc2379a 617 ptr = isptr;
059ec3d9
PH
618 }
619
620 /* Get the RH argument. */
621
622 ptr = nextitem(ptr, buffer, sizeof(buffer), TRUE);
4dc2379a 623 if (*error_pointer) break;
059ec3d9
PH
624 c->right.u = string_copy(buffer);
625 }
626 }
627
628 /* We have read some new condition and set it up in the condition block
629 c; point the current pointer at it, and then deal with what follows. */
630
631 *current = c;
632
633 /* Closing bracket terminates if this is a lower-level condition. Otherwise
634 it is unexpected. */
635
636 if (*ptr == ')')
637 {
638 if (toplevel)
639 *error_pointer = string_sprintf("unexpected \")\" in line %d of "
640 "filter file", line_number);
641 break;
642 }
643
644 /* Opening bracket following a condition is an error; give an explicit
645 message to make it clearer what is wrong. */
646
647 else if (*ptr == '(')
648 {
649 *error_pointer = string_sprintf("unexpected \"(\" in line %d of "
650 "filter file", line_number);
651 break;
652 }
653
654 /* Otherwise the next thing must be one of the words "and", "or" or "then" */
655
656 else
657 {
658 uschar *saveptr = ptr;
659 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
4dc2379a 660 if (*error_pointer) break;
059ec3d9
PH
661
662 /* "Then" terminates a toplevel condition; otherwise a closing bracket
663 has been omitted. Put a string terminator at the start of "then" so
664 that reflecting the condition can be done when testing. */
665
666 if (Ustrcmp(buffer, "then") == 0)
667 {
668 if (toplevel) *saveptr = 0;
4dc2379a 669 else *error_pointer = string_sprintf("missing \")\" at end of "
059ec3d9
PH
670 "condition near line %d of filter file", line_number);
671 break;
672 }
673
674 /* "And" causes a new condition block to replace the one we have
675 just read, which becomes the left sub-condition. The current pointer
676 is reset to the pointer for the right sub-condition. We have to keep
677 track of the tree of sequential "ands", so as to traverse back up it
678 if an "or" is met. */
679
680 else if (Ustrcmp(buffer, "and") == 0)
681 {
f3ebb786 682 condition_block *andc = store_get(sizeof(condition_block), FALSE);
059ec3d9
PH
683 andc->parent = current_parent;
684 andc->type = cond_and;
685 andc->testfor = TRUE;
686 andc->left.c = c;
687 andc->right.u = NULL; /* insurance */
688 *current = andc;
689 current = &(andc->right.c);
690 current_parent = andc;
691 }
692
693 /* "Or" is similar, but has to be done a bit more carefully to
694 ensure that "and" is more binding. If there's a parent set, we
695 are following a sequence of "and"s and must track back to their
696 start. */
697
698 else if (Ustrcmp(buffer, "or") == 0)
699 {
f3ebb786 700 condition_block *orc = store_get(sizeof(condition_block), FALSE);
059ec3d9
PH
701 condition_block *or_parent = NULL;
702
4dc2379a 703 if (current_parent)
059ec3d9 704 {
4dc2379a 705 while (current_parent->parent &&
059ec3d9
PH
706 current_parent->parent->type == cond_and)
707 current_parent = current_parent->parent;
708
709 /* If the parent has a parent, it must be an "or" parent. */
710
4dc2379a 711 if (current_parent->parent)
059ec3d9
PH
712 or_parent = current_parent->parent;
713 }
714
715 orc->parent = or_parent;
4dc2379a
JH
716 if (!or_parent) *cond = orc;
717 else or_parent->right.c = orc;
059ec3d9
PH
718 orc->type = cond_or;
719 orc->testfor = TRUE;
720 orc->left.c = (current_parent == NULL)? c : current_parent;
721 orc->right.c = NULL; /* insurance */
722 current = &(orc->right.c);
723 current_parent = orc;
724 }
725
726 /* Otherwise there is a disaster */
727
728 else
729 {
730 *error_pointer = string_sprintf("\"and\" or \"or\" or \"%s\" "
731 "expected near line %d of filter file, but found \"%s\"",
732 toplevel? "then" : ")", line_number, buffer);
733 break;
734 }
735 }
736 }
737
738return nextsigchar(ptr, TRUE);
739}
740
741
742
743/*************************************************
4c04137d 744* Output the current indent *
059ec3d9
PH
745*************************************************/
746
747static void
748indent(void)
749{
750int i;
751for (i = 0; i < output_indent; i++) debug_printf(" ");
752}
753
754
755
756/*************************************************
757* Condition printer: for debugging *
758*************************************************/
759
760/*
761Arguments:
762 c the block at the top of the tree
763 toplevel TRUE at toplevel - stops overall brackets
764
765Returns: nothing
766*/
767
768static void
769print_condition(condition_block *c, BOOL toplevel)
770{
1ba28e2b 771const char *name = (c->testfor)? cond_names[c->type] : cond_not_names[c->type];
059ec3d9
PH
772switch(c->type)
773 {
774 case cond_personal:
775 case cond_delivered:
776 case cond_errormsg:
777 case cond_firsttime:
778 case cond_manualthaw:
779 debug_printf("%s", name);
780 break;
781
782 case cond_is:
783 case cond_IS:
784 case cond_matches:
785 case cond_MATCHES:
786 case cond_contains:
787 case cond_CONTAINS:
788 case cond_begins:
789 case cond_BEGINS:
790 case cond_ends:
791 case cond_ENDS:
792 case cond_above:
793 case cond_below:
1ba28e2b 794 debug_printf("%s %s %s", c->left.u, name, c->right.u);
059ec3d9
PH
795 break;
796
797 case cond_and:
798 if (!c->testfor) debug_printf("not (");
799 print_condition(c->left.c, FALSE);
800 debug_printf(" %s ", cond_names[c->type]);
801 print_condition(c->right.c, FALSE);
802 if (!c->testfor) debug_printf(")");
803 break;
804
805 case cond_or:
806 if (!c->testfor) debug_printf("not (");
807 else if (!toplevel) debug_printf("(");
808 print_condition(c->left.c, FALSE);
809 debug_printf(" %s ", cond_names[c->type]);
810 print_condition(c->right.c, FALSE);
811 if (!toplevel || !c->testfor) debug_printf(")");
812 break;
813
814 case cond_foranyaddress:
815 debug_printf("%s %s (", name, c->left.u);
816 print_condition(c->right.c, FALSE);
817 debug_printf(")");
818 break;
819 }
820}
821
822
823
824
825/*************************************************
826* Read one filtering command *
827*************************************************/
828
829/*
830Arguments:
831 pptr points to pointer to first character of command; the pointer
832 is updated to point after the last character read
833 lastcmdptr points to pointer to pointer to last command; used for hanging
834 on the newly read command
835
836Returns: TRUE if command successfully read, else FALSE
837*/
838
839static BOOL
840read_command(uschar **pptr, filter_cmd ***lastcmdptr)
841{
842int command, i, cmd_bit;
843filter_cmd *new, **newlastcmdptr;
844BOOL yield = TRUE;
845BOOL was_seen_or_unseen = FALSE;
846BOOL was_noerror = FALSE;
847uschar buffer[1024];
848uschar *ptr = *pptr;
849uschar *saveptr;
850uschar *fmsg = NULL;
851
852/* Read the next word and find which command it is. Command words are normally
853terminated by white space, but there are two exceptions, which are the "if" and
854"elif" commands. We must allow for them to be terminated by an opening bracket,
855as brackets are allowed in conditions and users will expect not to require
856white space here. */
857
858if (Ustrncmp(ptr, "if(", 3) == 0)
859 {
f3ebb786 860 Ustrcpy(buffer, US"if");
059ec3d9
PH
861 ptr += 2;
862 }
863else if (Ustrncmp(ptr, "elif(", 5) == 0)
864 {
f3ebb786 865 Ustrcpy(buffer, US"elif");
059ec3d9
PH
866 ptr += 4;
867 }
868else
869 {
870 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
871 if (*error_pointer != NULL) return FALSE;
872 }
873
874for (command = 0; command < command_list_count; command++)
875 if (Ustrcmp(buffer, command_list[command]) == 0) break;
876
877/* Handle the individual commands */
878
879switch (command)
880 {
881 /* Add takes two arguments, separated by the word "to". Headers has two
882 arguments, but the first must be "add", "remove", or "charset", and it gets
883 stored in the second argument slot. Neither may be preceded by seen, unseen
884 or noerror. */
885
886 case add_command:
887 case headers_command:
888 if (seen_force || noerror_force)
889 {
890 *error_pointer = string_sprintf("\"seen\", \"unseen\", or \"noerror\" "
891 "found before an \"%s\" command near line %d",
892 command_list[command], line_number);
893 yield = FALSE;
894 }
895 /* Fall through */
896
897 /* Logwrite, logfile, pipe, and testprint all take a single argument, save
898 and logfile can have an option second argument for the mode, and deliver can
899 have "errors_to <address>" in a system filter, or in a user filter if the
900 address is the current one. */
901
902 case deliver_command:
903 case logfile_command:
904 case logwrite_command:
905 case pipe_command:
906 case save_command:
907 case testprint_command:
908
909 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
910 if (*buffer == 0)
911 *error_pointer = string_sprintf("\"%s\" requires an argument "
912 "near line %d of filter file", command_list[command], line_number);
913
914 if (*error_pointer != NULL) yield = FALSE; else
915 {
916 union argtypes argument, second_argument;
917
918 argument.u = second_argument.u = NULL;
919
920 if (command == add_command)
921 {
922 argument.u = string_copy(buffer);
923 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
924 if (*buffer == 0 || Ustrcmp(buffer, "to") != 0)
925 *error_pointer = string_sprintf("\"to\" expected in \"add\" command "
926 "near line %d of filter file", line_number);
927 else
928 {
929 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
930 if (*buffer == 0)
931 *error_pointer = string_sprintf("value missing after \"to\" "
932 "near line %d of filter file", line_number);
933 else second_argument.u = string_copy(buffer);
934 }
935 }
936
937 else if (command == headers_command)
938 {
939 if (Ustrcmp(buffer, "add") == 0)
940 second_argument.b = TRUE;
941 else
942 if (Ustrcmp(buffer, "remove") == 0) second_argument.b = FALSE;
943 else
944 if (Ustrcmp(buffer, "charset") == 0)
945 second_argument.b = TRUE_UNSET;
946 else
947 {
948 *error_pointer = string_sprintf("\"add\", \"remove\", or \"charset\" "
949 "expected after \"headers\" near line %d of filter file",
950 line_number);
951 yield = FALSE;
952 }
953
8768d548 954 if (!f.system_filtering && second_argument.b != TRUE_UNSET)
059ec3d9
PH
955 {
956 *error_pointer = string_sprintf("header addition and removal is "
957 "available only in system filters: near line %d of filter file",
958 line_number);
959 yield = FALSE;
960 break;
961 }
962
963 if (yield)
964 {
965 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
966 if (*buffer == 0)
967 *error_pointer = string_sprintf("value missing after \"add\", "
968 "\"remove\", or \"charset\" near line %d of filter file",
969 line_number);
970 else argument.u = string_copy(buffer);
971 }
972 }
973
974 /* The argument for the logwrite command must end in a newline, and the save
975 and logfile commands can have an optional mode argument. The deliver
976 command can have an optional "errors_to <address>" for a system filter,
977 or for a user filter if the address is the user's address. Accept the
978 syntax here - the check is later. */
979
980 else
981 {
982 if (command == logwrite_command)
983 {
984 int len = Ustrlen(buffer);
f3ebb786 985 if (len == 0 || buffer[len-1] != '\n') Ustrcat(buffer, US"\n");
059ec3d9
PH
986 }
987
988 argument.u = string_copy(buffer);
989
990 if (command == save_command || command == logfile_command)
991 {
992 if (isdigit(*ptr))
993 {
994 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
995 second_argument.i = (int)Ustrtol(buffer, NULL, 8);
996 }
997 else second_argument.i = -1;
998 }
999
1000 else if (command == deliver_command)
1001 {
1002 uschar *save_ptr = ptr;
1003 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1004 if (Ustrcmp(buffer, "errors_to") == 0)
1005 {
1006 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1007 second_argument.u = string_copy(buffer);
1008 }
1009 else ptr = save_ptr;
1010 }
1011 }
1012
1013 /* Set up the command block. Seen defaults TRUE for delivery commands,
1014 FALSE for logging commands, and it doesn't matter for testprint, as
1015 that doesn't change the "delivered" status. */
1016
1017 if (*error_pointer != NULL) yield = FALSE; else
1018 {
f3ebb786 1019 new = store_get(sizeof(filter_cmd) + sizeof(union argtypes), FALSE);
059ec3d9
PH
1020 new->next = NULL;
1021 **lastcmdptr = new;
1022 *lastcmdptr = &(new->next);
1023 new->command = command;
1024 new->seen = seen_force? seen_value : command_exparg_count[command] >= 128;
1025 new->noerror = noerror_force;
1026 new->args[0] = argument;
1027 new->args[1] = second_argument;
1028 }
1029 }
1030 break;
1031
1032
1033 /* Elif, else and endif just set a flag if expected. */
1034
1035 case elif_command:
1036 case else_command:
1037 case endif_command:
41609df5
PH
1038 if (seen_force || noerror_force)
1039 {
1040 *error_pointer = string_sprintf("\"seen\", \"unseen\", or \"noerror\" "
1041 "near line %d is not followed by a command", line_number);
1042 yield = FALSE;
1043 }
1044
059ec3d9
PH
1045 if (expect_endif > 0)
1046 had_else_endif = (command == elif_command)? had_elif :
1047 (command == else_command)? had_else : had_endif;
1048 else
1049 {
1050 *error_pointer = string_sprintf("unexpected \"%s\" command near "
1051 "line %d of filter file", buffer, line_number);
1052 yield = FALSE;
1053 }
1054 break;
1055
1056
1057 /* Defer, freeze, and fail are available only if permitted. */
1058
1059 case defer_command:
1060 cmd_bit = RDO_DEFER;
1061 goto DEFER_FREEZE_FAIL;
1062
1063 case fail_command:
1064 cmd_bit = RDO_FAIL;
1065 goto DEFER_FREEZE_FAIL;
1066
1067 case freeze_command:
1068 cmd_bit = RDO_FREEZE;
1069
1070 DEFER_FREEZE_FAIL:
1071 if ((filter_options & cmd_bit) == 0)
1072 {
1073 *error_pointer = string_sprintf("filtering command \"%s\" is disabled: "
1074 "near line %d of filter file", buffer, line_number);
1075 yield = FALSE;
1076 break;
1077 }
1078
1079 /* A text message can be provided after the "text" keyword, or
1080 as a string in quotes. */
1081
1082 saveptr = ptr;
1083 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
1084 if (*saveptr != '\"' && (*buffer == 0 || Ustrcmp(buffer, "text") != 0))
1085 {
1086 ptr = saveptr;
1087 fmsg = US"";
1088 }
1089 else
1090 {
1091 if (*saveptr != '\"')
1092 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
1093 fmsg = string_copy(buffer);
1094 }
1095
1096 /* Drop through and treat as "finish", but never set "seen". */
1097
1098 seen_value = FALSE;
1099
1100 /* Finish has no arguments; fmsg defaults to NULL */
1101
1102 case finish_command:
f3ebb786 1103 new = store_get(sizeof(filter_cmd), FALSE);
059ec3d9
PH
1104 new->next = NULL;
1105 **lastcmdptr = new;
1106 *lastcmdptr = &(new->next);
1107 new->command = command;
1108 new->seen = seen_force? seen_value : FALSE;
1109 new->args[0].u = fmsg;
1110 break;
1111
1112
1113 /* Seen, unseen, and noerror are not allowed before if, which takes a
1114 condition argument and then and else sub-commands. */
1115
1116 case if_command:
1117 if (seen_force || noerror_force)
1118 {
1119 *error_pointer = string_sprintf("\"seen\", \"unseen\", or \"noerror\" "
1120 "found before an \"if\" command near line %d",
1121 line_number);
1122 yield = FALSE;
1123 }
1124
1125 /* Set up the command block for if */
1126
f3ebb786 1127 new = store_get(sizeof(filter_cmd) + 4 * sizeof(union argtypes), FALSE);
059ec3d9
PH
1128 new->next = NULL;
1129 **lastcmdptr = new;
1130 *lastcmdptr = &(new->next);
1131 new->command = command;
1132 new->seen = FALSE;
1133 new->args[0].u = NULL;
1134 new->args[1].u = new->args[2].u = NULL;
1135 new->args[3].u = ptr;
1136
1137 /* Read the condition */
1138
1139 ptr = read_condition(ptr, &(new->args[0].c), TRUE);
1140 if (*error_pointer != NULL) { yield = FALSE; break; }
1141
1142 /* Read the commands to be obeyed if the condition is true */
1143
1144 newlastcmdptr = &(new->args[1].f);
1145 if (!read_command_list(&ptr, &newlastcmdptr, TRUE)) yield = FALSE;
1146
1147 /* If commands were successfully read, handle the various possible
1148 terminators. There may be a number of successive "elif" sections. */
1149
1150 else
1151 {
1152 while (had_else_endif == had_elif)
1153 {
1154 filter_cmd *newnew =
f3ebb786 1155 store_get(sizeof(filter_cmd) + 4 * sizeof(union argtypes), FALSE);
059ec3d9
PH
1156 new->args[2].f = newnew;
1157 new = newnew;
1158 new->next = NULL;
1159 new->command = command;
1160 new->seen = FALSE;
1161 new->args[0].u = NULL;
1162 new->args[1].u = new->args[2].u = NULL;
1163 new->args[3].u = ptr;
1164
1165 ptr = read_condition(ptr, &(new->args[0].c), TRUE);
1166 if (*error_pointer != NULL) { yield = FALSE; break; }
1167 newlastcmdptr = &(new->args[1].f);
1168 if (!read_command_list(&ptr, &newlastcmdptr, TRUE))
1169 yield = FALSE;
1170 }
1171
1172 if (yield == FALSE) break;
1173
1174 /* Handle termination by "else", possibly following one or more
1175 "elsif" sections. */
1176
1177 if (had_else_endif == had_else)
1178 {
1179 newlastcmdptr = &(new->args[2].f);
1180 if (!read_command_list(&ptr, &newlastcmdptr, TRUE))
1181 yield = FALSE;
1182 else if (had_else_endif != had_endif)
1183 {
1184 *error_pointer = string_sprintf("\"endif\" missing near line %d of "
1185 "filter file", line_number);
1186 yield = FALSE;
1187 }
1188 }
1189
1190 /* Otherwise the terminator was "endif" - this is checked by
1191 read_command_list(). The pointer is already set to NULL. */
1192 }
1193
1194 /* Reset the terminator flag. */
1195
1196 had_else_endif = had_neither;
1197 break;
1198
1199
1200 /* The mail & vacation commands have a whole slew of keyworded arguments.
1201 The final argument values are the file expand and return message booleans,
1202 whose offsets are defined in mailarg_index_{expand,return}. Although they
1203 are logically booleans, because they are stored in a uschar * value, we use
1204 NULL and not FALSE, to keep 64-bit compilers happy. */
1205
1206 case mail_command:
1207 case vacation_command:
f3ebb786 1208 new = store_get(sizeof(filter_cmd) + mailargs_total * sizeof(union argtypes), FALSE);
059ec3d9
PH
1209 new->next = NULL;
1210 new->command = command;
1211 new->seen = seen_force? seen_value : FALSE;
1212 new->noerror = noerror_force;
1213 for (i = 0; i < mailargs_total; i++) new->args[i].u = NULL;
1214
1215 /* Read keyword/value pairs until we hit one that isn't. The data
1216 must contain only printing chars plus tab, though the "text" value
1217 can also contain newlines. The "file" keyword can be preceded by the
1218 word "expand", and "return message" has no data. */
1219
1220 for (;;)
1221 {
1222 uschar *saveptr = ptr;
1223 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1224 if (*error_pointer != NULL)
1225 {
1226 yield = FALSE;
1227 break;
1228 }
1229
1230 /* Ensure "return" is followed by "message"; that's a complete option */
1231
1232 if (Ustrcmp(buffer, "return") == 0)
1233 {
1234 new->args[mailarg_index_return].u = US""; /* not NULL => TRUE */
1235 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1236 if (Ustrcmp(buffer, "message") != 0)
1237 {
1238 *error_pointer = string_sprintf("\"return\" not followed by \"message\" "
1239 " near line %d of filter file", line_number);
1240 yield = FALSE;
1241 break;
1242 }
1243 continue;
1244 }
1245
1246 /* Ensure "expand" is followed by "file", then fall through to process the
1247 file keyword. */
1248
1249 if (Ustrcmp(buffer, "expand") == 0)
1250 {
1251 new->args[mailarg_index_expand].u = US""; /* not NULL => TRUE */
1252 ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1253 if (Ustrcmp(buffer, "file") != 0)
1254 {
1255 *error_pointer = string_sprintf("\"expand\" not followed by \"file\" "
1256 " near line %d of filter file", line_number);
1257 yield = FALSE;
1258 break;
1259 }
1260 }
1261
1262 /* Scan for the keyword */
1263
1264 for (i = 0; i < MAILARGS_STRING_COUNT; i++)
1265 if (Ustrcmp(buffer, mailargs[i]) == 0) break;
1266
1267 /* Not found keyword; assume end of this command */
1268
1269 if (i >= MAILARGS_STRING_COUNT)
1270 {
1271 ptr = saveptr;
1272 break;
1273 }
1274
1275 /* Found keyword, read the data item */
1276
1277 ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
1278 if (*error_pointer != NULL)
1279 {
1280 yield = FALSE;
1281 break;
1282 }
1283 else new->args[i].u = string_copy(buffer);
1284 }
1285
1286 /* If this is the vacation command, apply some default settings to
1287 some of the arguments. */
1288
1289 if (command == vacation_command)
1290 {
1291 if (new->args[mailarg_index_file].u == NULL)
1292 {
1293 new->args[mailarg_index_file].u = string_copy(US".vacation.msg");
1294 new->args[mailarg_index_expand].u = US""; /* not NULL => TRUE */
1295 }
1296 if (new->args[mailarg_index_log].u == NULL)
1297 new->args[mailarg_index_log].u = string_copy(US".vacation.log");
1298 if (new->args[mailarg_index_once].u == NULL)
1299 new->args[mailarg_index_once].u = string_copy(US".vacation");
1300 if (new->args[mailarg_index_once_repeat].u == NULL)
1301 new->args[mailarg_index_once_repeat].u = string_copy(US"7d");
1302 if (new->args[mailarg_index_subject].u == NULL)
1303 new->args[mailarg_index_subject].u = string_copy(US"On vacation");
1304 }
1305
1306 /* Join the address on to the chain of generated addresses */
1307
1308 **lastcmdptr = new;
1309 *lastcmdptr = &(new->next);
1310 break;
1311
1312
1313 /* Seen and unseen just set flags */
1314
1315 case seen_command:
1316 case unseen_command:
41609df5
PH
1317 if (*ptr == 0)
1318 {
1319 *error_pointer = string_sprintf("\"seen\" or \"unseen\" "
1320 "near line %d is not followed by a command", line_number);
1321 yield = FALSE;
1322 }
059ec3d9
PH
1323 if (seen_force)
1324 {
1325 *error_pointer = string_sprintf("\"seen\" or \"unseen\" repeated "
1326 "near line %d", line_number);
1327 yield = FALSE;
1328 }
1329 seen_value = (command == seen_command);
1330 seen_force = TRUE;
1331 was_seen_or_unseen = TRUE;
1332 break;
1333
1334
1335 /* So does noerror */
1336
1337 case noerror_command:
41609df5
PH
1338 if (*ptr == 0)
1339 {
1340 *error_pointer = string_sprintf("\"noerror\" "
1341 "near line %d is not followed by a command", line_number);
1342 yield = FALSE;
1343 }
059ec3d9
PH
1344 noerror_force = TRUE;
1345 was_noerror = TRUE;
1346 break;
1347
1348
1349 /* Oops */
1350
1351 default:
1352 *error_pointer = string_sprintf("unknown filtering command \"%s\" "
1353 "near line %d of filter file", buffer, line_number);
1354 yield = FALSE;
1355 break;
1356 }
1357
1358if (!was_seen_or_unseen && !was_noerror)
1359 {
1360 seen_force = FALSE;
1361 noerror_force = FALSE;
1362 }
1363
1364*pptr = ptr;
1365return yield;
1366}
1367
1368
1369
1370/*************************************************
1371* Read a list of commands *
1372*************************************************/
1373
4c04137d 1374/* If conditional is TRUE, the list must be terminated
059ec3d9
PH
1375by the words "else" or "endif".
1376
1377Arguments:
1378 pptr points to pointer to next character; the pointer is updated
1379 lastcmdptr points to pointer to pointer to previously-read command; used
1380 for hanging on the new command
1381 conditional TRUE if this command is the subject of a condition
1382
1383Returns: TRUE on success
1384*/
1385
1386static BOOL
1387read_command_list(uschar **pptr, filter_cmd ***lastcmdptr, BOOL conditional)
1388{
1389if (conditional) expect_endif++;
1390had_else_endif = had_neither;
1391while (**pptr != 0 && had_else_endif == had_neither)
1392 {
1393 if (!read_command(pptr, lastcmdptr)) return FALSE;
1394 *pptr = nextsigchar(*pptr, TRUE);
1395 }
1396if (conditional)
1397 {
1398 expect_endif--;
1399 if (had_else_endif == had_neither)
1400 {
1401 *error_pointer = US"\"endif\" missing at end of filter file";
1402 return FALSE;
1403 }
1404 }
1405return TRUE;
1406}
1407
1408
1409
1410
1411/*************************************************
1412* Test a condition *
1413*************************************************/
1414
1415/*
1416Arguments:
1417 c points to the condition block; c->testfor indicated whether
1418 it's a positive or negative condition
1419 toplevel TRUE if called from "if" directly; FALSE otherwise
1420
1421Returns: TRUE if the condition is met
1422*/
1423
1424static BOOL
1425test_condition(condition_block *c, BOOL toplevel)
1426{
91ecef39 1427BOOL yield = FALSE;
059ec3d9
PH
1428const pcre *re;
1429uschar *exp[2], *p, *pp;
1430const uschar *regcomp_error = NULL;
1431int regcomp_error_offset;
1432int val[2];
1433int i;
1434
1435if (c == NULL) return TRUE; /* does this ever occur? */
1436
1437switch (c->type)
1438 {
1439 case cond_and:
1440 yield = test_condition(c->left.c, FALSE) &&
1441 *error_pointer == NULL &&
1442 test_condition(c->right.c, FALSE);
1443 break;
1444
1445 case cond_or:
1446 yield = test_condition(c->left.c, FALSE) ||
1447 (*error_pointer == NULL &&
1448 test_condition(c->right.c, FALSE));
1449 break;
1450
1451 /* The personal test is meaningless in a system filter. The tests are now in
1452 a separate function (so Sieve can use them). However, an Exim filter does not
1453 scan Cc: (hence the FALSE argument). */
1454
1455 case cond_personal:
8768d548 1456 yield = f.system_filtering? FALSE : filter_personal(c->left.a, FALSE);
059ec3d9
PH
1457 break;
1458
1459 case cond_delivered:
1460 yield = filter_delivered;
1461 break;
1462
1463 /* Only TRUE if a message is actually being processed; FALSE for address
1464 testing and verification. */
1465
1466 case cond_errormsg:
1467 yield = message_id[0] != 0 &&
1468 (sender_address == NULL || sender_address[0] == 0);
1469 break;
1470
1471 /* Only FALSE if a message is actually being processed; TRUE for address
1472 and filter testing and verification. */
1473
1474 case cond_firsttime:
8768d548 1475 yield = filter_test != FTEST_NONE || message_id[0] == 0 || f.deliver_firsttime;
059ec3d9
PH
1476 break;
1477
1478 /* Only TRUE if a message is actually being processed; FALSE for address
1479 testing and verification. */
1480
1481 case cond_manualthaw:
8768d548 1482 yield = message_id[0] != 0 && f.deliver_manual_thaw;
059ec3d9
PH
1483 break;
1484
1485 /* The foranyaddress condition loops through a list of addresses */
1486
1487 case cond_foranyaddress:
1488 p = c->left.u;
1489 pp = expand_string(p);
1490 if (pp == NULL)
1491 {
1492 *error_pointer = string_sprintf("failed to expand \"%s\" in "
1493 "filter file: %s", p, expand_string_message);
1494 return FALSE;
1495 }
1496
1497 yield = FALSE;
8768d548 1498 f.parse_allow_group = TRUE; /* Allow group syntax */
059ec3d9
PH
1499
1500 while (*pp != 0)
1501 {
1502 uschar *error;
1503 int start, end, domain;
1504 int saveend;
1505
1506 p = parse_find_address_end(pp, FALSE);
1507 saveend = *p;
1508
1509 *p = 0;
1510 filter_thisaddress =
1511 parse_extract_address(pp, &error, &start, &end, &domain, FALSE);
1512 *p = saveend;
1513
5fcc791a 1514 if (filter_thisaddress)
059ec3d9 1515 {
f05da2e8 1516 if ((filter_test != FTEST_NONE && debug_selector != 0) ||
059ec3d9
PH
1517 (debug_selector & D_filter) != 0)
1518 {
1519 indent();
f3ebb786 1520 debug_printf_indent("Extracted address %s\n", filter_thisaddress);
059ec3d9
PH
1521 }
1522 yield = test_condition(c->right.c, FALSE);
1523 }
1524
1525 if (yield) break;
1526 if (saveend == 0) break;
1527 pp = p + 1;
1528 }
1529
8768d548
JH
1530 f.parse_allow_group = FALSE; /* Reset group syntax flags */
1531 f.parse_found_group = FALSE;
059ec3d9
PH
1532 break;
1533
1534 /* All other conditions have left and right values that need expanding;
1535 on error, it doesn't matter what value is returned. */
1536
1537 default:
1538 p = c->left.u;
1539 for (i = 0; i < 2; i++)
1540 {
1541 exp[i] = expand_string(p);
1542 if (exp[i] == NULL)
1543 {
1544 *error_pointer = string_sprintf("failed to expand \"%s\" in "
1545 "filter file: %s", p, expand_string_message);
1546 return FALSE;
1547 }
1548 p = c->right.u;
1549 }
1550
1551 /* Inner switch for the different cases */
1552
1553 switch(c->type)
1554 {
1555 case cond_is:
1556 yield = strcmpic(exp[0], exp[1]) == 0;
1557 break;
1558
1559 case cond_IS:
1560 yield = Ustrcmp(exp[0], exp[1]) == 0;
1561 break;
1562
1563 case cond_contains:
1564 yield = strstric(exp[0], exp[1], FALSE) != NULL;
1565 break;
1566
1567 case cond_CONTAINS:
1568 yield = Ustrstr(exp[0], exp[1]) != NULL;
1569 break;
1570
1571 case cond_begins:
1572 yield = strncmpic(exp[0], exp[1], Ustrlen(exp[1])) == 0;
1573 break;
1574
1575 case cond_BEGINS:
1576 yield = Ustrncmp(exp[0], exp[1], Ustrlen(exp[1])) == 0;
1577 break;
1578
1579 case cond_ends:
1580 case cond_ENDS:
1581 {
1582 int len = Ustrlen(exp[1]);
1583 uschar *s = exp[0] + Ustrlen(exp[0]) - len;
1584 yield = (s < exp[0])? FALSE :
1585 ((c->type == cond_ends)? strcmpic(s, exp[1]) : Ustrcmp(s, exp[1])) == 0;
1586 }
1587 break;
1588
1589 case cond_matches:
1590 case cond_MATCHES:
f05da2e8 1591 if ((filter_test != FTEST_NONE && debug_selector != 0) ||
059ec3d9
PH
1592 (debug_selector & D_filter) != 0)
1593 {
f3ebb786
JH
1594 debug_printf_indent("Match expanded arguments:\n");
1595 debug_printf_indent(" Subject = %s\n", exp[0]);
1596 debug_printf_indent(" Pattern = %s\n", exp[1]);
059ec3d9
PH
1597 }
1598
3d2e82c5 1599 if (!(re = pcre_compile(CS exp[1],
059ec3d9 1600 PCRE_COPT | ((c->type == cond_matches)? PCRE_CASELESS : 0),
3d2e82c5 1601 CCSS &regcomp_error, &regcomp_error_offset, NULL)))
059ec3d9
PH
1602 {
1603 *error_pointer = string_sprintf("error while compiling "
1604 "regular expression \"%s\": %s at offset %d",
1605 exp[1], regcomp_error, regcomp_error_offset);
1606 return FALSE;
1607 }
1608
1609 yield = regex_match_and_setup(re, exp[0], PCRE_EOPT, -1);
1610 break;
1611
1612 /* For above and below, convert the strings to numbers */
1613
1614 case cond_above:
1615 case cond_below:
1616 for (i = 0; i < 2; i++)
1617 {
1618 val[i] = get_number(exp[i], &yield);
1619 if (!yield)
1620 {
1621 *error_pointer = string_sprintf("malformed numerical string \"%s\"",
1622 exp[i]);
1623 return FALSE;
1624 }
1625 }
1626 yield = (c->type == cond_above)? (val[0] > val[1]) : (val[0] < val[1]);
1627 break;
1628 }
1629 break;
1630 }
1631
f05da2e8 1632if ((filter_test != FTEST_NONE && debug_selector != 0) ||
059ec3d9
PH
1633 (debug_selector & D_filter) != 0)
1634 {
1635 indent();
f3ebb786 1636 debug_printf_indent("%sondition is %s: ",
059ec3d9
PH
1637 toplevel? "C" : "Sub-c",
1638 (yield == c->testfor)? "true" : "false");
1639 print_condition(c, TRUE);
f3ebb786 1640 debug_printf_indent("\n");
059ec3d9
PH
1641 }
1642
1643return yield == c->testfor;
1644}
1645
1646
1647
1648/*************************************************
1649* Interpret chain of commands *
1650*************************************************/
1651
1652/* In testing state, just say what would be done rather than doing it. The
1653testprint command just expands and outputs its argument in testing state, and
1654does nothing otherwise.
1655
1656Arguments:
1657 commands points to chain of commands to interpret
1658 generated where to hang newly-generated addresses
1659
1660Returns: FF_DELIVERED success, a significant action was taken
1661 FF_NOTDELIVERED success, no significant action
1662 FF_DEFER defer requested
1663 FF_FAIL fail requested
1664 FF_FREEZE freeze requested
1665 FF_ERROR there was a problem
1666*/
1667
1668static int
1669interpret_commands(filter_cmd *commands, address_item **generated)
1670{
1671uschar *s;
1672int mode;
1673address_item *addr;
1674BOOL condition_value;
1675
f3ebb786 1676while (commands)
059ec3d9
PH
1677 {
1678 int ff_ret;
1679 uschar *fmsg, *ff_name;
1680 uschar *expargs[MAILARGS_STRING_COUNT];
1681
1682 int i, n[2];
1683
1684 /* Expand the relevant number of arguments for the command that are
1685 not NULL. */
1686
1687 for (i = 0; i < (command_exparg_count[commands->command] & 15); i++)
1688 {
1689 uschar *ss = commands->args[i].u;
f3ebb786 1690 if (!ss)
059ec3d9 1691 expargs[i] = NULL;
059ec3d9 1692 else
f3ebb786 1693 if (!(expargs[i] = expand_string(ss)))
059ec3d9
PH
1694 {
1695 *error_pointer = string_sprintf("failed to expand \"%s\" in "
1696 "%s command: %s", ss, command_list[commands->command],
1697 expand_string_message);
1698 return FF_ERROR;
1699 }
059ec3d9
PH
1700 }
1701
1702 /* Now switch for each command, setting the "delivered" flag if any of them
1703 have "seen" set. */
1704
1705 if (commands->seen) filter_delivered = TRUE;
1706
1707 switch(commands->command)
1708 {
1709 case add_command:
f3ebb786
JH
1710 for (i = 0; i < 2; i++)
1711 {
1712 uschar *ss = expargs[i];
1713 uschar *end;
059ec3d9 1714
f3ebb786
JH
1715 if (i == 1 && (*ss++ != 'n' || ss[1] != 0))
1716 {
1717 *error_pointer = string_sprintf("unknown variable \"%s\" in \"add\" "
1718 "command", expargs[i]);
1719 return FF_ERROR;
1720 }
059ec3d9 1721
f3ebb786
JH
1722 /* Allow for "--" at the start of the value (from -$n0) for example */
1723 if (i == 0) while (ss[0] == '-' && ss[1] == '-') ss += 2;
059ec3d9 1724
f3ebb786
JH
1725 n[i] = (int)Ustrtol(ss, &end, 0);
1726 if (*end != 0)
1727 {
1728 *error_pointer = string_sprintf("malformed number \"%s\" in \"add\" "
1729 "command", ss);
1730 return FF_ERROR;
1731 }
1732 }
059ec3d9 1733
f3ebb786
JH
1734 filter_n[n[1]] += n[0];
1735 if (filter_test != FTEST_NONE) printf("Add %d to n%d\n", n[0], n[1]);
1736 break;
059ec3d9 1737
f3ebb786
JH
1738 /* A deliver command's argument must be a valid address. Its optional
1739 second argument (system filter only) must also be a valid address. */
059ec3d9
PH
1740
1741 case deliver_command:
f3ebb786
JH
1742 for (i = 0; i < 2; i++)
1743 {
1744 s = expargs[i];
1745 if (s != NULL)
1746 {
1747 int start, end, domain;
1748 uschar *error;
1749 uschar *ss = parse_extract_address(s, &error, &start, &end, &domain,
1750 FALSE);
5fcc791a
JH
1751 if (ss)
1752 expargs[i] = filter_options & RDO_REWRITE
1753 ? rewrite_address(ss, TRUE, FALSE, global_rewrite_rules,
1754 rewrite_existflags)
1755 : rewrite_address_qualify(ss, TRUE);
f3ebb786
JH
1756 else
1757 {
1758 *error_pointer = string_sprintf("malformed address \"%s\" in "
1759 "filter file: %s", s, error);
1760 return FF_ERROR;
1761 }
1762 }
1763 }
059ec3d9 1764
f3ebb786
JH
1765 /* Stick the errors address into a simple variable, as it will
1766 be referenced a few times. Check that the caller is permitted to
1767 specify it. */
059ec3d9 1768
f3ebb786 1769 s = expargs[1];
059ec3d9 1770
f3ebb786
JH
1771 if (s != NULL && !f.system_filtering)
1772 {
1773 uschar *ownaddress = expand_string(US"$local_part@$domain");
1774 if (strcmpic(ownaddress, s) != 0)
1775 {
1776 *error_pointer = US"errors_to must point to the caller's address";
1777 return FF_ERROR;
1778 }
1779 }
059ec3d9 1780
f3ebb786 1781 /* Test case: report what would happen */
059ec3d9 1782
f3ebb786
JH
1783 if (filter_test != FTEST_NONE)
1784 {
1785 indent();
1786 printf("%seliver message to: %s%s%s%s\n",
1787 (commands->seen)? "D" : "Unseen d",
1788 expargs[0],
1789 commands->noerror? " (noerror)" : "",
1790 (s != NULL)? " errors_to " : "",
1791 (s != NULL)? s : US"");
1792 }
059ec3d9 1793
f3ebb786 1794 /* Real case. */
059ec3d9 1795
f3ebb786
JH
1796 else
1797 {
1798 DEBUG(D_filter) debug_printf_indent("Filter: %sdeliver message to: %s%s%s%s\n",
1799 (commands->seen)? "" : "unseen ",
1800 expargs[0],
1801 commands->noerror? " (noerror)" : "",
1802 (s != NULL)? " errors_to " : "",
1803 (s != NULL)? s : US"");
1804
1805 /* Create the new address and add it to the chain, setting the
1806 af_ignore_error flag if necessary, and the errors address, which can be
1807 set in a system filter and to the local address in user filters. */
1808
1809 addr = deliver_make_addr(expargs[0], TRUE); /* TRUE => copy s */
1810 addr->prop.errors_address = (s == NULL)?
1811 s : string_copy(s); /* Default is NULL */
1812 if (commands->noerror) addr->prop.ignore_error = TRUE;
1813 addr->next = *generated;
1814 *generated = addr;
1815 }
1816 break;
059ec3d9
PH
1817
1818 case save_command:
f3ebb786
JH
1819 s = expargs[0];
1820 mode = commands->args[1].i;
059ec3d9 1821
f3ebb786 1822 /* Test case: report what would happen */
059ec3d9 1823
f3ebb786
JH
1824 if (filter_test != FTEST_NONE)
1825 {
1826 indent();
1827 if (mode < 0)
1828 printf("%save message to: %s%s\n", (commands->seen)?
1829 "S" : "Unseen s", s, commands->noerror? " (noerror)" : "");
1830 else
1831 printf("%save message to: %s %04o%s\n", (commands->seen)?
1832 "S" : "Unseen s", s, mode, commands->noerror? " (noerror)" : "");
1833 }
059ec3d9 1834
f3ebb786
JH
1835 /* Real case: Ensure save argument starts with / if there is a home
1836 directory to prepend. */
059ec3d9 1837
f3ebb786
JH
1838 else
1839 {
1840 if (s[0] != '/' && (filter_options & RDO_PREPEND_HOME) != 0 &&
1841 deliver_home != NULL && deliver_home[0] != 0)
1842 s = string_sprintf("%s/%s", deliver_home, s);
1843 DEBUG(D_filter) debug_printf_indent("Filter: %ssave message to: %s%s\n",
1844 (commands->seen)? "" : "unseen ", s,
1845 commands->noerror? " (noerror)" : "");
1846
1847 /* Create the new address and add it to the chain, setting the
1848 af_pfr and af_file flags, the af_ignore_error flag if necessary, and the
1849 mode value. */
1850
1851 addr = deliver_make_addr(s, TRUE); /* TRUE => copy s */
1852 setflag(addr, af_pfr);
1853 setflag(addr, af_file);
1854 if (commands->noerror) addr->prop.ignore_error = TRUE;
1855 addr->mode = mode;
1856 addr->next = *generated;
1857 *generated = addr;
1858 }
1859 break;
059ec3d9
PH
1860
1861 case pipe_command:
f3ebb786
JH
1862 s = string_copy(commands->args[0].u);
1863 if (filter_test != FTEST_NONE)
1864 {
1865 indent();
1866 printf("%sipe message to: %s%s\n", (commands->seen)?
1867 "P" : "Unseen p", s, commands->noerror? " (noerror)" : "");
1868 }
1869 else /* Ensure pipe command starts with | */
1870 {
1871 DEBUG(D_filter) debug_printf_indent("Filter: %spipe message to: %s%s\n",
1872 commands->seen ? "" : "unseen ", s,
1873 commands->noerror ? " (noerror)" : "");
1874 if (s[0] != '|') s = string_sprintf("|%s", s);
059ec3d9 1875
f3ebb786
JH
1876 /* Create the new address and add it to the chain, setting the
1877 af_ignore_error flag if necessary. Set the af_expand_pipe flag so that
1878 each command argument is expanded in the transport after the command
1879 has been split up into separate arguments. */
1880
1881 addr = deliver_make_addr(s, TRUE); /* TRUE => copy s */
1882 setflag(addr, af_pfr);
1883 setflag(addr, af_expand_pipe);
1884 if (commands->noerror) addr->prop.ignore_error = TRUE;
1885 addr->next = *generated;
1886 *generated = addr;
1887
1888 /* If there are any numeric variables in existence (e.g. after a regex
1889 condition), or if $thisaddress is set, take a copy for use in the
1890 expansion. Note that we can't pass NULL for filter_thisaddress, because
1891 NULL terminates the list. */
1892
1893 if (expand_nmax >= 0 || filter_thisaddress != NULL)
1894 {
1895 int ecount = expand_nmax >= 0 ? expand_nmax : -1;
1896 uschar **ss = store_get(sizeof(uschar *) * (ecount + 3), FALSE);
1897
1898 addr->pipe_expandn = ss;
1899 if (!filter_thisaddress) filter_thisaddress = US"";
1900 *ss++ = string_copy(filter_thisaddress);
1901 for (int i = 0; i <= expand_nmax; i++)
1902 *ss++ = string_copyn(expand_nstring[i], expand_nlength[i]);
1903 *ss = NULL;
1904 }
1905 }
1906 break;
1907
1908 /* Set up the file name and mode, and close any previously open
1909 file. */
059ec3d9
PH
1910
1911 case logfile_command:
f3ebb786
JH
1912 log_mode = commands->args[1].i;
1913 if (log_mode == -1) log_mode = 0600;
1914 if (log_fd >= 0)
1915 {
1916 (void)close(log_fd);
1917 log_fd = -1;
1918 }
1919 log_filename = expargs[0];
1920 if (filter_test != FTEST_NONE)
1921 {
1922 indent();
1923 printf("%sogfile %s\n", (commands->seen)? "Seen l" : "L", log_filename);
1924 }
1925 break;
059ec3d9
PH
1926
1927 case logwrite_command:
f3ebb786 1928 s = expargs[0];
059ec3d9 1929
f3ebb786
JH
1930 if (filter_test != FTEST_NONE)
1931 {
1932 indent();
1933 printf("%sogwrite \"%s\"\n", (commands->seen)? "Seen l" : "L",
1934 string_printing(s));
1935 }
059ec3d9 1936
f3ebb786
JH
1937 /* Attempt to write to a log file only if configured as permissible.
1938 Logging may be forcibly skipped for verifying or testing. */
059ec3d9 1939
f3ebb786
JH
1940 else if ((filter_options & RDO_LOG) != 0) /* Locked out */
1941 {
1942 DEBUG(D_filter)
1943 debug_printf_indent("filter log command aborted: euid=%ld\n",
1944 (long int)geteuid());
1945 *error_pointer = US"logwrite command forbidden";
1946 return FF_ERROR;
1947 }
1948 else if ((filter_options & RDO_REALLOG) != 0)
1949 {
1950 int len;
1951 DEBUG(D_filter) debug_printf_indent("writing filter log as euid %ld\n",
1952 (long int)geteuid());
1953 if (log_fd < 0)
1954 {
1955 if (log_filename == NULL)
1956 {
1957 *error_pointer = US"attempt to obey \"logwrite\" command "
1958 "without a previous \"logfile\"";
1959 return FF_ERROR;
1960 }
1961 log_fd = Uopen(log_filename, O_CREAT|O_APPEND|O_WRONLY, log_mode);
1962 if (log_fd < 0)
1963 {
1964 *error_pointer = string_open_failed(errno, "filter log file \"%s\"",
1965 log_filename);
1966 return FF_ERROR;
1967 }
1968 }
1969 len = Ustrlen(s);
1970 if (write(log_fd, s, len) != len)
1971 {
1972 *error_pointer = string_sprintf("write error on file \"%s\": %s",
1973 log_filename, strerror(errno));
1974 return FF_ERROR;
1975 }
1976 }
1977 else
1978 {
1979 DEBUG(D_filter) debug_printf_indent("skipping logwrite (verifying or testing)\n");
1980 }
1981 break;
059ec3d9 1982
f3ebb786
JH
1983 /* Header addition and removal is available only in the system filter. The
1984 command is rejected at parse time otherwise. However "headers charset" is
1985 always permitted. */
059ec3d9
PH
1986
1987 case headers_command:
f3ebb786
JH
1988 {
1989 int subtype = commands->args[1].i;
1990 s = expargs[0];
059ec3d9 1991
f3ebb786
JH
1992 if (filter_test != FTEST_NONE)
1993 printf("Headers %s \"%s\"\n", (subtype == TRUE)? "add" :
1994 (subtype == FALSE)? "remove" : "charset", string_printing(s));
059ec3d9 1995
f3ebb786
JH
1996 if (subtype == TRUE)
1997 {
1998 while (isspace(*s)) s++;
1999 if (s[0] != 0)
2000 {
2001 header_add(htype_other, "%s%s", s, (s[Ustrlen(s)-1] == '\n')?
2002 "" : "\n");
2003 header_last->type = header_checkname(header_last, FALSE);
2004 if (header_last->type >= 'a') header_last->type = htype_other;
2005 }
2006 }
059ec3d9 2007
f3ebb786
JH
2008 else if (subtype == FALSE)
2009 {
2010 int sep = 0;
2011 uschar *ss;
2012 const uschar *list = s;
2013 uschar buffer[128];
2014 while ((ss = string_nextinlist(&list, &sep, buffer, sizeof(buffer)))
2015 != NULL)
2016 header_remove(0, ss);
2017 }
059ec3d9 2018
f3ebb786
JH
2019 /* This setting lasts only while the filter is running; on exit, the
2020 variable is reset to the previous value. */
059ec3d9 2021
f3ebb786
JH
2022 else headers_charset = s;
2023 }
2024 break;
059ec3d9 2025
f3ebb786
JH
2026 /* Defer, freeze, and fail are available only when explicitly permitted.
2027 These commands are rejected at parse time otherwise. The message can get
2028 very long by the inclusion of message headers; truncate if it is, and also
2029 ensure printing characters so as not to mess up log files. */
059ec3d9
PH
2030
2031 case defer_command:
f3ebb786
JH
2032 ff_name = US"defer";
2033 ff_ret = FF_DEFER;
2034 goto DEFERFREEZEFAIL;
059ec3d9
PH
2035
2036 case fail_command:
f3ebb786
JH
2037 ff_name = US"fail";
2038 ff_ret = FF_FAIL;
2039 goto DEFERFREEZEFAIL;
059ec3d9
PH
2040
2041 case freeze_command:
f3ebb786
JH
2042 ff_name = US"freeze";
2043 ff_ret = FF_FREEZE;
059ec3d9 2044
f3ebb786
JH
2045 DEFERFREEZEFAIL:
2046 fmsg = expargs[0];
2047 if (Ustrlen(fmsg) > 1024) Ustrcpy(fmsg + 1000, US" ... (truncated)");
2048 fmsg = US string_printing(fmsg);
2049 *error_pointer = fmsg;
059ec3d9 2050
f3ebb786
JH
2051 if (filter_test != FTEST_NONE)
2052 {
2053 indent();
2054 printf("%c%s text \"%s\"\n", toupper(ff_name[0]), ff_name+1, fmsg);
2055 }
2056 else DEBUG(D_filter) debug_printf_indent("Filter: %s \"%s\"\n", ff_name, fmsg);
2057 return ff_ret;
059ec3d9
PH
2058
2059 case finish_command:
f3ebb786
JH
2060 if (filter_test != FTEST_NONE)
2061 {
2062 indent();
2063 printf("%sinish\n", (commands->seen)? "Seen f" : "F");
2064 }
2065 else
2066 {
2067 DEBUG(D_filter) debug_printf_indent("Filter: %sfinish\n",
2068 (commands->seen)? " Seen " : "");
2069 }
2070 finish_obeyed = TRUE;
2071 return filter_delivered? FF_DELIVERED : FF_NOTDELIVERED;
059ec3d9
PH
2072
2073 case if_command:
f3ebb786
JH
2074 {
2075 uschar *save_address = filter_thisaddress;
2076 int ok = FF_DELIVERED;
2077 condition_value = test_condition(commands->args[0].c, TRUE);
2078 if (*error_pointer != NULL) ok = FF_ERROR; else
2079 {
2080 output_indent += 2;
2081 ok = interpret_commands(commands->args[condition_value? 1:2].f,
2082 generated);
2083 output_indent -= 2;
2084 }
2085 filter_thisaddress = save_address;
2086 if (finish_obeyed || (ok != FF_DELIVERED && ok != FF_NOTDELIVERED))
2087 return ok;
2088 }
2089 break;
059ec3d9
PH
2090
2091
f3ebb786
JH
2092 /* To try to catch runaway loops, do not generate mail if the
2093 return path is unset or if a non-trusted user supplied -f <>
2094 as the return path. */
059ec3d9
PH
2095
2096 case mail_command:
2097 case vacation_command:
f3ebb786
JH
2098 if (return_path == NULL || return_path[0] == 0)
2099 {
2100 if (filter_test != FTEST_NONE)
2101 printf("%s command ignored because return_path is empty\n",
2102 command_list[commands->command]);
2103 else DEBUG(D_filter) debug_printf_indent("%s command ignored because return_path "
2104 "is empty\n", command_list[commands->command]);
2105 break;
2106 }
acec9514 2107
f3ebb786
JH
2108 /* Check the contents of the strings. The type of string can be deduced
2109 from the value of i.
acec9514 2110
f3ebb786
JH
2111 . If i is equal to mailarg_index_text it's a text string for the body,
2112 where anything goes.
acec9514 2113
f3ebb786
JH
2114 . If i is > mailarg_index_text, we are dealing with a file name, which
2115 cannot contain non-printing characters.
acec9514 2116
f3ebb786
JH
2117 . If i is less than mailarg_index_headers we are dealing with something
2118 that will go in a single message header line, where newlines must be
2119 followed by white space.
acec9514 2120
f3ebb786
JH
2121 . If i is equal to mailarg_index_headers, we have a string that contains
2122 one or more headers. Newlines that are not followed by white space must
2123 be followed by a header name.
2124 */
acec9514 2125
f3ebb786
JH
2126 for (i = 0; i < MAILARGS_STRING_COUNT; i++)
2127 {
2128 uschar *p;
2129 uschar *s = expargs[i];
acec9514 2130
f3ebb786 2131 if (s == NULL) continue;
acec9514 2132
f3ebb786 2133 if (i != mailarg_index_text) for (p = s; *p != 0; p++)
acec9514 2134 {
f3ebb786
JH
2135 int c = *p;
2136 if (i > mailarg_index_text)
acec9514 2137 {
f3ebb786
JH
2138 if (!mac_isprint(c))
2139 {
2140 *error_pointer = string_sprintf("non-printing character in \"%s\" "
2141 "in %s command", string_printing(s),
2142 command_list[commands->command]);
2143 return FF_ERROR;
2144 }
acec9514 2145 }
acec9514 2146
f3ebb786 2147 /* i < mailarg_index_text */
acec9514 2148
f3ebb786 2149 else if (c == '\n' && !isspace(p[1]))
acec9514 2150 {
f3ebb786
JH
2151 if (i < mailarg_index_headers)
2152 {
2153 *error_pointer = string_sprintf("\\n not followed by space in "
2154 "\"%.1024s\" in %s command", string_printing(s),
2155 command_list[commands->command]);
2156 return FF_ERROR;
2157 }
acec9514 2158
f3ebb786 2159 /* Check for the start of a new header line within the string */
acec9514 2160
f3ebb786 2161 else
acec9514 2162 {
f3ebb786
JH
2163 uschar *pp;
2164 for (pp = p + 1;; pp++)
acec9514 2165 {
f3ebb786
JH
2166 c = *pp;
2167 if (c == ':' && pp != p + 1) break;
2168 if (c == 0 || c == ':' || isspace(*pp))
2169 {
2170 *error_pointer = string_sprintf("\\n not followed by space or "
2171 "valid header name in \"%.1024s\" in %s command",
2172 string_printing(s), command_list[commands->command]);
2173 return FF_ERROR;
2174 }
acec9514 2175 }
f3ebb786 2176 p = pp;
acec9514 2177 }
acec9514 2178 }
f3ebb786 2179 } /* Loop to scan the string */
acec9514 2180
f3ebb786 2181 /* The string is OK */
acec9514 2182
f3ebb786 2183 commands->args[i].u = s;
acec9514 2184 }
acec9514 2185
f3ebb786 2186 /* Proceed with mail or vacation command */
acec9514 2187
f3ebb786 2188 if (filter_test != FTEST_NONE)
acec9514 2189 {
f3ebb786
JH
2190 uschar *to = commands->args[mailarg_index_to].u;
2191 indent();
2192 printf("%sail to: %s%s%s\n", (commands->seen)? "Seen m" : "M",
2193 to ? to : US"<default>",
acec9514
JH
2194 commands->command == vacation_command ? " (vacation)" : "",
2195 commands->noerror ? " (noerror)" : "");
2196 for (i = 1; i < MAILARGS_STRING_COUNT; i++)
2197 {
2198 uschar *arg = commands->args[i].u;
f3ebb786 2199 if (arg)
acec9514
JH
2200 {
2201 int len = Ustrlen(mailargs[i]);
f3ebb786
JH
2202 int indent = (debug_selector != 0)? output_indent : 0;
2203 while (len++ < 7 + indent) printf(" ");
2204 printf("%s: %s%s\n", mailargs[i], string_printing(arg),
acec9514
JH
2205 (commands->args[mailarg_index_expand].u != NULL &&
2206 Ustrcmp(mailargs[i], "file") == 0)? " (expanded)" : "");
2207 }
2208 }
f3ebb786
JH
2209 if (commands->args[mailarg_index_return].u)
2210 printf("Return original message\n");
acec9514 2211 }
f3ebb786 2212 else
acec9514 2213 {
f3ebb786
JH
2214 uschar *tt;
2215 uschar *to = commands->args[mailarg_index_to].u;
2216 gstring * log_addr = NULL;
acec9514 2217
f3ebb786
JH
2218 if (!to) to = expand_string(US"$reply_address");
2219 while (isspace(*to)) to++;
acec9514 2220
f3ebb786
JH
2221 for (tt = to; *tt != 0; tt++) /* Get rid of newlines */
2222 if (*tt == '\n') *tt = ' ';
acec9514 2223
f3ebb786 2224 DEBUG(D_filter)
acec9514 2225 {
f3ebb786
JH
2226 debug_printf_indent("Filter: %smail to: %s%s%s\n",
2227 commands->seen ? "seen " : "",
2228 to,
2229 commands->command == vacation_command ? " (vacation)" : "",
2230 commands->noerror ? " (noerror)" : "");
2231 for (i = 1; i < MAILARGS_STRING_COUNT; i++)
2232 {
2233 uschar *arg = commands->args[i].u;
2234 if (arg != NULL)
2235 {
2236 int len = Ustrlen(mailargs[i]);
2237 while (len++ < 15) debug_printf_indent(" ");
2238 debug_printf_indent("%s: %s%s\n", mailargs[i], string_printing(arg),
2239 (commands->args[mailarg_index_expand].u != NULL &&
2240 Ustrcmp(mailargs[i], "file") == 0)? " (expanded)" : "");
2241 }
2242 }
acec9514
JH
2243 }
2244
f3ebb786
JH
2245 /* Create the "address" for the autoreply. This is used only for logging,
2246 as the actual recipients are extracted from the To: line by -t. We use the
2247 same logic here to extract the working addresses (there may be more than
2248 one). Just in case there are a vast number of addresses, stop when the
2249 string gets too long. */
acec9514 2250
f3ebb786
JH
2251 tt = to;
2252 while (*tt != 0)
acec9514 2253 {
f3ebb786
JH
2254 uschar *ss = parse_find_address_end(tt, FALSE);
2255 uschar *recipient, *errmess;
2256 int start, end, domain;
2257 int temp = *ss;
acec9514 2258
f3ebb786
JH
2259 *ss = 0;
2260 recipient = parse_extract_address(tt, &errmess, &start, &end, &domain,
2261 FALSE);
2262 *ss = temp;
acec9514 2263
f3ebb786
JH
2264 /* Ignore empty addresses and errors; an error will occur later if
2265 there's something really bad. */
acec9514 2266
f3ebb786
JH
2267 if (recipient)
2268 {
2269 log_addr = string_catn(log_addr, log_addr ? US"," : US">", 1);
2270 log_addr = string_cat (log_addr, recipient);
2271 }
acec9514 2272
f3ebb786 2273 /* Check size */
acec9514 2274
f3ebb786
JH
2275 if (log_addr && log_addr->ptr > 256)
2276 {
2277 log_addr = string_catn(log_addr, US", ...", 5);
2278 break;
2279 }
2280
2281 /* Move on past this address */
2282
2283 tt = ss + (*ss ? 1 : 0);
2284 while (isspace(*tt)) tt++;
2285 }
2286
2287 if (log_addr)
2288 addr = deliver_make_addr(string_from_gstring(log_addr), FALSE);
2289 else
acec9514 2290 {
f3ebb786
JH
2291 addr = deliver_make_addr(US ">**bad-reply**", FALSE);
2292 setflag(addr, af_bad_reply);
acec9514 2293 }
acec9514 2294
f3ebb786
JH
2295 setflag(addr, af_pfr);
2296 if (commands->noerror) addr->prop.ignore_error = TRUE;
2297 addr->next = *generated;
2298 *generated = addr;
2299
2300 addr->reply = store_get(sizeof(reply_item), FALSE);
2301 addr->reply->from = NULL;
2302 addr->reply->to = string_copy(to);
2303 addr->reply->file_expand =
2304 commands->args[mailarg_index_expand].u != NULL;
2305 addr->reply->expand_forbid = expand_forbid;
2306 addr->reply->return_message =
2307 commands->args[mailarg_index_return].u != NULL;
2308 addr->reply->once_repeat = 0;
2309
2310 if (commands->args[mailarg_index_once_repeat].u != NULL)
2311 {
2312 addr->reply->once_repeat =
2313 readconf_readtime(commands->args[mailarg_index_once_repeat].u, 0,
2314 FALSE);
2315 if (addr->reply->once_repeat < 0)
2316 {
2317 *error_pointer = string_sprintf("Bad time value for \"once_repeat\" "
2318 "in mail or vacation command: %s",
2319 commands->args[mailarg_index_once_repeat].u);
2320 return FF_ERROR;
2321 }
2322 }
acec9514 2323
f3ebb786
JH
2324 /* Set up all the remaining string arguments (those other than "to") */
2325
2326 for (i = 1; i < mailargs_string_passed; i++)
2327 {
2328 uschar *ss = commands->args[i].u;
2329 *(USS((US addr->reply) + reply_offsets[i])) =
2330 ss ? string_copy(ss) : NULL;
2331 }
acec9514 2332 }
f3ebb786 2333 break;
059ec3d9
PH
2334
2335 case testprint_command:
f3ebb786
JH
2336 if (filter_test != FTEST_NONE || (debug_selector & D_filter) != 0)
2337 {
2338 const uschar *s = string_printing(expargs[0]);
2339 if (filter_test == FTEST_NONE)
2340 debug_printf_indent("Filter: testprint: %s\n", s);
2341 else
2342 printf("Testprint: %s\n", s);
2343 }
059ec3d9
PH
2344 }
2345
2346 commands = commands->next;
2347 }
2348
2349return filter_delivered? FF_DELIVERED : FF_NOTDELIVERED;
2350}
2351
2352
2353
2354/*************************************************
2355* Test for a personal message *
2356*************************************************/
2357
2358/* This function is global so that it can also be called from the code that
2359implements Sieve filters.
2360
2361Arguments:
2362 aliases a chain of aliases
2363 scan_cc TRUE if Cc: and Bcc: are to be scanned (Exim filters do not)
2364
2365Returns: TRUE if the message is deemed to be personal
2366*/
2367
2368BOOL
2369filter_personal(string_item *aliases, BOOL scan_cc)
2370{
2371uschar *self, *self_from, *self_to;
2372uschar *psself = NULL, *psself_from = NULL, *psself_to = NULL;
f3ebb786 2373rmark reset_point = store_mark();
059ec3d9
PH
2374BOOL yield;
2375header_line *h;
2376int to_count = 2;
2377int from_count = 9;
2378
4b233853
PH
2379/* If any header line in the message is a defined "List-" header field, it is
2380not a personal message. We used to check for any header line that started with
2381"List-", but this was tightened up for release 4.54. The check is now for
2382"List-Id", defined in RFC 2929, or "List-Help", "List-Subscribe", "List-
2383Unsubscribe", "List-Post", "List-Owner" or "List-Archive", all of which are
2384defined in RFC 2369. We also scan for "Auto-Submitted"; if it is found to
2385contain any value other than "no", the message is not personal (RFC 3834).
2386Previously the test was for "auto-". */
059ec3d9 2387
f3ebb786 2388for (h = header_list; h; h = h->next)
059ec3d9 2389 {
4b233853
PH
2390 if (h->type == htype_old) continue;
2391
2392 if (strncmpic(h->text, US"List-", 5) == 0)
2393 {
137ae145 2394 uschar * s = h->text + 5;
4b233853
PH
2395 if (strncmpic(s, US"Id:", 3) == 0 ||
2396 strncmpic(s, US"Help:", 5) == 0 ||
2397 strncmpic(s, US"Subscribe:", 10) == 0 ||
2398 strncmpic(s, US"Unsubscribe:", 12) == 0 ||
2399 strncmpic(s, US"Post:", 5) == 0 ||
2400 strncmpic(s, US"Owner:", 6) == 0 ||
2401 strncmpic(s, US"Archive:", 8) == 0)
2402 return FALSE;
2403 }
2404
2405 else if (strncmpic(h->text, US"Auto-submitted:", 15) == 0)
2406 {
137ae145
JH
2407 uschar * s = h->text + 15;
2408 Uskip_whitespace(&s);
4b233853
PH
2409 if (strncmpic(s, US"no", 2) != 0) return FALSE;
2410 s += 2;
137ae145
JH
2411 Uskip_whitespace(&s);
2412 if (*s) return FALSE;
4b233853 2413 }
059ec3d9
PH
2414 }
2415
2416/* Set up "my" address */
2417
2418self = string_sprintf("%s@%s", deliver_localpart, deliver_domain);
2419self_from = rewrite_one(self, rewrite_from, NULL, FALSE, US"",
2420 global_rewrite_rules);
2421self_to = rewrite_one(self, rewrite_to, NULL, FALSE, US"",
2422 global_rewrite_rules);
2423
2424
137ae145
JH
2425if (!self_from) self_from = self;
2426if (self_to) self_to = self;
059ec3d9
PH
2427
2428/* If there's a prefix or suffix set, we must include the prefixed/
2429suffixed version of the local part in the tests. */
2430
137ae145 2431if (deliver_localpart_prefix || deliver_localpart_suffix)
059ec3d9
PH
2432 {
2433 psself = string_sprintf("%s%s%s@%s",
19849de0 2434 deliver_localpart_prefix ? deliver_localpart_prefix : US"",
059ec3d9 2435 deliver_localpart,
19849de0 2436 deliver_localpart_suffix ? deliver_localpart_suffix : US"",
059ec3d9
PH
2437 deliver_domain);
2438 psself_from = rewrite_one(psself, rewrite_from, NULL, FALSE, US"",
2439 global_rewrite_rules);
2440 psself_to = rewrite_one(psself, rewrite_to, NULL, FALSE, US"",
2441 global_rewrite_rules);
2442 if (psself_from == NULL) psself_from = psself;
2443 if (psself_to == NULL) psself_to = psself;
2444 to_count += 2;
2445 from_count += 2;
2446 }
2447
2448/* Do all the necessary tests; the counts are adjusted for {pre,suf}fix */
2449
2450yield =
2451 (
2452 header_match(US"to:", TRUE, TRUE, aliases, to_count, self, self_to, psself,
2453 psself_to) ||
2454 (scan_cc &&
2455 (
2456 header_match(US"cc:", TRUE, TRUE, aliases, to_count, self, self_to,
2457 psself, psself_to)
2458 ||
2459 header_match(US"bcc:", TRUE, TRUE, aliases, to_count, self, self_to,
2460 psself, psself_to)
2461 )
2462 )
2463 ) &&
2464
2465 header_match(US"from:", TRUE, FALSE, aliases, from_count, "^server@",
2466 "^daemon@", "^root@", "^listserv@", "^majordomo@", "^.*?-request@",
2467 "^owner-[^@]+@", self, self_from, psself, psself_from) &&
2468
059ec3d9
PH
2469 header_match(US"precedence:", FALSE, FALSE, NULL, 3, "bulk","list","junk") &&
2470
2471 (sender_address == NULL || sender_address[0] != 0);
2472
2473store_reset(reset_point);
2474return yield;
2475}
2476
2477
2478
2479/*************************************************
2480* Interpret a mail filter file *
2481*************************************************/
2482
2483/*
2484Arguments:
2485 filter points to the entire file, read into store as a single string
2486 options controls whether various special things are allowed, and requests
2487 special actions
2488 generated where to hang newly-generated addresses
2489 error where to pass back an error text
2490
2491Returns: FF_DELIVERED success, a significant action was taken
2492 FF_NOTDELIVERED success, no significant action
2493 FF_DEFER defer requested
2494 FF_FAIL fail requested
2495 FF_FREEZE freeze requested
2496 FF_ERROR there was a problem
2497*/
2498
2499int
2500filter_interpret(uschar *filter, int options, address_item **generated,
2501 uschar **error)
2502{
2503int i;
2504int yield = FF_ERROR;
2505uschar *ptr = filter;
2506uschar *save_headers_charset = headers_charset;
2507filter_cmd *commands = NULL;
2508filter_cmd **lastcmdptr = &commands;
2509
2510DEBUG(D_route) debug_printf("Filter: start of processing\n");
f3ebb786 2511acl_level++;
059ec3d9
PH
2512
2513/* Initialize "not in an if command", set the global flag that is always TRUE
2514while filtering, and zero the variables. */
2515
2516expect_endif = 0;
2517output_indent = 0;
8768d548 2518f.filter_running = TRUE;
059ec3d9
PH
2519for (i = 0; i < FILTER_VARIABLE_COUNT; i++) filter_n[i] = 0;
2520
2521/* To save having to pass certain values about all the time, make them static.
2522Also initialize the line number, for error messages, and the log file
2523variables. */
2524
2525filter_options = options;
2526filter_delivered = FALSE;
2527finish_obeyed = FALSE;
2528error_pointer = error;
2529*error_pointer = NULL;
2530line_number = 1;
2531log_fd = -1;
2532log_mode = 0600;
2533log_filename = NULL;
2534
2535/* Scan filter file for syntax and build up an interpretation thereof, and
2536interpret the compiled commands, and if testing, say whether we ended up
2537delivered or not, unless something went wrong. */
2538
2539seen_force = FALSE;
2540ptr = nextsigchar(ptr, TRUE);
2541
2542if (read_command_list(&ptr, &lastcmdptr, FALSE))
2543 yield = interpret_commands(commands, generated);
2544
f05da2e8 2545if (filter_test != FTEST_NONE || (debug_selector & D_filter) != 0)
059ec3d9
PH
2546 {
2547 uschar *s = US"";
2548 switch(yield)
2549 {
2550 case FF_DEFER:
f3ebb786
JH
2551 s = US"Filtering ended by \"defer\".";
2552 break;
059ec3d9
PH
2553
2554 case FF_FREEZE:
f3ebb786
JH
2555 s = US"Filtering ended by \"freeze\".";
2556 break;
059ec3d9
PH
2557
2558 case FF_FAIL:
f3ebb786
JH
2559 s = US"Filtering ended by \"fail\".";
2560 break;
059ec3d9
PH
2561
2562 case FF_DELIVERED:
f3ebb786
JH
2563 s = US"Filtering set up at least one significant delivery "
2564 "or other action.\n"
2565 "No other deliveries will occur.";
2566 break;
059ec3d9
PH
2567
2568 case FF_NOTDELIVERED:
f3ebb786
JH
2569 s = US"Filtering did not set up a significant delivery.\n"
2570 "Normal delivery will occur.";
2571 break;
059ec3d9
PH
2572
2573 case FF_ERROR:
f3ebb786
JH
2574 s = string_sprintf("Filter error: %s", *error);
2575 break;
059ec3d9
PH
2576 }
2577
f05da2e8 2578 if (filter_test != FTEST_NONE) printf("%s\n", CS s);
f3ebb786 2579 else debug_printf_indent("%s\n", s);
059ec3d9
PH
2580 }
2581
2582/* Close the log file if it was opened, and kill off any numerical variables
2583before returning. Reset the header decoding charset. */
2584
f1e894f3 2585if (log_fd >= 0) (void)close(log_fd);
059ec3d9 2586expand_nmax = -1;
8768d548 2587f.filter_running = FALSE;
059ec3d9
PH
2588headers_charset = save_headers_charset;
2589
f3ebb786 2590acl_level--;
059ec3d9
PH
2591DEBUG(D_route) debug_printf("Filter: end of processing\n");
2592return yield;
2593}
2594
2595
2596/* End of filter.c */