+$11111111111111111111111111111111111
+${11111111111111111111111111111111111}
+# List operations
+
+filter: "${filter{a:b:c}{eq{1}{1}}}"
+filter: ${filter{a:b:c}{!eq{$item}{b}}}
+filter: ${filter{<' a'b'c}{!eq{$item}{b}}}
+filter: ${filter{<' ''a'b' ''c}{!eq{$item}{b}}}
+filter: "${filter{}{!eq{$item}{b}}}"
+
+map: "${map{}{$item}}"
+map: ${map{a:b:c}{$item}}
+map: ${map{a:b:c}{:$item:}}
+map: ${if eq{1}{0}{${map{a:b:c}{:$item:}}}{fail string}}
+map: ${map{:b:c}{[$item]}}
+
+reduce: "${reduce{}{+}{$value$item}}"
+reduce: ${reduce{a:b:c}{+}{$value$item}}
+reduce: ${reduce {<, 1,2,3}{0}{${eval:$value+$item}}}
+reduce: ${reduce {3:0:9:4:6}{0}{${if >{$item}{$value}{$item}{$value}}}}
+
+# Tests with iscntrl() and illegal separators
+
+map: ${map{<\n a\n\nb\nc}{'$item'}}
+
+reduce: ${reduce {<n 1\n2\n3}{0}{${eval:$value+$item}}}
+reduce: ${reduce {<\n 1\n2\n3}{0}{${eval:$value+$item}}}
+reduce: ${reduce { <\n 1\n 2 \n 3 }{0}{${eval:$value+$item}}}
+reduce: ${reduce {<\x7f 1\x7f2\177 3}{0}{${eval:$value+$item}}}
+
# Operators
addrss: ${address:local-part@dom.ain}
addrss: ${address:Exim Person <local-part@dom.ain> (that's me)}
domain: ${domain:local-part@dom.ain}
domain: ${domain:Exim Person <local-part@dom.ain> (that's me)}
+
+addresses: ${addresses:>' 'abc@xyz, 'pqr@xyz}
+addresses: ${addresses:Exim Person <local-part@dom.ain> (that's me)}
+addresses: ${addresses:>+ Exim Person <local-part@dom.ain> (that's me),\
+ xyz@abc}
+addresses: ${addresses:Exim Person <local-part@dom.ain> (that's me), \
+ xyz@abc, nullgroupname:;, group: p@q, r@s; }
+addresses: ${addresses:local-part@dom.ain <local-part@dom.ain>}
+
escape: ${escape:B7·F2ò}
eval: ${eval:1+1}
eval: ${eval:1+2*3}
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}
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.}
mask: ${if eq {1}{2}{${mask:invalid}}{NO}}
# Numeric overflow
+# >32b should work, >64b not
4096M ${if >{1}{4096M}{y}{n}}
4096000000 ${if >{1}{4096000000}{y}{n}}
+4611686018427387904 ${if >{1}{4611686018427387904} {y}{n}}
+46116860184273879040 ${if >{1}{46116860184273879040}{y}{n}}
# Conditions
${if match{x@zz.aa.bb}{^(.*)} \
{ \
- >$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@y.z}{p@q:*@y.z}{yes}{no}}
match_address: ${if match_address{x@y.z}{p@q:x@*.z}{yes}{no}}
match_ip: 12 ${if match_ip{1.2.3.4}{lsearch;DIR/aux-fixed/0002.matchip}}
match_ip: 13 ${if match_ip{1.2.3.4}{net-lsearch;DIR/aux-fixed/0002.matchip}}
match_ip: 14 ${if match_ip{5.6.7.8}{net24-lsearch;DIR/aux-fixed/0002.matchip}}
+match_ip: 15 ${if match_ip{abcd::dcba}{net-iplsearch;DIR/aux-fixed/0002.matchip}}
queue_running: ${if queue_running{y}{n}}
first_delivery: ${if first_delivery{y}{n}}
abcdea a ${tr{abcdea}{a}{}}
abcdea abc z ${tr{abcdea}{abc}{z}}
+# Boolean
+"TrUe" ${if bool{TrUe}{true}{false}} EXPECT: true
+"FALSE" ${if bool{FALSE}{true}{false}} EXPECT: false
+" yes" ${if bool{ yes}{true}{false}} EXPECT: true
+" no" ${if bool{ no}{true}{false}} EXPECT: false
+"yes " ${if bool{yes }{true}{false}} EXPECT: true
+"-1" ${if bool{-1}{true}{false}} EXPECT: error
+"0" ${if bool{0}{true}{false}} EXPECT: false
+"1" ${if bool{1}{true}{false}} EXPECT: true
+" 0 " ${if bool{ 0 }{true}{false}} EXPECT: false
+" 1 " ${if bool{ 1 }{true}{false}} EXPECT: true
+"1111111111111111111" ${if bool{1111111111111111111}{true}{false}} EXPECT: true
+"9" ${if bool{9}{true}{false}} EXPECT: true
+" " ${if bool{ }{true}{false}} EXPECT: false
+"text" ${if bool{text}{true}{false}} EXPECT: error
+" text" ${if bool{ text}{true}{false}} EXPECT: error
+"text " ${if bool{text }{true}{false}} EXPECT: error
+" text " ${if bool{ text }{true}{false}} EXPECT: error
+"00" ${if bool{00}{true}{false}} EXPECT: false
+"!true" ${if !bool{true}{true}{false}} EXPECT: false
+"!false" ${if !bool{false}{true}{false}} EXPECT: true
+
+"TrUe" ${if bool_lax{TrUe}{true}{false}} EXPECT: true
+"FALSE" ${if bool_lax{FALSE}{true}{false}} EXPECT: false
+" yes" ${if bool_lax{ yes}{true}{false}} EXPECT: true
+" no" ${if bool_lax{ no}{true}{false}} EXPECT: false
+"yes " ${if bool_lax{yes }{true}{false}} EXPECT: true
+"-1" ${if bool_lax{-1}{true}{false}} EXPECT: true
+"0" ${if bool_lax{0}{true}{false}} EXPECT: false
+"1" ${if bool_lax{1}{true}{false}} EXPECT: true
+" 0 " ${if bool_lax{ 0 }{true}{false}} EXPECT: false
+" 1 " ${if bool_lax{ 1 }{true}{false}} EXPECT: true
+"1111111111111111111" ${if bool_lax{1111111111111111111}{true}{false}} EXPECT: true
+"9" ${if bool_lax{9}{true}{false}} EXPECT: true
+" " ${if bool_lax{ }{true}{false}} EXPECT: false
+"text" ${if bool_lax{text}{true}{false}} EXPECT: true
+" text" ${if bool_lax{ text}{true}{false}} EXPECT: true
+"text " ${if bool_lax{text }{true}{false}} EXPECT: true
+" text " ${if bool_lax{ text }{true}{false}} EXPECT: true
+"00" ${if bool_lax{00}{true}{false}} EXPECT: true
+"!true" ${if !bool_lax{true}{true}{false}} EXPECT: false
+"!false" ${if !bool_lax{false}{true}{false}} EXPECT: true
+
# RFC 2047
abcd ${rfc2047:abcd}
${prvs{userx@test.ex}{secret}{}}
# Correct checks; can't put explicit addresses in the tests, because they
-# will change over time.
+# will change over time.
${prvscheck{${prvs{userx@test.ex}{secret}}}{secret}}
result=$prvscheck_result
${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)
${if ={1}{1} {true}{${if ={1}{1} {true}{${if ={1}{1}{true}fail}}}}}