Added bool_lax{} expansion operator, which uses Router condition logic to
authorPhil Pennock <pdp@exim.org>
Mon, 7 Jun 2010 08:23:20 +0000 (08:23 +0000)
committerPhil Pennock <pdp@exim.org>
Mon, 7 Jun 2010 08:23:20 +0000 (08:23 +0000)
determine whether or not a string is true.
Switch the multiple-condition logic to use bool_lax{}.
Add note where we combine multiple conditions regarding the memory leak.

doc/doc-docbook/spec.xfpt
doc/doc-txt/ChangeLog
doc/doc-txt/NewStuff
src/src/expand.c
src/src/readconf.c

index dd8db236733e8bcec2c471ad6290df5452516504..8254bee5163c7fbd9f59c9c0baf7dedffd581d02 100644 (file)
@@ -1,4 +1,4 @@
-. $Cambridge: exim/doc/doc-docbook/spec.xfpt,v 1.83 2010/06/07 07:09:10 pdp Exp $
+. $Cambridge: exim/doc/doc-docbook/spec.xfpt,v 1.84 2010/06/07 08:23:20 pdp Exp $
 .
 . /////////////////////////////////////////////////////////////////////////////
 . This is the primary source of the Exim Manual. It is an xfpt document that is
 .
 . /////////////////////////////////////////////////////////////////////////////
 . This is the primary source of the Exim Manual. It is an xfpt document that is
