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