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