Doc: Improve clarity on -be
[exim.git] / src / src / filter.c
index e551abef86decbfeb7ee42e41d579583ebca1ad1..bba1a520e7c2e18094d0e46905aa3a04eb46efa1 100644 (file)
@@ -1,10 +1,8 @@
-/* $Cambridge: exim/src/src/filter.c,v 1.6 2005/11/10 15:00:46 ph10 Exp $ */
-
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2005 */
+/* Copyright (c) University of Cambridge 1995 - 2015 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 
@@ -76,8 +74,8 @@ permitted to include \n followed by white space) first, and then the body text
 one (it can have \n anywhere). Then the file names and once_repeat, which may
 not contain \n. */
 
-static char *mailargs[] = {  /* "to" must be first, and */
-  "to",                      /* "cc" and "bcc" must follow */
+static const char *mailargs[] = {  /* "to" must be first, and */
+  "to",                            /* "cc" and "bcc" must follow */
   "cc",
   "bcc",
   "from",
@@ -146,14 +144,14 @@ enum { cond_and, cond_or, cond_personal, cond_begins, cond_BEGINS,
        cond_above, cond_below, cond_errormsg, cond_firsttime,
        cond_manualthaw, cond_foranyaddress };
 
-static char *cond_names[] = {
+static const char *cond_names[] = {
   "and", "or", "personal",
   "begins", "BEGINS", "ends", "ENDS",
   "is", "IS", "matches", "MATCHES", "contains",
   "CONTAINS", "delivered", "above", "below", "error_message",
   "first_delivery", "manually_thawed", "foranyaddress" };
 
-static char *cond_not_names[] = {
+static const char *cond_not_names[] = {
   "", "", "not personal",
   "does not begin", "does not BEGIN",
   "does not end", "does not END",
@@ -165,7 +163,7 @@ static char *cond_not_names[] = {
 /* Tables of binary condition words and their corresponding types. Not easy
 to amalgamate with the above because of the different variants. */
 
-static char *cond_words[] = {
+static const char *cond_words[] = {
    "BEGIN",
    "BEGINS",
    "CONTAIN",
@@ -203,7 +201,7 @@ enum { add_command, defer_command, deliver_command, elif_command, else_command,
        mail_command, noerror_command, pipe_command, save_command, seen_command,
        testprint_command, unseen_command, vacation_command };
 
-static char *command_list[] = {
+static const char *command_list[] = {
   "add",     "defer",   "deliver", "elif", "else",      "endif",    "finish",
   "fail",    "freeze",  "headers", "if",   "logfile",   "logwrite", "mail",
   "noerror", "pipe",    "save",    "seen", "testprint", "unseen",   "vacation"
@@ -357,7 +355,7 @@ while (*(++ptr) != 0 && *ptr != '\"' && *ptr != '\n')
         }
       }
 
-    *bp++ = string_interpret_escape(&ptr);
+    *bp++ = string_interpret_escape(CUSS &ptr);
     }
   }
 
@@ -777,7 +775,7 @@ Returns:      nothing
 static void
 print_condition(condition_block *c, BOOL toplevel)
 {
-char *name = (c->testfor)? cond_names[c->type] : cond_not_names[c->type];
+const char *name = (c->testfor)? cond_names[c->type] : cond_not_names[c->type];
 switch(c->type)
   {
   case cond_personal:
@@ -800,7 +798,7 @@ switch(c->type)
   case cond_ENDS:
   case cond_above:
   case cond_below:
-  debug_printf("%s %s %s", c->left.u, (char *)name, c->right.u);
+  debug_printf("%s %s %s", c->left.u, name, c->right.u);
   break;
 
   case cond_and:
@@ -1044,6 +1042,13 @@ switch (command)
   case elif_command:
   case else_command:
   case endif_command:
+  if (seen_force || noerror_force)
+    {
+    *error_pointer = string_sprintf("\"seen\", \"unseen\", or \"noerror\" "
+      "near line %d is not followed by a command", line_number);
+    yield = FALSE;
+    }
+
   if (expect_endif > 0)
     had_else_endif = (command == elif_command)? had_elif :
                      (command == else_command)? had_else : had_endif;
@@ -1316,6 +1321,12 @@ switch (command)
 
   case seen_command:
   case unseen_command:
+  if (*ptr == 0)
+    {
+    *error_pointer = string_sprintf("\"seen\" or \"unseen\" "
+      "near line %d is not followed by a command", line_number);
+    yield = FALSE;
+    }
   if (seen_force)
     {
     *error_pointer = string_sprintf("\"seen\" or \"unseen\" repeated "
@@ -1331,6 +1342,12 @@ switch (command)
   /* So does noerror */
 
   case noerror_command:
+  if (*ptr == 0)
+    {
+    *error_pointer = string_sprintf("\"noerror\" "
+      "near line %d is not followed by a command", line_number);
+    yield = FALSE;
+    }
   noerror_force = TRUE;
   was_noerror = TRUE;
   break;
@@ -1414,7 +1431,7 @@ Returns:         TRUE if the condition is met
 static BOOL
 test_condition(condition_block *c, BOOL toplevel)
 {
-BOOL yield;
+BOOL yield = FALSE;
 const pcre *re;
 uschar *exp[2], *p, *pp;
 const uschar *regcomp_error = NULL;
@@ -1804,7 +1821,7 @@ while (commands != NULL)
       set in a system filter and to the local address in user filters. */
 
       addr = deliver_make_addr(expargs[0], TRUE);  /* TRUE => copy s */
-      addr->p.errors_address = (s == NULL)?
+      addr->prop.errors_address = (s == NULL)?
         s : string_copy(s);                        /* Default is NULL */
       if (commands->noerror) setflag(addr, af_ignore_error);
       addr->next = *generated;
@@ -1834,11 +1851,12 @@ while (commands != NULL)
 
     else
       {
+      if (s[0] != '/' && (filter_options & RDO_PREPEND_HOME) != 0 &&
+          deliver_home != NULL && deliver_home[0] != 0)
+        s = string_sprintf("%s/%s", deliver_home, s);
       DEBUG(D_filter) debug_printf("Filter: %ssave message to: %s%s\n",
         (commands->seen)? "" : "unseen ", s,
         commands->noerror? " (noerror)" : "");
-      if (s[0] != '/' && deliver_home != NULL && deliver_home[0] != 0)
-        s = string_sprintf("%s/%s", deliver_home, s);
 
       /* Create the new address and add it to the chain, setting the
       af_pfr and af_file flags, the af_ignore_error flag if necessary, and the
@@ -2003,7 +2021,7 @@ while (commands != NULL)
         {
         int sep = 0;
         uschar *ss;
-        uschar *list = s;
+        const uschar *list = s;
         uschar buffer[128];
         while ((ss = string_nextinlist(&list, &sep, buffer, sizeof(buffer)))
                != NULL)
@@ -2039,7 +2057,7 @@ while (commands != NULL)
     DEFERFREEZEFAIL:
     fmsg = expargs[0];
     if (Ustrlen(fmsg) > 1024) Ustrcpy(fmsg + 1000, " ... (truncated)");
-    fmsg = string_printing(fmsg);
+    fmsg = US string_printing(fmsg);
     *error_pointer = fmsg;
 
     if (filter_test != FTEST_NONE)
@@ -2166,7 +2184,6 @@ while (commands != NULL)
                   string_printing(s), command_list[commands->command]);
                 return FF_ERROR;
                 }
-              pp++;
               }
             p = pp;
             }
@@ -2211,6 +2228,7 @@ while (commands != NULL)
       uschar *to = commands->args[mailarg_index_to].u;
       int size = 0;
       int ptr = 0;
+      int badflag = 0;
 
       if (to == NULL) to = expand_string(US"$reply_address");
       while (isspace(*to)) to++;
@@ -2240,9 +2258,10 @@ while (commands != NULL)
         }
 
       /* Create the "address" for the autoreply. This is used only for logging,
-      as the actual recipients are extraced from the To: line by -t. We use the
+      as the actual recipients are extracted from the To: line by -t. We use the
       same logic here to extract the working addresses (there may be more than
-      one). */
+      one). Just in case there are a vast number of addresses, stop when the
+      string gets too long. */
 
       tt = to;
       while (*tt != 0)
@@ -2268,17 +2287,29 @@ while (commands != NULL)
             Ustrlen(recipient));
           }
 
+        /* Check size */
+
+        if (ptr > 256)
+          {
+          log_addr = string_cat(log_addr, &size, &ptr, US", ...", 5);
+          break;
+          }
+
         /* Move on past this address */
 
         tt = ss + (*ss? 1:0);
         while (isspace(*tt)) tt++;
         }
 
-      if (log_addr == NULL) log_addr = string_sprintf("invalid-to-line");
-        else log_addr[ptr] = 0;
+      if (log_addr == NULL)
+        {
+        log_addr = string_sprintf(">**bad-reply**");
+        badflag = af_bad_reply;
+        }
+      else log_addr[ptr] = 0;
 
       addr = deliver_make_addr(log_addr, FALSE);
-      setflag(addr, af_pfr);
+      setflag(addr, (af_pfr|badflag));
       if (commands->noerror) setflag(addr, af_ignore_error);
       addr->next = *generated;
       *generated = addr;
@@ -2320,7 +2351,7 @@ while (commands != NULL)
     case testprint_command:
     if (filter_test != FTEST_NONE || (debug_selector & D_filter) != 0)
       {
-      uschar *s = string_printing(expargs[0]);
+      const uschar *s = string_printing(expargs[0]);
       if (filter_test == FTEST_NONE)
         debug_printf("Filter: testprint: %s\n", s);
       else