@@ -9812,6 +9812,17 @@ For example:
 ${if bool{$acl_m_privileged_sender} ...
 .endd
 
 ${if bool{$acl_m_privileged_sender} ...
 .endd
 
+.vitem &*bool_lax&~{*&<&'string'&>&*}*&
+.cindex "expansion" "boolean parsing"
+.cindex "&%bool_lax%& expansion condition"
+Like &%bool%&, this condition turns a string into a boolean state.  But
+where &%bool%& accepts a strict set of strings, &%bool_lax%& uses the same
+loose definition that the Router &%condition%& option uses.  The empty string
+and the values &"false"&, &"no"& and &"0"& map to false, all others map to
+true.
+
+Note that where &"bool{00}"& is false, &"bool_lax{00}"& is true.
+
 .vitem &*crypteq&~{*&<&'string1'&>&*}{*&<&'string2'&>&*}*&
 .cindex "expansion" "encrypted comparison"
 .cindex "encrypted strings, comparing"
 .vitem &*crypteq&~{*&<&'string1'&>&*}{*&<&'string2'&>&*}*&
 .cindex "expansion" "encrypted comparison"
 .cindex "encrypted strings, comparing"
@@ -15670,10 +15681,7 @@ If the result is any other value, the router is run (as this is the last
 precondition to be evaluated, all the other preconditions must be true).
 
 This option is unique in that multiple &%condition%& options may be present.
 precondition to be evaluated, all the other preconditions must be true).
 
 This option is unique in that multiple &%condition%& options may be present.
-In this case, the previous statement does not quite apply: the result of each
-&%condition%& option must be a string recognised by the &%bool%& expansion
-operator, or failure will be forced.  The effect is to "and" the conditions
-together, as each must pass.
+All &%condition%& options must succeed.
 
 The &%condition%& option provides a means of applying custom conditions to the
 running of routers. Note that in the case of a simple conditional expansion,
 
 The &%condition%& option provides a means of applying custom conditions to the
 running of routers. Note that in the case of a simple conditional expansion,
@@ -15685,10 +15693,11 @@ Because of the default behaviour of the string expansion, this is equivalent to
 .code
 condition = ${if >{$message_age}{600}{true}{}}
 .endd
 .code
 condition = ${if >{$message_age}{600}{true}{}}
 .endd
-A multiple condition example:
+A multiple condition example, which succeeds:
 .code
 condition = ${if >{$message_age}{600}}
 condition = ${if !eq{${lc:$local_part}}{postmaster}}
 .code
 condition = ${if >{$message_age}{600}}
 condition = ${if !eq{${lc:$local_part}}{postmaster}}
+condition = foobar
 .endd
 If the expansion fails (other than forced failure) delivery is deferred. Some
 of the other precondition options are common special cases that could in fact
 .endd
 If the expansion fails (other than forced failure) delivery is deferred. Some
 of the other precondition options are common special cases that could in fact
index 65d5d2dc9e2b869588297dd5160e9f1b808700d5..e2904ba48c15a784a6ac93fce60e9a4b25d285cb 100644 (file)
@@ -1,4 +1,4 @@
-$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.628 2010/06/07 07:09:10 pdp Exp $
+$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.629 2010/06/07 08:23:20 pdp Exp $
 
 Change log file for Exim from version 4.21
 -------------------------------------------
 
 Change log file for Exim from version 4.21
 -------------------------------------------
@@ -46,6 +46,9 @@ PP/14 Build without WITH_CONTENT_SCAN. Path from Andreas Metzler.
 
 PP/15 Bugzilla 816: support multiple condition rules on Routers.
 
 
 PP/15 Bugzilla 816: support multiple condition rules on Routers.
 
+PP/16 Add bool_lax{} expansion operator and use that for combining multiple
+      condition rules, instead of bool{}.
+
 
 Exim version 4.72
 -----------------
 
 Exim version 4.72
 -----------------
index 559a9f4c0f7efa0cc24c99e28bf4054519e94290..91c9b5f715ad4099962cb140a864aaa6844ffb1e 100644 (file)
@@ -1,4 +1,4 @@
-$Cambridge: exim/doc/doc-txt/NewStuff,v 1.173 2010/06/07 07:09:10 pdp Exp $
+$Cambridge: exim/doc/doc-txt/NewStuff,v 1.174 2010/06/07 08:23:20 pdp Exp $
 
 New Features in Exim
 --------------------
 
 New Features in Exim
 --------------------
@@ -75,14 +75,13 @@ Version 4.73
     then henceforth you will have to maintain your own local patches to strip
     the safeties off.
 
     then henceforth you will have to maintain your own local patches to strip
     the safeties off.
 
- 8. Routers now support multiple "condition" tests, IF each router yields
-    a string which the bool{} operator recognises.  Note that this is a departure
-    from normal Router "condition" truth, requiring the stricter standard of
-    "true" that ACLS use.  This might be relaxed in a future release if there
-    is sufficient demand.
-    When debugging, bear in mind that these are internally wrapped up into
-    a longer, more complicated, string.  There's a reason that the bool{}
-    logic is a dependency.
+ 8. There is a new expansion operator, bool_lax{}.  Where bool{} uses the ACL
+    condition logic to determine truth/failure and will fail to expand many
+    strings, bool_lax{} uses the router condition logic, where most strings
+    do evaluate true.
+    Note: bool{00} is false, bool_lax{00} is true.
+
+ 9. Routers now support multiple "condition" tests,
 
 
 Version 4.72
 
 
 Version 4.72
index e5daff1a89447ac1762827c79cd0cab7ba54a591..9f9cbb7befffed14bd4074ac55af4b8bc2ece200 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/expand.c,v 1.106 2010/06/05 23:50:18 pdp 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    *
@@ -247,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",
@@ -289,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,
@@ -734,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
@@ -2491,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;
@@ -2512,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 "
index 6fd0dd8ea975095d234aec2be9ebfad69ba293a3..6b11621e0f7a34a3009a1f881fa34967039b8b34 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/readconf.c,v 1.42 2010/06/07 07:09:10 pdp Exp $ */
+/* $Cambridge: exim/src/src/readconf.c,v 1.43 2010/06/07 08:23:20 pdp Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -1516,12 +1516,25 @@ switch (type)
       str_target = (uschar **)((uschar *)data_block + (long int)(ol->value));
     if (extra_condition)
       {
       str_target = (uschar **)((uschar *)data_block + (long int)(ol->value));
     if (extra_condition)
       {
-      /* We already have a condition, we're conducting a crude hack to let multiple
-      condition rules be chained together, despite storing them in text form. */
+      /* We already have a condition, we're conducting a crude hack to let
+      multiple condition rules be chained together, despite storing them in
+      text form. */
       saved_condition = *str_target;
       saved_condition = *str_target;
-      strtemp = string_sprintf("${if and{{bool{%s}}{bool{%s}}}}",
+      strtemp = string_sprintf("${if and{{bool_lax{%s}}{bool_lax{%s}}}}",
           saved_condition, sptr);
       *str_target = string_copy_malloc(strtemp);
           saved_condition, sptr);
       *str_target = string_copy_malloc(strtemp);
+      /* TODO(pdp): there is a memory leak here when we set 3 or more
+      conditions; I still don't understand the store mechanism enough
+      to know what's the safe way to free content from an earlier store.
+      AFAICT, stores stack, so freeing an early stored item also stores
+      all data alloc'd after it.  If we knew conditions were adjacent,
+      we could survive that, but we don't.  So I *think* we need to take
+      another bit from opt_type to indicate "malloced"; this seems like
+      quite a hack, especially for this one case.  It also means that
+      we can't ever reclaim the store from the *first* condition.
+
+      Because we only do this once, near process start-up, I'm prepared to
+      let this slide for the time being, even though it rankles.  */
       }
     else
       {
       }
     else
       {