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