Testsuite: fix munge for mailq
[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 /* 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 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 != NULL)? " errors_to " : "",
1825           (s != NULL)? 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 != NULL)? " errors_to " : "",
1837           (s != NULL)? 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", (commands->seen)?
1862             "S" : "Unseen s", s, commands->noerror? " (noerror)" : "");
1863         else
1864           printf("%save message to: %s %04o%s\n", (commands->seen)?
1865             "S" : "Unseen s", s, mode, commands->noerror? " (noerror)" : "");
1866         }
1867
1868       /* Real case: Ensure save argument starts with / if there is a home
1869       directory to prepend. */
1870
1871       else
1872         {
1873         if (s[0] != '/' && (filter_options & RDO_PREPEND_HOME) != 0 &&
1874             deliver_home != NULL && deliver_home[0] != 0)
1875           s = string_sprintf("%s/%s", deliver_home, s);
1876         DEBUG(D_filter) debug_printf_indent("Filter: %ssave message to: %s%s\n",
1877           (commands->seen)? "" : "unseen ", s,
1878           commands->noerror? " (noerror)" : "");
1879
1880         /* Create the new address and add it to the chain, setting the
1881         af_pfr and af_file flags, the af_ignore_error flag if necessary, and the
1882         mode value. */
1883
1884         addr = deliver_make_addr(US s, TRUE);  /* TRUE => copy s, so deconst ok */
1885         setflag(addr, af_pfr);
1886         setflag(addr, af_file);
1887         if (commands->noerror) addr->prop.ignore_error = TRUE;
1888         addr->mode = mode;
1889         addr->next = *generated;
1890         *generated = addr;
1891         }
1892       break;
1893
1894     case PIPE_COMMAND:
1895       s = string_copy(commands->args[0].u);
1896       if (filter_test != FTEST_NONE)
1897         {
1898         indent();
1899         printf("%sipe message to: %s%s\n", (commands->seen)?
1900           "P" : "Unseen p", s, commands->noerror? " (noerror)" : "");
1901         }
1902       else /* Ensure pipe command starts with | */
1903         {
1904         DEBUG(D_filter) debug_printf_indent("Filter: %spipe message to: %s%s\n",
1905           commands->seen ? "" : "unseen ", s,
1906           commands->noerror ? " (noerror)" : "");
1907         if (s[0] != '|') s = string_sprintf("|%s", s);
1908
1909         /* Create the new address and add it to the chain, setting the
1910         af_ignore_error flag if necessary. Set the af_expand_pipe flag so that
1911         each command argument is expanded in the transport after the command
1912         has been split up into separate arguments. */
1913
1914         addr = deliver_make_addr(US s, TRUE);  /* TRUE => copy s, so deconst ok */
1915         setflag(addr, af_pfr);
1916         setflag(addr, af_expand_pipe);
1917         if (commands->noerror) addr->prop.ignore_error = TRUE;
1918         addr->next = *generated;
1919         *generated = addr;
1920
1921         /* If there are any numeric variables in existence (e.g. after a regex
1922         condition), or if $thisaddress is set, take a copy for use in the
1923         expansion. Note that we can't pass NULL for filter_thisaddress, because
1924         NULL terminates the list. */
1925
1926         if (expand_nmax >= 0 || filter_thisaddress != NULL)
1927           {
1928           int ecount = expand_nmax >= 0 ? expand_nmax : -1;
1929           uschar ** ss = store_get(sizeof(uschar *) * (ecount + 3), GET_UNTAINTED);
1930
1931           addr->pipe_expandn = ss;
1932           if (!filter_thisaddress) filter_thisaddress = US"";
1933           *ss++ = string_copy(filter_thisaddress);
1934           for (int i = 0; i <= expand_nmax; i++)
1935             *ss++ = string_copyn(expand_nstring[i], expand_nlength[i]);
1936           *ss = NULL;
1937           }
1938         }
1939       break;
1940
1941       /* Set up the file name and mode, and close any previously open
1942       file. */
1943
1944     case LOGFILE_COMMAND:
1945       log_mode = commands->args[1].i;
1946       if (log_mode == -1) log_mode = 0600;
1947       if (log_fd >= 0)
1948         {
1949         (void)close(log_fd);
1950         log_fd = -1;
1951         }
1952       log_filename = expargs[0];
1953       if (filter_test != FTEST_NONE)
1954         {
1955         indent();
1956         printf("%sogfile %s\n", (commands->seen)? "Seen l" : "L", log_filename);
1957         }
1958       break;
1959
1960     case LOGWRITE_COMMAND:
1961       s = expargs[0];
1962
1963       if (filter_test != FTEST_NONE)
1964         {
1965         indent();
1966         printf("%sogwrite \"%s\"\n", (commands->seen)? "Seen l" : "L",
1967           string_printing(s));
1968         }
1969
1970       /* Attempt to write to a log file only if configured as permissible.
1971       Logging may be forcibly skipped for verifying or testing. */
1972
1973       else if ((filter_options & RDO_LOG) != 0)   /* Locked out */
1974         {
1975         DEBUG(D_filter)
1976           debug_printf_indent("filter log command aborted: euid=%ld\n",
1977           (long int)geteuid());
1978         *error_pointer = US"logwrite command forbidden";
1979         return FF_ERROR;
1980         }
1981       else if ((filter_options & RDO_REALLOG) != 0)
1982         {
1983         int len;
1984         DEBUG(D_filter) debug_printf_indent("writing filter log as euid %ld\n",
1985           (long int)geteuid());
1986         if (log_fd < 0)
1987           {
1988           if (!log_filename)
1989             {
1990             *error_pointer = US"attempt to obey \"logwrite\" command "
1991               "without a previous \"logfile\"";
1992             return FF_ERROR;
1993             }
1994           log_fd = Uopen(log_filename, O_CREAT|O_APPEND|O_WRONLY, log_mode);
1995           if (log_fd < 0)
1996             {
1997             *error_pointer = string_open_failed("filter log file \"%s\"",
1998               log_filename);
1999             return FF_ERROR;
2000             }
2001           }
2002         len = Ustrlen(s);
2003         if (write(log_fd, s, len) != len)
2004           {
2005           *error_pointer = string_sprintf("write error on file \"%s\": %s",
2006             log_filename, strerror(errno));
2007           return FF_ERROR;
2008           }
2009         }
2010       else
2011         DEBUG(D_filter)
2012           debug_printf_indent("skipping logwrite (verifying or testing)\n");
2013       break;
2014
2015       /* Header addition and removal is available only in the system filter. The
2016       command is rejected at parse time otherwise. However "headers charset" is
2017       always permitted. */
2018
2019     case HEADERS_COMMAND:
2020         {
2021         int subtype = commands->args[1].i;
2022         s = expargs[0];
2023
2024         if (filter_test != FTEST_NONE)
2025           printf("Headers %s \"%s\"\n",
2026             subtype == TRUE ? "add"
2027             : subtype == FALSE ? "remove"
2028             : "charset",
2029             string_printing(s));
2030
2031         if (subtype == TRUE)
2032           {
2033           if (Uskip_whitespace(&s))
2034             {
2035             header_add(htype_other, "%s%s", s,
2036               s[Ustrlen(s)-1] == '\n' ? "" : "\n");
2037             header_last->type = header_checkname(header_last, FALSE);
2038             if (header_last->type >= 'a') header_last->type = htype_other;
2039             }
2040           }
2041
2042         else if (subtype == FALSE)
2043           {
2044           int sep = 0;
2045           const uschar * list = s;
2046
2047           for (uschar * ss; ss = string_nextinlist(&list, &sep, NULL, 0); )
2048             header_remove(0, ss);
2049           }
2050
2051         /* This setting lasts only while the filter is running; on exit, the
2052         variable is reset to the previous value. */
2053
2054         else headers_charset = s;
2055         }
2056       break;
2057
2058       /* Defer, freeze, and fail are available only when explicitly permitted.
2059       These commands are rejected at parse time otherwise. The message can get
2060       very long by the inclusion of message headers; truncate if it is, and also
2061       ensure printing characters so as not to mess up log files. */
2062
2063     case DEFER_COMMAND:
2064       ff_name = US"defer";
2065       ff_ret = FF_DEFER;
2066       goto DEFERFREEZEFAIL;
2067
2068     case FAIL_COMMAND:
2069       ff_name = US"fail";
2070       ff_ret = FF_FAIL;
2071       goto DEFERFREEZEFAIL;
2072
2073     case FREEZE_COMMAND:
2074       ff_name = US"freeze";
2075       ff_ret = FF_FREEZE;
2076
2077     DEFERFREEZEFAIL:
2078       *error_pointer = fmsg = US string_printing(Ustrlen(expargs[0]) > 1024
2079         ? string_sprintf("%.1000s ... (truncated)", expargs[0])
2080         : string_copy(expargs[0]));
2081       for(uschar * s = fmsg; *s; s++)
2082         if (!s[1] && *s == '\n') { *s = '\0'; break; }  /* drop trailing newline */
2083
2084       if (filter_test != FTEST_NONE)
2085         {
2086         indent();
2087         printf("%c%s text \"%s\"\n", toupper(ff_name[0]), ff_name+1, fmsg);
2088         }
2089       else
2090         DEBUG(D_filter) debug_printf_indent("Filter: %s \"%s\"\n", ff_name, fmsg);
2091       return ff_ret;
2092
2093     case FINISH_COMMAND:
2094       if (filter_test != FTEST_NONE)
2095         {
2096         indent();
2097         printf("%sinish\n", (commands->seen)? "Seen f" : "F");
2098         }
2099       else
2100         DEBUG(D_filter) debug_printf_indent("Filter: %sfinish\n",
2101           commands->seen ? " Seen " : "");
2102       finish_obeyed = TRUE;
2103       return filter_delivered ? FF_DELIVERED : FF_NOTDELIVERED;
2104
2105     case IF_COMMAND:
2106         {
2107         uschar *save_address = filter_thisaddress;
2108         int ok = FF_DELIVERED;
2109         condition_value = test_condition(commands->args[0].c, TRUE);
2110         if (*error_pointer)
2111           ok = FF_ERROR;
2112         else
2113           {
2114           output_indent += 2;
2115           ok = interpret_commands(commands->args[condition_value? 1:2].f,
2116             generated);
2117           output_indent -= 2;
2118           }
2119         filter_thisaddress = save_address;
2120         if (finish_obeyed  ||  ok != FF_DELIVERED && ok != FF_NOTDELIVERED)
2121           return ok;
2122         }
2123       break;
2124
2125
2126       /* To try to catch runaway loops, do not generate mail if the
2127       return path is unset or if a non-trusted user supplied -f <>
2128       as the return path. */
2129
2130     case MAIL_COMMAND:
2131     case VACATION_COMMAND:
2132         if (!return_path || !*return_path)
2133           {
2134           if (filter_test != FTEST_NONE)
2135             printf("%s command ignored because return_path is empty\n",
2136               command_list[commands->command]);
2137           else DEBUG(D_filter) debug_printf_indent("%s command ignored because return_path "
2138             "is empty\n", command_list[commands->command]);
2139           break;
2140           }
2141
2142         /* Check the contents of the strings. The type of string can be deduced
2143         from the value of i.
2144
2145         . If i is equal to mailarg_index_text it's a text string for the body,
2146           where anything goes.
2147
2148         . If i is > mailarg_index_text, we are dealing with a file name, which
2149           cannot contain non-printing characters.
2150
2151         . If i is less than mailarg_index_headers we are dealing with something
2152           that will go in a single message header line, where newlines must be
2153           followed by white space.
2154
2155         . If i is equal to mailarg_index_headers, we have a string that contains
2156           one or more headers. Newlines that are not followed by white space must
2157           be followed by a header name.
2158         */
2159
2160         for (i = 0; i < MAILARGS_STRING_COUNT; i++)
2161           {
2162           const uschar *s = expargs[i];
2163
2164           if (!s) continue;
2165
2166           if (i != mailarg_index_text) for (const uschar * p = s; *p; p++)
2167             {
2168             int c = *p;
2169             if (i > mailarg_index_text)
2170               {
2171               if (!mac_isprint(c))
2172                 {
2173                 *error_pointer = string_sprintf("non-printing character in \"%s\" "
2174                   "in %s command", string_printing(s),
2175                   command_list[commands->command]);
2176                 return FF_ERROR;
2177                 }
2178               }
2179
2180             /* i < mailarg_index_text */
2181
2182             else if (c == '\n' && !isspace(p[1]))
2183               {
2184               if (i < mailarg_index_headers)
2185                 {
2186                 *error_pointer = string_sprintf("\\n not followed by space in "
2187                   "\"%.1024s\" in %s command", string_printing(s),
2188                   command_list[commands->command]);
2189                 return FF_ERROR;
2190                 }
2191
2192               /* Check for the start of a new header line within the string */
2193
2194               else
2195                 {
2196                 const uschar *pp;
2197                 for (pp = p + 1;; pp++)
2198                   {
2199                   c = *pp;
2200                   if (c == ':' && pp != p + 1) break;
2201                   if (!c || c == ':' || isspace(c))
2202                     {
2203                     *error_pointer = string_sprintf("\\n not followed by space or "
2204                       "valid header name in \"%.1024s\" in %s command",
2205                       string_printing(s), command_list[commands->command]);
2206                     return FF_ERROR;
2207                     }
2208                   }
2209                 p = pp;
2210                 }
2211               }
2212             }       /* Loop to scan the string */
2213
2214           /* The string is OK */
2215
2216           commands->args[i].u = s;
2217           }
2218
2219         /* Proceed with mail or vacation command */
2220
2221         if (filter_test != FTEST_NONE)
2222           {
2223           const uschar *to = commands->args[mailarg_index_to].u;
2224           indent();
2225           printf("%sail to: %s%s%s\n", (commands->seen)? "Seen m" : "M",
2226             to ? to : US"<default>",
2227             commands->command == VACATION_COMMAND ? " (vacation)" : "",
2228             commands->noerror ? " (noerror)" : "");
2229           for (i = 1; i < MAILARGS_STRING_COUNT; i++)
2230             {
2231             const uschar *arg = commands->args[i].u;
2232             if (arg)
2233               {
2234               int len = Ustrlen(mailargs[i]);
2235               int indent = (debug_selector != 0)? output_indent : 0;
2236               while (len++ < 7 + indent) printf(" ");
2237               printf("%s: %s%s\n", mailargs[i], string_printing(arg),
2238                 (commands->args[mailarg_index_expand].u != NULL &&
2239                   Ustrcmp(mailargs[i], "file") == 0)? " (expanded)" : "");
2240               }
2241             }
2242           if (commands->args[mailarg_index_return].u)
2243             printf("Return original message\n");
2244           }
2245         else
2246           {
2247           const uschar *tt;
2248           const uschar *to = commands->args[mailarg_index_to].u;
2249           gstring * log_addr = NULL;
2250
2251           if (!to) to = expand_string(US"$reply_address");
2252           Uskip_whitespace(&to);
2253
2254           for (tt = to; *tt; tt++)     /* Get rid of newlines */
2255             if (*tt == '\n')
2256               {
2257               uschar * s = string_copy(to);
2258               for (uschar * ss = s; *ss; ss++)
2259                 if (*ss == '\n') *ss = ' ';
2260               to = s;
2261               break;
2262               }
2263
2264           DEBUG(D_filter)
2265             {
2266             debug_printf_indent("Filter: %smail to: %s%s%s\n",
2267               commands->seen ? "seen " : "",
2268               to,
2269               commands->command == VACATION_COMMAND ? " (vacation)" : "",
2270               commands->noerror ? " (noerror)" : "");
2271             for (i = 1; i < MAILARGS_STRING_COUNT; i++)
2272               {
2273               const uschar *arg = commands->args[i].u;
2274               if (arg)
2275                 {
2276                 int len = Ustrlen(mailargs[i]);
2277                 while (len++ < 15) debug_printf_indent(" ");
2278                 debug_printf_indent("%s: %s%s\n", mailargs[i], string_printing(arg),
2279                   (commands->args[mailarg_index_expand].u != NULL &&
2280                     Ustrcmp(mailargs[i], "file") == 0)? " (expanded)" : "");
2281                 }
2282               }
2283             }
2284
2285           /* Create the "address" for the autoreply. This is used only for logging,
2286           as the actual recipients are extracted from the To: line by -t. We use the
2287           same logic here to extract the working addresses (there may be more than
2288           one). Just in case there are a vast number of addresses, stop when the
2289           string gets too long. */
2290
2291           tt = to;
2292           while (*tt)
2293             {
2294             uschar *ss = parse_find_address_end(tt, FALSE);
2295             uschar *recipient, *errmess;
2296             int start, end, domain;
2297             int temp = *ss;
2298
2299             *ss = 0;
2300             recipient = parse_extract_address(tt, &errmess, &start, &end, &domain,
2301               FALSE);
2302             *ss = temp;
2303
2304             /* Ignore empty addresses and errors; an error will occur later if
2305             there's something really bad. */
2306
2307             if (recipient)
2308               {
2309               log_addr = string_catn(log_addr, log_addr ? US"," : US">", 1);
2310               log_addr = string_cat (log_addr, recipient);
2311               }
2312
2313             /* Check size */
2314
2315             if (log_addr && log_addr->ptr > 256)
2316               {
2317               log_addr = string_catn(log_addr, US", ...", 5);
2318               break;
2319               }
2320
2321             /* Move on past this address */
2322
2323             tt = ss + (*ss ? 1 : 0);
2324             Uskip_whitespace(&tt);
2325             }
2326
2327           if (log_addr)
2328             addr = deliver_make_addr(string_from_gstring(log_addr), FALSE);
2329           else
2330             {
2331             addr = deliver_make_addr(US ">**bad-reply**", FALSE);
2332             setflag(addr, af_bad_reply);
2333             }
2334
2335           setflag(addr, af_pfr);
2336           if (commands->noerror) addr->prop.ignore_error = TRUE;
2337           addr->next = *generated;
2338           *generated = addr;
2339
2340           addr->reply = store_get(sizeof(reply_item), GET_UNTAINTED);
2341           addr->reply->from = NULL;
2342           addr->reply->to = string_copy(to);
2343           addr->reply->file_expand =
2344             commands->args[mailarg_index_expand].u != NULL;
2345           addr->reply->expand_forbid = expand_forbid;
2346           addr->reply->return_message =
2347             commands->args[mailarg_index_return].u != NULL;
2348           addr->reply->once_repeat = 0;
2349
2350           if (commands->args[mailarg_index_once_repeat].u != NULL)
2351             {
2352             addr->reply->once_repeat =
2353               readconf_readtime(commands->args[mailarg_index_once_repeat].u, 0,
2354                 FALSE);
2355             if (addr->reply->once_repeat < 0)
2356               {
2357               *error_pointer = string_sprintf("Bad time value for \"once_repeat\" "
2358                 "in mail or vacation command: %s",
2359                 commands->args[mailarg_index_once_repeat].u);
2360               return FF_ERROR;
2361               }
2362             }
2363
2364           /* Set up all the remaining string arguments (those other than "to") */
2365
2366           for (i = 1; i < mailargs_string_passed; i++)
2367             {
2368             const uschar *ss = commands->args[i].u;
2369             *(USS((US addr->reply) + reply_offsets[i])) =
2370               ss ? string_copy(ss) : NULL;
2371             }
2372           }
2373         break;
2374
2375     case TESTPRINT_COMMAND:
2376         if (filter_test != FTEST_NONE || (debug_selector & D_filter) != 0)
2377           {
2378           const uschar *s = string_printing(expargs[0]);
2379           if (filter_test == FTEST_NONE)
2380             debug_printf_indent("Filter: testprint: %s\n", s);
2381           else
2382             printf("Testprint: %s\n", s);
2383           }
2384     }
2385
2386   commands = commands->next;
2387   }
2388
2389 return filter_delivered ? FF_DELIVERED : FF_NOTDELIVERED;
2390 }
2391
2392
2393
2394 /*************************************************
2395 *        Test for a personal message             *
2396 *************************************************/
2397
2398 /* This function is global so that it can also be called from the code that
2399 implements Sieve filters.
2400
2401 Arguments:
2402   aliases    a chain of aliases
2403   scan_cc    TRUE if Cc: and Bcc: are to be scanned (Exim filters do not)
2404
2405 Returns:     TRUE if the message is deemed to be personal
2406 */
2407
2408 BOOL
2409 filter_personal(string_item *aliases, BOOL scan_cc)
2410 {
2411 const uschar *self, *self_from, *self_to;
2412 uschar *psself = NULL;
2413 const uschar *psself_from = NULL, *psself_to = NULL;
2414 rmark reset_point = store_mark();
2415 BOOL yield;
2416 header_line *h;
2417 int to_count = 2;
2418 int from_count = 9;
2419
2420 /* If any header line in the message is a defined "List-" header field, it is
2421 not a personal message. We used to check for any header line that started with
2422 "List-", but this was tightened up for release 4.54. The check is now for
2423 "List-Id", defined in RFC 2929, or "List-Help", "List-Subscribe", "List-
2424 Unsubscribe", "List-Post", "List-Owner" or "List-Archive", all of which are
2425 defined in RFC 2369. We also scan for "Auto-Submitted"; if it is found to
2426 contain any value other than "no", the message is not personal (RFC 3834).
2427 Previously the test was for "auto-". */
2428
2429 for (h = header_list; h; h = h->next)
2430   {
2431   if (h->type == htype_old) continue;
2432
2433   if (strncmpic(h->text, US"List-", 5) == 0)
2434     {
2435     uschar * s = h->text + 5;
2436     if (strncmpic(s, US"Id:", 3) == 0 ||
2437         strncmpic(s, US"Help:", 5) == 0 ||
2438         strncmpic(s, US"Subscribe:", 10) == 0 ||
2439         strncmpic(s, US"Unsubscribe:", 12) == 0 ||
2440         strncmpic(s, US"Post:", 5) == 0 ||
2441         strncmpic(s, US"Owner:", 6) == 0 ||
2442         strncmpic(s, US"Archive:", 8) == 0)
2443       return FALSE;
2444     }
2445
2446   else if (strncmpic(h->text, US"Auto-submitted:", 15) == 0)
2447     {
2448     uschar * s = h->text + 15;
2449     Uskip_whitespace(&s);
2450     if (strncmpic(s, US"no", 2) != 0) return FALSE;
2451     s += 2;
2452     Uskip_whitespace(&s);
2453     if (*s) return FALSE;
2454     }
2455   }
2456
2457 /* Set up "my" address */
2458
2459 self = string_sprintf("%s@%s", deliver_localpart, deliver_domain);
2460 self_from = rewrite_one(self, rewrite_from, NULL, FALSE, US"",
2461   global_rewrite_rules);
2462 self_to   = rewrite_one(self, rewrite_to, NULL, FALSE, US"",
2463   global_rewrite_rules);
2464
2465
2466 if (!self_from) self_from = self;
2467 if (self_to) self_to = self;
2468
2469 /* If there's a prefix or suffix set, we must include the prefixed/
2470 suffixed version of the local part in the tests. */
2471
2472 if (deliver_localpart_prefix || deliver_localpart_suffix)
2473   {
2474   psself = string_sprintf("%s%s%s@%s",
2475     deliver_localpart_prefix ? deliver_localpart_prefix : US"",
2476     deliver_localpart,
2477     deliver_localpart_suffix ? deliver_localpart_suffix : US"",
2478     deliver_domain);
2479   psself_from = rewrite_one(psself, rewrite_from, NULL, FALSE, US"",
2480     global_rewrite_rules);
2481   psself_to   = rewrite_one(psself, rewrite_to, NULL, FALSE, US"",
2482     global_rewrite_rules);
2483   if (psself_from == NULL) psself_from = psself;
2484   if (psself_to == NULL) psself_to = psself;
2485   to_count += 2;
2486   from_count += 2;
2487   }
2488
2489 /* Do all the necessary tests; the counts are adjusted for {pre,suf}fix */
2490
2491 yield =
2492   (
2493   header_match(US"to:", TRUE, TRUE, aliases, to_count, self, self_to, psself,
2494                psself_to) ||
2495     (scan_cc &&
2496        (
2497        header_match(US"cc:", TRUE, TRUE, aliases, to_count, self, self_to,
2498                              psself, psself_to)
2499        ||
2500        header_match(US"bcc:", TRUE, TRUE, aliases, to_count, self, self_to,
2501                               psself, psself_to)
2502        )
2503     )
2504   ) &&
2505
2506   header_match(US"from:", TRUE, FALSE, aliases, from_count, "^server@",
2507     "^daemon@", "^root@", "^listserv@", "^majordomo@", "^.*?-request@",
2508     "^owner-[^@]+@", self, self_from, psself, psself_from) &&
2509
2510   header_match(US"precedence:", FALSE, FALSE, NULL, 3, "bulk","list","junk") &&
2511
2512   (sender_address == NULL || sender_address[0] != 0);
2513
2514 store_reset(reset_point);
2515 return yield;
2516 }
2517
2518
2519
2520 /*************************************************
2521 *            Interpret a mail filter file        *
2522 *************************************************/
2523
2524 /*
2525 Arguments:
2526   filter      points to the entire file, read into store as a single string
2527   options     controls whether various special things are allowed, and requests
2528               special actions
2529   generated   where to hang newly-generated addresses
2530   error       where to pass back an error text
2531
2532 Returns:      FF_DELIVERED     success, a significant action was taken
2533               FF_NOTDELIVERED  success, no significant action
2534               FF_DEFER         defer requested
2535               FF_FAIL          fail requested
2536               FF_FREEZE        freeze requested
2537               FF_ERROR         there was a problem
2538 */
2539
2540 int
2541 filter_interpret(const uschar *filter, int options, address_item **generated,
2542   uschar **error)
2543 {
2544 int i;
2545 int yield = FF_ERROR;
2546 const uschar *ptr = filter;
2547 const uschar *save_headers_charset = headers_charset;
2548 filter_cmd *commands = NULL;
2549 filter_cmd **lastcmdptr = &commands;
2550
2551 DEBUG(D_route) debug_printf("Filter: start of processing\n");
2552 acl_level++;
2553
2554 /* Initialize "not in an if command", set the global flag that is always TRUE
2555 while filtering, and zero the variables. */
2556
2557 expect_endif = 0;
2558 output_indent = 0;
2559 f.filter_running = TRUE;
2560 for (i = 0; i < FILTER_VARIABLE_COUNT; i++) filter_n[i] = 0;
2561
2562 /* To save having to pass certain values about all the time, make them static.
2563 Also initialize the line number, for error messages, and the log file
2564 variables. */
2565
2566 filter_options = options;
2567 filter_delivered = FALSE;
2568 finish_obeyed = FALSE;
2569 error_pointer = error;
2570 *error_pointer = NULL;
2571 line_number = 1;
2572 log_fd = -1;
2573 log_mode = 0600;
2574 log_filename = NULL;
2575
2576 /* Scan filter file for syntax and build up an interpretation thereof, and
2577 interpret the compiled commands, and if testing, say whether we ended up
2578 delivered or not, unless something went wrong. */
2579
2580 seen_force = FALSE;
2581 ptr = nextsigchar(ptr, TRUE);
2582
2583 if (read_command_list(&ptr, &lastcmdptr, FALSE))
2584   yield = interpret_commands(commands, generated);
2585
2586 if (filter_test != FTEST_NONE || (debug_selector & D_filter) != 0)
2587   {
2588   uschar *s = US"";
2589   switch(yield)
2590     {
2591     case FF_DEFER:
2592       s = US"Filtering ended by \"defer\".";
2593       break;
2594
2595     case FF_FREEZE:
2596       s = US"Filtering ended by \"freeze\".";
2597       break;
2598
2599     case FF_FAIL:
2600       s = US"Filtering ended by \"fail\".";
2601       break;
2602
2603     case FF_DELIVERED:
2604       s = US"Filtering set up at least one significant delivery "
2605              "or other action.\n"
2606              "No other deliveries will occur.";
2607       break;
2608
2609     case FF_NOTDELIVERED:
2610       s = US"Filtering did not set up a significant delivery.\n"
2611              "Normal delivery will occur.";
2612       break;
2613
2614     case FF_ERROR:
2615       s = string_sprintf("Filter error: %s", *error);
2616       break;
2617     }
2618
2619   if (filter_test != FTEST_NONE) printf("%s\n", CS s);
2620     else debug_printf_indent("%s\n", s);
2621   }
2622
2623 /* Close the log file if it was opened, and kill off any numerical variables
2624 before returning. Reset the header decoding charset. */
2625
2626 if (log_fd >= 0) (void)close(log_fd);
2627 expand_nmax = -1;
2628 f.filter_running = FALSE;
2629 headers_charset = save_headers_charset;
2630
2631 acl_level--;
2632 DEBUG(D_route) debug_printf("Filter: end of processing\n");
2633 return yield;
2634 }
2635
2636
2637 /* End of filter.c */
2638 /* vi: aw ai sw=2
2639 */