SPDX: license tags (mostly by guesswork)
[exim.git] / src / src / filter.c
1 /*************************************************
2 *     Exim - an Internet mail transport agent    *
3 *************************************************/
4
5 /* Copyright (c) The Exim Maintainers 2020 - 2022 */
6 /* Copyright (c) University of Cambridge 1995 - 2018 */
7 /* See the file NOTICE for conditions of use and distribution. */
8 /* SPDX-License-Identifier: GPL-2.0-only */
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
17 types 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
19 warnings in some environments. So now it is done "properly", with a union. We
20 need to declare the structures first because some of them are recursive. */
21
22 struct filter_cmd;
23 struct condition_block;
24
25 union argtypes {
26   struct string_item     *a;
27   BOOL                    b;
28   struct condition_block *c;
29   struct filter_cmd      *f;
30   int                     i;
31   const uschar            *u;
32 };
33
34 /* Local structures used in this module */
35
36 typedef 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
44 typedef 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
54 static uschar **error_pointer;
55 static const uschar *log_filename;
56 static int  filter_options;
57 static int  line_number;
58 static int  expect_endif;
59 static int  had_else_endif;
60 static int  log_fd;
61 static int  log_mode;
62 static int  output_indent;
63 static BOOL filter_delivered;
64 static BOOL finish_obeyed;
65 static BOOL seen_force;
66 static BOOL seen_value;
67 static BOOL noerror_force;
68
69 enum { had_neither, had_else, had_elif, had_endif };
70
71 static BOOL read_command_list(const uschar **, filter_cmd ***, BOOL);
72
73
74 /* The string arguments for the mail command. The header line ones (that are
75 permitted to include \n followed by white space) first, and then the body text
76 one (it can have \n anywhere). Then the file names and once_repeat, which may
77 not contain \n. */
78
79 static const 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 (nelem(mailargs))
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
104 then the non-string ones. The order must be as above. */
105
106 enum { 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
124 once_repeat isn't a string argument at this point.) */
125
126 static 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
141 of them. */
142
143 enum { 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
149 static const 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
156 static const 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
166 to amalgamate with the above because of the different variants. */
167
168 static const 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
190 static int cond_word_count = nelem(cond_words);
191
192 static 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
198 and the list of expanded argument counts which follow. */
199
200 enum { 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
206 static const 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
212 static int command_list_count = nelem(command_list);
213
214 /* This table contains the number of expanded arguments in the bottom 4 bits.
215 If the top bit is set, it means that the default for the command is "seen". */
216
217 static 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
249 Arguments:
250   ptr              pointer to next character
251   comment_allowed  if TRUE, comments (# to \n) are skipped
252
253 Returns:           pointer to next non-whitespace character
254 */
255
256 static const uschar *
257 nextsigchar(const uschar *ptr, BOOL comment_allowed)
258 {
259 for (;;)
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   }
273 return ptr;
274 }
275
276
277
278 /*************************************************
279 *                Read one word                   *
280 *************************************************/
281
282 /* The terminator is white space unless bracket is TRUE, in which
283 case ( and ) terminate.
284
285 Arguments
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
291 Returns:    pointer to the next significant character after the word
292 */
293
294 static const uschar *
295 nextword(const uschar *ptr, uschar *buffer, int size, BOOL bracket)
296 {
297 uschar *bp = buffer;
298 while (*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;
309 return 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
319 do the escape stuff.
320
321 Arguments:
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
327 Returns:     the next significant character after the item
328 */
329
330 static const uschar *
331 nextitem(const uschar *ptr, uschar *buffer, int size, BOOL bracket)
332 {
333 uschar *bp = buffer;
334 if (*ptr != '\"') return nextword(ptr, buffer, size, bracket);
335
336 while (*++ptr && *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       const 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(CUSS &ptr);
361     }
362   }
363
364 if (*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;
370 return nextsigchar(ptr, TRUE);
371 }
372
373
374
375
376 /*************************************************
377 *          Convert a string + K|M to a number    *
378 *************************************************/
379
380 /*
381 Arguments:
382   s        points to text string
383   OK       set TRUE if a valid number was read
384
385 Returns:   the number, or 0 on error (with *OK FALSE)
386 */
387
388 static int
389 get_number(const uschar *s, BOOL *ok)
390 {
391 int value, count;
392 *ok = FALSE;
393 if (sscanf(CS s, "%i%n", &value, &count) != 1) return 0;
394 if (tolower(s[count]) == 'k') { value *= 1024; count++; }
395 if (tolower(s[count]) == 'm') { value *= 1024*1024; count++; }
396 while (isspace((s[count]))) count++;
397 if (s[count] != 0) return 0;
398 *ok = TRUE;
399 return value;
400 }
401
402
403
404 /*************************************************
405 *            Read one condition                  *
406 *************************************************/
407
408 /* A complete condition must be terminated by "then"; bracketed internal
409 conditions must be terminated by a closing bracket. They are read by calling
410 this function recursively.
411
412 Arguments:
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
417 Returns:          points to next character after "then"
418 */
419
420 static const uschar *
421 read_condition(const uschar *ptr, condition_block **cond, BOOL toplevel)
422 {
423 uschar buffer[1024];
424 BOOL testfor = TRUE;
425 condition_block *current_parent = NULL;
426 condition_block **current = cond;
427
428 *current = NULL;
429
430 /* Loop to read next condition */
431
432 for (;;)
433   {
434   condition_block *c;
435
436   /* reaching the end of the input is an error. */
437
438   if (!*ptr)
439     {
440     *error_pointer = US"\"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) 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), GET_UNTAINTED);
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         const uschar * saveptr = ptr;
523         ptr = nextword(ptr, buffer, sizeof(buffer), TRUE);
524         if (*error_pointer) 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) break;
532         aa = store_get(sizeof(string_item), GET_UNTAINTED);
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) 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) break;
558       if (*ptr != ')')
559         {
560         *error_pointer = string_sprintf("expected \")\" in line %d of "
561           "filter file", line_number);
562         break;
563         }
564       ptr = nextsigchar(ptr+1, TRUE);
565       }
566
567     /* If it's not a word we recognize, then it must be the lefthand
568     operand of one of the comparison words. */
569
570     else
571       {
572       int i;
573       const uschar *isptr = NULL;
574
575       c->left.u = string_copy(buffer);
576       ptr = nextword(ptr, buffer, sizeof(buffer), TRUE);
577       if (*error_pointer) break;
578
579       /* Handle "does|is [not]", preserving the pointer after "is" in
580       case it isn't that, but the form "is <string>". */
581
582       if (strcmpic(buffer, US"does") == 0 || strcmpic(buffer, US"is") == 0)
583         {
584         if (buffer[0] == 'i') { c->type = cond_is; isptr = ptr; }
585         if (buffer[0] == 'I') { c->type = cond_IS; isptr = ptr; }
586
587         ptr = nextword(ptr, buffer, sizeof(buffer), TRUE);
588         if (*error_pointer) break;
589         if (strcmpic(buffer, US"not") == 0)
590           {
591           c->testfor = !c->testfor;
592           if (isptr) isptr = ptr;
593           ptr = nextword(ptr, buffer, sizeof(buffer), TRUE);
594           if (*error_pointer) break;
595           }
596         }
597
598       for (i = 0; i < cond_word_count; i++)
599         {
600         if (Ustrcmp(buffer, cond_words[i]) == 0)
601           {
602           c->type = cond_types[i];
603           break;
604           }
605         }
606
607       /* If an unknown word follows "is" or "is not"
608       it's actually the argument. Reset to read it. */
609
610       if (i >= cond_word_count)
611         {
612         if (!isptr)
613           {
614           *error_pointer = string_sprintf("unrecognized condition word \"%s\" "
615             "near line %d of filter file", buffer, line_number);
616           break;
617           }
618         ptr = isptr;
619         }
620
621       /* Get the RH argument. */
622
623       ptr = nextitem(ptr, buffer, sizeof(buffer), TRUE);
624       if (*error_pointer) break;
625       c->right.u = string_copy(buffer);
626       }
627     }
628
629   /* We have read some new condition and set it up in the condition block
630   c; point the current pointer at it, and then deal with what follows. */
631
632   *current = c;
633
634   /* Closing bracket terminates if this is a lower-level condition. Otherwise
635   it is unexpected. */
636
637   if (*ptr == ')')
638     {
639     if (toplevel)
640       *error_pointer = string_sprintf("unexpected \")\" in line %d of "
641         "filter file", line_number);
642     break;
643     }
644
645   /* Opening bracket following a condition is an error; give an explicit
646   message to make it clearer what is wrong. */
647
648   else if (*ptr == '(')
649     {
650     *error_pointer = string_sprintf("unexpected \"(\" in line %d of "
651       "filter file", line_number);
652     break;
653     }
654
655   /* Otherwise the next thing must be one of the words "and", "or" or "then" */
656
657   else
658     {
659 //    const uschar *saveptr = ptr;
660     ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
661     if (*error_pointer) break;
662
663     /* "Then" terminates a toplevel condition; otherwise a closing bracket
664     has been omitted. Put a string terminator at the start of "then" so
665     that reflecting the condition can be done when testing. */
666     /*XXX This stops us doing a constification job in this file, unfortunately.
667     Comment it out and see if anything breaks.
668     With one addition down at DEFERFREEZEFAIL it passes the testsuite. */
669
670     if (Ustrcmp(buffer, "then") == 0)
671       {
672 //      if (toplevel) *saveptr = 0;
673 //      else
674    if (!toplevel)
675       *error_pointer = string_sprintf("missing \")\" at end of "
676           "condition near line %d of filter file", line_number);
677       break;
678       }
679
680     /* "And" causes a new condition block to replace the one we have
681     just read, which becomes the left sub-condition. The current pointer
682     is reset to the pointer for the right sub-condition. We have to keep
683     track of the tree of sequential "ands", so as to traverse back up it
684     if an "or" is met. */
685
686     else if (Ustrcmp(buffer, "and") == 0)
687       {
688       condition_block * andc = store_get(sizeof(condition_block), GET_UNTAINTED);
689       andc->parent = current_parent;
690       andc->type = cond_and;
691       andc->testfor = TRUE;
692       andc->left.c = c;
693       andc->right.u = NULL;    /* insurance */
694       *current = andc;
695       current = &(andc->right.c);
696       current_parent = andc;
697       }
698
699     /* "Or" is similar, but has to be done a bit more carefully to
700     ensure that "and" is more binding. If there's a parent set, we
701     are following a sequence of "and"s and must track back to their
702     start. */
703
704     else if (Ustrcmp(buffer, "or") == 0)
705       {
706       condition_block * orc = store_get(sizeof(condition_block), GET_UNTAINTED);
707       condition_block * or_parent = NULL;
708
709       if (current_parent)
710         {
711         while (current_parent->parent &&
712                current_parent->parent->type == cond_and)
713           current_parent = current_parent->parent;
714
715         /* If the parent has a parent, it must be an "or" parent. */
716
717         if (current_parent->parent)
718           or_parent = current_parent->parent;
719         }
720
721       orc->parent = or_parent;
722       if (!or_parent) *cond = orc;
723       else or_parent->right.c = orc;
724       orc->type = cond_or;
725       orc->testfor = TRUE;
726       orc->left.c = (current_parent == NULL)? c : current_parent;
727       orc->right.c = NULL;   /* insurance */
728       current = &(orc->right.c);
729       current_parent = orc;
730       }
731
732     /* Otherwise there is a disaster */
733
734     else
735       {
736       *error_pointer = string_sprintf("\"and\" or \"or\" or \"%s\" "
737         "expected near line %d of filter file, but found \"%s\"",
738           toplevel? "then" : ")", line_number, buffer);
739       break;
740       }
741     }
742   }
743
744 return nextsigchar(ptr, TRUE);
745 }
746
747
748
749 /*************************************************
750 *             Output the current indent          *
751 *************************************************/
752
753 static void
754 indent(void)
755 {
756 int i;
757 for (i = 0; i < output_indent; i++) debug_printf(" ");
758 }
759
760
761
762 /*************************************************
763 *          Condition printer: for debugging      *
764 *************************************************/
765
766 /*
767 Arguments:
768   c           the block at the top of the tree
769   toplevel    TRUE at toplevel - stops overall brackets
770
771 Returns:      nothing
772 */
773
774 static void
775 print_condition(condition_block *c, BOOL toplevel)
776 {
777 const char *name = (c->testfor)? cond_names[c->type] : cond_not_names[c->type];
778 switch(c->type)
779   {
780   case cond_personal:
781   case cond_delivered:
782   case cond_errormsg:
783   case cond_firsttime:
784   case cond_manualthaw:
785   debug_printf("%s", name);
786   break;
787
788   case cond_is:
789   case cond_IS:
790   case cond_matches:
791   case cond_MATCHES:
792   case cond_contains:
793   case cond_CONTAINS:
794   case cond_begins:
795   case cond_BEGINS:
796   case cond_ends:
797   case cond_ENDS:
798   case cond_above:
799   case cond_below:
800   debug_printf("%s %s %s", c->left.u, name, c->right.u);
801   break;
802
803   case cond_and:
804   if (!c->testfor) debug_printf("not (");
805   print_condition(c->left.c, FALSE);
806   debug_printf(" %s ", cond_names[c->type]);
807   print_condition(c->right.c, FALSE);
808   if (!c->testfor) debug_printf(")");
809   break;
810
811   case cond_or:
812   if (!c->testfor) debug_printf("not (");
813   else if (!toplevel) debug_printf("(");
814   print_condition(c->left.c, FALSE);
815   debug_printf(" %s ", cond_names[c->type]);
816   print_condition(c->right.c, FALSE);
817   if (!toplevel || !c->testfor) debug_printf(")");
818   break;
819
820   case cond_foranyaddress:
821   debug_printf("%s %s (", name, c->left.u);
822   print_condition(c->right.c, FALSE);
823   debug_printf(")");
824   break;
825   }
826 }
827
828
829
830
831 /*************************************************
832 *            Read one filtering command          *
833 *************************************************/
834
835 /*
836 Arguments:
837    pptr        points to pointer to first character of command; the pointer
838                  is updated to point after the last character read
839    lastcmdptr  points to pointer to pointer to last command; used for hanging
840                  on the newly read command
841
842 Returns:       TRUE if command successfully read, else FALSE
843 */
844
845 static BOOL
846 read_command(const uschar **pptr, filter_cmd ***lastcmdptr)
847 {
848 int command, i, cmd_bit;
849 filter_cmd *new, **newlastcmdptr;
850 BOOL yield = TRUE;
851 BOOL was_seen_or_unseen = FALSE;
852 BOOL was_noerror = FALSE;
853 uschar buffer[1024];
854 const uschar *ptr = *pptr;
855 const uschar *saveptr;
856 uschar *fmsg = NULL;
857
858 /* Read the next word and find which command it is. Command words are normally
859 terminated by white space, but there are two exceptions, which are the "if" and
860 "elif" commands. We must allow for them to be terminated by an opening bracket,
861 as brackets are allowed in conditions and users will expect not to require
862 white space here. */
863
864 *buffer = '\0'; /* compiler quietening */
865
866 if (Ustrncmp(ptr, "if(", 3) == 0)
867   {
868   Ustrcpy(buffer, US"if");
869   ptr += 2;
870   }
871 else if (Ustrncmp(ptr, "elif(", 5) == 0)
872   {
873   Ustrcpy(buffer, US"elif");
874   ptr += 4;
875   }
876 else
877   {
878   ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
879   if (*error_pointer) return FALSE;
880   }
881
882 for (command = 0; command < command_list_count; command++)
883   if (Ustrcmp(buffer, command_list[command]) == 0) break;
884
885 /* Handle the individual commands */
886
887 switch (command)
888   {
889   /* Add takes two arguments, separated by the word "to". Headers has two
890   arguments, but the first must be "add", "remove", or "charset", and it gets
891   stored in the second argument slot. Neither may be preceded by seen, unseen
892   or noerror. */
893
894   case add_command:
895   case headers_command:
896   if (seen_force || noerror_force)
897     {
898     *error_pointer = string_sprintf("\"seen\", \"unseen\", or \"noerror\" "
899       "found before an \"%s\" command near line %d",
900         command_list[command], line_number);
901     yield = FALSE;
902     }
903   /* Fall through */
904
905   /* Logwrite, logfile, pipe, and testprint all take a single argument, save
906   and logfile can have an option second argument for the mode, and deliver can
907   have "errors_to <address>" in a system filter, or in a user filter if the
908   address is the current one. */
909
910   case deliver_command:
911   case logfile_command:
912   case logwrite_command:
913   case pipe_command:
914   case save_command:
915   case testprint_command:
916
917   ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
918   if (!*buffer)
919     *error_pointer = string_sprintf("\"%s\" requires an argument "
920       "near line %d of filter file", command_list[command], line_number);
921
922   if (*error_pointer) yield = FALSE; else
923     {
924     union argtypes argument, second_argument;
925
926     argument.u = second_argument.u = NULL;
927
928     if (command == add_command)
929       {
930       argument.u = string_copy(buffer);
931       ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
932       if (!*buffer || Ustrcmp(buffer, "to") != 0)
933         *error_pointer = string_sprintf("\"to\" expected in \"add\" command "
934           "near line %d of filter file", line_number);
935       else
936         {
937         ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
938         if (!*buffer)
939           *error_pointer = string_sprintf("value missing after \"to\" "
940             "near line %d of filter file", line_number);
941         else second_argument.u = string_copy(buffer);
942         }
943       }
944
945     else if (command == headers_command)
946       {
947       if (Ustrcmp(buffer, "add") == 0)
948         second_argument.b = TRUE;
949       else
950         if (Ustrcmp(buffer, "remove") == 0) second_argument.b = FALSE;
951       else
952         if (Ustrcmp(buffer, "charset") == 0)
953           second_argument.b = TRUE_UNSET;
954       else
955         {
956         *error_pointer = string_sprintf("\"add\", \"remove\", or \"charset\" "
957           "expected after \"headers\" near line %d of filter file",
958             line_number);
959         yield = FALSE;
960         }
961
962       if (!f.system_filtering && second_argument.b != TRUE_UNSET)
963         {
964         *error_pointer = string_sprintf("header addition and removal is "
965           "available only in system filters: near line %d of filter file",
966           line_number);
967         yield = FALSE;
968         break;
969         }
970
971       if (yield)
972         {
973         ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
974         if (!*buffer)
975           *error_pointer = string_sprintf("value missing after \"add\", "
976             "\"remove\", or \"charset\" near line %d of filter file",
977               line_number);
978         else argument.u = string_copy(buffer);
979         }
980       }
981
982     /* The argument for the logwrite command must end in a newline, and the save
983     and logfile commands can have an optional mode argument. The deliver
984     command can have an optional "errors_to <address>" for a system filter,
985     or for a user filter if the address is the user's address. Accept the
986     syntax here - the check is later. */
987
988     else
989       {
990       if (command == logwrite_command)
991         {
992         int len = Ustrlen(buffer);
993         if (len == 0 || buffer[len-1] != '\n') Ustrcat(buffer, US"\n");
994         }
995
996       argument.u = string_copy(buffer);
997
998       if (command == save_command || command == logfile_command)
999         {
1000         if (isdigit(*ptr))
1001           {
1002           ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1003           second_argument.i = (int)Ustrtol(buffer, NULL, 8);
1004           }
1005         else second_argument.i = -1;
1006         }
1007
1008       else if (command == deliver_command)
1009         {
1010         const uschar *save_ptr = ptr;
1011         ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1012         if (Ustrcmp(buffer, "errors_to") == 0)
1013           {
1014           ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1015           second_argument.u = string_copy(buffer);
1016           }
1017         else ptr = save_ptr;
1018         }
1019       }
1020
1021     /* Set up the command block. Seen defaults TRUE for delivery commands,
1022     FALSE for logging commands, and it doesn't matter for testprint, as
1023     that doesn't change the "delivered" status. */
1024
1025     if (*error_pointer) yield = FALSE;
1026     else
1027       {
1028       new = store_get(sizeof(filter_cmd) + sizeof(union argtypes), GET_UNTAINTED);
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:
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
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 || 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), GET_UNTAINTED);
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), GET_UNTAINTED);
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) { 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), GET_UNTAINTED);
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) { 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), GET_UNTAINTED);
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     const uschar *saveptr = ptr;
1232     ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1233     if (*error_pointer)
1234       { yield = FALSE; break; }
1235
1236     /* Ensure "return" is followed by "message"; that's a complete option */
1237
1238     if (Ustrcmp(buffer, "return") == 0)
1239       {
1240       new->args[mailarg_index_return].u = US"";  /* not NULL => TRUE */
1241       ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1242       if (Ustrcmp(buffer, "message") != 0)
1243         {
1244         *error_pointer = string_sprintf("\"return\" not followed by \"message\" "
1245           " near line %d of filter file", line_number);
1246         yield = FALSE;
1247         break;
1248         }
1249       continue;
1250       }
1251
1252     /* Ensure "expand" is followed by "file", then fall through to process the
1253     file keyword. */
1254
1255     if (Ustrcmp(buffer, "expand") == 0)
1256       {
1257       new->args[mailarg_index_expand].u = US"";  /* not NULL => TRUE */
1258       ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1259       if (Ustrcmp(buffer, "file") != 0)
1260         {
1261         *error_pointer = string_sprintf("\"expand\" not followed by \"file\" "
1262           " near line %d of filter file", line_number);
1263         yield = FALSE;
1264         break;
1265         }
1266       }
1267
1268     /* Scan for the keyword */
1269
1270     for (i = 0; i < MAILARGS_STRING_COUNT; i++)
1271       if (Ustrcmp(buffer, mailargs[i]) == 0) break;
1272
1273     /* Not found keyword; assume end of this command */
1274
1275     if (i >= MAILARGS_STRING_COUNT)
1276       {
1277       ptr = saveptr;
1278       break;
1279       }
1280
1281     /* Found keyword, read the data item */
1282
1283     ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
1284     if (*error_pointer)
1285       { yield = FALSE; break; }
1286     else new->args[i].u = string_copy(buffer);
1287     }
1288
1289   /* If this is the vacation command, apply some default settings to
1290   some of the arguments. */
1291
1292   if (command == vacation_command)
1293     {
1294     if (!new->args[mailarg_index_file].u)
1295       {
1296       new->args[mailarg_index_file].u = string_copy(US".vacation.msg");
1297       new->args[mailarg_index_expand].u = US"";   /* not NULL => TRUE */
1298       }
1299     if (!new->args[mailarg_index_log].u)
1300       new->args[mailarg_index_log].u = string_copy(US".vacation.log");
1301     if (!new->args[mailarg_index_once].u)
1302       new->args[mailarg_index_once].u = string_copy(US".vacation");
1303     if (!new->args[mailarg_index_once_repeat].u)
1304       new->args[mailarg_index_once_repeat].u = string_copy(US"7d");
1305     if (!new->args[mailarg_index_subject].u)
1306       new->args[mailarg_index_subject].u = string_copy(US"On vacation");
1307     }
1308
1309   /* Join the address on to the chain of generated addresses */
1310
1311   **lastcmdptr = new;
1312   *lastcmdptr = &(new->next);
1313   break;
1314
1315
1316   /* Seen and unseen just set flags */
1317
1318   case seen_command:
1319   case unseen_command:
1320   if (!*ptr)
1321     {
1322     *error_pointer = string_sprintf("\"seen\" or \"unseen\" "
1323       "near line %d is not followed by a command", line_number);
1324     yield = FALSE;
1325     }
1326   if (seen_force)
1327     {
1328     *error_pointer = string_sprintf("\"seen\" or \"unseen\" repeated "
1329       "near line %d", line_number);
1330     yield = FALSE;
1331     }
1332   seen_value = (command == seen_command);
1333   seen_force = TRUE;
1334   was_seen_or_unseen = TRUE;
1335   break;
1336
1337
1338   /* So does noerror */
1339
1340   case noerror_command:
1341   if (!*ptr)
1342     {
1343     *error_pointer = string_sprintf("\"noerror\" "
1344       "near line %d is not followed by a command", line_number);
1345     yield = FALSE;
1346     }
1347   noerror_force = TRUE;
1348   was_noerror = TRUE;
1349   break;
1350
1351
1352   /* Oops */
1353
1354   default:
1355   *error_pointer = string_sprintf("unknown filtering command \"%s\" "
1356     "near line %d of filter file", buffer, line_number);
1357   yield = FALSE;
1358   break;
1359   }
1360
1361 if (!was_seen_or_unseen && !was_noerror)
1362   {
1363   seen_force = FALSE;
1364   noerror_force = FALSE;
1365   }
1366
1367 *pptr = ptr;
1368 return yield;
1369 }
1370
1371
1372
1373 /*************************************************
1374 *              Read a list of commands           *
1375 *************************************************/
1376
1377 /* If conditional is TRUE, the list must be terminated
1378 by the words "else" or "endif".
1379
1380 Arguments:
1381   pptr        points to pointer to next character; the pointer is updated
1382   lastcmdptr  points to pointer to pointer to previously-read command; used
1383                 for hanging on the new command
1384   conditional TRUE if this command is the subject of a condition
1385
1386 Returns:      TRUE on success
1387 */
1388
1389 static BOOL
1390 read_command_list(const uschar **pptr, filter_cmd ***lastcmdptr, BOOL conditional)
1391 {
1392 if (conditional) expect_endif++;
1393 had_else_endif = had_neither;
1394 while (**pptr && had_else_endif == had_neither)
1395   {
1396   if (!read_command(pptr, lastcmdptr)) return FALSE;
1397   *pptr = nextsigchar(*pptr, TRUE);
1398   }
1399 if (conditional)
1400   {
1401   expect_endif--;
1402   if (had_else_endif == had_neither)
1403     {
1404     *error_pointer = US"\"endif\" missing at end of filter file";
1405     return FALSE;
1406     }
1407   }
1408 return TRUE;
1409 }
1410
1411
1412
1413
1414 /*************************************************
1415 *             Test a condition                   *
1416 *************************************************/
1417
1418 /*
1419 Arguments:
1420   c              points to the condition block; c->testfor indicated whether
1421                    it's a positive or negative condition
1422   toplevel       TRUE if called from "if" directly; FALSE otherwise
1423
1424 Returns:         TRUE if the condition is met
1425 */
1426
1427 static BOOL
1428 test_condition(condition_block * c, BOOL toplevel)
1429 {
1430 BOOL yield = FALSE, textonly_re;
1431 const uschar * exp[2], * p, * pp;
1432 int val[2];
1433
1434 if (!c) return TRUE;  /* does this ever occur? */
1435
1436 switch (c->type)
1437   {
1438   case cond_and:
1439     yield = test_condition(c->left.c, FALSE) &&
1440             *error_pointer == NULL &&
1441             test_condition(c->right.c, FALSE);
1442     break;
1443
1444   case cond_or:
1445     yield = test_condition(c->left.c, FALSE) ||
1446             (*error_pointer == NULL &&
1447             test_condition(c->right.c, FALSE));
1448     break;
1449
1450     /* The personal test is meaningless in a system filter. The tests are now in
1451     a separate function (so Sieve can use them). However, an Exim filter does not
1452     scan Cc: (hence the FALSE argument). */
1453
1454   case cond_personal:
1455     yield = f.system_filtering? FALSE : filter_personal(c->left.a, FALSE);
1456     break;
1457
1458   case cond_delivered:
1459     yield = filter_delivered;
1460     break;
1461
1462     /* Only TRUE if a message is actually being processed; FALSE for address
1463     testing and verification. */
1464
1465   case cond_errormsg:
1466     yield = message_id[0] != 0 &&
1467       (sender_address == NULL || sender_address[0] == 0);
1468     break;
1469
1470     /* Only FALSE if a message is actually being processed; TRUE for address
1471     and filter testing and verification. */
1472
1473   case cond_firsttime:
1474     yield = filter_test != FTEST_NONE || message_id[0] == 0 || f.deliver_firsttime;
1475     break;
1476
1477     /* Only TRUE if a message is actually being processed; FALSE for address
1478     testing and verification. */
1479
1480   case cond_manualthaw:
1481     yield = message_id[0] != 0 && f.deliver_manual_thaw;
1482     break;
1483
1484     /* The foranyaddress condition loops through a list of addresses */
1485
1486   case cond_foranyaddress:
1487     p = c->left.u;
1488     if (!(pp = expand_cstring(p)))
1489       {
1490       *error_pointer = string_sprintf("failed to expand \"%s\" in "
1491         "filter file: %s", p, expand_string_message);
1492       return FALSE;
1493       }
1494
1495     yield = FALSE;
1496     f.parse_allow_group = TRUE;     /* Allow group syntax */
1497
1498     while (*pp)
1499       {
1500       uschar *error;
1501       int start, end, domain;
1502       uschar * s;
1503
1504       p = parse_find_address_end(pp, FALSE);
1505       s = string_copyn(pp, p - pp);
1506
1507       filter_thisaddress =
1508         parse_extract_address(s, &error, &start, &end, &domain, FALSE);
1509
1510       if (filter_thisaddress)
1511         {
1512         if ((filter_test != FTEST_NONE && debug_selector != 0) ||
1513             (debug_selector & D_filter) != 0)
1514           {
1515           indent();
1516           debug_printf_indent("Extracted address %s\n", filter_thisaddress);
1517           }
1518         yield = test_condition(c->right.c, FALSE);
1519         }
1520
1521       if (yield) break;
1522       if (!*p) break;
1523       pp = p + 1;
1524       }
1525
1526     f.parse_allow_group = FALSE;      /* Reset group syntax flags */
1527     f.parse_found_group = FALSE;
1528     break;
1529
1530     /* All other conditions have left and right values that need expanding;
1531     on error, it doesn't matter what value is returned. */
1532
1533     default:
1534     p = c->left.u;
1535     for (int i = 0; i < 2; i++)
1536       {
1537       if (!(exp[i] = expand_string_2(p, &textonly_re)))
1538         {
1539         *error_pointer = string_sprintf("failed to expand \"%s\" in "
1540           "filter file: %s", p, expand_string_message);
1541         return FALSE;
1542         }
1543       p = c->right.u;
1544       }
1545
1546     /* Inner switch for the different cases */
1547
1548     switch(c->type)
1549       {
1550       case cond_is:
1551         yield = strcmpic(exp[0], exp[1]) == 0;
1552         break;
1553
1554       case cond_IS:
1555         yield = Ustrcmp(exp[0], exp[1]) == 0;
1556         break;
1557
1558       case cond_contains:
1559         yield = strstric_c(exp[0], exp[1], FALSE) != NULL;
1560         break;
1561
1562       case cond_CONTAINS:
1563         yield = Ustrstr(exp[0], exp[1]) != NULL;
1564         break;
1565
1566       case cond_begins:
1567         yield = strncmpic(exp[0], exp[1], Ustrlen(exp[1])) == 0;
1568         break;
1569
1570       case cond_BEGINS:
1571         yield = Ustrncmp(exp[0], exp[1], Ustrlen(exp[1])) == 0;
1572         break;
1573
1574       case cond_ends:
1575       case cond_ENDS:
1576         {
1577         int len = Ustrlen(exp[1]);
1578         const uschar *s = exp[0] + Ustrlen(exp[0]) - len;
1579         yield = s < exp[0]
1580           ? FALSE
1581           : (c->type == cond_ends ? strcmpic(s, exp[1]) : Ustrcmp(s, exp[1])) == 0;
1582         break;
1583         }
1584
1585       case cond_matches:
1586       case cond_MATCHES:
1587         {
1588         const pcre2_code * re;
1589         mcs_flags flags = textonly_re ? MCS_CACHEABLE : MCS_NOFLAGS;
1590
1591         if ((filter_test != FTEST_NONE && debug_selector != 0) ||
1592             (debug_selector & D_filter) != 0)
1593           {
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]);
1597           }
1598
1599         if (c->type == cond_matches) flags |= MCS_CASELESS;
1600         if (!(re = regex_compile(exp[1], flags, error_pointer, pcre_gen_cmp_ctx)))
1601           return FALSE;
1602
1603         yield = regex_match_and_setup(re, exp[0], PCRE_EOPT, -1);
1604         break;
1605         }
1606
1607       /* For above and below, convert the strings to numbers */
1608
1609       case cond_above:
1610       case cond_below:
1611         for (int i = 0; i < 2; i++)
1612           {
1613           val[i] = get_number(exp[i], &yield);
1614           if (!yield)
1615             {
1616             *error_pointer = string_sprintf("malformed numerical string \"%s\"",
1617               exp[i]);
1618             return FALSE;
1619             }
1620           }
1621         yield = c->type == cond_above ? (val[0] > val[1]) : (val[0] < val[1]);
1622         break;
1623       }
1624     break;
1625   }
1626
1627 if ((filter_test != FTEST_NONE && debug_selector != 0) ||
1628     (debug_selector & D_filter) != 0)
1629   {
1630   indent();
1631   debug_printf_indent("%sondition is %s: ",
1632     toplevel? "C" : "Sub-c",
1633     (yield == c->testfor)? "true" : "false");
1634   print_condition(c, TRUE);
1635   debug_printf_indent("\n");
1636   }
1637
1638 return yield == c->testfor;
1639 }
1640
1641
1642
1643 /*************************************************
1644 *          Interpret chain of commands           *
1645 *************************************************/
1646
1647 /* In testing state, just say what would be done rather than doing it. The
1648 testprint command just expands and outputs its argument in testing state, and
1649 does nothing otherwise.
1650
1651 Arguments:
1652   commands    points to chain of commands to interpret
1653   generated   where to hang newly-generated addresses
1654
1655 Returns:      FF_DELIVERED     success, a significant action was taken
1656               FF_NOTDELIVERED  success, no significant action
1657               FF_DEFER         defer requested
1658               FF_FAIL          fail requested
1659               FF_FREEZE        freeze requested
1660               FF_ERROR         there was a problem
1661 */
1662
1663 static int
1664 interpret_commands(filter_cmd *commands, address_item **generated)
1665 {
1666 const uschar *s;
1667 int mode;
1668 address_item *addr;
1669 BOOL condition_value;
1670
1671 while (commands)
1672   {
1673   int ff_ret;
1674   uschar *fmsg, *ff_name;
1675   const uschar *expargs[MAILARGS_STRING_COUNT];
1676
1677   int i, n[2];
1678
1679   /* Expand the relevant number of arguments for the command that are
1680   not NULL. */
1681
1682   for (i = 0; i < (command_exparg_count[commands->command] & 15); i++)
1683     {
1684     const uschar *ss = commands->args[i].u;
1685     if (!ss)
1686       expargs[i] = NULL;
1687     else if (!(expargs[i] = expand_cstring(ss)))
1688       {
1689       *error_pointer = string_sprintf("failed to expand \"%s\" in "
1690         "%s command: %s", ss, command_list[commands->command],
1691         expand_string_message);
1692       return FF_ERROR;
1693       }
1694     }
1695
1696   /* Now switch for each command, setting the "delivered" flag if any of them
1697   have "seen" set. */
1698
1699   if (commands->seen) filter_delivered = TRUE;
1700
1701   switch(commands->command)
1702     {
1703     case add_command:
1704       for (i = 0; i < 2; i++)
1705         {
1706         const uschar *ss = expargs[i];
1707         uschar *end;
1708
1709         if (i == 1 && (*ss++ != 'n' || ss[1] != 0))
1710           {
1711           *error_pointer = string_sprintf("unknown variable \"%s\" in \"add\" "
1712             "command", expargs[i]);
1713           return FF_ERROR;
1714           }
1715
1716         /* Allow for "--" at the start of the value (from -$n0) for example */
1717         if (i == 0) while (ss[0] == '-' && ss[1] == '-') ss += 2;
1718
1719         n[i] = (int)Ustrtol(ss, &end, 0);
1720         if (*end != 0)
1721           {
1722           *error_pointer = string_sprintf("malformed number \"%s\" in \"add\" "
1723             "command", ss);
1724           return FF_ERROR;
1725           }
1726         }
1727
1728       filter_n[n[1]] += n[0];
1729       if (filter_test != FTEST_NONE) printf("Add %d to n%d\n", n[0], n[1]);
1730       break;
1731
1732       /* A deliver command's argument must be a valid address. Its optional
1733       second argument (system filter only) must also be a valid address. */
1734
1735     case deliver_command:
1736       for (i = 0; i < 2; i++)
1737         {
1738         s = expargs[i];
1739         if (s != NULL)
1740           {
1741           int start, end, domain;
1742           uschar *error;
1743           uschar *ss = parse_extract_address(s, &error, &start, &end, &domain,
1744             FALSE);
1745           if (ss)
1746             expargs[i] = filter_options & RDO_REWRITE
1747               ? rewrite_address(ss, TRUE, FALSE, global_rewrite_rules,
1748                                 rewrite_existflags)
1749               : rewrite_address_qualify(ss, TRUE);
1750           else
1751             {
1752             *error_pointer = string_sprintf("malformed address \"%s\" in "
1753               "filter file: %s", s, error);
1754             return FF_ERROR;
1755             }
1756           }
1757         }
1758
1759       /* Stick the errors address into a simple variable, as it will
1760       be referenced a few times. Check that the caller is permitted to
1761       specify it. */
1762
1763       s = expargs[1];
1764
1765       if (s != NULL && !f.system_filtering)
1766         {
1767         uschar *ownaddress = expand_string(US"$local_part@$domain");
1768         if (strcmpic(ownaddress, s) != 0)
1769           {
1770           *error_pointer = US"errors_to must point to the caller's address";
1771           return FF_ERROR;
1772           }
1773         }
1774
1775       /* Test case: report what would happen */
1776
1777       if (filter_test != FTEST_NONE)
1778         {
1779         indent();
1780         printf("%seliver message to: %s%s%s%s\n",
1781           (commands->seen)? "D" : "Unseen d",
1782           expargs[0],
1783           commands->noerror? " (noerror)" : "",
1784           (s != NULL)? " errors_to " : "",
1785           (s != NULL)? s : US"");
1786         }
1787
1788       /* Real case. */
1789
1790       else
1791         {
1792         DEBUG(D_filter) debug_printf_indent("Filter: %sdeliver message to: %s%s%s%s\n",
1793           (commands->seen)? "" : "unseen ",
1794           expargs[0],
1795           commands->noerror? " (noerror)" : "",
1796           (s != NULL)? " errors_to " : "",
1797           (s != NULL)? s : US"");
1798
1799         /* Create the new address and add it to the chain, setting the
1800         af_ignore_error flag if necessary, and the errors address, which can be
1801         set in a system filter and to the local address in user filters. */
1802
1803         addr = deliver_make_addr(US expargs[0], TRUE);  /* TRUE => copy s, so deconst ok */
1804         addr->prop.errors_address = !s ? NULL : string_copy(s); /* Default is NULL */
1805         if (commands->noerror) addr->prop.ignore_error = TRUE;
1806         addr->next = *generated;
1807         *generated = addr;
1808         }
1809       break;
1810
1811     case save_command:
1812       s = expargs[0];
1813       mode = commands->args[1].i;
1814
1815       /* Test case: report what would happen */
1816
1817       if (filter_test != FTEST_NONE)
1818         {
1819         indent();
1820         if (mode < 0)
1821           printf("%save message to: %s%s\n", (commands->seen)?
1822             "S" : "Unseen s", s, commands->noerror? " (noerror)" : "");
1823         else
1824           printf("%save message to: %s %04o%s\n", (commands->seen)?
1825             "S" : "Unseen s", s, mode, commands->noerror? " (noerror)" : "");
1826         }
1827
1828       /* Real case: Ensure save argument starts with / if there is a home
1829       directory to prepend. */
1830
1831       else
1832         {
1833         if (s[0] != '/' && (filter_options & RDO_PREPEND_HOME) != 0 &&
1834             deliver_home != NULL && deliver_home[0] != 0)
1835           s = string_sprintf("%s/%s", deliver_home, s);
1836         DEBUG(D_filter) debug_printf_indent("Filter: %ssave message to: %s%s\n",
1837           (commands->seen)? "" : "unseen ", s,
1838           commands->noerror? " (noerror)" : "");
1839
1840         /* Create the new address and add it to the chain, setting the
1841         af_pfr and af_file flags, the af_ignore_error flag if necessary, and the
1842         mode value. */
1843
1844         addr = deliver_make_addr(US s, TRUE);  /* TRUE => copy s, so deconst ok */
1845         setflag(addr, af_pfr);
1846         setflag(addr, af_file);
1847         if (commands->noerror) addr->prop.ignore_error = TRUE;
1848         addr->mode = mode;
1849         addr->next = *generated;
1850         *generated = addr;
1851         }
1852       break;
1853
1854     case pipe_command:
1855       s = string_copy(commands->args[0].u);
1856       if (filter_test != FTEST_NONE)
1857         {
1858         indent();
1859         printf("%sipe message to: %s%s\n", (commands->seen)?
1860           "P" : "Unseen p", s, commands->noerror? " (noerror)" : "");
1861         }
1862       else /* Ensure pipe command starts with | */
1863         {
1864         DEBUG(D_filter) debug_printf_indent("Filter: %spipe message to: %s%s\n",
1865           commands->seen ? "" : "unseen ", s,
1866           commands->noerror ? " (noerror)" : "");
1867         if (s[0] != '|') s = string_sprintf("|%s", s);
1868
1869         /* Create the new address and add it to the chain, setting the
1870         af_ignore_error flag if necessary. Set the af_expand_pipe flag so that
1871         each command argument is expanded in the transport after the command
1872         has been split up into separate arguments. */
1873
1874         addr = deliver_make_addr(US s, TRUE);  /* TRUE => copy s, so deconst ok */
1875         setflag(addr, af_pfr);
1876         setflag(addr, af_expand_pipe);
1877         if (commands->noerror) addr->prop.ignore_error = TRUE;
1878         addr->next = *generated;
1879         *generated = addr;
1880
1881         /* If there are any numeric variables in existence (e.g. after a regex
1882         condition), or if $thisaddress is set, take a copy for use in the
1883         expansion. Note that we can't pass NULL for filter_thisaddress, because
1884         NULL terminates the list. */
1885
1886         if (expand_nmax >= 0 || filter_thisaddress != NULL)
1887           {
1888           int ecount = expand_nmax >= 0 ? expand_nmax : -1;
1889           uschar ** ss = store_get(sizeof(uschar *) * (ecount + 3), GET_UNTAINTED);
1890
1891           addr->pipe_expandn = ss;
1892           if (!filter_thisaddress) filter_thisaddress = US"";
1893           *ss++ = string_copy(filter_thisaddress);
1894           for (int i = 0; i <= expand_nmax; i++)
1895             *ss++ = string_copyn(expand_nstring[i], expand_nlength[i]);
1896           *ss = NULL;
1897           }
1898         }
1899       break;
1900
1901       /* Set up the file name and mode, and close any previously open
1902       file. */
1903
1904     case logfile_command:
1905       log_mode = commands->args[1].i;
1906       if (log_mode == -1) log_mode = 0600;
1907       if (log_fd >= 0)
1908         {
1909         (void)close(log_fd);
1910         log_fd = -1;
1911         }
1912       log_filename = expargs[0];
1913       if (filter_test != FTEST_NONE)
1914         {
1915         indent();
1916         printf("%sogfile %s\n", (commands->seen)? "Seen l" : "L", log_filename);
1917         }
1918       break;
1919
1920     case logwrite_command:
1921       s = expargs[0];
1922
1923       if (filter_test != FTEST_NONE)
1924         {
1925         indent();
1926         printf("%sogwrite \"%s\"\n", (commands->seen)? "Seen l" : "L",
1927           string_printing(s));
1928         }
1929
1930       /* Attempt to write to a log file only if configured as permissible.
1931       Logging may be forcibly skipped for verifying or testing. */
1932
1933       else if ((filter_options & RDO_LOG) != 0)   /* Locked out */
1934         {
1935         DEBUG(D_filter)
1936           debug_printf_indent("filter log command aborted: euid=%ld\n",
1937           (long int)geteuid());
1938         *error_pointer = US"logwrite command forbidden";
1939         return FF_ERROR;
1940         }
1941       else if ((filter_options & RDO_REALLOG) != 0)
1942         {
1943         int len;
1944         DEBUG(D_filter) debug_printf_indent("writing filter log as euid %ld\n",
1945           (long int)geteuid());
1946         if (log_fd < 0)
1947           {
1948           if (!log_filename)
1949             {
1950             *error_pointer = US"attempt to obey \"logwrite\" command "
1951               "without a previous \"logfile\"";
1952             return FF_ERROR;
1953             }
1954           log_fd = Uopen(log_filename, O_CREAT|O_APPEND|O_WRONLY, log_mode);
1955           if (log_fd < 0)
1956             {
1957             *error_pointer = string_open_failed("filter log file \"%s\"",
1958               log_filename);
1959             return FF_ERROR;
1960             }
1961           }
1962         len = Ustrlen(s);
1963         if (write(log_fd, s, len) != len)
1964           {
1965           *error_pointer = string_sprintf("write error on file \"%s\": %s",
1966             log_filename, strerror(errno));
1967           return FF_ERROR;
1968           }
1969         }
1970       else
1971         DEBUG(D_filter)
1972           debug_printf_indent("skipping logwrite (verifying or testing)\n");
1973       break;
1974
1975       /* Header addition and removal is available only in the system filter. The
1976       command is rejected at parse time otherwise. However "headers charset" is
1977       always permitted. */
1978
1979     case headers_command:
1980         {
1981         int subtype = commands->args[1].i;
1982         s = expargs[0];
1983
1984         if (filter_test != FTEST_NONE)
1985           printf("Headers %s \"%s\"\n",
1986             subtype == TRUE ? "add"
1987             : subtype == FALSE ? "remove"
1988             : "charset",
1989             string_printing(s));
1990
1991         if (subtype == TRUE)
1992           {
1993           while (isspace(*s)) s++;
1994           if (*s)
1995             {
1996             header_add(htype_other, "%s%s", s,
1997               s[Ustrlen(s)-1] == '\n' ? "" : "\n");
1998             header_last->type = header_checkname(header_last, FALSE);
1999             if (header_last->type >= 'a') header_last->type = htype_other;
2000             }
2001           }
2002
2003         else if (subtype == FALSE)
2004           {
2005           int sep = 0;
2006           const uschar * list = s;
2007
2008           for (uschar * ss; ss = string_nextinlist(&list, &sep, NULL, 0); )
2009             header_remove(0, ss);
2010           }
2011
2012         /* This setting lasts only while the filter is running; on exit, the
2013         variable is reset to the previous value. */
2014
2015         else headers_charset = s;
2016         }
2017       break;
2018
2019       /* Defer, freeze, and fail are available only when explicitly permitted.
2020       These commands are rejected at parse time otherwise. The message can get
2021       very long by the inclusion of message headers; truncate if it is, and also
2022       ensure printing characters so as not to mess up log files. */
2023
2024     case defer_command:
2025       ff_name = US"defer";
2026       ff_ret = FF_DEFER;
2027       goto DEFERFREEZEFAIL;
2028
2029     case fail_command:
2030       ff_name = US"fail";
2031       ff_ret = FF_FAIL;
2032       goto DEFERFREEZEFAIL;
2033
2034     case freeze_command:
2035       ff_name = US"freeze";
2036       ff_ret = FF_FREEZE;
2037
2038     DEFERFREEZEFAIL:
2039       *error_pointer = fmsg = US string_printing(Ustrlen(expargs[0]) > 1024
2040         ? string_sprintf("%.1000s ... (truncated)", expargs[0])
2041         : string_copy(expargs[0]));
2042       for(uschar * s = fmsg; *s; s++)
2043         if (!s[1] && *s == '\n') { *s = '\0'; break; }  /* drop trailing newline */
2044
2045       if (filter_test != FTEST_NONE)
2046         {
2047         indent();
2048         printf("%c%s text \"%s\"\n", toupper(ff_name[0]), ff_name+1, fmsg);
2049         }
2050       else
2051         DEBUG(D_filter) debug_printf_indent("Filter: %s \"%s\"\n", ff_name, fmsg);
2052       return ff_ret;
2053
2054     case finish_command:
2055       if (filter_test != FTEST_NONE)
2056         {
2057         indent();
2058         printf("%sinish\n", (commands->seen)? "Seen f" : "F");
2059         }
2060       else
2061         DEBUG(D_filter) debug_printf_indent("Filter: %sfinish\n",
2062           commands->seen ? " Seen " : "");
2063       finish_obeyed = TRUE;
2064       return filter_delivered ? FF_DELIVERED : FF_NOTDELIVERED;
2065
2066     case if_command:
2067         {
2068         uschar *save_address = filter_thisaddress;
2069         int ok = FF_DELIVERED;
2070         condition_value = test_condition(commands->args[0].c, TRUE);
2071         if (*error_pointer)
2072           ok = FF_ERROR;
2073         else
2074           {
2075           output_indent += 2;
2076           ok = interpret_commands(commands->args[condition_value? 1:2].f,
2077             generated);
2078           output_indent -= 2;
2079           }
2080         filter_thisaddress = save_address;
2081         if (finish_obeyed  ||  ok != FF_DELIVERED && ok != FF_NOTDELIVERED)
2082           return ok;
2083         }
2084       break;
2085
2086
2087       /* To try to catch runaway loops, do not generate mail if the
2088       return path is unset or if a non-trusted user supplied -f <>
2089       as the return path. */
2090
2091     case mail_command:
2092     case vacation_command:
2093         if (!return_path || !*return_path)
2094           {
2095           if (filter_test != FTEST_NONE)
2096             printf("%s command ignored because return_path is empty\n",
2097               command_list[commands->command]);
2098           else DEBUG(D_filter) debug_printf_indent("%s command ignored because return_path "
2099             "is empty\n", command_list[commands->command]);
2100           break;
2101           }
2102
2103         /* Check the contents of the strings. The type of string can be deduced
2104         from the value of i.
2105
2106         . If i is equal to mailarg_index_text it's a text string for the body,
2107           where anything goes.
2108
2109         . If i is > mailarg_index_text, we are dealing with a file name, which
2110           cannot contain non-printing characters.
2111
2112         . If i is less than mailarg_index_headers we are dealing with something
2113           that will go in a single message header line, where newlines must be
2114           followed by white space.
2115
2116         . If i is equal to mailarg_index_headers, we have a string that contains
2117           one or more headers. Newlines that are not followed by white space must
2118           be followed by a header name.
2119         */
2120
2121         for (i = 0; i < MAILARGS_STRING_COUNT; i++)
2122           {
2123           const uschar *s = expargs[i];
2124
2125           if (!s) continue;
2126
2127           if (i != mailarg_index_text) for (const uschar * p = s; *p; p++)
2128             {
2129             int c = *p;
2130             if (i > mailarg_index_text)
2131               {
2132               if (!mac_isprint(c))
2133                 {
2134                 *error_pointer = string_sprintf("non-printing character in \"%s\" "
2135                   "in %s command", string_printing(s),
2136                   command_list[commands->command]);
2137                 return FF_ERROR;
2138                 }
2139               }
2140
2141             /* i < mailarg_index_text */
2142
2143             else if (c == '\n' && !isspace(p[1]))
2144               {
2145               if (i < mailarg_index_headers)
2146                 {
2147                 *error_pointer = string_sprintf("\\n not followed by space in "
2148                   "\"%.1024s\" in %s command", string_printing(s),
2149                   command_list[commands->command]);
2150                 return FF_ERROR;
2151                 }
2152
2153               /* Check for the start of a new header line within the string */
2154
2155               else
2156                 {
2157                 const uschar *pp;
2158                 for (pp = p + 1;; pp++)
2159                   {
2160                   c = *pp;
2161                   if (c == ':' && pp != p + 1) break;
2162                   if (!c || c == ':' || isspace(c))
2163                     {
2164                     *error_pointer = string_sprintf("\\n not followed by space or "
2165                       "valid header name in \"%.1024s\" in %s command",
2166                       string_printing(s), command_list[commands->command]);
2167                     return FF_ERROR;
2168                     }
2169                   }
2170                 p = pp;
2171                 }
2172               }
2173             }       /* Loop to scan the string */
2174
2175           /* The string is OK */
2176
2177           commands->args[i].u = s;
2178           }
2179
2180         /* Proceed with mail or vacation command */
2181
2182         if (filter_test != FTEST_NONE)
2183           {
2184           const uschar *to = commands->args[mailarg_index_to].u;
2185           indent();
2186           printf("%sail to: %s%s%s\n", (commands->seen)? "Seen m" : "M",
2187             to ? to : US"<default>",
2188             commands->command == vacation_command ? " (vacation)" : "",
2189             commands->noerror ? " (noerror)" : "");
2190           for (i = 1; i < MAILARGS_STRING_COUNT; i++)
2191             {
2192             const uschar *arg = commands->args[i].u;
2193             if (arg)
2194               {
2195               int len = Ustrlen(mailargs[i]);
2196               int indent = (debug_selector != 0)? output_indent : 0;
2197               while (len++ < 7 + indent) printf(" ");
2198               printf("%s: %s%s\n", mailargs[i], string_printing(arg),
2199                 (commands->args[mailarg_index_expand].u != NULL &&
2200                   Ustrcmp(mailargs[i], "file") == 0)? " (expanded)" : "");
2201               }
2202             }
2203           if (commands->args[mailarg_index_return].u)
2204             printf("Return original message\n");
2205           }
2206         else
2207           {
2208           const uschar *tt;
2209           const uschar *to = commands->args[mailarg_index_to].u;
2210           gstring * log_addr = NULL;
2211
2212           if (!to) to = expand_string(US"$reply_address");
2213           while (isspace(*to)) to++;
2214
2215           for (tt = to; *tt; tt++)     /* Get rid of newlines */
2216             if (*tt == '\n')
2217               {
2218               uschar * s = string_copy(to);
2219               for (uschar * ss = s; *ss; ss++)
2220                 if (*ss == '\n') *ss = ' ';
2221               to = s;
2222               break;
2223               }
2224
2225           DEBUG(D_filter)
2226             {
2227             debug_printf_indent("Filter: %smail to: %s%s%s\n",
2228               commands->seen ? "seen " : "",
2229               to,
2230               commands->command == vacation_command ? " (vacation)" : "",
2231               commands->noerror ? " (noerror)" : "");
2232             for (i = 1; i < MAILARGS_STRING_COUNT; i++)
2233               {
2234               const uschar *arg = commands->args[i].u;
2235               if (arg)
2236                 {
2237                 int len = Ustrlen(mailargs[i]);
2238                 while (len++ < 15) debug_printf_indent(" ");
2239                 debug_printf_indent("%s: %s%s\n", mailargs[i], string_printing(arg),
2240                   (commands->args[mailarg_index_expand].u != NULL &&
2241                     Ustrcmp(mailargs[i], "file") == 0)? " (expanded)" : "");
2242                 }
2243               }
2244             }
2245
2246           /* Create the "address" for the autoreply. This is used only for logging,
2247           as the actual recipients are extracted from the To: line by -t. We use the
2248           same logic here to extract the working addresses (there may be more than
2249           one). Just in case there are a vast number of addresses, stop when the
2250           string gets too long. */
2251
2252           tt = to;
2253           while (*tt)
2254             {
2255             uschar *ss = parse_find_address_end(tt, FALSE);
2256             uschar *recipient, *errmess;
2257             int start, end, domain;
2258             int temp = *ss;
2259
2260             *ss = 0;
2261             recipient = parse_extract_address(tt, &errmess, &start, &end, &domain,
2262               FALSE);
2263             *ss = temp;
2264
2265             /* Ignore empty addresses and errors; an error will occur later if
2266             there's something really bad. */
2267
2268             if (recipient)
2269               {
2270               log_addr = string_catn(log_addr, log_addr ? US"," : US">", 1);
2271               log_addr = string_cat (log_addr, recipient);
2272               }
2273
2274             /* Check size */
2275
2276             if (log_addr && log_addr->ptr > 256)
2277               {
2278               log_addr = string_catn(log_addr, US", ...", 5);
2279               break;
2280               }
2281
2282             /* Move on past this address */
2283
2284             tt = ss + (*ss ? 1 : 0);
2285             while (isspace(*tt)) tt++;
2286             }
2287
2288           if (log_addr)
2289             addr = deliver_make_addr(string_from_gstring(log_addr), FALSE);
2290           else
2291             {
2292             addr = deliver_make_addr(US ">**bad-reply**", FALSE);
2293             setflag(addr, af_bad_reply);
2294             }
2295
2296           setflag(addr, af_pfr);
2297           if (commands->noerror) addr->prop.ignore_error = TRUE;
2298           addr->next = *generated;
2299           *generated = addr;
2300
2301           addr->reply = store_get(sizeof(reply_item), GET_UNTAINTED);
2302           addr->reply->from = NULL;
2303           addr->reply->to = string_copy(to);
2304           addr->reply->file_expand =
2305             commands->args[mailarg_index_expand].u != NULL;
2306           addr->reply->expand_forbid = expand_forbid;
2307           addr->reply->return_message =
2308             commands->args[mailarg_index_return].u != NULL;
2309           addr->reply->once_repeat = 0;
2310
2311           if (commands->args[mailarg_index_once_repeat].u != NULL)
2312             {
2313             addr->reply->once_repeat =
2314               readconf_readtime(commands->args[mailarg_index_once_repeat].u, 0,
2315                 FALSE);
2316             if (addr->reply->once_repeat < 0)
2317               {
2318               *error_pointer = string_sprintf("Bad time value for \"once_repeat\" "
2319                 "in mail or vacation command: %s",
2320                 commands->args[mailarg_index_once_repeat].u);
2321               return FF_ERROR;
2322               }
2323             }
2324
2325           /* Set up all the remaining string arguments (those other than "to") */
2326
2327           for (i = 1; i < mailargs_string_passed; i++)
2328             {
2329             const uschar *ss = commands->args[i].u;
2330             *(USS((US addr->reply) + reply_offsets[i])) =
2331               ss ? string_copy(ss) : NULL;
2332             }
2333           }
2334         break;
2335
2336     case testprint_command:
2337         if (filter_test != FTEST_NONE || (debug_selector & D_filter) != 0)
2338           {
2339           const uschar *s = string_printing(expargs[0]);
2340           if (filter_test == FTEST_NONE)
2341             debug_printf_indent("Filter: testprint: %s\n", s);
2342           else
2343             printf("Testprint: %s\n", s);
2344           }
2345     }
2346
2347   commands = commands->next;
2348   }
2349
2350 return filter_delivered ? FF_DELIVERED : FF_NOTDELIVERED;
2351 }
2352
2353
2354
2355 /*************************************************
2356 *        Test for a personal message             *
2357 *************************************************/
2358
2359 /* This function is global so that it can also be called from the code that
2360 implements Sieve filters.
2361
2362 Arguments:
2363   aliases    a chain of aliases
2364   scan_cc    TRUE if Cc: and Bcc: are to be scanned (Exim filters do not)
2365
2366 Returns:     TRUE if the message is deemed to be personal
2367 */
2368
2369 BOOL
2370 filter_personal(string_item *aliases, BOOL scan_cc)
2371 {
2372 const uschar *self, *self_from, *self_to;
2373 uschar *psself = NULL;
2374 const uschar *psself_from = NULL, *psself_to = NULL;
2375 rmark reset_point = store_mark();
2376 BOOL yield;
2377 header_line *h;
2378 int to_count = 2;
2379 int from_count = 9;
2380
2381 /* If any header line in the message is a defined "List-" header field, it is
2382 not a personal message. We used to check for any header line that started with
2383 "List-", but this was tightened up for release 4.54. The check is now for
2384 "List-Id", defined in RFC 2929, or "List-Help", "List-Subscribe", "List-
2385 Unsubscribe", "List-Post", "List-Owner" or "List-Archive", all of which are
2386 defined in RFC 2369. We also scan for "Auto-Submitted"; if it is found to
2387 contain any value other than "no", the message is not personal (RFC 3834).
2388 Previously the test was for "auto-". */
2389
2390 for (h = header_list; h; h = h->next)
2391   {
2392   if (h->type == htype_old) continue;
2393
2394   if (strncmpic(h->text, US"List-", 5) == 0)
2395     {
2396     uschar * s = h->text + 5;
2397     if (strncmpic(s, US"Id:", 3) == 0 ||
2398         strncmpic(s, US"Help:", 5) == 0 ||
2399         strncmpic(s, US"Subscribe:", 10) == 0 ||
2400         strncmpic(s, US"Unsubscribe:", 12) == 0 ||
2401         strncmpic(s, US"Post:", 5) == 0 ||
2402         strncmpic(s, US"Owner:", 6) == 0 ||
2403         strncmpic(s, US"Archive:", 8) == 0)
2404       return FALSE;
2405     }
2406
2407   else if (strncmpic(h->text, US"Auto-submitted:", 15) == 0)
2408     {
2409     uschar * s = h->text + 15;
2410     Uskip_whitespace(&s);
2411     if (strncmpic(s, US"no", 2) != 0) return FALSE;
2412     s += 2;
2413     Uskip_whitespace(&s);
2414     if (*s) return FALSE;
2415     }
2416   }
2417
2418 /* Set up "my" address */
2419
2420 self = string_sprintf("%s@%s", deliver_localpart, deliver_domain);
2421 self_from = rewrite_one(self, rewrite_from, NULL, FALSE, US"",
2422   global_rewrite_rules);
2423 self_to   = rewrite_one(self, rewrite_to, NULL, FALSE, US"",
2424   global_rewrite_rules);
2425
2426
2427 if (!self_from) self_from = self;
2428 if (self_to) self_to = self;
2429
2430 /* If there's a prefix or suffix set, we must include the prefixed/
2431 suffixed version of the local part in the tests. */
2432
2433 if (deliver_localpart_prefix || deliver_localpart_suffix)
2434   {
2435   psself = string_sprintf("%s%s%s@%s",
2436     deliver_localpart_prefix ? deliver_localpart_prefix : US"",
2437     deliver_localpart,
2438     deliver_localpart_suffix ? deliver_localpart_suffix : US"",
2439     deliver_domain);
2440   psself_from = rewrite_one(psself, rewrite_from, NULL, FALSE, US"",
2441     global_rewrite_rules);
2442   psself_to   = rewrite_one(psself, rewrite_to, NULL, FALSE, US"",
2443     global_rewrite_rules);
2444   if (psself_from == NULL) psself_from = psself;
2445   if (psself_to == NULL) psself_to = psself;
2446   to_count += 2;
2447   from_count += 2;
2448   }
2449
2450 /* Do all the necessary tests; the counts are adjusted for {pre,suf}fix */
2451
2452 yield =
2453   (
2454   header_match(US"to:", TRUE, TRUE, aliases, to_count, self, self_to, psself,
2455                psself_to) ||
2456     (scan_cc &&
2457        (
2458        header_match(US"cc:", TRUE, TRUE, aliases, to_count, self, self_to,
2459                              psself, psself_to)
2460        ||
2461        header_match(US"bcc:", TRUE, TRUE, aliases, to_count, self, self_to,
2462                               psself, psself_to)
2463        )
2464     )
2465   ) &&
2466
2467   header_match(US"from:", TRUE, FALSE, aliases, from_count, "^server@",
2468     "^daemon@", "^root@", "^listserv@", "^majordomo@", "^.*?-request@",
2469     "^owner-[^@]+@", self, self_from, psself, psself_from) &&
2470
2471   header_match(US"precedence:", FALSE, FALSE, NULL, 3, "bulk","list","junk") &&
2472
2473   (sender_address == NULL || sender_address[0] != 0);
2474
2475 store_reset(reset_point);
2476 return yield;
2477 }
2478
2479
2480
2481 /*************************************************
2482 *            Interpret a mail filter file        *
2483 *************************************************/
2484
2485 /*
2486 Arguments:
2487   filter      points to the entire file, read into store as a single string
2488   options     controls whether various special things are allowed, and requests
2489               special actions
2490   generated   where to hang newly-generated addresses
2491   error       where to pass back an error text
2492
2493 Returns:      FF_DELIVERED     success, a significant action was taken
2494               FF_NOTDELIVERED  success, no significant action
2495               FF_DEFER         defer requested
2496               FF_FAIL          fail requested
2497               FF_FREEZE        freeze requested
2498               FF_ERROR         there was a problem
2499 */
2500
2501 int
2502 filter_interpret(const uschar *filter, int options, address_item **generated,
2503   uschar **error)
2504 {
2505 int i;
2506 int yield = FF_ERROR;
2507 const uschar *ptr = filter;
2508 const uschar *save_headers_charset = headers_charset;
2509 filter_cmd *commands = NULL;
2510 filter_cmd **lastcmdptr = &commands;
2511
2512 DEBUG(D_route) debug_printf("Filter: start of processing\n");
2513 acl_level++;
2514
2515 /* Initialize "not in an if command", set the global flag that is always TRUE
2516 while filtering, and zero the variables. */
2517
2518 expect_endif = 0;
2519 output_indent = 0;
2520 f.filter_running = TRUE;
2521 for (i = 0; i < FILTER_VARIABLE_COUNT; i++) filter_n[i] = 0;
2522
2523 /* To save having to pass certain values about all the time, make them static.
2524 Also initialize the line number, for error messages, and the log file
2525 variables. */
2526
2527 filter_options = options;
2528 filter_delivered = FALSE;
2529 finish_obeyed = FALSE;
2530 error_pointer = error;
2531 *error_pointer = NULL;
2532 line_number = 1;
2533 log_fd = -1;
2534 log_mode = 0600;
2535 log_filename = NULL;
2536
2537 /* Scan filter file for syntax and build up an interpretation thereof, and
2538 interpret the compiled commands, and if testing, say whether we ended up
2539 delivered or not, unless something went wrong. */
2540
2541 seen_force = FALSE;
2542 ptr = nextsigchar(ptr, TRUE);
2543
2544 if (read_command_list(&ptr, &lastcmdptr, FALSE))
2545   yield = interpret_commands(commands, generated);
2546
2547 if (filter_test != FTEST_NONE || (debug_selector & D_filter) != 0)
2548   {
2549   uschar *s = US"";
2550   switch(yield)
2551     {
2552     case FF_DEFER:
2553       s = US"Filtering ended by \"defer\".";
2554       break;
2555
2556     case FF_FREEZE:
2557       s = US"Filtering ended by \"freeze\".";
2558       break;
2559
2560     case FF_FAIL:
2561       s = US"Filtering ended by \"fail\".";
2562       break;
2563
2564     case FF_DELIVERED:
2565       s = US"Filtering set up at least one significant delivery "
2566              "or other action.\n"
2567              "No other deliveries will occur.";
2568       break;
2569
2570     case FF_NOTDELIVERED:
2571       s = US"Filtering did not set up a significant delivery.\n"
2572              "Normal delivery will occur.";
2573       break;
2574
2575     case FF_ERROR:
2576       s = string_sprintf("Filter error: %s", *error);
2577       break;
2578     }
2579
2580   if (filter_test != FTEST_NONE) printf("%s\n", CS s);
2581     else debug_printf_indent("%s\n", s);
2582   }
2583
2584 /* Close the log file if it was opened, and kill off any numerical variables
2585 before returning. Reset the header decoding charset. */
2586
2587 if (log_fd >= 0) (void)close(log_fd);
2588 expand_nmax = -1;
2589 f.filter_running = FALSE;
2590 headers_charset = save_headers_charset;
2591
2592 acl_level--;
2593 DEBUG(D_route) debug_printf("Filter: end of processing\n");
2594 return yield;
2595 }
2596
2597
2598 /* End of filter.c */