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