Added bool_lax{} expansion operator, which uses Router condition logic to
[exim.git] / src / src / expand.c
index 0e7d31d973afbf437de421c556621f930d334a83..9f9cbb7befffed14bd4074ac55af4b8bc2ece200 100644 (file)
@@ -1,10 +1,10 @@
-/* $Cambridge: exim/src/src/expand.c,v 1.104 2009/10/16 09:10:40 tom Exp $ */
+/* $Cambridge: exim/src/src/expand.c,v 1.107 2010/06/07 08:23:20 pdp Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2007 */
+/* Copyright (c) University of Cambridge 1995 - 2009 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 
 /* See the file NOTICE for conditions of use and distribution. */
 
 
@@ -156,6 +156,7 @@ static uschar *op_table_underscore[] = {
   US"from_utf8",
   US"local_part",
   US"quote_local_part",
   US"from_utf8",
   US"local_part",
   US"quote_local_part",
+  US"reverse_ip",
   US"time_eval",
   US"time_interval"};
 
   US"time_eval",
   US"time_interval"};
 
@@ -163,6 +164,7 @@ enum {
   EOP_FROM_UTF8,
   EOP_LOCAL_PART,
   EOP_QUOTE_LOCAL_PART,
   EOP_FROM_UTF8,
   EOP_LOCAL_PART,
   EOP_QUOTE_LOCAL_PART,
+  EOP_REVERSE_IP,
   EOP_TIME_EVAL,
   EOP_TIME_INTERVAL };
 
   EOP_TIME_EVAL,
   EOP_TIME_INTERVAL };
 
@@ -245,6 +247,7 @@ static uschar *cond_table[] = {
   US">=",
   US"and",
   US"bool",
   US">=",
   US"and",
   US"bool",
+  US"bool_lax",
   US"crypteq",
   US"def",
   US"eq",
   US"crypteq",
   US"def",
   US"eq",
@@ -287,6 +290,7 @@ enum {
   ECOND_NUM_GE,
   ECOND_AND,
   ECOND_BOOL,
   ECOND_NUM_GE,
   ECOND_AND,
   ECOND_BOOL,
+  ECOND_BOOL_LAX,
   ECOND_CRYPTEQ,
   ECOND_DEF,
   ECOND_STR_EQ,
   ECOND_CRYPTEQ,
   ECOND_DEF,
   ECOND_STR_EQ,
@@ -732,6 +736,8 @@ or "false" value. Failure of the expansion yields FALSE; logged unless it was a
 forced fail or lookup defer. All store used by the function can be released on
 exit.
 
 forced fail or lookup defer. All store used by the function can be released on
 exit.
 
+The actual false-value tests should be replicated for ECOND_BOOL_LAX.
+
 Arguments:
   condition     the condition string
   m1            text to be incorporated in panic error
 Arguments:
   condition     the condition string
   m1            text to be incorporated in panic error
@@ -2489,19 +2495,25 @@ switch(cond_type)
   interpretation, where general data can be used and only a few values
   map to FALSE.
   Note that readconf.c boolean matching, for boolean configuration options,
   interpretation, where general data can be used and only a few values
   map to FALSE.
   Note that readconf.c boolean matching, for boolean configuration options,
-  only matches true/yes/false/no. */
+  only matches true/yes/false/no.
+  The bool_lax{} condition matches the Router logic, which is much more
+  liberal. */
   case ECOND_BOOL:
   case ECOND_BOOL:
+  case ECOND_BOOL_LAX:
     {
     uschar *sub_arg[1];
     uschar *t;
     {
     uschar *sub_arg[1];
     uschar *t;
+    uschar *ourname;
     size_t len;
     BOOL boolvalue = FALSE;
     while (isspace(*s)) s++;
     if (*s != '{') goto COND_FAILED_CURLY_START;
     size_t len;
     BOOL boolvalue = FALSE;
     while (isspace(*s)) s++;
     if (*s != '{') goto COND_FAILED_CURLY_START;
-    switch(read_subs(sub_arg, 1, 1, &s, yield == NULL, FALSE, US"bool"))
+    ourname = cond_type == ECOND_BOOL_LAX ? US"bool_lax" : US"bool";
+    switch(read_subs(sub_arg, 1, 1, &s, yield == NULL, FALSE, ourname))
       {
       {
-      case 1: expand_string_message = US"too few arguments or bracketing "
-        "error for bool";
+      case 1: expand_string_message = string_sprintf(
+                  "too few arguments or bracketing error for %s",
+                  ourname);
       /*FALLTHROUGH*/
       case 2:
       case 3: return NULL;
       /*FALLTHROUGH*/
       case 2:
       case 3: return NULL;
@@ -2510,15 +2522,25 @@ switch(cond_type)
     while (isspace(*t)) t++;
     len = Ustrlen(t);
     DEBUG(D_expand)
     while (isspace(*t)) t++;
     len = Ustrlen(t);
     DEBUG(D_expand)
-      debug_printf("considering bool: %s\n", len ? t : US"<empty>");
+      debug_printf("considering %s: %s\n", ourname, len ? t : US"<empty>");
+    /* logic for the lax case from expand_check_condition(), which also does
+    expands, and the logic is both short and stable enough that there should
+    be no maintenance burden from replicating it. */
     if (len == 0)
       boolvalue = FALSE;
     else if (Ustrspn(t, "0123456789") == len)
     if (len == 0)
       boolvalue = FALSE;
     else if (Ustrspn(t, "0123456789") == len)
+      {
       boolvalue = (Uatoi(t) == 0) ? FALSE : TRUE;
       boolvalue = (Uatoi(t) == 0) ? FALSE : TRUE;
+      /* expand_check_condition only does a literal string "0" check */
+      if ((cond_type == ECOND_BOOL_LAX) && (len > 1))
+        boolvalue = TRUE;
+      }
     else if (strcmpic(t, US"true") == 0 || strcmpic(t, US"yes") == 0)
       boolvalue = TRUE;
     else if (strcmpic(t, US"false") == 0 || strcmpic(t, US"no") == 0)
       boolvalue = FALSE;
     else if (strcmpic(t, US"true") == 0 || strcmpic(t, US"yes") == 0)
       boolvalue = TRUE;
     else if (strcmpic(t, US"false") == 0 || strcmpic(t, US"no") == 0)
       boolvalue = FALSE;
+    else if (cond_type == ECOND_BOOL_LAX)
+      boolvalue = TRUE;
     else
       {
       expand_string_message = string_sprintf("unrecognised boolean "
     else
       {
       expand_string_message = string_sprintf("unrecognised boolean "
@@ -5790,6 +5812,25 @@ while (*s != 0)
         continue;
         }
 
         continue;
         }
 
+      /* Reverse IP, including IPv6 to dotted-nibble */
+
+      case EOP_REVERSE_IP:
+        {
+        int family, maskptr;
+        uschar reversed[128];
+
+        family = string_is_ip_address(sub, &maskptr);
+        if (family == 0)
+          {
+          expand_string_message = string_sprintf(
+              "reverse_ip() not given an IP address [%s]", sub);
+          goto EXPAND_FAILED;
+          }
+        invert_address(reversed, sub);
+        yield = string_cat(yield, &size, &ptr, reversed, Ustrlen(reversed));
+        continue;
+        }
+
       /* Unknown operator */
 
       default:
       /* Unknown operator */
 
       default: