ph10 2007/02/06 10:00:25 GMT
Modified files:
exim-doc/doc-txt ChangeLog NewStuff
exim-src ACKNOWLEDGMENTS
exim-src/src expand.c globals.c globals.h
exim-test/scripts/0000-Basic 0002
exim-test/stdout 0002
Log:
Add forany/forall (Marcus Holmgren's patch, basically).
Revision Changes Path
1.469 +2 -0 exim/exim-doc/doc-txt/ChangeLog
1.136 +32 -0 exim/exim-doc/doc-txt/NewStuff
1.72 +2 -1 exim/exim-src/ACKNOWLEDGMENTS
1.80 +67 -0 exim/exim-src/src/expand.c
1.69 +1 -0 exim/exim-src/src/globals.c
1.49 +1 -0 exim/exim-src/src/globals.h
1.11 +72 -19 exim/exim-test/scripts/0000-Basic/0002
1.11 +35 -0 exim/exim-test/stdout/0002
Index: ChangeLog
===================================================================
RCS file: /home/cvs/exim/exim-doc/doc-txt/ChangeLog,v
retrieving revision 1.468
retrieving revision 1.469
diff -u -r1.468 -r1.469
--- ChangeLog 5 Feb 2007 12:35:46 -0000 1.468
+++ ChangeLog 6 Feb 2007 10:00:24 -0000 1.469
@@ -1,4 +1,4 @@
-$Cambridge: exim/exim-doc/doc-txt/ChangeLog,v 1.468 2007/02/05 12:35:46 ph10 Exp $
+$Cambridge: exim/exim-doc/doc-txt/ChangeLog,v 1.469 2007/02/06 10:00:24 ph10 Exp $
Change log file for Exim from version 4.21
-------------------------------------------
@@ -72,6 +72,8 @@
PH/14 Added log_selector = +pid.
PH/15 Flush SMTP output before delaying, unless control=no_delay_flush is set.
+
+PH/16 Add ${if forany and ${if forall.
Exim version 4.66
Index: NewStuff
===================================================================
RCS file: /home/cvs/exim/exim-doc/doc-txt/NewStuff,v
retrieving revision 1.135
retrieving revision 1.136
diff -u -r1.135 -r1.136
--- NewStuff 5 Feb 2007 12:35:46 -0000 1.135
+++ NewStuff 6 Feb 2007 10:00:24 -0000 1.136
@@ -1,4 +1,4 @@
-$Cambridge: exim/exim-doc/doc-txt/NewStuff,v 1.135 2007/02/05 12:35:46 ph10 Exp $
+$Cambridge: exim/exim-doc/doc-txt/NewStuff,v 1.136 2007/02/06 10:00:24 ph10 Exp $
New Features in Exim
--------------------
@@ -235,6 +235,38 @@
11. Exim has been modified so that it flushes SMTP output before implementing
a delay in an ACL. This behaviour can be disabled by obeying control =
no_delay_flush at some earlier point.
+
+12. There are two new expansion conditions that iterate over a list. They are
+ called forany and forall, and they are used like this:
+
+ ${if forany{<a list>}{<a condition>}{<yes-string>}{<no-string>}}
+ ${if forall{<a list>}{<a condition>}{<yes-string>}{<no-string>}}
+
+ The first argument is expanded, and the result is treated as a list. By
+ default, the list separator is a colon, but it can be changed by the normal
+ method. The second argument is interpreted as a condition that is to be
+ applied to each item in the list in turn. During the interpretation of the
+ condition, the current list item is placed in a variable called $item.
+
+ - For forany, interpretation stops if the condition is true for any item,
+ and the yes-string is then expanded. If the condition is false for all
+ items in the list, the no-string is expanded.
+
+ - For forall, interpration stops if the condition is false for any item,
+ and the no-string is then expanded. If the condition is true for all
+ items in the list, the yes-string is expanded.
+
+ Note that negation of forany means that the condition must be false for all
+ items for the overall condition to succeed, and negation of forall means
+ that the condition must be false for at least one item.
+
+ In this example, the list separator is changed to a comma:
+
+ ${if forany{<, $recipients}{match{$item}{^user3@}}{yes}{no}}
+
+ Outside a forany/forall condition, the value of $item is an empty string.
+ Its value is saved and restored while forany/forall is being processed, to
+ enable these expansion items to be nested.
Version 4.66
Index: ACKNOWLEDGMENTS
===================================================================
RCS file: /home/cvs/exim/exim-src/ACKNOWLEDGMENTS,v
retrieving revision 1.71
retrieving revision 1.72
diff -u -r1.71 -r1.72
--- ACKNOWLEDGMENTS 31 Jan 2007 16:52:12 -0000 1.71
+++ ACKNOWLEDGMENTS 6 Feb 2007 10:00:24 -0000 1.72
@@ -1,4 +1,4 @@
-$Cambridge: exim/exim-src/ACKNOWLEDGMENTS,v 1.71 2007/01/31 16:52:12 ph10 Exp $
+$Cambridge: exim/exim-src/ACKNOWLEDGMENTS,v 1.72 2007/02/06 10:00:24 ph10 Exp $
EXIM ACKNOWLEDGEMENTS
@@ -20,7 +20,7 @@
Philip Hazel
Lists created: 20 November 2002
-Last updated: 31 January 2007
+Last updated: 06 February 2007
THE OLD LIST
@@ -168,6 +168,7 @@
Patch for "h" flag in Domain Keys
Patch for $sending_ip_address/$sending_port
Patch for ${rfc2047d:
+ ... and several more
Lots of other maintenance support
Kjetil Torgrim Homme Patch for require_files problem on NFS file systems
Tom Hughes Suggested patch for $n bug in pipe command from filter
Index: expand.c
===================================================================
RCS file: /home/cvs/exim/exim-src/src/expand.c,v
retrieving revision 1.79
retrieving revision 1.80
diff -u -r1.79 -r1.80
--- expand.c 31 Jan 2007 11:30:08 -0000 1.79
+++ expand.c 6 Feb 2007 10:00:24 -0000 1.80
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/exim-src/src/expand.c,v 1.79 2007/01/31 11:30:08 ph10 Exp $ */
+/* $Cambridge: exim/exim-src/src/expand.c,v 1.80 2007/02/06 10:00:24 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -240,6 +240,8 @@
US"eqi",
US"exists",
US"first_delivery",
+ US"forall",
+ US"forany",
US"ge",
US"gei",
US"gt",
@@ -279,6 +281,8 @@
ECOND_STR_EQI,
ECOND_EXISTS,
ECOND_FIRST_DELIVERY,
+ ECOND_FORALL,
+ ECOND_FORANY,
ECOND_STR_GE,
ECOND_STR_GEI,
ECOND_STR_GT,
@@ -420,6 +424,7 @@
{ "inode", vtype_ino, &deliver_inode },
{ "interface_address", vtype_stringptr, &interface_address },
{ "interface_port", vtype_int, &interface_port },
+ { "item", vtype_stringptr, &iterate_item },
#ifdef LOOKUP_LDAP
{ "ldap_dn", vtype_stringptr, &eldap_dn },
#endif
@@ -2347,6 +2352,68 @@
if (yield != NULL) *yield = (combined_cond == testfor);
return ++s;
+
+
+ /* forall/forany: iterates a condition with different values */
+
+ case ECOND_FORALL:
+ case ECOND_FORANY:
+ {
+ int sep = 0;
+ uschar *iterate_item_save = iterate_item;
+
+ while (isspace(*s)) s++;
+ if (*s++ != '{') goto COND_FAILED_CURLY_START;
+
+ sub[0] = expand_string_internal(s, TRUE, &s, (yield == NULL));
+ if (sub[0] == NULL) return NULL;
+ if (*s++ != '}') goto COND_FAILED_CURLY_END;
+
+ while (isspace(*s)) s++;
+ if (*s++ != '{') goto COND_FAILED_CURLY_START;
+
+ sub[1] = s;
+
+ /* Call eval_condition once, with result discarded (as if scanning a
+ "false" part). This allows us to find the end of the condition, because if
+ the list it empty, we won't actually evaluate the condition for real. */
+
+ s = eval_condition(sub[1], NULL);
+ if (s == NULL)
+ {
+ expand_string_message = string_sprintf("%s inside \"%s\" condition",
+ expand_string_message, name);
+ return NULL;
+ }
+ while (isspace(*s)) s++;
+
+ if (*s++ != '}')
+ {
+ expand_string_message = string_sprintf("missing } at end of condition "
+ "inside \"%s\"", name);
+ return NULL;
+ }
+
+ if (yield != NULL) *yield = !testfor;
+ while ((iterate_item = string_nextinlist(&sub[0], &sep, NULL, 0)) != NULL)
+ {
+ DEBUG(D_expand) debug_printf("%s: $item = \"%s\"\n", name, iterate_item);
+ if (eval_condition(sub[1], &tempcond) == NULL)
+ {
+ expand_string_message = string_sprintf("%s inside \"%s\" condition",
+ expand_string_message, name);
+ return NULL;
+ }
+ DEBUG(D_expand) debug_printf("%s: condition evaluated to %s\n", name,
+ tempcond? "true":"false");
+
+ if (yield != NULL) *yield = (tempcond == testfor);
+ if (tempcond == (cond_type == ECOND_FORANY)) break;
+ }
+
+ iterate_item = iterate_item_save;
+ return s;
+ }
/* Unknown condition */
Index: globals.c
===================================================================
RCS file: /home/cvs/exim/exim-src/src/globals.c,v
retrieving revision 1.68
retrieving revision 1.69
diff -u -r1.68 -r1.69
--- globals.c 5 Feb 2007 12:35:46 -0000 1.68
+++ globals.c 6 Feb 2007 10:00:24 -0000 1.69
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/exim-src/src/globals.c,v 1.68 2007/02/05 12:35:46 ph10 Exp $ */
+/* $Cambridge: exim/exim-src/src/globals.c,v 1.69 2007/02/06 10:00:24 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -630,6 +630,7 @@
uschar *interface_address = NULL;
int interface_port = -1;
BOOL is_inetd = FALSE;
+uschar *iterate_item = NULL;
int journal_fd = -1;
Index: globals.h
===================================================================
RCS file: /home/cvs/exim/exim-src/src/globals.h,v
retrieving revision 1.48
retrieving revision 1.49
diff -u -r1.48 -r1.49
--- globals.h 5 Feb 2007 12:35:46 -0000 1.48
+++ globals.h 6 Feb 2007 10:00:24 -0000 1.49
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/exim-src/src/globals.h,v 1.48 2007/02/05 12:35:46 ph10 Exp $ */
+/* $Cambridge: exim/exim-src/src/globals.h,v 1.49 2007/02/06 10:00:24 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -385,6 +385,7 @@
extern BOOL ignore_fromline_local; /* Local SMTP ignore fromline */
extern uschar *ignore_fromline_hosts; /* Hosts permitted to send "From " */
extern BOOL is_inetd; /* True for inetd calls */
+extern uschar *iterate_item; /* Item from iterate list */
extern int journal_fd; /* Fd for journal file */
Index: 0002
===================================================================
RCS file: /home/cvs/exim/exim-test/scripts/0000-Basic/0002,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -r1.10 -r1.11
--- 0002 31 Jan 2007 11:30:08 -0000 1.10
+++ 0002 6 Feb 2007 10:00:25 -0000 1.11
@@ -69,17 +69,17 @@
eval10: ${eval10:08}
eval10: ${eval10:0x1234}
eval: ${eval:2+42%5}
-eval: ${eval:0xc&5}
-eval: ${eval:0xc & 5 }
-eval: ${eval:0x0c|5}
-eval: ${eval:0xc^5}
-eval: ${eval:0xc>>1}
-eval: ${eval:0xc >> 2}
-eval: ${eval:0xc >> 4 }
-eval: ${eval:0xc<<1}
-eval: ${eval:~255&0x1234}
-eval: ${eval:~ 255&0x1234}
-eval: ${eval: -(~255&0x1234)}
+eval: ${eval:0xc&5}
+eval: ${eval:0xc & 5 }
+eval: ${eval:0x0c|5}
+eval: ${eval:0xc^5}
+eval: ${eval:0xc>>1}
+eval: ${eval:0xc >> 2}
+eval: ${eval:0xc >> 4 }
+eval: ${eval:0xc<<1}
+eval: ${eval:~255&0x1234}
+eval: ${eval:~ 255&0x1234}
+eval: ${eval: -(~255&0x1234)}
expand: \$primary_hostname ${expand:\$primary_hostname}
hash: ${hash_3:monty} ${hash_5:monty} ${hash_4_62:monty python}
@@ -100,15 +100,15 @@
base62: ${if or {\
{eq {${base62:12345}}{0003D7}}\
{eq {${base62:12345}}{0009IX}}\
- }{OK}{NOT OK}}
+ }{OK}{NOT OK}}
base62d: ${if or {\
{eq {${base62d:0003D7}}{12345}}\
{eq {${base62d:0009IX}}{12345}}\
- }{OK}{NOT OK}}
+ }{OK}{NOT OK}}
base62d: ${if or {\
{eq {${base62d:3D7}}{12345}}\
{eq {${base62d:9IX}}{12345}}\
- }{OK}{NOT OK}}
+ }{OK}{NOT OK}}
base62 error: ${base62:12345x}
base62d error:${base62d:0003D7.}
@@ -304,19 +304,19 @@
${if match{x@???}{^(.*)} \
{ \
- >$1< \
+ >$1< \
${if match_domain{${domain:$1}}{+dlist}{[$1]}} \
>$1< \
} \
- { CAN'T HAPPEN}}
+ { CAN'T HAPPEN}}
${if match{x@xxxabc}{^(.*)} \
{ \
- >$1< \
+ >$1< \
${if match_domain{${domain:$1}}{^\Nxxx(.*)\N}{[$1]}} \
>$1< \
} \
- { CAN'T HAPPEN}}
+ { CAN'T HAPPEN}}
match_address: ${if match_address{x@???}{p@q:*@y.z}{yes}{no}}
match_address: ${if match_address{x@???}{p@q:x@*.z}{yes}{no}}
@@ -569,7 +569,7 @@
${prvs{userx@???}{secret}{}}
# Correct checks; can't put explicit addresses in the tests, because they
-# will change over time.
+# will change over time.
${prvscheck{${prvs{userx@???}{secret}}}{secret}}
result=$prvscheck_result
@@ -612,6 +612,59 @@
${if or {{eq {}{}}{yes}{no}}
${substr_1_:12345}
${substr__3:12345}
+
+# Iterations: forany and forall
+
+${if forany{a:b:c}{eq{$item}{a}}{yes}{no}}
+${if forany{a:b:c}{eq{$item}{b}}{yes}{no}}
+${if forany{a:b:c}{eq{$item}{c}}{yes}{no}}
+${if forany {a:b:c} {eq {$item} {z}} {yes} {no}}
+${if !forany{a:b:c}{eq{$item}{z}}{yes}{no}}
+${if !forany{a:b:c}{eq{$item}{a}}{yes}{no}}
+${if forany{}{eq{$item}{a}}{yes}{no}}
+${if !forany{}{eq{$item}{a}}{yes}{no}}
+${if forany{<, $primary_hostname,foo,bar}{eq{$item}{$primary_hostname}}{yes}{no}}
+
+${if forany{}{yes}{no}}
+${if forany{a:b:c}{gt{$item}{a}{yes}{no}}
+
+${if forall{a:b:c}{match{$item}{^[a-c]\$}}{yes}{no}}
+${if forall{q:b:c}{match{$item}{^[a-c]\$}}{yes}{no}}
+${if forall{a:b:z}{match{$item}{^[a-c]\$}}{yes}{no}}
+${if forall{}{match{$item}{^[a-c]\$}}{yes}{no}}
+
+${if !forall{a:b:c}{match{$item}{^[a-c]\$}}{yes}{no}}
+${if !forall{q:b:c}{match{$item}{^[a-c]\$}}{yes}{no}}
+${if !forall{a:b:z}{match{$item}{^[a-c]\$}}{yes}{no}}
+${if !forall{}{match{$item}{^[a-c]\$}}{yes}{no}}
+
+# Expect yes
+${if forany{a:b:c}\
+ {\
+ eq\
+ {$item: ${if forall{x:y:z}{match{$item}{^[x-z]\$}}{true}{false}}}\
+ {$item: true}\
+ }\
+{outer=yes}{outer=no}} item='$item' (unset)
+
+# Expect no
+${if forany{a:b:c}\
+ {\
+ eq\
+ {$item: ${if !forall{x:y:z}{match{$item}{^[x-z]\$}}{true}{false}}}\
+ {$item: true}\
+ }\
+{outer=yes}{outer=no}}
+
+# Error inside nest - check message is helpful
+${if forany{a:b:c}\
+ {\
+ eq\
+ {$item: ${if forall{x:y:z}{match{$item}{^[x-z]\$}{true}{false}}}\
+ {$item: true}\
+ }\
+{outer=yes}{outer=no}}
+
# Miscellaneous (for bug fixes, etc)
Index: 0002
===================================================================
RCS file: /home/cvs/exim/exim-test/stdout/0002,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -r1.10 -r1.11
--- 0002 31 Jan 2007 11:30:08 -0000 1.10
+++ 0002 6 Feb 2007 10:00:25 -0000 1.11
@@ -590,6 +590,41 @@
> Failed: non-digit after underscore in "substr_1_"
> Failed: non-digit after underscore in "substr__3"
>
+> # Iterations: forany and forall
+>
+> yes
+> yes
+> yes
+> no
+> yes
+> no
+> no
+> yes
+> yes
+>
+> Failed: unknown condition "yes" inside "forany" condition
+> Failed: missing } at end of condition inside "forany"
+>
+> yes
+> no
+> no
+> no
+>
+> no
+> yes
+> yes
+> yes
+>
+> # Expect yes
+> outer=yes item='' (unset)
+>
+> # Expect no
+> outer=no
+>
+> # Error inside nest - check message is helpful
+> Failed: missing } at end of condition inside "forall" inside "forany" condition
+>
+>
> # Miscellaneous (for bug fixes, etc)
>
> true