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.
-. $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
${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"
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,
.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}}
+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
-$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
-------------------------------------------
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
-----------------
-$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
--------------------
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
-/* $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 *
US">=",
US"and",
US"bool",
+ US"bool_lax",
US"crypteq",
US"def",
US"eq",
ECOND_NUM_GE,
ECOND_AND,
ECOND_BOOL,
+ ECOND_BOOL_LAX,
ECOND_CRYPTEQ,
ECOND_DEF,
ECOND_STR_EQ,
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
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_LAX:
{
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;
- 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;
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)
+ {
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 (cond_type == ECOND_BOOL_LAX)
+ boolvalue = TRUE;
else
{
expand_string_message = string_sprintf("unrecognised boolean "
-/* $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 *
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;
- 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);
+ /* 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
{