- queue_fast_ramp (main) true (was false)
- remote_max_parallel (main) 4 (was 2)
+JH/03 Cache static regex pattern compilations, for use by ACLs.
+
Exim version 4.96
-----------------
filtertest.o globals.o dkim.o dkim_transport.o dnsbl.o hash.o \
header.o host.o host_address.o ip.o log.o lss.o match.o md5.o moan.o \
os.o parse.o priv.o queue.o \
- rda.o readconf.o receive.o retry.o rewrite.o rfc2047.o \
+ rda.o readconf.o receive.o retry.o rewrite.o rfc2047.o regex_cache.o \
route.o search.o sieve.o smtp_in.o smtp_out.o spool_in.o spool_out.o \
std-crypto.o store.o string.o tls.o tod.o transport.o tree.o verify.o \
environment.o macro.o \
receive.o: $(HDRS) receive.c
retry.o: $(HDRS) retry.c
rewrite.o: $(HDRS) rewrite.c
+regex_cache.o: $(HDRS) regex_cache.c
rfc2047.o: $(HDRS) rfc2047.c
route.o: $(HDRS) route.c
search.o: $(HDRS) search.c
exim_dbmbuild.c exim_dbutil.c exim_lock.c expand.c filter.c filtertest.c \
globals.c hash.c header.c host.c host_address.c ip.c log.c lss.c match.c md5.c moan.c \
parse.c perl.c priv.c queue.c rda.c readconf.c receive.c retry.c rewrite.c \
- rfc2047.c route.c search.c setenv.c environment.c \
+ regex_cache.c rfc2047.c route.c search.c setenv.c environment.c \
sieve.c smtp_in.c smtp_out.c spool_in.c spool_out.c std-crypto.c store.c \
string.c tls.c tlscert-gnu.c tlscert-openssl.c tls-cipher-stdname.c \
tls-gnu.c tls-openssl.c \
for (; cb; cb = cb->next)
{
- const uschar *arg;
+ const uschar * arg;
int control_type;
+ BOOL textonly = FALSE;
/* The message and log_message items set up messages to be used in
case of rejection. They are expanded later. */
if (!conditions[cb->type].expand_at_top)
arg = cb->arg;
- else if (!(arg = expand_string(cb->arg)))
+
+ else if (!(arg = expand_string_2(cb->arg, &textonly)))
{
if (f.expand_string_forcedfail) continue;
*log_msgptr = string_sprintf("failed to expand ACL string \"%s\": %s",
return ERROR;
}
- rc = malware(ss, timeout);
+ rc = malware(ss, textonly, timeout);
if (rc == DEFER && defer_ok)
rc = FAIL; /* FAIL so that the message is passed to the next ACL */
break;
}
case ACLC_MIME_REGEX:
- rc = mime_regex(&arg);
+ rc = mime_regex(&arg, textonly);
break;
#endif
#ifdef WITH_CONTENT_SCAN
case ACLC_REGEX:
- rc = regex(&arg);
+ rc = regex(&arg, textonly);
break;
#endif
* Listener socket for local work prompts *
*************************************************/
+ssize_t
+daemon_client_sockname(struct sockaddr_un * sup, uschar ** sname)
+{
+#ifdef EXIM_HAVE_ABSTRACT_UNIX_SOCKETS
+sup->sun_path[0] = 0; /* Abstract local socket addr - Linux-specific? */
+return offsetof(struct sockaddr_un, sun_path) + 1
+ + snprintf(sup->sun_path+1, sizeof(sup->sun_path)-1, "exim_%d", getpid());
+#else
+*sname = string_sprintf("%s/p_%d", spool_directory, getpid());
+return offsetof(struct sockaddr_un, sun_path)
+ + snprintf(sup->sun_path, sizeof(sup->sun_path), "%s", sname);
+#endif
+}
+
ssize_t
daemon_notifier_sockname(struct sockaddr_un * sup)
{
static uschar queuerun_msgid[MESSAGE_ID_LENGTH+1];
-/* Return TRUE if a sigalrm should be emulated */
+/* The notifier socket has something to read. Pull the message from it, decode
+and do the action.
+
+Return TRUE if a sigalrm should be emulated */
+
static BOOL
daemon_notification(void)
{
{
DEBUG(D_queue_run) debug_printf("%s: sender creds pid %d uid %d gid %d\n",
__FUNCTION__, (int)cr->pid, (int)cr->uid, (int)cr->gid);
- return FALSE;
}
# elif defined(LOCAL_CREDS) /* BSD-ish */
struct sockcred * cr = (struct sockcred *) CMSG_DATA(cp);
{
DEBUG(D_queue_run) debug_printf("%s: sender creds pid ??? uid %d gid %d\n",
__FUNCTION__, (int)cr->sc_uid, (int)cr->sc_gid);
- return FALSE;
}
# endif
break;
(const struct sockaddr *)&sa_un, msg.msg_namelen) < 0)
log_write(0, LOG_MAIN|LOG_PANIC,
"%s: sendto: %s\n", __FUNCTION__, strerror(errno));
- return FALSE;
+ break;
}
+
+ case NOTIFY_REGEX:
+ regex_at_daemon(buf);
+ break;
}
return FALSE;
}
if (!regex_IGNOREQUOTA)
regex_IGNOREQUOTA =
- regex_must_compile(US"\\n250[\\s\\-]IGNOREQUOTA(\\s|\\n|$)", FALSE, TRUE);
+ regex_must_compile(US"\\n250[\\s\\-]IGNOREQUOTA(\\s|\\n|$)", MCS_NOFLAGS, TRUE);
/* Handle local deliveries */
{
if (check_dns_names_pattern[0] != 0 && !regex_check_dns_names)
regex_check_dns_names =
- regex_must_compile(check_dns_names_pattern, FALSE, TRUE);
+ regex_must_compile(check_dns_names_pattern, MCS_NOFLAGS, TRUE);
}
/* vi: aw ai sw=2
}
else
{
- const pcre2_code *regex_islookupmod = regex_must_compile(
- US"\\." DYNLIB_FN_EXT "$", FALSE, TRUE);
+ const pcre2_code * regex_islookupmod = regex_must_compile(
+ US"\\." DYNLIB_FN_EXT "$", MCS_NOFLAGS, TRUE);
DEBUG(D_lookup) debug_printf("Loading lookup modules from %s\n", LOOKUP_MODULE_DIR);
while ((ent = readdir(dd)))
-/*************************************************
-* Compile regular expression and panic on fail *
-*************************************************/
-
-/* This function is called when failure to compile a regular expression leads
-to a panic exit. In other cases, pcre_compile() is called directly. In many
-cases where this function is used, the results of the compilation are to be
-placed in long-lived store, so we temporarily reset the store management
-functions that PCRE uses if the use_malloc flag is set.
-
-Argument:
- pattern the pattern to compile
- caseless TRUE if caseless matching is required
- use_malloc TRUE if compile into malloc store
-
-Returns: pointer to the compiled pattern
-*/
-
-const pcre2_code *
-regex_must_compile(const uschar * pattern, BOOL caseless, BOOL use_malloc)
-{
-size_t offset;
-int options = caseless ? PCRE_COPT|PCRE2_CASELESS : PCRE_COPT;
-const pcre2_code * yield;
-int err;
-
-if (!(yield = pcre2_compile((PCRE2_SPTR)pattern, PCRE2_ZERO_TERMINATED, options,
- &err, &offset, use_malloc ? pcre_mlc_cmp_ctx : pcre_gen_cmp_ctx)))
- {
- uschar errbuf[128];
- pcre2_get_error_message(err, errbuf, sizeof(errbuf));
- log_write(0, LOG_MAIN|LOG_PANIC_DIE, "regular expression error: "
- "%s at offset %ld while compiling %s", errbuf, (long)offset, pattern);
- }
-
-return yield;
-}
-
-
static void
pcre_init(void)
{
using mac_ismsgid, which uses this. */
regex_ismsgid =
- regex_must_compile(US"^(?:[^\\W_]{6}-){2}[^\\W_]{2}$", FALSE, TRUE);
+ regex_must_compile(US"^(?:[^\\W_]{6}-){2}[^\\W_]{2}$", MCS_NOFLAGS, TRUE);
/* Precompile the regular expression that is used for matching an SMTP error
code, possibly extended, at the start of an error message. Note that the
regex_smtp_code =
regex_must_compile(US"^\\d\\d\\d\\s(?:\\d\\.\\d\\d?\\d?\\.\\d\\d?\\d?\\s)?",
- FALSE, TRUE);
+ MCS_NOFLAGS, TRUE);
#ifdef WHITELIST_D_MACROS
/* Precompile the regular expression used to filter the content of macros
given to -D for permissibility. */
regex_whitelisted_macro =
- regex_must_compile(US"^[A-Za-z0-9_/.-]*$", FALSE, TRUE);
+ regex_must_compile(US"^[A-Za-z0-9_/.-]*$", MCS_NOFLAGS, TRUE);
#endif
for (i = 0; i < REGEX_VARS; i++) regex_vars[i] = NULL;
-bdf: Ditto, but in the foreground.
*/
case 'd':
- f.daemon_listen = TRUE;
+ f.daemon_listen = f.daemon_scion = TRUE;
if (*argrest == 'f') f.background_daemon = FALSE;
else if (*argrest) badarg = TRUE;
break;
case 'w':
f.inetd_wait_mode = TRUE;
f.background_daemon = FALSE;
- f.daemon_listen = TRUE;
+ f.daemon_listen = f.daemon_scion = TRUE;
if (*argrest)
if ((inetd_wait_timeout = readconf_readtime(argrest, 0, FALSE)) <= 0)
exim_fail("exim: bad time value %s: abandoned\n", argv[i]);
if (gecos_pattern && gecos_name)
{
const pcre2_code *re;
- re = regex_must_compile(gecos_pattern, FALSE, TRUE); /* Use malloc */
+ re = regex_must_compile(gecos_pattern, MCS_NOFLAGS, TRUE); /* Use malloc */
if (regex_match_and_setup(re, name, 0, -1))
{
/* Recursively called function */
-static uschar *expand_string_internal(const uschar *, BOOL, const uschar **, BOOL, BOOL, BOOL *);
+static uschar *expand_string_internal(const uschar *, BOOL, const uschar **, BOOL, BOOL, BOOL *, BOOL *);
static int_eximarith_t expanded_string_integer(const uschar *, BOOL);
#ifdef STAND_ALONE
int fd;
ssize_t len;
const uschar * where;
-#ifndef EXIM_HAVE_ABSTRACT_UNIX_SOCKETS
uschar * sname;
-#endif
if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
{
return NULL;
}
-#ifdef EXIM_HAVE_ABSTRACT_UNIX_SOCKETS
-sa_un.sun_path[0] = 0; /* Abstract local socket addr - Linux-specific? */
-len = offsetof(struct sockaddr_un, sun_path) + 1
- + snprintf(sa_un.sun_path+1, sizeof(sa_un.sun_path)-1, "exim_%d", getpid());
-#else
-sname = string_sprintf("%s/p_%d", spool_directory, getpid());
-len = offsetof(struct sockaddr_un, sun_path)
- + snprintf(sa_un.sun_path, sizeof(sa_un.sun_path), "%s", sname);
-#endif
+len = daemon_client_sockname(&sa_un, &sname);
-if (bind(fd, (const struct sockaddr *)&sa_un, len) < 0)
+if (bind(fd, (const struct sockaddr *)&sa_un, (socklen_t)len) < 0)
{ where = US"bind"; goto bad; }
#ifdef notdef
check_end if TRUE, check for final '}'
name name of item, for error message
resetok if not NULL, pointer to flag - write FALSE if unsafe to reset
- the store.
+ the store
+ textonly_p if not NULL, pointer to bitmask of which subs were text-only
+ (did not change when expended)
Returns: 0 OK; string pointer updated
1 curly bracketing error (too few arguments)
static int
read_subs(uschar **sub, int n, int m, const uschar **sptr, BOOL skipping,
- BOOL check_end, uschar *name, BOOL *resetok)
+ BOOL check_end, uschar *name, BOOL *resetok, unsigned * textonly_p)
{
-const uschar *s = *sptr;
+const uschar * s = *sptr;
+unsigned textonly_l = 0;
Uskip_whitespace(&s);
for (int i = 0; i < n; i++)
{
+ BOOL textonly;
if (*s != '{')
{
if (i < m)
sub[i] = NULL;
break;
}
- if (!(sub[i] = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, resetok)))
+ if (!(sub[i] = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, resetok,
+ textonly_p ? &textonly : NULL)))
return 3;
if (*s++ != '}') return 1;
+ if (textonly_p && textonly) textonly_l |= BIT(i);
Uskip_whitespace(&s);
}
if (check_end && *s++ != '}')
return 1;
}
+if (textonly_p) *textonly_p = textonly_l;
*sptr = s;
return 0;
}
*/
static const uschar *
-eval_condition(const uschar *s, BOOL *resetok, BOOL *yield)
+eval_condition(const uschar * s, BOOL * resetok, BOOL * yield)
{
BOOL testfor = TRUE;
BOOL tempcond, combined_cond;
-BOOL *subcondptr;
+BOOL * subcondptr;
BOOL sub2_honour_dollar = TRUE;
BOOL is_forany, is_json, is_jsons;
int rc, cond_type;
struct stat statbuf;
uschar * opname;
uschar name[256];
-const uschar *sub[10];
+const uschar * sub[10];
+unsigned sub_textonly = 0;
for (;;)
if (Uskip_whitespace(&s) == '!') { testfor = !testfor; s++; } else break;
if (Uskip_whitespace(&s) != '{') goto COND_FAILED_CURLY_START; /* }-for-text-editors */
- sub[0] = expand_string_internal(s+1, TRUE, &s, yield == NULL, TRUE, resetok);
- if (!sub[0]) return NULL;
+ {
+ BOOL textonly;
+ sub[0] = expand_string_internal(s+1, TRUE, &s, yield == NULL, TRUE, resetok, &textonly);
+ if (!sub[0]) return NULL;
+ if (textonly) sub_textonly |= BIT(0);
+ }
/* {-for-text-editors */
if (*s++ != '}') goto COND_FAILED_CURLY_END;
if (*s++ != '{') goto COND_FAILED_CURLY_START; /*}*/
switch(read_subs(sub, nelem(sub), 1,
- &s, yield == NULL, TRUE, name, resetok))
+ &s, yield == NULL, TRUE, name, resetok, NULL))
{
case 1: expand_string_message = US"too few arguments or bracketing "
"error for acl";
Uskip_whitespace(&s);
if (*s++ != '{') goto COND_FAILED_CURLY_START; /* }-for-text-editors */
switch(read_subs(sub, nelem(sub), 2, &s, yield == NULL, TRUE, name,
- resetok))
+ resetok, NULL))
{
case 1: expand_string_message = US"too few arguments or bracketing "
"error for saslauthd";
for (int i = 0; i < 2; i++)
{
+ BOOL textonly;
/* Sometimes, we don't expand substrings; too many insecure configurations
created using match_address{}{} and friends, where the second param
includes information from untrustworthy sources. */
+ /*XXX is this moot given taint-tracking? */
BOOL honour_dollar = TRUE;
if ((i > 0) && !sub2_honour_dollar)
honour_dollar = FALSE;
return NULL;
}
if (!(sub[i] = expand_string_internal(s+1, TRUE, &s, yield == NULL,
- honour_dollar, resetok)))
+ honour_dollar, resetok, &textonly)))
return NULL;
+ if (textonly) sub_textonly |= BIT(i);
DEBUG(D_expand) if (i == 1 && !sub2_honour_dollar && Ustrchr(sub[1], '$'))
debug_printf_indent("WARNING: the second arg is NOT expanded,"
" for security reasons\n");
case ECOND_MATCH: /* Regular expression match */
{
- const pcre2_code * re;
- PCRE2_SIZE offset;
- int err;
-
- if (!(re = pcre2_compile((PCRE2_SPTR)sub[1], PCRE2_ZERO_TERMINATED,
- PCRE_COPT, &err, &offset, pcre_gen_cmp_ctx)))
- {
- uschar errbuf[128];
- pcre2_get_error_message(err, errbuf, sizeof(errbuf));
- expand_string_message = string_sprintf("regular expression error in "
- "\"%s\": %s at offset %ld", sub[1], errbuf, (long)offset);
+ const pcre2_code * re = regex_compile(sub[1],
+ sub_textonly & BIT(1) ? MCS_CACHEABLE : MCS_NOFLAGS,
+ &expand_string_message, pcre_gen_cmp_ctx);
+ if (!re)
return NULL;
- }
tempcond = regex_match_and_setup(re, sub[0], 0, -1);
break;
Uskip_whitespace(&s);
if (*s++ != '{') goto COND_FAILED_CURLY_START; /* }-for-text-editors */
- if (!(sub[0] = expand_string_internal(s, TRUE, &s, yield == NULL, TRUE, resetok)))
+ if (!(sub[0] = expand_string_internal(s, TRUE, &s, yield == NULL, TRUE, resetok, NULL)))
return NULL;
/* {-for-text-editors */
if (*s++ != '}') goto COND_FAILED_CURLY_END;
if (Uskip_whitespace(&s) != '{') goto COND_FAILED_CURLY_START; /* }-for-text-editors */
ourname = cond_type == ECOND_BOOL_LAX ? US"bool_lax" : US"bool";
- switch(read_subs(sub_arg, 1, 1, &s, yield == NULL, FALSE, ourname, resetok))
+ switch(read_subs(sub_arg, 1, 1, &s, yield == NULL, FALSE, ourname, resetok, NULL))
{
case 1: expand_string_message = string_sprintf(
"too few arguments or bracketing error for %s",
uschar cksum[4];
BOOL boolvalue = FALSE;
- switch(read_subs(sub, 2, 2, CUSS &s, yield == NULL, FALSE, name, resetok))
+ switch(read_subs(sub, 2, 2, CUSS &s, yield == NULL, FALSE, name, resetok, NULL))
{
case 1: expand_string_message = US"too few arguments or bracketing "
"error for inbound_srs";
/* Match the given local_part against the SRS-encoded pattern */
re = regex_must_compile(US"^(?i)SRS0=([^=]+)=([A-Z2-7]+)=([^=]*)=(.*)$",
- TRUE, FALSE);
+ MCS_CASELESS | MCS_CACHEABLE, FALSE);
md = pcre2_match_data_create(4+1, pcre_gen_ctx);
if (pcre2_match(re, sub[0], PCRE2_ZERO_TERMINATED, 0, PCRE_EOPT,
md, pcre_gen_mtc_ctx) < 0)
want this string. Set skipping in the call in the fail case (this will always
be the case if we were already skipping). */
-sub1 = expand_string_internal(s, TRUE, &s, !yes, TRUE, resetok);
+sub1 = expand_string_internal(s, TRUE, &s, !yes, TRUE, resetok, NULL);
if (sub1 == NULL && (yes || !f.expand_string_forcedfail)) goto FAILED;
f.expand_string_forcedfail = FALSE;
if (*s++ != '}')
if (skip_whitespace(&s) == '{')
{
- sub2 = expand_string_internal(s+1, TRUE, &s, yes || skipping, TRUE, resetok);
+ sub2 = expand_string_internal(s+1, TRUE, &s, yes || skipping, TRUE, resetok, NULL);
if (sub2 == NULL && (!yes || !f.expand_string_forcedfail)) goto FAILED;
f.expand_string_forcedfail = FALSE;
if (*s++ != '}')
FALSE if it's just another character
resetok_p if not NULL, pointer to flag - write FALSE if unsafe to reset
the store.
+ textonly_p if not NULL, pointer to flag - write bool for only-met-text
Returns: NULL if expansion fails:
expand_string_forcedfail is set TRUE if failure was forced
static uschar *
expand_string_internal(const uschar *string, BOOL ket_ends, const uschar **left,
- BOOL skipping, BOOL honour_dollar, BOOL *resetok_p)
+ BOOL skipping, BOOL honour_dollar, BOOL *resetok_p, BOOL * textonly_p)
{
rmark reset_point = store_mark();
gstring * yield = string_get(Ustrlen(string) + 64);
const uschar * s = string;
const uschar * save_expand_nstring[EXPAND_MAXN+1];
int save_expand_nlength[EXPAND_MAXN+1];
-BOOL resetok = TRUE, first = TRUE;
+BOOL resetok = TRUE, first = TRUE, textonly = TRUE;
expand_level++;
f.expand_string_forcedfail = FALSE;
s += i;
continue;
}
+ textonly = FALSE;
/* No { after the $ - must be a plain name or a number for string
match variable. There has to be a fudge for variables that are the
int rc;
switch(read_subs(sub, nelem(sub), 1, &s, skipping, TRUE, name,
- &resetok))
+ &resetok, NULL))
{
case 1: goto EXPAND_FAILED_CURLY;
case 2:
uschar * sub_arg[1];
switch(read_subs(sub_arg, nelem(sub_arg), 1, &s, skipping, TRUE, name,
- &resetok))
+ &resetok, NULL))
{
case 1: goto EXPAND_FAILED_CURLY;
case 2:
uschar *encoded;
switch(read_subs(sub_arg, nelem(sub_arg), 1, &s, skipping, TRUE, name,
- &resetok))
+ &resetok, NULL))
{
case 1: goto EXPAND_FAILED_CURLY;
case 2:
if (Uskip_whitespace(&s) == '{') /*}*/
{
- key = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok);
+ key = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok, NULL);
if (!key) goto EXPAND_FAILED; /*{{*/
if (*s++ != '}')
{
expand_string_message = US"missing '{' for lookup file-or-query arg";
goto EXPAND_FAILED_CURLY; /*}}*/
}
- if (!(filename = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok)))
+ if (!(filename = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok, NULL)))
goto EXPAND_FAILED;
/*{{*/
if (*s++ != '}')
}
switch(read_subs(sub_arg, EXIM_PERL_MAX_ARGS + 1, 1, &s, skipping, TRUE,
- name, &resetok))
+ name, &resetok, NULL))
{
case 1: goto EXPAND_FAILED_CURLY;
case 2:
{
uschar * sub_arg[3], * p, * domain;
- switch(read_subs(sub_arg, 3, 2, &s, skipping, TRUE, name, &resetok))
+ switch(read_subs(sub_arg, 3, 2, &s, skipping, TRUE, name, &resetok, NULL))
{
case 1: goto EXPAND_FAILED_CURLY;
case 2:
prvscheck_address = NULL;
prvscheck_keynum = NULL;
- switch(read_subs(sub_arg, 1, 1, &s, skipping, FALSE, name, &resetok))
+ switch(read_subs(sub_arg, 1, 1, &s, skipping, FALSE, name, &resetok, NULL))
{
case 1: goto EXPAND_FAILED_CURLY;
case 2:
case 3: goto EXPAND_FAILED;
}
- re = regex_must_compile(US"^prvs\\=([0-9])([0-9]{3})([A-F0-9]{6})\\=(.+)\\@(.+)$",
- TRUE,FALSE);
+ re = regex_must_compile(
+ US"^prvs\\=([0-9])([0-9]{3})([A-F0-9]{6})\\=(.+)\\@(.+)$",
+ MCS_CASELESS | MCS_CACHEABLE, FALSE);
if (regex_match_and_setup(re,sub_arg[0],0,-1))
{
uschar * hash = string_copyn(expand_nstring[3],expand_nlength[3]);
uschar * domain = string_copyn(expand_nstring[5],expand_nlength[5]);
- DEBUG(D_expand) debug_printf_indent("prvscheck localpart: %s\n", local_part);
- DEBUG(D_expand) debug_printf_indent("prvscheck key number: %s\n", key_num);
- DEBUG(D_expand) debug_printf_indent("prvscheck daystamp: %s\n", daystamp);
- DEBUG(D_expand) debug_printf_indent("prvscheck hash: %s\n", hash);
- DEBUG(D_expand) debug_printf_indent("prvscheck domain: %s\n", domain);
+ DEBUG(D_expand)
+ {
+ debug_printf_indent("prvscheck localpart: %s\n", local_part);
+ debug_printf_indent("prvscheck key number: %s\n", key_num);
+ debug_printf_indent("prvscheck daystamp: %s\n", daystamp);
+ debug_printf_indent("prvscheck hash: %s\n", hash);
+ debug_printf_indent("prvscheck domain: %s\n", domain);
+ }
/* Set up expansion variables */
g = string_cat (NULL, local_part);
prvscheck_keynum = string_copy(key_num);
/* Now expand the second argument */
- switch(read_subs(sub_arg, 1, 1, &s, skipping, FALSE, name, &resetok))
+ switch(read_subs(sub_arg, 1, 1, &s, skipping, FALSE, name, &resetok, NULL))
{
case 1: goto EXPAND_FAILED_CURLY;
case 2:
p = prvs_hmac_sha1(prvscheck_address, sub_arg[0], prvscheck_keynum,
daystamp);
-
if (!p)
{
expand_string_message = US"hmac-sha1 conversion failed";
/* Now expand the final argument. We leave this till now so that
it can include $prvscheck_result. */
- switch(read_subs(sub_arg, 1, 0, &s, skipping, TRUE, name, &resetok))
+ switch(read_subs(sub_arg, 1, 0, &s, skipping, TRUE, name, &resetok, NULL))
{
case 1: goto EXPAND_FAILED_CURLY;
case 2:
We need to make sure all subs are expanded first, so as to skip over
the entire item. */
- switch(read_subs(sub_arg, 2, 1, &s, skipping, TRUE, name, &resetok))
+ switch(read_subs(sub_arg, 2, 1, &s, skipping, TRUE, name, &resetok, NULL))
{
case 1: goto EXPAND_FAILED_CURLY;
case 2:
goto EXPAND_FAILED;
}
- switch(read_subs(sub_arg, 2, 1, &s, skipping, TRUE, name, &resetok))
+ switch(read_subs(sub_arg, 2, 1, &s, skipping, TRUE, name, &resetok, NULL))
{
case 1: goto EXPAND_FAILED_CURLY;
case 2:
/* Read up to 4 arguments, but don't do the end of item check afterwards,
because there may be a string for expansion on failure. */
- switch(read_subs(sub_arg, 4, 2, &s, skipping, FALSE, name, &resetok))
+ switch(read_subs(sub_arg, 4, 2, &s, skipping, FALSE, name, &resetok, NULL))
{
case 1: goto EXPAND_FAILED_CURLY;
case 2: /* Won't occur: no end check */
if (*s == '{') /*}*/
{
- if (!expand_string_internal(s+1, TRUE, &s, TRUE, TRUE, &resetok))
+ if (!expand_string_internal(s+1, TRUE, &s, TRUE, TRUE, &resetok, NULL))
goto EXPAND_FAILED; /*{*/
if (*s++ != '}')
{ /*{*/
SOCK_FAIL:
if (*s != '{') goto EXPAND_FAILED; /*}*/
DEBUG(D_any) debug_printf("%s\n", expand_string_message);
- if (!(arg = expand_string_internal(s+1, TRUE, &s, FALSE, TRUE, &resetok)))
+ if (!(arg = expand_string_internal(s+1, TRUE, &s, FALSE, TRUE, &resetok, NULL)))
goto EXPAND_FAILED;
yield = string_cat(yield, arg); /*{*/
if (*s++ != '}')
s++;
if (late_expand) /* this is the default case */
- {
+ { /*{*/
int n = Ustrcspn(s, "}");
arg = skipping ? NULL : string_copyn(s, n);
s += n;
}
else
{
- if (!(arg = expand_string_internal(s, TRUE, &s, skipping, TRUE, &resetok)))
+ if (!(arg = expand_string_internal(s, TRUE, &s, skipping, TRUE, &resetok, NULL)))
goto EXPAND_FAILED;
Uskip_whitespace(&s);
}
int o2m;
uschar * sub[3];
- switch(read_subs(sub, 3, 3, &s, skipping, TRUE, name, &resetok))
+ switch(read_subs(sub, 3, 3, &s, skipping, TRUE, name, &resetok, NULL))
{
case 1: goto EXPAND_FAILED_CURLY;
case 2:
sub[2] = NULL;
switch(read_subs(sub, (item_type == EITEM_LENGTH)? 2:3, 2, &s, skipping,
- TRUE, name, &resetok))
+ TRUE, name, &resetok, NULL))
{
case 1: goto EXPAND_FAILED_CURLY;
case 2:
uschar innerkey[MAX_HASHBLOCKLEN];
uschar outerkey[MAX_HASHBLOCKLEN];
- switch (read_subs(sub, 3, 3, &s, skipping, TRUE, name, &resetok))
+ switch (read_subs(sub, 3, 3, &s, skipping, TRUE, name, &resetok, NULL))
{
case 1: goto EXPAND_FAILED_CURLY;
case 2:
{
const pcre2_code * re;
int moffset, moffsetextra, slen;
- PCRE2_SIZE roffset;
pcre2_match_data * md;
- int err, emptyopt;
+ int emptyopt;
uschar * subject, * sub[3];
int save_expand_nmax =
save_expand_strings(save_expand_nstring, save_expand_nlength);
+ unsigned sub_textonly = 0;
- switch(read_subs(sub, 3, 3, &s, skipping, TRUE, name, &resetok))
+ switch(read_subs(sub, 3, 3, &s, skipping, TRUE, name, &resetok, &sub_textonly))
{
case 1: goto EXPAND_FAILED_CURLY;
case 2:
/* Compile the regular expression */
- if (!(re = pcre2_compile((PCRE2_SPTR)sub[1], PCRE2_ZERO_TERMINATED,
- PCRE_COPT, &err, &roffset, pcre_gen_cmp_ctx)))
- {
- uschar errbuf[128];
- pcre2_get_error_message(err, errbuf, sizeof(errbuf));
- expand_string_message = string_sprintf("regular expression error in "
- "\"%s\": %s at offset %ld", sub[1], errbuf, (long)roffset);
+ re = regex_compile(sub[1],
+ sub_textonly & BIT(1) ? MCS_CACHEABLE : MCS_NOFLAGS,
+ &expand_string_message, pcre_gen_cmp_ctx);
+ if (!re)
goto EXPAND_FAILED;
- }
+
md = pcre2_match_data_create(EXPAND_MAXN + 1, pcre_gen_ctx);
/* Now run a loop to do the substitutions as often as necessary. It ends
{
for (int j = 5; j > 0 && *s == '{'; j--) /*'}'*/
{
- if (!expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok))
+ if (!expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok, NULL))
goto EXPAND_FAILED; /*'{'*/
if (*s++ != '}')
{
{
if (Uskip_whitespace(&s) == '{') /*'}'*/
{
- if (!(sub[i] = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok)))
+ if (!(sub[i] = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok, NULL)))
goto EXPAND_FAILED; /*'{'*/
if (*s++ != '}')
{
goto EXPAND_FAILED_CURLY;
}
- sub[i] = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok);
+ sub[i] = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok, NULL);
if (!sub[i]) goto EXPAND_FAILED; /*{{*/
if (*s++ != '}')
{
case EITEM_LISTQUOTE:
{
uschar * sub[2];
- switch(read_subs(sub, 2, 2, &s, skipping, TRUE, name, &resetok))
+ switch(read_subs(sub, 2, 2, &s, skipping, TRUE, name, &resetok, NULL))
{
case 1: goto EXPAND_FAILED_CURLY;
case 2:
expand_string_message = US"missing '{' for field arg of certextract";
goto EXPAND_FAILED_CURLY; /*}*/
}
- sub[0] = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok);
+ sub[0] = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok, NULL);
if (!sub[0]) goto EXPAND_FAILED; /*{{*/
if (*s++ != '}')
{
"be a certificate variable";
goto EXPAND_FAILED;
}
- sub[1] = expand_string_internal(s+1, TRUE, &s, skipping, FALSE, &resetok);
+ sub[1] = expand_string_internal(s+1, TRUE, &s, skipping, FALSE, &resetok, NULL);
if (!sub[1]) goto EXPAND_FAILED; /*{{*/
if (*s++ != '}')
{
goto EXPAND_FAILED_CURLY; /*}*/
}
- if (!(list = expand_string_internal(s, TRUE, &s, skipping, TRUE, &resetok)))
+ if (!(list = expand_string_internal(s, TRUE, &s, skipping, TRUE, &resetok, NULL)))
goto EXPAND_FAILED; /*{{*/
if (*s++ != '}')
{
expand_string_message = US"missing '{' for second arg of reduce";
goto EXPAND_FAILED_CURLY; /*}*/
}
- t = expand_string_internal(s, TRUE, &s, skipping, TRUE, &resetok);
+ t = expand_string_internal(s, TRUE, &s, skipping, TRUE, &resetok, NULL);
if (!t) goto EXPAND_FAILED;
lookup_value = t; /*{{*/
if (*s++ != '}')
the normal internal expansion function. */
if (item_type != EITEM_FILTER)
- temp = expand_string_internal(s, TRUE, &s, TRUE, TRUE, &resetok);
+ temp = expand_string_internal(s, TRUE, &s, TRUE, TRUE, &resetok, NULL);
else
if ((temp = eval_condition(expr, &resetok, NULL))) s = temp;
else
{
- uschar * t = expand_string_internal(expr, TRUE, NULL, skipping, TRUE, &resetok);
+ uschar * t = expand_string_internal(expr, TRUE, NULL, skipping, TRUE, &resetok, NULL);
temp = t;
if (!temp)
{
goto EXPAND_FAILED_CURLY; /*}*/
}
- srclist = expand_string_internal(s, TRUE, &s, skipping, TRUE, &resetok);
+ srclist = expand_string_internal(s, TRUE, &s, skipping, TRUE, &resetok, NULL);
if (!srclist) goto EXPAND_FAILED; /*{{*/
if (*s++ != '}')
{
goto EXPAND_FAILED_CURLY; /*}*/
}
- cmp = expand_string_internal(s, TRUE, &s, skipping, FALSE, &resetok);
+ cmp = expand_string_internal(s, TRUE, &s, skipping, FALSE, &resetok, NULL);
if (!cmp) goto EXPAND_FAILED; /*{{*/
if (*s++ != '}')
{
}
xtract = s;
- if (!(tmp = expand_string_internal(s, TRUE, &s, TRUE, TRUE, &resetok)))
+ if (!(tmp = expand_string_internal(s, TRUE, &s, TRUE, TRUE, &resetok, NULL)))
goto EXPAND_FAILED;
xtract = string_copyn(xtract, s - xtract);
/*{{*/
/* extract field for comparisons */
iterate_item = srcitem;
if ( !(srcfield = expand_string_internal(xtract, FALSE, NULL, FALSE,
- TRUE, &resetok))
+ TRUE, &resetok, NULL))
|| !*srcfield)
{
expand_string_message = string_sprintf(
}
switch(read_subs(argv, EXPAND_DLFUNC_MAX_ARGS + 2, 2, &s, skipping,
- TRUE, name, &resetok))
+ TRUE, name, &resetok, NULL))
{
case 1: goto EXPAND_FAILED_CURLY;
case 2:
if (Uskip_whitespace(&s) != '{') /*}*/
goto EXPAND_FAILED;
- key = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok);
+ key = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok, NULL);
if (!key) goto EXPAND_FAILED; /*{{*/
if (*s++ != '}')
{
gstring * g = NULL;
BOOL quoted = FALSE;
- switch (read_subs(sub, 3, 3, CUSS &s, skipping, TRUE, name, &resetok))
+ switch (read_subs(sub, 3, 3, CUSS &s, skipping, TRUE, name, &resetok, NULL))
{
case 1: goto EXPAND_FAILED_CURLY;
case 2:
{
const uschar * s1 = s;
sub = expand_string_internal(s+2, TRUE, &s1, skipping,
- FALSE, &resetok);
+ FALSE, &resetok, NULL);
if (!sub) goto EXPAND_FAILED; /*{*/
if (*s1 != '}')
{ /*{*/
/*FALLTHROUGH*/
#endif
default:
- sub = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok);
+ sub = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok, NULL);
if (!sub) goto EXPAND_FAILED;
s++;
break;
case EOP_EXPAND:
{
- uschar *expanded = expand_string_internal(sub, FALSE, NULL, skipping, TRUE, &resetok);
+ uschar *expanded = expand_string_internal(sub, FALSE, NULL, skipping, TRUE, &resetok, NULL);
if (!expanded)
{
expand_string_message =
terminating brace. */
if (ket_ends && !*s)
- {
+ { /*{{*/
expand_string_message = malformed_header
? US"missing } at end of string - could be header name not terminated by colon"
: US"missing } at end of string";
"skipping: result is not used\n");
}
}
+if (textonly_p) *textonly_p = textonly;
expand_level--;
return yield->s;
}
+
/* This is the external function call. Do a quick check for any expansion
metacharacters, and if there are none, just return the input string.
-Argument: the string to be expanded
+Arguments
+ the string to be expanded
+ optional pointer for return boolean indicating no-dynamic-expansions
+
Returns: the expanded string, or NULL if expansion failed; if failure was
due to a lookup deferring, search_find_defer will be TRUE
*/
const uschar *
-expand_cstring(const uschar * string)
+expand_string_2(const uschar * string, BOOL * textonly_p)
{
if (Ustrpbrk(string, "$\\") != NULL)
{
f.search_find_defer = FALSE;
malformed_header = FALSE;
store_pool = POOL_MAIN;
- s = expand_string_internal(string, FALSE, NULL, FALSE, TRUE, NULL);
+ s = expand_string_internal(string, FALSE, NULL, FALSE, TRUE, NULL, textonly_p);
store_pool = old_pool;
return s;
}
+if (textonly_p) *textonly_p = TRUE;
return string;
}
+const uschar *
+expand_cstring(const uschar * string)
+{ return expand_string_2(string, NULL); }
uschar *
expand_string(uschar * string)
-{
-return US expand_cstring(CUS string);
-}
+{ return US expand_string_2(CUS string, NULL); }
+
*/
static BOOL
-test_condition(condition_block *c, BOOL toplevel)
+test_condition(condition_block * c, BOOL toplevel)
{
-BOOL yield = FALSE;
-const uschar *exp[2], * p, * pp;
+BOOL yield = FALSE, textonly_re;
+const uschar * exp[2], * p, * pp;
int val[2];
-int i;
-if (c == NULL) return TRUE; /* does this ever occur? */
+if (!c) return TRUE; /* does this ever occur? */
switch (c->type)
{
case cond_and:
- yield = test_condition(c->left.c, FALSE) &&
- *error_pointer == NULL &&
- test_condition(c->right.c, FALSE);
- break;
+ yield = test_condition(c->left.c, FALSE) &&
+ *error_pointer == NULL &&
+ test_condition(c->right.c, FALSE);
+ break;
case cond_or:
- yield = test_condition(c->left.c, FALSE) ||
- (*error_pointer == NULL &&
- test_condition(c->right.c, FALSE));
- break;
+ yield = test_condition(c->left.c, FALSE) ||
+ (*error_pointer == NULL &&
+ test_condition(c->right.c, FALSE));
+ break;
- /* The personal test is meaningless in a system filter. The tests are now in
- a separate function (so Sieve can use them). However, an Exim filter does not
- scan Cc: (hence the FALSE argument). */
+ /* The personal test is meaningless in a system filter. The tests are now in
+ a separate function (so Sieve can use them). However, an Exim filter does not
+ scan Cc: (hence the FALSE argument). */
case cond_personal:
- yield = f.system_filtering? FALSE : filter_personal(c->left.a, FALSE);
- break;
+ yield = f.system_filtering? FALSE : filter_personal(c->left.a, FALSE);
+ break;
case cond_delivered:
- yield = filter_delivered;
- break;
+ yield = filter_delivered;
+ break;
- /* Only TRUE if a message is actually being processed; FALSE for address
- testing and verification. */
+ /* Only TRUE if a message is actually being processed; FALSE for address
+ testing and verification. */
case cond_errormsg:
- yield = message_id[0] != 0 &&
- (sender_address == NULL || sender_address[0] == 0);
- break;
+ yield = message_id[0] != 0 &&
+ (sender_address == NULL || sender_address[0] == 0);
+ break;
- /* Only FALSE if a message is actually being processed; TRUE for address
- and filter testing and verification. */
+ /* Only FALSE if a message is actually being processed; TRUE for address
+ and filter testing and verification. */
case cond_firsttime:
- yield = filter_test != FTEST_NONE || message_id[0] == 0 || f.deliver_firsttime;
- break;
+ yield = filter_test != FTEST_NONE || message_id[0] == 0 || f.deliver_firsttime;
+ break;
- /* Only TRUE if a message is actually being processed; FALSE for address
- testing and verification. */
+ /* Only TRUE if a message is actually being processed; FALSE for address
+ testing and verification. */
case cond_manualthaw:
- yield = message_id[0] != 0 && f.deliver_manual_thaw;
- break;
+ yield = message_id[0] != 0 && f.deliver_manual_thaw;
+ break;
- /* The foranyaddress condition loops through a list of addresses */
+ /* The foranyaddress condition loops through a list of addresses */
case cond_foranyaddress:
- p = c->left.u;
- if (!(pp = expand_cstring(p)))
- {
- *error_pointer = string_sprintf("failed to expand \"%s\" in "
- "filter file: %s", p, expand_string_message);
- return FALSE;
- }
+ p = c->left.u;
+ if (!(pp = expand_cstring(p)))
+ {
+ *error_pointer = string_sprintf("failed to expand \"%s\" in "
+ "filter file: %s", p, expand_string_message);
+ return FALSE;
+ }
- yield = FALSE;
- f.parse_allow_group = TRUE; /* Allow group syntax */
+ yield = FALSE;
+ f.parse_allow_group = TRUE; /* Allow group syntax */
- while (*pp)
- {
- uschar *error;
- int start, end, domain;
- uschar * s;
+ while (*pp)
+ {
+ uschar *error;
+ int start, end, domain;
+ uschar * s;
- p = parse_find_address_end(pp, FALSE);
- s = string_copyn(pp, p - pp);
+ p = parse_find_address_end(pp, FALSE);
+ s = string_copyn(pp, p - pp);
- filter_thisaddress =
- parse_extract_address(s, &error, &start, &end, &domain, FALSE);
+ filter_thisaddress =
+ parse_extract_address(s, &error, &start, &end, &domain, FALSE);
- if (filter_thisaddress)
- {
- if ((filter_test != FTEST_NONE && debug_selector != 0) ||
- (debug_selector & D_filter) != 0)
- {
- indent();
- debug_printf_indent("Extracted address %s\n", filter_thisaddress);
- }
- yield = test_condition(c->right.c, FALSE);
- }
+ if (filter_thisaddress)
+ {
+ if ((filter_test != FTEST_NONE && debug_selector != 0) ||
+ (debug_selector & D_filter) != 0)
+ {
+ indent();
+ debug_printf_indent("Extracted address %s\n", filter_thisaddress);
+ }
+ yield = test_condition(c->right.c, FALSE);
+ }
- if (yield) break;
- if (!*p) break;
- pp = p + 1;
- }
+ if (yield) break;
+ if (!*p) break;
+ pp = p + 1;
+ }
- f.parse_allow_group = FALSE; /* Reset group syntax flags */
- f.parse_found_group = FALSE;
- break;
+ f.parse_allow_group = FALSE; /* Reset group syntax flags */
+ f.parse_found_group = FALSE;
+ break;
- /* All other conditions have left and right values that need expanding;
- on error, it doesn't matter what value is returned. */
+ /* All other conditions have left and right values that need expanding;
+ on error, it doesn't matter what value is returned. */
- default:
- p = c->left.u;
- for (i = 0; i < 2; i++)
- {
- if (!(exp[i] = expand_cstring(p)))
+ default:
+ p = c->left.u;
+ for (int i = 0; i < 2; i++)
{
- *error_pointer = string_sprintf("failed to expand \"%s\" in "
- "filter file: %s", p, expand_string_message);
- return FALSE;
+ if (!(exp[i] = expand_string_2(p, &textonly_re)))
+ {
+ *error_pointer = string_sprintf("failed to expand \"%s\" in "
+ "filter file: %s", p, expand_string_message);
+ return FALSE;
+ }
+ p = c->right.u;
}
- p = c->right.u;
- }
- /* Inner switch for the different cases */
-
- switch(c->type)
- {
- case cond_is:
- yield = strcmpic(exp[0], exp[1]) == 0;
- break;
+ /* Inner switch for the different cases */
- case cond_IS:
- yield = Ustrcmp(exp[0], exp[1]) == 0;
- break;
-
- case cond_contains:
- yield = strstric_c(exp[0], exp[1], FALSE) != NULL;
- break;
+ switch(c->type)
+ {
+ case cond_is:
+ yield = strcmpic(exp[0], exp[1]) == 0;
+ break;
- case cond_CONTAINS:
- yield = Ustrstr(exp[0], exp[1]) != NULL;
- break;
+ case cond_IS:
+ yield = Ustrcmp(exp[0], exp[1]) == 0;
+ break;
- case cond_begins:
- yield = strncmpic(exp[0], exp[1], Ustrlen(exp[1])) == 0;
- break;
+ case cond_contains:
+ yield = strstric_c(exp[0], exp[1], FALSE) != NULL;
+ break;
- case cond_BEGINS:
- yield = Ustrncmp(exp[0], exp[1], Ustrlen(exp[1])) == 0;
- break;
+ case cond_CONTAINS:
+ yield = Ustrstr(exp[0], exp[1]) != NULL;
+ break;
- case cond_ends:
- case cond_ENDS:
- {
- int len = Ustrlen(exp[1]);
- const uschar *s = exp[0] + Ustrlen(exp[0]) - len;
- yield = s < exp[0]
- ? FALSE
- : (c->type == cond_ends ? strcmpic(s, exp[1]) : Ustrcmp(s, exp[1])) == 0;
- }
- break;
+ case cond_begins:
+ yield = strncmpic(exp[0], exp[1], Ustrlen(exp[1])) == 0;
+ break;
- case cond_matches:
- case cond_MATCHES:
- {
- const pcre2_code *re;
- int err;
- PCRE2_SIZE offset;
+ case cond_BEGINS:
+ yield = Ustrncmp(exp[0], exp[1], Ustrlen(exp[1])) == 0;
+ break;
- if ((filter_test != FTEST_NONE && debug_selector != 0) ||
- (debug_selector & D_filter) != 0)
+ case cond_ends:
+ case cond_ENDS:
{
- debug_printf_indent("Match expanded arguments:\n");
- debug_printf_indent(" Subject = %s\n", exp[0]);
- debug_printf_indent(" Pattern = %s\n", exp[1]);
+ int len = Ustrlen(exp[1]);
+ const uschar *s = exp[0] + Ustrlen(exp[0]) - len;
+ yield = s < exp[0]
+ ? FALSE
+ : (c->type == cond_ends ? strcmpic(s, exp[1]) : Ustrcmp(s, exp[1])) == 0;
+ break;
}
- if (!(re = pcre2_compile((PCRE2_SPTR)exp[1], PCRE2_ZERO_TERMINATED,
- PCRE_COPT | (c->type == cond_matches ? PCRE2_CASELESS : 0),
- &err, &offset, pcre_gen_cmp_ctx)))
+ case cond_matches:
+ case cond_MATCHES:
{
- uschar errbuf[128];
- pcre2_get_error_message(err, errbuf, sizeof(errbuf));
- *error_pointer = string_sprintf("error while compiling "
- "regular expression \"%s\": %s at offset %ld",
- exp[1], errbuf, (long)offset);
- return FALSE;
- }
+ const pcre2_code * re;
+ mcs_flags flags = textonly_re ? MCS_CACHEABLE : MCS_NOFLAGS;
- yield = regex_match_and_setup(re, exp[0], PCRE_EOPT, -1);
- break;
- }
+ if ((filter_test != FTEST_NONE && debug_selector != 0) ||
+ (debug_selector & D_filter) != 0)
+ {
+ debug_printf_indent("Match expanded arguments:\n");
+ debug_printf_indent(" Subject = %s\n", exp[0]);
+ debug_printf_indent(" Pattern = %s\n", exp[1]);
+ }
- /* For above and below, convert the strings to numbers */
+ if (c->type == cond_matches) flags |= MCS_CASELESS;
+ if (!(re = regex_compile(exp[1], flags, error_pointer, pcre_gen_cmp_ctx)))
+ return FALSE;
- case cond_above:
- case cond_below:
- for (i = 0; i < 2; i++)
- {
- val[i] = get_number(exp[i], &yield);
- if (!yield)
- {
- *error_pointer = string_sprintf("malformed numerical string \"%s\"",
- exp[i]);
- return FALSE;
- }
+ yield = regex_match_and_setup(re, exp[0], PCRE_EOPT, -1);
+ break;
+ }
+
+ /* For above and below, convert the strings to numbers */
+
+ case cond_above:
+ case cond_below:
+ for (int i = 0; i < 2; i++)
+ {
+ val[i] = get_number(exp[i], &yield);
+ if (!yield)
+ {
+ *error_pointer = string_sprintf("malformed numerical string \"%s\"",
+ exp[i]);
+ return FALSE;
+ }
+ }
+ yield = c->type == cond_above ? (val[0] > val[1]) : (val[0] < val[1]);
+ break;
}
- yield = (c->type == cond_above)? (val[0] > val[1]) : (val[0] < val[1]);
break;
- }
- break;
}
if ((filter_test != FTEST_NONE && debug_selector != 0) ||
commands = commands->next;
}
-return filter_delivered? FF_DELIVERED : FF_NOTDELIVERED;
+return filter_delivered ? FF_DELIVERED : FF_NOTDELIVERED;
}
extern void daemon_go(void);
#ifndef COMPILE_UTILITY
+extern ssize_t daemon_client_sockname(struct sockaddr_un *, uschar **);
extern ssize_t daemon_notifier_sockname(struct sockaddr_un *);
#endif
extern BOOL expand_check_condition(uschar *, uschar *, uschar *);
extern uschar *expand_file_big_buffer(const uschar *);
extern uschar *expand_string(uschar *); /* public, cannot make const */
+extern const uschar *expand_string_2(const uschar *, BOOL *);
extern const uschar *expand_cstring(const uschar *); /* ... so use this one */
extern uschar *expand_getkeyed(const uschar *, const uschar *);
extern uschar *macros_expand(int, int *, BOOL *);
extern void mainlog_close(void);
#ifdef WITH_CONTENT_SCAN
-extern int malware(const uschar *, int);
+extern int malware(const uschar *, BOOL, int);
extern int malware_in_file(uschar *);
extern void malware_init(void);
extern gstring * malware_show_supported(gstring *);
const uschar *, const uschar **);
extern int match_isinlist(const uschar *, const uschar **, int, tree_node **,
unsigned int *, int, BOOL, const uschar **);
-extern int match_check_string(const uschar *, const uschar *, int, BOOL, BOOL, BOOL,
+extern int match_check_string(const uschar *, const uschar *, int, mcs_flags,
const uschar **);
extern void message_start(void);
struct mime_boundary_context *, uschar **, uschar **);
extern int mime_decode(const uschar **);
extern ssize_t mime_decode_base64(FILE *, FILE *, uschar *);
-extern int mime_regex(const uschar **);
+extern int mime_regex(const uschar **, BOOL);
extern void mime_set_anomaly(int);
#endif
extern uschar *moan_check_errorcopy(uschar *);
extern int_eximarith_t receive_statvfs(BOOL, int *);
extern void receive_swallow_smtp(void);
#ifdef WITH_CONTENT_SCAN
-extern int regex(const uschar **);
+extern int regex(const uschar **, BOOL);
#endif
+extern void regex_at_daemon(const uschar *);
extern BOOL regex_match(const pcre2_code *, const uschar *, int, uschar **);
extern BOOL regex_match_and_setup(const pcre2_code *, const uschar *, int, int);
-extern const pcre2_code *regex_must_compile(const uschar *, BOOL, BOOL);
+extern const pcre2_code *regex_compile(const uschar *, mcs_flags, uschar **,
+ pcre2_compile_context *);
+extern const pcre2_code *regex_must_compile(const uschar *, mcs_flags, BOOL);
extern void retry_add_item(address_item *, uschar *, int);
extern BOOL retry_check_address(const uschar *, host_item *, uschar *, BOOL,
uschar **, uschar **);
DEBUG(D_any) debug_printf("%s forking for %s\n", process_purpose, purpose);
if ((pid = fork()) == 0)
{
+ f.daemon_listen = FALSE;
process_purpose = purpose;
DEBUG(D_any) debug_printf("postfork: %s\n", purpose);
}
.continue_more = FALSE,
.daemon_listen = FALSE,
+ .daemon_scion = FALSE,
.debug_daemon = FALSE,
.deliver_firsttime = FALSE,
.deliver_force = FALSE,
BOOL continue_more :1; /* Flag more addresses waiting */
BOOL daemon_listen :1; /* True if listening required */
+ BOOL daemon_scion :1; /* Ancestor proc is daemon, and not re-exec'd */
BOOL debug_daemon :1; /* Debug the daemon process only */
BOOL deliver_firsttime :1; /* True for first delivery attempt */
BOOL deliver_force :1; /* TRUE if delivery was forced */
/* First we have a local subroutine to handle a single pattern */
static BOOL
-one_pattern_match(uschar *name, int slen, BOOL has_addresses, uschar *pattern)
+one_pattern_match(uschar * name, int slen, BOOL has_addresses, uschar * pattern)
{
BOOL yield = FALSE;
const pcre2_code *re = NULL;
/* If the pattern is a regex, compile it. Bomb out if compiling fails; these
patterns are all constructed internally and should be valid. */
-if (*pattern == '^') re = regex_must_compile(pattern, TRUE, FALSE);
+if (*pattern == '^') re = regex_must_compile(pattern, MCS_CASELESS, FALSE);
/* Scan for the required header(s) and scan each one */
/* The externally visible interface */
BOOL
-header_match(uschar *name, BOOL has_addresses, BOOL cond, string_item *strings,
+header_match(uschar * name, BOOL has_addresses, BOOL cond, string_item * strings,
int count, ...)
{
va_list ap;
#define NOTIFIER_SOCKET_NAME "exim_daemon_notify"
-#define NOTIFY_MSG_QRUN 1 /* Notify message types */
+/* Notify message types */
+#define NOTIFY_MSG_QRUN 1
#define NOTIFY_QUEUE_SIZE_REQ 2
+#define NOTIFY_REGEX 3
+
+/* Flags for match_check_string() */
+typedef unsigned mcs_flags;
+#define MCS_NOFLAGS 0
+#define MCS_PARTIAL BIT(0) /* permit partial- search types */
+#define MCS_CASELESS BIT(1) /* caseless matching where possible */
+#define MCS_AT_SPECIAL BIT(2) /* recognize @, @[], etc. */
+#define MCS_CACHEABLE BIT(3) /* no dynamic expansions used for pattern */
/* End of macros.h */
}
static const pcre2_code *
-m_pcre_compile(const uschar * re, uschar ** errstr)
+m_pcre_compile(const uschar * re, BOOL cacheable, uschar ** errstr)
{
-int err;
-PCRE2_SIZE roffset;
-const pcre2_code * cre;
-
-if (!(cre = pcre2_compile((PCRE2_SPTR)re, PCRE2_ZERO_TERMINATED,
- PCRE_COPT, &err, &roffset, pcre_gen_cmp_ctx)))
- {
- uschar errbuf[128];
- pcre2_get_error_message(err, errbuf, sizeof(errbuf));
- *errstr= string_sprintf("regular expression error in '%s': %s at offset %ld",
- re, errbuf, (long)roffset);
- }
-return cre;
+return regex_compile(re, cacheable ? MCS_CACHEABLE : MCS_NOFLAGS, errstr,
+ pcre_gen_cmp_ctx);
}
uschar *
static const pcre2_code *
m_pcre_nextinlist(const uschar ** list, int * sep,
- char * listerr, uschar ** errstr)
+ BOOL cacheable, char * listerr, uschar ** errstr)
{
const uschar * list_ele;
const pcre2_code * cre = NULL;
{
DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "RE: ",
string_printing(list_ele));
- cre = m_pcre_compile(CUS list_ele, errstr);
+ cre = m_pcre_compile(CUS list_ele, cacheable, errstr);
}
return cre;
}
Arguments:
malware_re match condition for "malware="
+ cacheable the RE did not use any dynamic elements during expansion
scan_filename the file holding the email to be scanned, if we're faking
this up for the -bmalware test, else NULL
timeout if nonzero, non-default timeoutl
where true means malware was found (condition applies)
*/
static int
-malware_internal(const uschar * malware_re, const uschar * scan_filename,
- int timeout)
+malware_internal(const uschar * malware_re, BOOL cacheable,
+ const uschar * scan_filename, int timeout)
{
int sep = 0;
const uschar *av_scanner_work = av_scanner;
+BOOL av_scanner_textonly;
uschar *scanner_name;
unsigned long mbox_size;
FILE *mbox_file;
eml_dir = string_copyn(eml_filename, Ustrrchr(eml_filename, '/') - eml_filename);
/* parse 1st option */
-if (strcmpic(malware_re, US"false") == 0 || Ustrcmp(malware_re,"0") == 0)
+if (strcmpic(malware_re, US"false") == 0 || Ustrcmp(malware_re, "0") == 0)
return FAIL; /* explicitly no matching */
/* special cases (match anything except empty) */
-if ( strcmpic(malware_re,US"true") == 0
- || Ustrcmp(malware_re,"*") == 0
- || Ustrcmp(malware_re,"1") == 0
+if ( strcmpic(malware_re, US"true") == 0
+ || Ustrcmp(malware_re, "*") == 0
+ || Ustrcmp(malware_re, "1") == 0
)
{
if ( !malware_default_re
- && !(malware_default_re = m_pcre_compile(malware_regex_default, &errstr)))
+ && !(malware_default_re = m_pcre_compile(malware_regex_default, FALSE, &errstr)))
return malware_panic_defer(errstr);
malware_re = malware_regex_default;
re = malware_default_re;
}
/* compile the regex, see if it works */
-else if (!(re = m_pcre_compile(malware_re, &errstr)))
+else if (!(re = m_pcre_compile(malware_re, cacheable, &errstr)))
return malware_panic_defer(errstr);
/* if av_scanner starts with a dollar, expand it first */
if (*av_scanner == '$')
{
- if (!(av_scanner_work = expand_string(av_scanner)))
+ if (!(av_scanner_work = expand_string_2(av_scanner, &av_scanner_textonly)))
return malware_panic_defer(
string_sprintf("av_scanner starts with $, but expansion failed: %s",
expand_string_message));
malware_name = NULL;
malware_ok = FALSE;
}
+else
+ av_scanner_textonly = TRUE;
/* Do not scan twice (unless av_scanner is dynamic). */
if (!malware_ok)
case M_FPROT6D: /* "f-prot6d" scanner type ----------------------------------- */
{
int bread;
- uschar * e;
- uschar * linebuffer;
- uschar * scanrequest;
+ uschar * e, * linebuffer, * scanrequest;
uschar av_buffer[1024];
- if ((!fprot6d_re_virus && !(fprot6d_re_virus = m_pcre_compile(fprot6d_re_virus_str, &errstr)))
- || (!fprot6d_re_error && !(fprot6d_re_error = m_pcre_compile(fprot6d_re_error_str, &errstr))))
+ if ((!fprot6d_re_virus && !(fprot6d_re_virus = m_pcre_compile(fprot6d_re_virus_str, FALSE, &errstr)))
+ || (!fprot6d_re_error && !(fprot6d_re_error = m_pcre_compile(fprot6d_re_error_str, FALSE, &errstr))))
return malware_panic_defer(errstr);
scanrequest = string_sprintf("SCAN FILE %s\n", eml_filename);
/* set up match regex */
if (!drweb_re)
- drweb_re = m_pcre_compile(drweb_re_str, &errstr);
+ drweb_re = m_pcre_compile(drweb_re_str, FALSE, &errstr);
/* read and concatenate virus names into one string */
for (int i = 0; i < drweb_vnum; i++)
/* set up match */
/* todo also SUSPICION\t */
if (!fsec_re)
- fsec_re = m_pcre_compile(fsec_re_str, &errstr);
+ fsec_re = m_pcre_compile(fsec_re_str, FALSE, &errstr);
/* read report, linewise. Apply a timeout as the Fsecure daemon
sometimes wants an answer to "PING" but they won't tell us what */
/* set up match regex, depends on retcode */
if (kav_rc == 3)
{
- if (!kav_re_sus) kav_re_sus = m_pcre_compile(kav_re_sus_str, &errstr);
+ if (!kav_re_sus) kav_re_sus = m_pcre_compile(kav_re_sus_str, FALSE, &errstr);
kav_re = kav_re_sus;
}
else
{
- if (!kav_re_inf) kav_re_inf = m_pcre_compile(kav_re_inf_str, &errstr);
+ if (!kav_re_inf) kav_re_inf = m_pcre_compile(kav_re_inf_str, FALSE, &errstr);
kav_re = kav_re_inf;
}
return m_panic_defer(scanent, NULL, errstr);
/* find scanner output trigger */
- cmdline_trigger_re = m_pcre_nextinlist(&av_scanner_work, &sep,
+ cmdline_trigger_re = m_pcre_nextinlist(&av_scanner_work, &sep, av_scanner_textonly,
"missing trigger specification", &errstr);
if (!cmdline_trigger_re)
return m_panic_defer(scanent, NULL, errstr);
/* find scanner name regex */
- cmdline_regex_re = m_pcre_nextinlist(&av_scanner_work, &sep,
+ cmdline_regex_re = m_pcre_nextinlist(&av_scanner_work, &sep, av_scanner_textonly,
"missing virus name regex specification", &errstr);
if (!cmdline_regex_re)
return m_panic_defer(scanent, NULL, errstr);
string_printing(sockline_scanner));
/* find scanner output trigger */
- sockline_trig_re = m_pcre_nextinlist(&av_scanner_work, &sep,
+ sockline_trig_re = m_pcre_nextinlist(&av_scanner_work, &sep, av_scanner_textonly,
"missing trigger specification", &errstr);
if (!sockline_trig_re)
return m_panic_defer_3(scanent, NULL, errstr, malware_daemon_ctx.sock);
/* find virus name regex */
- sockline_name_re = m_pcre_nextinlist(&av_scanner_work, &sep,
+ sockline_name_re = m_pcre_nextinlist(&av_scanner_work, &sep, av_scanner_textonly,
"missing virus name regex specification", &errstr);
if (!sockline_name_re)
return m_panic_defer_3(scanent, NULL, errstr, malware_daemon_ctx.sock);
*/
if ( ( !ava_re_clean
- && !(ava_re_clean = m_pcre_compile(ava_re_clean_str, &errstr)))
+ && !(ava_re_clean = m_pcre_compile(ava_re_clean_str, FALSE, &errstr)))
|| ( !ava_re_virus
- && !(ava_re_virus = m_pcre_compile(ava_re_virus_str, &errstr)))
+ && !(ava_re_virus = m_pcre_compile(ava_re_virus_str, FALSE, &errstr)))
|| ( !ava_re_error
- && !(ava_re_error = m_pcre_compile(ava_re_error_str, &errstr)))
+ && !(ava_re_error = m_pcre_compile(ava_re_error_str, FALSE, &errstr)))
)
return malware_panic_defer(errstr);
Arguments:
malware_re match condition for "malware="
+ cacheable the RE did not use any dynamic elements during expansion
timeout if nonzero, timeout in seconds
Returns: Exim message processing code (OK, FAIL, DEFER, ...)
where true means malware was found (condition applies)
*/
int
-malware(const uschar * malware_re, int timeout)
+malware(const uschar * malware_re, BOOL cacheable, int timeout)
{
-int ret = malware_internal(malware_re, NULL, timeout);
+int ret = malware_internal(malware_re, cacheable, NULL, timeout);
if (ret == DEFER) av_failed = TRUE;
return ret;
receive_add_recipient(US"malware-victim@example.net", -1);
f.enable_dollar_recipients = TRUE;
-ret = malware_internal(US"*", eml_filename, 0);
+ret = malware_internal(US"*", TRUE, eml_filename, 0);
Ustrncpy(spooled_message_id, message_id, sizeof(spooled_message_id));
spool_mbox_ok = 1;
malware_init(void)
{
if (!malware_default_re)
- malware_default_re = regex_must_compile(malware_regex_default, FALSE, TRUE);
+ malware_default_re = regex_must_compile(malware_regex_default, MCS_NOFLAGS, TRUE);
#ifndef DISABLE_MAL_DRWEB
if (!drweb_re)
- drweb_re = regex_must_compile(drweb_re_str, FALSE, TRUE);
+ drweb_re = regex_must_compile(drweb_re_str, MCS_NOFLAGS, TRUE);
#endif
#ifndef DISABLE_MAL_FSECURE
if (!fsec_re)
- fsec_re = regex_must_compile(fsec_re_str, FALSE, TRUE);
+ fsec_re = regex_must_compile(fsec_re_str, MCS_NOFLAGS, TRUE);
#endif
#ifndef DISABLE_MAL_KAV
if (!kav_re_sus)
- kav_re_sus = regex_must_compile(kav_re_sus_str, FALSE, TRUE);
+ kav_re_sus = regex_must_compile(kav_re_sus_str, MCS_NOFLAGS, TRUE);
if (!kav_re_inf)
- kav_re_inf = regex_must_compile(kav_re_inf_str, FALSE, TRUE);
+ kav_re_inf = regex_must_compile(kav_re_inf_str, MCS_NOFLAGS, TRUE);
#endif
#ifndef DISABLE_MAL_AVAST
if (!ava_re_clean)
- ava_re_clean = regex_must_compile(ava_re_clean_str, FALSE, TRUE);
+ ava_re_clean = regex_must_compile(ava_re_clean_str, MCS_NOFLAGS, TRUE);
if (!ava_re_virus)
- ava_re_virus = regex_must_compile(ava_re_virus_str, FALSE, TRUE);
+ ava_re_virus = regex_must_compile(ava_re_virus_str, MCS_NOFLAGS, TRUE);
if (!ava_re_error)
- ava_re_error = regex_must_compile(ava_re_error_str, FALSE, TRUE);
+ ava_re_error = regex_must_compile(ava_re_error_str, MCS_NOFLAGS, TRUE);
#endif
#ifndef DISABLE_MAL_FFROT6D
if (!fprot6d_re_error)
- fprot6d_re_error = regex_must_compile(fprot6d_re_error_str, FALSE, TRUE);
+ fprot6d_re_error = regex_must_compile(fprot6d_re_error_str, MCS_NOFLAGS, TRUE);
if (!fprot6d_re_virus)
- fprot6d_re_virus = regex_must_compile(fprot6d_re_virus_str, FALSE, TRUE);
+ fprot6d_re_virus = regex_must_compile(fprot6d_re_virus_str, MCS_NOFLAGS, TRUE);
#endif
}
const uschar *origsubject; /* caseful; keep these two first, in */
const uschar *subject; /* step with the block below */
int expand_setup;
- BOOL use_partial;
- BOOL caseless;
- BOOL at_is_special;
+ mcs_flags flags; /* MCS_* defs in macros.h */
} check_string_block;
const uschar *origaddress; /* caseful; keep these two first, in */
uschar *address; /* step with the block above */
int expand_setup;
- BOOL caseless;
+ mcs_flags flags; /* MCS_CASELESS, MCS_TEXTONLY_RE */
} check_address_block;
*/
static int
-check_string(void *arg, const uschar *pattern, const uschar **valueptr, uschar **error)
+check_string(void * arg, const uschar * pattern, const uschar ** valueptr,
+ uschar ** error)
{
-const check_string_block *cb = arg;
+const check_string_block * cb = arg;
int search_type, partial, affixlen, starflags;
int expand_setup = cb->expand_setup;
const uschar * affix, * opts;
if (pattern[0] == '^')
{
- const pcre2_code * re = regex_must_compile(pattern, cb->caseless, FALSE);
+ const pcre2_code * re = regex_must_compile(pattern,
+ cb->flags & (MCS_CACHEABLE | MCS_CASELESS), FALSE);
if (expand_setup < 0
? !regex_match(re, s, -1, NULL)
: !regex_match_and_setup(re, s, 0, expand_setup)
patlen = Ustrlen(++pattern);
if (patlen > slen) return FAIL;
- if (cb->caseless
+ if (cb->flags & MCS_CASELESS
? strncmpic(s + slen - patlen, pattern, patlen) != 0
: Ustrncmp(s + slen - patlen, pattern, patlen) != 0)
return FAIL;
cases we have to do some more work. If we don't recognize a special pattern,
just fall through - the match will fail. */
-if (cb->at_is_special && pattern[0] == '@')
+if (cb->flags & MCS_AT_SPECIAL && pattern[0] == '@')
{
if (pattern[1] == 0)
{
if ((semicolon = Ustrchr(pattern, ';')) == NULL)
{
- if (cb->caseless ? strcmpic(s, pattern) != 0 : Ustrcmp(s, pattern) != 0)
+ if (cb->flags & MCS_CASELESS ? strcmpic(s, pattern) != 0 : Ustrcmp(s, pattern) != 0)
return FAIL;
- if (expand_setup >= 0) expand_nmax = expand_setup; /* Original code! $0 gets the matched subject */
- if (valueptr) *valueptr = pattern; /* "value" gets the pattern */
+ if (expand_setup >= 0) expand_nmax = expand_setup; /* $0 gets the matched subject */
+ if (valueptr) *valueptr = pattern; /* "value" gets the pattern */
return OK;
}
/* Partial matching is not appropriate for certain lookups (e.g. when looking
up user@domain for sender rejection). There's a flag to disable it. */
-if (!cb->use_partial) partial = -1;
+if (!(cb->flags & MCS_PARTIAL)) partial = -1;
/* Set the parameters for the three different kinds of lookup. */
s the subject string to be checked
pattern the pattern to check it against
expand_setup expansion setup option (see check_string())
- use_partial if FALSE, override any partial- search types
- caseless TRUE for caseless matching where possible
- at_is_special TRUE to recognize @, @[], etc.
+ flags
+ use_partial if FALSE, override any partial- search types
+ caseless TRUE for caseless matching where possible
+ at_is_special TRUE to recognize @, @[], etc.
valueptr if not NULL, and a file lookup was done, return the result
here instead of discarding it; else set it to point to NULL
*/
int
-match_check_string(const uschar *s, const uschar *pattern, int expand_setup,
- BOOL use_partial, BOOL caseless, BOOL at_is_special, const uschar **valueptr)
+match_check_string(const uschar * s, const uschar * pattern, int expand_setup,
+ mcs_flags flags, const uschar ** valueptr)
{
check_string_block cb;
cb.origsubject = s;
-cb.subject = caseless ? string_copylc(s) : string_copy(s);
+cb.subject = flags & MCS_CASELESS ? string_copylc(s) : string_copy(s);
cb.expand_setup = expand_setup;
-cb.use_partial = use_partial;
-cb.caseless = caseless;
-cb.at_is_special = at_is_special;
+cb.flags = flags;
return check_string(&cb, pattern, valueptr, NULL);
}
{
case MCL_STRING:
case MCL_DOMAIN:
- case MCL_LOCALPART:
- return ((check_string_block *)arg)->subject;
-
- case MCL_HOST:
- return ((check_host_block *)arg)->host_address;
-
- case MCL_ADDRESS:
- return ((check_address_block *)arg)->address;
+ case MCL_LOCALPART: return ((check_string_block *)arg)->subject;
+ case MCL_HOST: return ((check_host_block *)arg)->host_address;
+ case MCL_ADDRESS: return ((check_address_block *)arg)->address;
}
return US""; /* In practice, should never happen */
}
const uschar *list;
uschar *sss;
uschar *ot = NULL;
+BOOL textonly_re;
/* Save time by not scanning for the option name when we don't need it. */
{
list = *listptr;
type -= MCL_NOEXPAND; /* Remove the "no expand" flag */
+ textonly_re = TRUE;
}
else
{
{
check_string_block *cb = (check_string_block *)arg;
deliver_domain = string_copy(cb->subject);
- list = expand_cstring(*listptr);
+ list = expand_string_2(*listptr, &textonly_re);
deliver_domain = NULL;
}
else
- list = expand_cstring(*listptr);
+ list = expand_string_2(*listptr, &textonly_re);
if (!list)
{
}
}
+if (textonly_re) switch (type)
+ {
+ case MCL_STRING:
+ case MCL_DOMAIN:
+ case MCL_LOCALPART: ((check_string_block *)arg)->flags |= MCS_CACHEABLE; break;
+ case MCL_HOST: ((check_host_block *)arg)->flags |= MCS_CACHEABLE; break;
+ case MCL_ADDRESS: ((check_address_block *)arg)->flags |= MCS_CACHEABLE; break;
+ }
+
/* For an unnamed list, use the expanded version in comments */
#define LIST_LIMIT_PR 2048
if (at)
Ustrncpy(cb->address, cb->origaddress, at - cb->origaddress);
- cb->caseless = FALSE;
+ cb->flags &= ~MCS_CASELESS;
continue;
}
}
{
check_string_block *cb = (check_string_block *)arg;
Ustrcpy(US cb->subject, cb->origsubject);
- cb->caseless = FALSE;
+ cb->flags &= ~MCS_CASELESS;
continue;
}
}
check_string_block cb;
cb.origsubject = s;
cb.subject = caseless ? string_copylc(s) : string_copy(s);
-cb.at_is_special = FALSE;
+cb.flags = caseless ? MCS_PARTIAL+MCS_CASELESS : MCS_PARTIAL;
switch (type & ~MCL_NOEXPAND)
{
- case MCL_DOMAIN: cb.at_is_special = TRUE; /*FALLTHROUGH*/
+ case MCL_DOMAIN: cb.flags |= MCS_AT_SPECIAL; /*FALLTHROUGH*/
case MCL_LOCALPART: cb.expand_setup = 0; break;
default: cb.expand_setup = sep > UCHAR_MAX ? 0 : -1; break;
}
-cb.use_partial = TRUE;
-cb.caseless = caseless;
if (valueptr) *valueptr = NULL;
return match_check_list(listptr, sep, anchorptr, &local_cache_bits,
check_string, &cb, type, s, valueptr);
*/
static int
-check_address(void *arg, const uschar *pattern, const uschar **valueptr, uschar **error)
+check_address(void * arg, const uschar * pattern, const uschar ** valueptr,
+ uschar ** error)
{
check_address_block * cb = (check_address_block *)arg;
check_string_block csb;
/* The only case where a subject may not have a domain is if the subject is
empty. Otherwise, a subject with no domain is a serious configuration error. */
-if (sdomain == NULL && *subject != 0)
+if (!sdomain && *subject)
{
log_write(0, LOG_MAIN|LOG_PANIC, "no @ found in the subject of an "
"address list match: subject=\"%s\" pattern=\"%s\"", subject, pattern);
This may be the empty address. */
if (*pattern == '^')
- return match_check_string(subject, pattern, cb->expand_setup, TRUE,
- cb->caseless, FALSE, NULL);
+ return match_check_string(subject, pattern, cb->expand_setup,
+ cb->flags | MCS_PARTIAL, NULL);
/* Handle a pattern that is just a lookup. Skip over possible lookup names
(letters, digits, hyphens). Skip over a possible * or *@ at the end. Then we
must have a semicolon for it to be a lookup. */
-for (s = pattern; isalnum(*s) || *s == '-'; s++);
+for (s = pattern; isalnum(*s) || *s == '-'; s++) ;
if (*s == '*') s++;
if (*s == '@') s++;
if (Ustrncmp(pattern, "partial-", 8) == 0)
log_write(0, LOG_MAIN|LOG_PANIC, "partial matching is not applicable to "
"whole-address lookups: ignored \"partial-\" in \"%s\"", pattern);
- return match_check_string(subject, pattern, -1, FALSE, cb->caseless, FALSE,
- valueptr);
+ return match_check_string(subject, pattern, -1, cb->flags, valueptr);
}
/* For the remaining cases, an empty subject matches only an empty pattern,
{
int sep = 0;
- if ((rc = match_check_string(key, pattern + 2, -1, TRUE, FALSE, FALSE,
- CUSS &list)) != OK) return rc;
+ if ((rc = match_check_string(key, pattern + 2, -1, MCS_PARTIAL, CUSS &list))
+ != OK)
+ return rc;
/* Check for chaining from the last item; set up the next key if one
is found. */
ss = Ustrrchr(list, ':');
- if (ss == NULL) ss = list; else ss++;
- while (isspace(*ss)) ss++;
+ if (!ss) ss = list; else ss++;
+ Uskip_whitespace(&ss);
if (*ss == '>')
{
*ss++ = 0;
- while (isspace(*ss)) ss++;
+ Uskip_whitespace(&ss);
key = string_copy(ss);
}
else key = NULL;
else local_yield = OK;
*sdomain = 0;
- rc = match_check_string(subject, ss, -1, TRUE, cb->caseless, FALSE,
- valueptr);
+ rc = match_check_string(subject, ss, -1, cb->flags + MCS_PARTIAL, valueptr);
*sdomain = '@';
switch(rc)
/* We get here if the pattern is not a lookup or a regular expression. If it
contains an @ there is both a local part and a domain. */
-pdomain = Ustrrchr(pattern, '@');
-if (pdomain != NULL)
+if ((pdomain = Ustrrchr(pattern, '@')))
{
int pllen, sllen;
{
int cllen = pllen - 1;
if (sllen < cllen) return FAIL;
- if (cb->caseless
+ if (cb->flags & MCS_CASELESS
? strncmpic(subject+sllen-cllen, pattern + 1, cllen) != 0
: Ustrncmp(subject+sllen-cllen, pattern + 1, cllen) != 0)
return FAIL;
else
{
if (sllen != pllen) return FAIL;
- if (cb->caseless
+ if (cb->flags & MCS_CASELESS
? strncmpic(subject, pattern, sllen) != 0
: Ustrncmp(subject, pattern, sllen) != 0) return FAIL;
}
return match_check_string(sdomain + 1,
pdomain ? pdomain + 1 : pattern,
- cb->expand_setup + expand_inc, TRUE, cb->caseless, TRUE, NULL);
+ cb->expand_setup + expand_inc, cb->flags, NULL);
This supported only literal domains and *.x.y patterns. In order to allow for
-named domain lists (so that you can right, for example, "senders=+xxxx"), it
+named domain lists (so that you can write, for example, "senders=+xxxx"), it
was changed to use the list scanning function. */
csb.origsubject = sdomain + 1;
-csb.subject = cb->caseless ? string_copylc(sdomain+1) : string_copy(sdomain+1);
+csb.subject = cb->flags & MCS_CASELESS
+ ? string_copylc(sdomain+1) : string_copy(sdomain+1);
csb.expand_setup = cb->expand_setup + expand_inc;
-csb.use_partial = TRUE;
-csb.caseless = cb->caseless;
-csb.at_is_special = TRUE;
+csb.flags = MCS_PARTIAL | MCS_AT_SPECIAL | cb->flags & MCS_CASELESS;
listptr = pdomain ? pdomain + 1 : pattern;
if (valueptr) *valueptr = NULL;
ab.origaddress = address;
/* ab.address is above */
ab.expand_setup = expand_setup;
-ab.caseless = caseless;
+ab.flags = caseless ? MCS_CASELESS : 0;
return match_check_list(listptr, sep, &addresslist_anchor, &local_cache_bits,
- check_address, &ab, MCL_ADDRESS + (expand? 0:MCL_NOEXPAND), address,
+ check_address, &ab, MCL_ADDRESS + (expand ? 0 : MCL_NOEXPAND), address,
valueptr);
}
/* If deliver_selectstring is a regex, compile it. */
if (deliver_selectstring && f.deliver_selectstring_regex)
- selectstring_regex = regex_must_compile(deliver_selectstring, TRUE, FALSE);
+ selectstring_regex = regex_must_compile(deliver_selectstring, MCS_CASELESS, FALSE);
if (deliver_selectstring_sender && f.deliver_selectstring_sender_regex)
selectstring_regex_sender =
- regex_must_compile(deliver_selectstring_sender, TRUE, FALSE);
+ regex_must_compile(deliver_selectstring_sender, MCS_CASELESS, FALSE);
/* If the spool is split into subdirectories, we want to process it one
directory at a time, so as to spread out the directory scanning and the
/* Compile the regex for matching a UUCP-style "From_" line in an incoming
message. */
-regex_From = regex_must_compile(uucp_from_pattern, FALSE, TRUE);
+regex_From = regex_must_compile(uucp_from_pattern, MCS_NOFLAGS, TRUE);
/* Unpick the SMTP rate limiting options, if set */
/* Structure to hold a list of Regular expressions */
typedef struct pcre_list {
- pcre2_code *re;
- uschar *pcre_text;
- struct pcre_list *next;
+ const pcre2_code * re;
+ uschar * pcre_text;
+ struct pcre_list * next;
} pcre_list;
uschar regex_match_string_buffer[1024];
extern FILE *mime_stream;
extern uschar *mime_current_boundary;
+
static pcre_list *
-compile(const uschar * list)
+compile(const uschar * list, BOOL cacheable)
{
int sep = 0;
-uschar *regex_string;
-pcre_list *re_list_head = NULL;
-pcre_list *ri;
+uschar * regex_string;
+pcre_list * re_list_head = NULL;
+pcre_list * ri;
/* precompile our regexes */
while ((regex_string = string_nextinlist(&list, &sep, NULL, 0)))
if (strcmpic(regex_string, US"false") != 0 && Ustrcmp(regex_string, "0") != 0)
{
- pcre2_code * re;
- int err;
- PCRE2_SIZE pcre_erroffset;
-
/* compile our regular expression */
- if (!(re = pcre2_compile( (PCRE2_SPTR) regex_string, PCRE2_ZERO_TERMINATED,
- 0, &err, &pcre_erroffset, pcre_gen_cmp_ctx)))
+ uschar * errstr;
+ const pcre2_code * re = regex_compile(regex_string,
+ cacheable ? MCS_CACHEABLE : MCS_NOFLAGS, &errstr, pcre_gen_cmp_ctx);
+
+ if (!re)
{
- uschar errbuf[128];
- pcre2_get_error_message(err, errbuf, sizeof(errbuf));
- log_write(0, LOG_MAIN,
- "regex acl condition warning - error in regex '%s': %s at offset %ld, skipped.",
- regex_string, errbuf, (long)pcre_erroffset);
+ log_write(0, LOG_MAIN, "regex acl condition warning - %s, skipped", errstr);
continue;
}
return FAIL;
}
+
+
int
-regex(const uschar **listptr)
+regex(const uschar **listptr, BOOL cacheable)
{
unsigned long mbox_size;
FILE *mbox_file;
}
/* precompile our regexes */
-if (!(re_list_head = compile(*listptr)))
+if (!(re_list_head = compile(*listptr, cacheable)))
return FAIL; /* no regexes -> nothing to do */
/* match each line against all regexes */
int
-mime_regex(const uschar **listptr)
+mime_regex(const uschar **listptr, BOOL cacheable)
{
pcre_list *re_list_head = NULL;
FILE *f;
regex_match_string = NULL;
/* precompile our regexes */
-if (!(re_list_head = compile(*listptr)))
+if (!(re_list_head = compile(*listptr, cacheable)))
return FAIL; /* no regexes -> nothing to do */
/* check if the file is already decoded */
--- /dev/null
+/*************************************************
+* Exim - an Internet mail transport agent *
+*************************************************/
+
+/*
+ * Copyright (c) The Exim Maintainers 2022
+ * License: GPL
+ */
+
+/* Caching layers for compiled REs. There is a local layer in the process,
+implemented as a tree for inserts and lookup. This cache is inherited from
+the daemon, for the process tree deriving from there - but not by re-exec'd
+proceses or commandline submission processes.
+
+If the process has to compile, and is not the daemon or a re-exec'd exim,
+it notifies the use of the RE to the daemon via a unix-domain socket.
+This is a fire-and-forget send with no response, hence cheap from the point-of
+view of the sender. I have not measured the overall comms costs. The
+daemon also compiles the RE, and caches the result.
+
+A second layer would be possible by asking the daemon via the notifier socket
+(for a result from its cache, or a compile if it must). The comms overhead
+is significant, not only for the channel but also for de/serialisation of
+the compiled object. This makes it untenable for the primary use-case, the
+transport process which has been re-exec'd to gain privs - and therefore does not
+have the daemon-maintained cache. Using shared-memory might reduce that cost
+(the attach time for the memory segment will matter); the implimentation
+would require suitable R/W locks.
+*/
+
+#include "exim.h"
+
+typedef struct re_req {
+ uschar notifier_reqtype;
+ BOOL caseless;
+ uschar re[1]; /* extensible */
+} re_req;
+
+static tree_node * regex_cache = NULL;
+static tree_node * regex_caseless_cache = NULL;
+
+/******************************************************************************/
+
+static void
+regex_to_daemon(const uschar * key, BOOL caseless)
+{
+int klen = Ustrlen(key) + 1;
+int rlen = sizeof(re_req) + klen;
+re_req * req;
+int fd, old_pool = store_pool;
+
+DEBUG(D_expand|D_lists)
+ debug_printf_indent("sending RE '%s' to daemon\n", key);
+
+store_pool = POOL_MAIN;
+ req = store_get(rlen, key); /* maybe need a size limit */
+store_pool = old_pool;;
+req->notifier_reqtype = NOTIFY_REGEX;
+req->caseless = caseless;
+memcpy(req->re, key, klen);
+
+if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) >= 0)
+ {
+ struct sockaddr_un sa_un = {.sun_family = AF_UNIX};
+ ssize_t len = daemon_notifier_sockname(&sa_un);
+
+ if (sendto(fd, req, rlen, 0, (struct sockaddr *)&sa_un, (socklen_t)len) < 0)
+ DEBUG(D_queue_run)
+ debug_printf("%s: sendto %s\n", __FUNCTION__, strerror(errno));
+ close(fd);
+ }
+else DEBUG(D_queue_run) debug_printf(" socket: %s\n", strerror(errno));
+}
+
+
+static const pcre2_code *
+regex_from_cache(const uschar * key, BOOL caseless)
+{
+tree_node * node =
+ tree_search(caseless ? regex_caseless_cache : regex_cache, key);
+DEBUG(D_expand|D_lists)
+ debug_printf_indent("compiled %sRE '%s' %sfound in local cache\n",
+ caseless ? "caseless " : "", key, node ? "" : "not ");
+
+return node ? node->data.ptr : NULL;
+}
+
+
+static void
+regex_to_cache(const uschar * key, BOOL caseless, const pcre2_code * cre)
+{
+PCRE2_SIZE srelen;
+uschar * sre;
+tree_node * node;
+
+node = store_get(sizeof(tree_node) + Ustrlen(key) + 1, key); /* we are called with STORE_PERM */
+Ustrcpy(node->name, key);
+node->data.ptr = (void *)cre;
+
+if (!tree_insertnode(caseless ? ®ex_caseless_cache : ®ex_cache, node))
+ { DEBUG(D_expand|D_lists) debug_printf_indent("duplicate key!\n"); }
+else DEBUG(D_expand|D_lists)
+ debug_printf_indent("compiled RE '%s' saved in local cache\n", key);
+
+/* Additionally, if not re-execed and not the daemon, tell the daemon of the RE
+so it can add to the cache */
+
+if (f.daemon_scion && !f.daemon_listen)
+ regex_to_daemon(key, caseless);
+
+return;
+}
+
+/******************************************************************************/
+
+/*************************************************
+* Compile regular expression and panic on fail *
+*************************************************/
+
+/* This function is called when failure to compile a regular expression leads
+to a panic exit. In other cases, pcre_compile() is called directly. In many
+cases where this function is used, the results of the compilation are to be
+placed in long-lived store, so we temporarily reset the store management
+functions that PCRE uses if the use_malloc flag is set.
+
+Argument:
+ pattern the pattern to compile
+ flags
+ caseless caseless matching is required
+ cacheable use (writeback) cache
+ use_malloc TRUE if compile into malloc store
+
+Returns: pointer to the compiled pattern
+*/
+
+const pcre2_code *
+regex_must_compile(const uschar * pattern, mcs_flags flags, BOOL use_malloc)
+{
+BOOL caseless = !!(flags & MCS_CASELESS);
+size_t offset;
+const pcre2_code * yield;
+int old_pool = store_pool, err;
+
+/* Optionall, check the cache and return if found */
+
+if ( flags & MCS_CACHEABLE
+ && (yield = regex_from_cache(pattern, caseless)))
+ return yield;
+
+store_pool = POOL_PERM;
+
+if (!(yield = pcre2_compile((PCRE2_SPTR)pattern, PCRE2_ZERO_TERMINATED,
+ caseless ? PCRE_COPT|PCRE2_CASELESS : PCRE_COPT,
+ &err, &offset, use_malloc ? pcre_mlc_cmp_ctx : pcre_gen_cmp_ctx)))
+ {
+ uschar errbuf[128];
+ pcre2_get_error_message(err, errbuf, sizeof(errbuf));
+ log_write(0, LOG_MAIN|LOG_PANIC_DIE, "regular expression error: "
+ "%s at offset %ld while compiling %s", errbuf, (long)offset, pattern);
+ }
+
+if (use_malloc)
+ {
+ /*pcre2_general_context_free(gctx);*/
+ }
+
+if (flags & MCS_CACHEABLE)
+ regex_to_cache(pattern, caseless, yield);
+
+store_pool = old_pool;
+return yield;
+}
+
+
+
+
+/* Wrapper for pcre2_compile() and error-message handling.
+
+Arguments: pattern regex to compile
+ flags
+ caseless flag for match variant
+ cacheable use (writeback) cache
+ errstr on error, filled in with error message
+ cctx compile-context for pcre2
+
+Return: NULL on error, with errstr set. Otherwise, the compiled RE object
+*/
+
+const pcre2_code *
+regex_compile(const uschar * pattern, mcs_flags flags, uschar ** errstr,
+ pcre2_compile_context * cctx)
+{
+const uschar * key = pattern;
+BOOL caseless = !!(flags & MCS_CASELESS);
+int err;
+PCRE2_SIZE offset;
+const pcre2_code * yield;
+int old_pool = store_pool;
+
+/* Optionally, check the cache and return if found */
+
+if ( flags & MCS_CACHEABLE
+ && (yield = regex_from_cache(key, caseless)))
+ return yield;
+
+DEBUG(D_expand|D_lists) debug_printf_indent("compiling %sRE '%s'\n",
+ caseless ? "caseless " : "", pattern);
+
+store_pool = POOL_PERM;
+if (!(yield = pcre2_compile((PCRE2_SPTR)pattern, PCRE2_ZERO_TERMINATED,
+ caseless ? PCRE_COPT|PCRE2_CASELESS : PCRE_COPT,
+ &err, &offset, cctx)))
+ {
+ uschar errbuf[128];
+ pcre2_get_error_message(err, errbuf, sizeof(errbuf));
+ store_pool = old_pool;
+ *errstr = string_sprintf("regular expression error in "
+ "\"%s\": %s at offset %ld", pattern, errbuf, (long)offset);
+ }
+else if (flags & MCS_CACHEABLE)
+ regex_to_cache(key, caseless, yield);
+store_pool = old_pool;
+
+return yield;
+}
+
+
+
+/* Handle a regex notify arriving at the daemon. We get sent the original RE;
+compile it (again) and write to the cache. Later forked procs will be able to
+read from the cache, unless they re-execed. Therefore, those latter never bother
+sending us a notification. */
+
+void
+regex_at_daemon(const uschar * reqbuf)
+{
+const re_req * req = (const re_req *)reqbuf;
+uschar * errstr;
+const pcre2_code * cre = regex_compile(req->re,
+ req->caseless ? MCS_CASELESS | MCS_CACHEABLE : MCS_CACHEABLE,
+ &errstr, pcre_gen_cmp_ctx);
+
+DEBUG(D_any) if (!cre) debug_printf("%s\n", errstr);
+return;
+}
if (flag & rewrite_smtp)
{
- uschar *key = expand_string(rule->key);
+ BOOL textonly_re;
+ const uschar * key = expand_string_2(rule->key, &textonly_re);
if (!key)
{
if (!f.expand_string_forcedfail)
"checking for SMTP rewriting: %s", rule->key, expand_string_message);
continue;
}
- if (match_check_string(subject, key, 0, TRUE, FALSE, FALSE, NULL) != OK)
+ if (match_check_string(subject, key, 0,
+ textonly_re ? MCS_CACHEABLE | MCS_PARTIAL : MCS_PARTIAL, NULL) != OK)
continue;
new = expand_string(rule->replacement);
}
consistency checks to be done, or anything else that needs to be set up. */
void
-iplookup_router_init(router_instance *rblock)
+iplookup_router_init(router_instance * rblock)
{
-iplookup_router_options_block *ob =
- (iplookup_router_options_block *)(rblock->options_block);
+iplookup_router_options_block * ob =
+ (iplookup_router_options_block *) rblock->options_block;
/* A port and a host list must be given */
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s router:\n "
"a port must be specified", rblock->name);
-if (ob->hosts == NULL)
+if (!ob->hosts)
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s router:\n "
"a host list must be specified", rblock->name);
/* Translate protocol name into value */
-if (ob->protocol_name != NULL)
+if (ob->protocol_name)
{
if (Ustrcmp(ob->protocol_name, "udp") == 0) ob->protocol = ip_udp;
else if (Ustrcmp(ob->protocol_name, "tcp") == 0) ob->protocol = ip_tcp;
/* If a response pattern is given, compile it now to get the error early. */
-if (ob->response_pattern != NULL)
+if (ob->response_pattern)
ob->re_response_pattern =
- regex_must_compile(ob->response_pattern, FALSE, TRUE);
+ regex_must_compile(ob->response_pattern, MCS_NOFLAGS, TRUE);
}
const uschar *host_name;
const uschar *host_address;
const uschar *host_ipv4;
- BOOL negative;
+ mcs_flags flags;
} check_host_block;
/* Structure for remembering lookup data when caching the result of
if (ob->quota_value > 0 || THRESHOLD_CHECK || ob->maildir_use_size_file)
{
- PCRE2_SIZE offset;
- int err;
-
/* Compile the regex if there is one. */
if (ob->quota_size_regex)
{
- if (!(re = pcre2_compile((PCRE2_SPTR)ob->quota_size_regex,
- PCRE2_ZERO_TERMINATED, PCRE_COPT, &err, &offset, pcre_gen_cmp_ctx)))
- {
- uschar errbuf[128];
- pcre2_get_error_message(err, errbuf, sizeof(errbuf));
- addr->message = string_sprintf("appendfile: regular expression "
- "error: %s at offset %ld while compiling %s", errbuf, (long)offset,
- ob->quota_size_regex);
+ if (!(re = regex_compile(ob->quota_size_regex,
+ MCS_NOFLAGS, &addr->message, pcre_gen_cmp_ctx)))
return FALSE;
- }
+
DEBUG(D_transport) debug_printf("using regex for file sizes: %s\n",
ob->quota_size_regex);
}
if (ob->maildir_use_size_file)
{
const pcre2_code * dir_regex = NULL;
- PCRE2_SIZE offset;
- int err;
if (ob->maildir_dir_regex)
{
int check_path_len = Ustrlen(check_path);
- if (!(dir_regex = pcre2_compile((PCRE2_SPTR)ob->maildir_dir_regex,
- PCRE2_ZERO_TERMINATED, PCRE_COPT, &err, &offset, pcre_gen_cmp_ctx)))
- {
- uschar errbuf[128];
- pcre2_get_error_message(err, errbuf, sizeof(errbuf));
- addr->message = string_sprintf("appendfile: regular expression "
- "error: %s at offset %ld while compiling %s", errbuf, (long)offset,
- ob->maildir_dir_regex);
+ if (!(dir_regex = regex_compile(ob->maildir_dir_regex,
+ MCS_NOFLAGS, &addr->message, pcre_gen_cmp_ctx)))
return FALSE;
- }
DEBUG(D_transport)
debug_printf("using regex for maildir directory selection: %s\n",
for (struct list * l = list; l < list + nelem(list); l++)
if (!*l->re)
- *l->re = regex_must_compile(l->string, FALSE, TRUE);
+ *l->re = regex_must_compile(l->string, MCS_NOFLAGS, TRUE);
}
unsigned short authbits = 0;
if (!sx->esmtp) return 0;
-if (!regex_AUTH) regex_AUTH = regex_must_compile(AUTHS_REGEX, FALSE, TRUE);
+if (!regex_AUTH) regex_AUTH = regex_must_compile(AUTHS_REGEX, MCS_NOFLAGS, TRUE);
if (!regex_match_and_setup(regex_AUTH, sx->buffer, 0, -1)) return 0;
expand_nmax = -1; /* reset */
names = string_copyn(expand_nstring[1], expand_nlength[1]);
client_authenticator = client_authenticated_id = client_authenticated_sender = NULL;
if (!regex_AUTH)
- regex_AUTH = regex_must_compile(AUTHS_REGEX, FALSE, TRUE);
+ regex_AUTH = regex_must_compile(AUTHS_REGEX, MCS_NOFLAGS, TRUE);
/* Is the server offering AUTH? */
if (maildirfolder_create_regex)
{
- int err;
- PCRE2_SIZE offset;
const pcre2_code * re;
DEBUG(D_transport) debug_printf("checking for maildirfolder requirement\n");
- if (!(re = pcre2_compile((PCRE2_SPTR)maildirfolder_create_regex,
- PCRE2_ZERO_TERMINATED, PCRE_COPT, &err, &offset, pcre_gen_cmp_ctx)))
- {
- uschar errbuf[128];
- pcre2_get_error_message(err, errbuf, sizeof(errbuf));
- addr->message = string_sprintf("appendfile: regular expression "
- "error: %s at offset %ld while compiling %s", errbuf, (long)offset,
- maildirfolder_create_regex);
+ if (!(re = regex_compile(maildirfolder_create_regex,
+ MCS_NOFLAGS, &addr->message, pcre_gen_cmp_ctx)))
return FALSE;
- }
if (regex_match(re, path, -1, NULL))
{
underscores, as they are all too commonly found. Sigh. Also, if
allow_utf8_domains is set, allow top-bit characters. */
-for (t = ss; *t != 0; t++)
+for (t = ss; *t; t++)
if (!isalnum(*t) && *t != '.' && *t != '-' && *t != '_' &&
(!allow_utf8_domains || *t < 128)) break;
its IP address and match against that. Note that a multi-homed host will add
items to the chain. */
-if (*t == 0)
+if (!*t)
{
int rc;
host_item h;
must use sender_host_name and its aliases, looking them up if necessary. */
if (cb->host_name) /* Explicit host name given */
- return match_check_string(cb->host_name, ss, -1, TRUE, TRUE, TRUE,
- valueptr);
+ return match_check_string(cb->host_name, ss, -1,
+ MCS_PARTIAL | MCS_CASELESS | MCS_AT_SPECIAL | cb->flags, valueptr);
/* Host name not given; in principle we need the sender host name and its
aliases. However, for query-style lookups, we do not need the name if the
if (isquery)
{
- switch(match_check_string(US"", ss, -1, TRUE, TRUE, TRUE, valueptr))
+ switch(match_check_string(US"", ss, -1,
+ MCS_PARTIAL| MCS_CASELESS| MCS_AT_SPECIAL | (cb->flags & MCS_CACHEABLE),
+ valueptr))
{
case OK: return OK;
case DEFER: return DEFER;
/* Match on the sender host name, using the general matching function */
-switch(match_check_string(sender_host_name, ss, -1, TRUE, TRUE, TRUE, valueptr))
+switch(match_check_string(sender_host_name, ss, -1,
+ MCS_PARTIAL| MCS_CASELESS| MCS_AT_SPECIAL | (cb->flags & MCS_CACHEABLE),
+ valueptr))
{
case OK: return OK;
case DEFER: return DEFER;
aliases = sender_host_aliases;
while (*aliases)
- switch(match_check_string(*aliases++, ss, -1, TRUE, TRUE, TRUE, valueptr))
+ switch(match_check_string(*aliases++, ss, -1,
+ MCS_PARTIAL| MCS_CASELESS| MCS_AT_SPECIAL | (cb->flags & MCS_CACHEABLE),
+ valueptr))
{
case OK: return OK;
case DEFER: return DEFER;
check_host, /* function for testing */
&cb, /* argument for function */
MCL_HOST, /* type of check */
- (host_address == sender_host_address)?
- US"host" : host_address, /* text for debugging */
+ host_address == sender_host_address
+ ? US"host" : host_address, /* text for debugging */
valueptr); /* where to pass back data */
deliver_host_address = save_host_address;
return rc;
--- /dev/null
+# Exim test configuration 0632
+
+.include DIR/aux-var/std_conf_prefix
+
+primary_hostname = myhost.test.ex
+queue_only
+
+# ----- Main settings -----
+
+acl_smtp_rcpt = chk_rcpt
+
+# ----- ACL -----
+
+begin acl
+
+chk_rcpt:
+ # We're doing these to see what REs the daemon compiles, in stderr
+ warn domains = ^nomatch_list
+ logwrite = should not match RE in list
+
+ warn condition = ${if match {a_random_string} {static_RE}}
+ logwrite = should not match RE in match cond
+ warn condition = ${if match {a_random_string} {tricky_static_RE\$}}
+ logwrite = should not match RE in match cond
+ warn condition = ${if match {a_random_string} {pid=${pid} uncacheable_RE}}
+ logwrite = should not match RE in match cond
+ accept
+
+# ----- Routers -----
+
+begin routers
+
+r0:
+ driver = redirect
+ data = :blackhole:
+#
+# End
--- /dev/null
+
+******** SERVER ********
+1999-03-02 09:44:33 exim x.yz daemon started: pid=p1234, no queue runs, listening for SMTP on port PORT_D
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@test.ex H=(test.ex) [127.0.0.1] P=smtp S=sss
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@test.ex H=(test.ex) [127.0.0.1] P=smtp S=sss
--- /dev/null
+# regex caching
+#
+exim -d-all+queue_run+expand+lookup -DSERVER=server -bd -oX PORT_D
+****
+#
+client 127.0.0.1 PORT_D
+??? 220
+HELO test.ex
+??? 250
+MAIL FROM:<CALLER@test.ex>
+??? 250
+RCPT TO:<dest_1@test.ex>
+??? 250
+DATA
+??? 354
+.
+??? 250
+QUIT
+??? 221
+****
+client 127.0.0.1 PORT_D
+??? 220
+HELO test.ex
+??? 250
+MAIL FROM:<CALLER@test.ex>
+??? 250
+RCPT TO:<dest_2@test.ex>
+??? 250
+DATA
+??? 354
+.
+??? 250
+QUIT
+??? 221
+****
+#
+killdaemon
+no_msglog_check
+no_stdout_check
├considering: }{$2$1}fail}
├──expanding: \N^([ab]+)(\w+)$\N
╰─────result: ^([ab]+)(\w+)$
+ compiled RE '^([ab]+)(\w+)$' not found in local cache
+ compiling RE '^([ab]+)(\w+)$'
+ compiled RE '^([ab]+)(\w+)$' saved in local cache
├──condition: match{abcd}{\N^([ab]+)(\w+)$\N}
├─────result: true
╭considering: $2$1}fail}
├considering: }{$2$1}fail}
├──expanding: \N^([ab]+)(\w+)$\N
╰─────result: ^([ab]+)(\w+)$
+ compiled RE '^([ab]+)(\w+)$' found in local cache
├──condition: match{wxyz}{\N^([ab]+)(\w+)$\N}
├─────result: false
╭───scanning: $2$1}fail}
|considering: }{$2$1}fail}
|--expanding: \N^([ab]+)(\w+)$\N
\_____result: ^([ab]+)(\w+)$
+ compiled RE '^([ab]+)(\w+)$' not found in local cache
+ compiling RE '^([ab]+)(\w+)$'
+ compiled RE '^([ab]+)(\w+)$' saved in local cache
|--condition: match{abcd}{\N^([ab]+)(\w+)$\N}
|-----result: true
/considering: $2$1}fail}
|considering: }{$2$1}fail}
|--expanding: \N^([ab]+)(\w+)$\N
\_____result: ^([ab]+)(\w+)$
+ compiled RE '^([ab]+)(\w+)$' found in local cache
|--condition: match{wxyz}{\N^([ab]+)(\w+)$\N}
|-----result: false
/---scanning: $2$1}fail}
--------> srv router <--------
local_part=userx domain=test.again.dns
checking local_parts
+compiled caseless RE '^srv' not found in local cache
+compiled RE '^srv' saved in local cache
userx in "^srv"? no (end of list)
srv router skipped: local_parts mismatch
--------> useryz router <--------
--------> srv router <--------
local_part=abcd domain=test.again.dns
checking local_parts
+compiled caseless RE '^srv' found in local cache
abcd in "^srv"? no (end of list)
srv router skipped: local_parts mismatch
--------> useryz router <--------
--------> srv router <--------
local_part=abcd domain=ten-1.test.ex
checking local_parts
+compiled caseless RE '^srv' found in local cache
abcd in "^srv"? no (end of list)
srv router skipped: local_parts mismatch
--------> useryz router <--------
--------> srv router <--------
local_part=usery domain=test.again.dns
checking local_parts
+compiled caseless RE '^srv' found in local cache
usery in "^srv"? no (end of list)
srv router skipped: local_parts mismatch
--------> useryz router <--------
--------> srv router <--------
local_part=userz domain=test.again.dns
checking local_parts
+compiled caseless RE '^srv' found in local cache
userz in "^srv"? no (end of list)
srv router skipped: local_parts mismatch
--------> useryz router <--------
--------> srv router <--------
local_part=xyz domain=ten-1.test.ex
checking local_parts
+compiled caseless RE '^srv' found in local cache
xyz in "^srv"? no (end of list)
srv router skipped: local_parts mismatch
--------> useryz router <--------
--------> srv router <--------
local_part=userx domain=test.fail.dns
checking local_parts
+compiled caseless RE '^srv' not found in local cache
+compiled RE '^srv' saved in local cache
userx in "^srv"? no (end of list)
srv router skipped: local_parts mismatch
--------> useryz router <--------
--------> srv router <--------
local_part=abcd domain=test.fail.dns
checking local_parts
+compiled caseless RE '^srv' found in local cache
abcd in "^srv"? no (end of list)
srv router skipped: local_parts mismatch
--------> useryz router <--------
--------> srv router <--------
local_part=abcd domain=ten-1.test.ex
checking local_parts
+compiled caseless RE '^srv' found in local cache
abcd in "^srv"? no (end of list)
srv router skipped: local_parts mismatch
--------> useryz router <--------
--------> srv router <--------
local_part=usery domain=test.fail.dns
checking local_parts
+compiled caseless RE '^srv' found in local cache
usery in "^srv"? no (end of list)
srv router skipped: local_parts mismatch
--------> useryz router <--------
--------> srv router <--------
local_part=userz domain=test.fail.dns
checking local_parts
+compiled caseless RE '^srv' found in local cache
userz in "^srv"? no (end of list)
srv router skipped: local_parts mismatch
--------> useryz router <--------
--------> srv router <--------
local_part=xyz domain=ten-1.test.ex
checking local_parts
+compiled caseless RE '^srv' found in local cache
xyz in "^srv"? no (end of list)
srv router skipped: local_parts mismatch
--------> useryz router <--------
--------> srv router <--------
local_part=userx domain=nonexist.test.ex
checking local_parts
+compiled caseless RE '^srv' not found in local cache
+compiled RE '^srv' saved in local cache
userx in "^srv"? no (end of list)
srv router skipped: local_parts mismatch
--------> useryz router <--------
--------> srv router <--------
local_part=abcd domain=nonexist.test.ex
checking local_parts
+compiled caseless RE '^srv' found in local cache
abcd in "^srv"? no (end of list)
srv router skipped: local_parts mismatch
--------> useryz router <--------
--------> srv router <--------
local_part=abcd domain=ten-1.test.ex
checking local_parts
+compiled caseless RE '^srv' found in local cache
abcd in "^srv"? no (end of list)
srv router skipped: local_parts mismatch
--------> useryz router <--------
--------> srv router <--------
local_part=usery domain=nonexist.test.ex
checking local_parts
+compiled caseless RE '^srv' found in local cache
usery in "^srv"? no (end of list)
srv router skipped: local_parts mismatch
--------> useryz router <--------
--------> srv router <--------
local_part=userz domain=nonexist.test.ex
checking local_parts
+compiled caseless RE '^srv' found in local cache
userz in "^srv"? no (end of list)
srv router skipped: local_parts mismatch
--------> useryz router <--------
--------> srv router <--------
local_part=xyz domain=ten-1.test.ex
checking local_parts
+compiled caseless RE '^srv' found in local cache
xyz in "^srv"? no (end of list)
srv router skipped: local_parts mismatch
--------> useryz router <--------
--------> srv router <--------
local_part=srv domain=test.again.dns
checking local_parts
+compiled caseless RE '^srv' not found in local cache
+compiled RE '^srv' saved in local cache
srv in "^srv"? yes (matched "^srv")
calling srv router
srv router called for srv@test.again.dns
--------> srv router <--------
local_part=srv domain=test.fail.dns
checking local_parts
+compiled caseless RE '^srv' found in local cache
srv in "^srv"? yes (matched "^srv")
calling srv router
srv router called for srv@test.fail.dns
--------> srv router <--------
local_part=userx domain=nonexist.example.com
checking local_parts
+compiled caseless RE '^srv' not found in local cache
+compiled RE '^srv' saved in local cache
userx in "^srv"? no (end of list)
srv router skipped: local_parts mismatch
--------> useryz router <--------
--------> srv router <--------
local_part=userd domain=nonexist.example.com
checking local_parts
+compiled caseless RE '^srv' found in local cache
userd in "^srv"? no (end of list)
srv router skipped: local_parts mismatch
--------> useryz router <--------
accept: condition test failed in ACL "TESTSUITE/aux-fixed/0386.acl1"
processing "deny" (TESTSUITE/test-config 44)
check local_parts = ^.*[@%!/|]
+ compiled caseless RE '^.*[@%!/|]' not found in local cache
+ compiled RE '^.*[@%!/|]' saved in local cache
1 in "^.*[@%!/|]"? no (end of list)
deny: condition test failed in ACL "TESTSUITE/aux-fixed/0386.acl1"
processing "require" (TESTSUITE/test-config 44)
accept: condition test failed in ACL "TESTSUITE/aux-fixed/0386.acl1"
processing "deny" (TESTSUITE/test-config 44)
check local_parts = ^.*[@%!/|]
+ compiled caseless RE '^.*[@%!/|]' found in local cache
1 in "^.*[@%!/|]"? no (end of list)
deny: condition test failed in ACL "TESTSUITE/aux-fixed/0386.acl1"
processing "require" (TESTSUITE/test-config 44)
SMTP>> EHLO myhost.test.ex
cmd buf flush ddd bytes
SMTP<< 250 OK
+ compiled RE '.outlook.com$' not found in local cache
+ compiling RE '.outlook.com$'
+ compiled RE '.outlook.com$' saved in local cache
127.0.0.1 in hosts_require_auth? no (option unset)
SMTP>> MAIL FROM:<CALLER@myhost.test.ex>
cmd buf flush ddd bytes
SMTP>> EHLO mail.test.ex
cmd buf flush ddd bytes
SMTP<< 250 OK
+ compiled RE '.outlook.com$' not found in local cache
+ compiling RE '.outlook.com$'
+ compiled RE '.outlook.com$' saved in local cache
not using PIPELINING
not using DSN
127.0.0.1 in hosts_require_auth? no (option unset)
SMTP>> EHLO myhost.test.ex
cmd buf flush ddd bytes
SMTP<< 250 OK
+ compiled RE '.outlook.com$' not found in local cache
+ compiling RE '.outlook.com$'
+ compiled RE '.outlook.com$' saved in local cache
not using PIPELINING
not using DSN
127.0.0.1 in hosts_require_auth? no (option unset)
qualify & rewrite recipients list
address match test: subject=r1@test.ex pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' not found in local cache
+ compiled RE '^.{40,}@*' saved in local cache
r1@test.ex in "^.{40,}@*"? no (end of list)
address match test: subject=r1@test.ex pattern=*@*
test.ex in "*"? yes (matched "*")
lookup failed
global rewrite rules
address match test: subject=CALLER@myhost.test.ex pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
CALLER@myhost.test.ex in "^.{40,}@*"? no (end of list)
address match test: subject=CALLER@myhost.test.ex pattern=*@*
myhost.test.ex in "*"? yes (matched "*")
random@test.exam
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.exa
**** debug string too long - truncated ****
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
remainder: random@test.example,
random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
**** debug string too long - truncated ****
remainder: random@test.example
address match test: subject=random@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
random@test.example in "^.{40,}@*"? no (end of list)
address match test: subject=random@test.example pattern=*@*
test.example in "*"? yes (matched "*")
rewrite_one_header: type=F:
From: CALLER_NAME <CALLER@myhost.test.ex>
address match test: subject=CALLER@myhost.test.ex pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
CALLER@myhost.test.ex in "^.{40,}@*"? no (end of list)
address match test: subject=CALLER@myhost.test.ex pattern=*@*
myhost.test.ex in "*"? yes (matched "*")
qualify & rewrite recipients list
address match test: subject=r2@test.ex pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' not found in local cache
+ compiled RE '^.{40,}@*' saved in local cache
r2@test.ex in "^.{40,}@*"? no (end of list)
address match test: subject=r2@test.ex pattern=*@*
test.ex in "*"? yes (matched "*")
lookup failed
global rewrite rules
address match test: subject=CALLER@myhost.test.ex pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
CALLER@myhost.test.ex in "^.{40,}@*"? no (end of list)
address match test: subject=CALLER@myhost.test.ex pattern=*@*
myhost.test.ex in "*"? yes (matched "*")
rewrite_one_header: type=T:
To: localpart_with_056_chars_56789012345678901234567890123456@test.example
address match test: subject=localpart_with_056_chars_56789012345678901234567890123456@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
localpart_with_056_chars_56789012345678901234567890123456@test.example in "^.{40,}@*"? yes (matched "^.{40,}@*")
LOG: address_rewrite MAIN
"localpart_with_056_chars_56789012345678901234567890123456@test.example" from to: rewritten as "deny_me@test.example" by rule 1
rewrite_one_header: type=F:
From: CALLER_NAME <CALLER@myhost.test.ex>
address match test: subject=CALLER@myhost.test.ex pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
CALLER@myhost.test.ex in "^.{40,}@*"? no (end of list)
address match test: subject=CALLER@myhost.test.ex pattern=*@*
myhost.test.ex in "*"? yes (matched "*")
qualify & rewrite recipients list
address match test: subject=r3@test.ex pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' not found in local cache
+ compiled RE '^.{40,}@*' saved in local cache
r3@test.ex in "^.{40,}@*"? no (end of list)
address match test: subject=r3@test.ex pattern=*@*
test.ex in "*"? yes (matched "*")
lookup failed
global rewrite rules
address match test: subject=CALLER@myhost.test.ex pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
CALLER@myhost.test.ex in "^.{40,}@*"? no (end of list)
address match test: subject=CALLER@myhost.test.ex pattern=*@*
myhost.test.ex in "*"? yes (matched "*")
rewrite_one_header: type=T:
To: localpart_with_236_chars_56789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456@test.example
address match test: subject=localpart_with_236_chars_56789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456@test.example pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
localpart_with_236_chars_56789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456@test.example in "^.{40,}@*"? yes (matched "^.{40,}@*")
LOG: address_rewrite MAIN
"localpart_with_236_chars_56789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456@test.example" from to: rewritten as "deny_me@test.example" by rule 1
rewrite_one_header: type=F:
From: CALLER_NAME <CALLER@myhost.test.ex>
address match test: subject=CALLER@myhost.test.ex pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
CALLER@myhost.test.ex in "^.{40,}@*"? no (end of list)
address match test: subject=CALLER@myhost.test.ex pattern=*@*
myhost.test.ex in "*"? yes (matched "*")
qualify & rewrite recipients list
address match test: subject=r4@test.ex pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' not found in local cache
+ compiled RE '^.{40,}@*' saved in local cache
r4@test.ex in "^.{40,}@*"? no (end of list)
address match test: subject=r4@test.ex pattern=*@*
test.ex in "*"? yes (matched "*")
lookup failed
global rewrite rules
address match test: subject=CALLER@myhost.test.ex pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
CALLER@myhost.test.ex in "^.{40,}@*"? no (end of list)
address match test: subject=CALLER@myhost.test.ex pattern=*@*
myhost.test.ex in "*"? yes (matched "*")
qualify & rewrite recipients list
address match test: subject=r5@test.ex pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' not found in local cache
+ compiled RE '^.{40,}@*' saved in local cache
r5@test.ex in "^.{40,}@*"? no (end of list)
address match test: subject=r5@test.ex pattern=*@*
test.ex in "*"? yes (matched "*")
lookup failed
global rewrite rules
address match test: subject=CALLER@myhost.test.ex pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
CALLER@myhost.test.ex in "^.{40,}@*"? no (end of list)
address match test: subject=CALLER@myhost.test.ex pattern=*@*
myhost.test.ex in "*"? yes (matched "*")
rewrite_one_header: type=F:
From: CALLER_NAME <CALLER@myhost.test.ex>
address match test: subject=CALLER@myhost.test.ex pattern=^.{40,}@*
+ compiled RE '^.{40,}@*' found in local cache
CALLER@myhost.test.ex in "^.{40,}@*"? no (end of list)
address match test: subject=CALLER@myhost.test.ex pattern=*@*
myhost.test.ex in "*"? yes (matched "*")
├considering: } }{ match{$h_auto-submitted:}{(?i)auto-generated|auto-replied} }} {no}{yes}}
├──expanding: (?i)bulk|list|junk
╰─────result: (?i)bulk|list|junk
+ compiled RE '(?i)bulk|list|junk' not found in local cache
+ compiling RE '(?i)bulk|list|junk'
+ compiled RE '(?i)bulk|list|junk' saved in local cache
╭considering: $h_auto-submitted:}{(?i)auto-generated|auto-replied} }} {no}{yes}}
├considering: }{(?i)auto-generated|auto-replied} }} {no}{yes}}
├──expanding: $h_auto-submitted:
├considering: } }} {no}{yes}}
├──expanding: (?i)auto-generated|auto-replied
╰─────result: (?i)auto-generated|auto-replied
+ compiled RE '(?i)auto-generated|auto-replied' not found in local cache
+ compiling RE '(?i)auto-generated|auto-replied'
+ compiled RE '(?i)auto-generated|auto-replied' saved in local cache
├──condition: or {{ !eq{$h_list-id:$h_list-post:$h_list-subscribe:}{} }{ match{$h_precedence:}{(?i)bulk|list|junk} }{ match{$h_auto-submitted:}{(?i)auto-generated|auto-replied} }}
├─────result: false
╭───scanning: no}{yes}}
--- /dev/null
+
+******** SERVER ********
+Exim version x.yz ....
+adding SSLKEYLOGFILE=TESTSUITE/spool/sslkeys
+configuration file is TESTSUITE/test-config
+admin user
+dropping to exim gid; retaining priv uid
+daemon_smtp_port overridden by -oX:
+ <: 1225
+creating notifier socket
+ ╭considering: $spool_directory/exim_daemon_notify
+ ├considering: /exim_daemon_notify
+ ├───────text: /exim_daemon_notify
+ ├──expanding: $spool_directory/exim_daemon_notify
+ ╰─────result: TESTSUITE/spool/exim_daemon_notify
+ TESTSUITE/spool/exim_daemon_notify
+listening on all interfaces (IPv6) port PORT_D
+listening on all interfaces (IPv4) port PORT_D
+pid written to TESTSUITE/spool/exim-daemon.pid
+LOG: MAIN
+ exim x.yz daemon started: pid=p1234, no queue runs, listening for SMTP on port PORT_D
+daemon running with uid=EXIM_UID gid=EXIM_GID euid=EXIM_UID egid=EXIM_GID
+Listening...
+Connection request from 127.0.0.1 port sssss
+search_tidyup called
+p1235 Process p1235 is handling incoming connection from [127.0.0.1]
+p1235 ╭considering: $smtp_active_hostname ESMTP Exim $version_number $tod_full
+p1235 ├considering: ESMTP Exim $version_number $tod_full
+p1235 ├───────text: ESMTP Exim
+p1235 ├considering: $version_number $tod_full
+p1235 ├considering: $tod_full
+p1235 ├───────text:
+p1235 ├considering: $tod_full
+p1235 ├──expanding: $smtp_active_hostname ESMTP Exim $version_number $tod_full
+p1235 ╰─────result: myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+p1235 Process p1235 is ready for new message
+p1235 compiled caseless RE '^nomatch_list' not found in local cache
+p1235 compiled RE '^nomatch_list' saved in local cache
+p1235 sending RE '^nomatch_list' to daemon
+p1235 ╭considering: $spool_directory/exim_daemon_notify
+p1235 ├considering: /exim_daemon_notify
+p1235 ├───────text: /exim_daemon_notify
+p1235 ├──expanding: $spool_directory/exim_daemon_notify
+p1235 ╰─────result: TESTSUITE/spool/exim_daemon_notify
+p1235 ╭considering: ${if match {a_random_string} {static_RE}}
+p1235 ╭considering: a_random_string} {static_RE}}
+p1235 ├───────text: a_random_string
+p1235 ├considering: } {static_RE}}
+p1235 ├──expanding: a_random_string
+p1235 ╰─────result: a_random_string
+p1235 ╭considering: static_RE}}
+p1235 ├───────text: static_RE
+p1235 ├considering: }}
+p1235 ├──expanding: static_RE
+p1235 ╰─────result: static_RE
+p1235 compiled RE 'static_RE' not found in local cache
+p1235 compiling RE 'static_RE'
+p1235 compiled RE 'static_RE' saved in local cache
+p1235 sending RE 'static_RE' to daemon
+p1235 ╭considering: $spool_directory/exim_daemon_notify
+p1235 ├considering: /exim_daemon_notify
+p1235 ├───────text: /exim_daemon_notify
+p1235 ├──expanding: $spool_directory/exim_daemon_notify
+p1235 ╰─────result: TESTSUITE/spool/exim_daemon_notify
+p1235 ├──condition: match {a_random_string} {static_RE}
+p1235 ├─────result: false
+p1235 ├──expanding: ${if match {a_random_string} {static_RE}}
+p1235 ╰─────result:
+p1235 ╭considering: ${if match {a_random_string} {tricky_static_RE\$}}
+p1235 ╭considering: a_random_string} {tricky_static_RE\$}}
+p1235 ├───────text: a_random_string
+p1235 ├considering: } {tricky_static_RE\$}}
+p1235 ├──expanding: a_random_string
+p1235 ╰─────result: a_random_string
+p1235 ╭considering: tricky_static_RE\$}}
+p1235 ├───────text: tricky_static_RE
+p1235 ├considering: \$}}
+p1235 ├backslashed: '\$'
+p1235 ├considering: }}
+p1235 ├──expanding: tricky_static_RE\$
+p1235 ╰─────result: tricky_static_RE$
+p1235 compiled RE 'tricky_static_RE$' not found in local cache
+p1235 compiling RE 'tricky_static_RE$'
+p1235 compiled RE 'tricky_static_RE$' saved in local cache
+p1235 sending RE 'tricky_static_RE$' to daemon
+p1235 ╭considering: $spool_directory/exim_daemon_notify
+p1235 ├considering: /exim_daemon_notify
+p1235 ├───────text: /exim_daemon_notify
+p1235 ├──expanding: $spool_directory/exim_daemon_notify
+p1235 ╰─────result: TESTSUITE/spool/exim_daemon_notify
+p1235 ├──condition: match {a_random_string} {tricky_static_RE\$}
+p1235 ├─────result: false
+p1235 ├──expanding: ${if match {a_random_string} {tricky_static_RE\$}}
+p1235 ╰─────result:
+p1235 ╭considering: ${if match {a_random_string} {pid=${pid} uncacheable_RE}}
+p1235 ╭considering: a_random_string} {pid=${pid} uncacheable_RE}}
+p1235 ├───────text: a_random_string
+p1235 ├considering: } {pid=${pid} uncacheable_RE}}
+p1235 ├──expanding: a_random_string
+p1235 ╰─────result: a_random_string
+p1235 ╭considering: pid=${pid} uncacheable_RE}}
+p1235 ├───────text: pid=
+p1235 ├considering: ${pid} uncacheable_RE}}
+p1235 ├considering: uncacheable_RE}}
+p1235 ├───────text: uncacheable_RE
+p1235 ├considering: }}
+p1235 ├──expanding: pid=${pid} uncacheable_RE
+p1235 ╰─────result: pid=p1235 uncacheable_RE
+p1235 compiling RE 'pid=p1235 uncacheable_RE'
+p1235 ├──condition: match {a_random_string} {pid=${pid} uncacheable_RE}
+p1235 ├─────result: false
+p1235 ├──expanding: ${if match {a_random_string} {pid=${pid} uncacheable_RE}}
+p1235 ╰─────result:
+p1235 search_tidyup called
+p1235 search_tidyup called
+p1235 ╭considering: ${tod_full}
+p1235 ├──expanding: ${tod_full}
+p1235 ╰─────result: Tue, 2 Mar 1999 09:44:33 +0000
+p1235 ╭considering: Received: ${if def:sender_rcvhost {from $sender_rcvhost
+p1235 }{${if def:sender_ident {from ${quote_local_part:$sender_ident} }}${if def:sender_helo_name {(helo=$sender_helo_name)
+p1235 }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1235 }}(Exim $version_number)
+p1235 ${if def:sender_address {(envelope-from <$sender_address>)
+p1235 }}id $message_exim_id${if def:received_for {
+p1235 for $received_for}}
+p1235 ├───────text: Received:
+p1235 ├considering: ${if def:sender_rcvhost {from $sender_rcvhost
+p1235 }{${if def:sender_ident {from ${quote_local_part:$sender_ident} }}${if def:sender_helo_name {(helo=$sender_helo_name)
+p1235 }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1235 }}(Exim $version_number)
+p1235 ${if def:sender_address {(envelope-from <$sender_address>)
+p1235 }}id $message_exim_id${if def:received_for {
+p1235 for $received_for}}
+p1235 ├──condition: def:sender_rcvhost
+p1235 ├─────result: true
+p1235 ╭considering: from $sender_rcvhost
+p1235 }{${if def:sender_ident {from ${quote_local_part:$sender_ident} }}${if def:sender_helo_name {(helo=$sender_helo_name)
+p1235 }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1235 }}(Exim $version_number)
+p1235 ${if def:sender_address {(envelope-from <$sender_address>)
+p1235 }}id $message_exim_id${if def:received_for {
+p1235 for $received_for}}
+p1235 ├───────text: from
+p1235 ├considering: $sender_rcvhost
+p1235 }{${if def:sender_ident {from ${quote_local_part:$sender_ident} }}${if def:sender_helo_name {(helo=$sender_helo_name)
+p1235 }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1235 }}(Exim $version_number)
+p1235 ${if def:sender_address {(envelope-from <$sender_address>)
+p1235 }}id $message_exim_id${if def:received_for {
+p1235 for $received_for}}
+p1235 ├considering:
+p1235 }{${if def:sender_ident {from ${quote_local_part:$sender_ident} }}${if def:sender_helo_name {(helo=$sender_helo_name)
+p1235 }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1235 }}(Exim $version_number)
+p1235 ${if def:sender_address {(envelope-from <$sender_address>)
+p1235 }}id $message_exim_id${if def:received_for {
+p1235 for $received_for}}
+p1235 ├───────text:
+p1235
+p1235 ├considering: }{${if def:sender_ident {from ${quote_local_part:$sender_ident} }}${if def:sender_helo_name {(helo=$sender_helo_name)
+p1235 }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1235 }}(Exim $version_number)
+p1235 ${if def:sender_address {(envelope-from <$sender_address>)
+p1235 }}id $message_exim_id${if def:received_for {
+p1235 for $received_for}}
+p1235 ├──expanding: from $sender_rcvhost
+p1235
+p1235 ╰─────result: from [127.0.0.1] (helo=test.ex)
+p1235
+p1235 ╰──(tainted)
+p1235 ╭───scanning: ${if def:sender_ident {from ${quote_local_part:$sender_ident} }}${if def:sender_helo_name {(helo=$sender_helo_name)
+p1235 }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1235 }}(Exim $version_number)
+p1235 ${if def:sender_address {(envelope-from <$sender_address>)
+p1235 }}id $message_exim_id${if def:received_for {
+p1235 for $received_for}}
+p1235 ├──condition: def:sender_ident
+p1235 ├─────result: false
+p1235 ╭───scanning: from ${quote_local_part:$sender_ident} }}${if def:sender_helo_name {(helo=$sender_helo_name)
+p1235 }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1235 }}(Exim $version_number)
+p1235 ${if def:sender_address {(envelope-from <$sender_address>)
+p1235 }}id $message_exim_id${if def:received_for {
+p1235 for $received_for}}
+p1235 ├───────text: from
+p1235 ├───scanning: ${quote_local_part:$sender_ident} }}${if def:sender_helo_name {(helo=$sender_helo_name)
+p1235 }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1235 }}(Exim $version_number)
+p1235 ${if def:sender_address {(envelope-from <$sender_address>)
+p1235 }}id $message_exim_id${if def:received_for {
+p1235 for $received_for}}
+p1235 ╎╭───scanning: $sender_ident} }}${if def:sender_helo_name {(helo=$sender_helo_name)
+p1235 ╎ }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1235 ╎ }}(Exim $version_number)
+p1235 ╎ ${if def:sender_address {(envelope-from <$sender_address>)
+p1235 ╎ }}id $message_exim_id${if def:received_for {
+p1235 ╎ for $received_for}}
+p1235 ╎├───scanning: } }}${if def:sender_helo_name {(helo=$sender_helo_name)
+p1235 ╎ }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1235 ╎ }}(Exim $version_number)
+p1235 ╎ ${if def:sender_address {(envelope-from <$sender_address>)
+p1235 ╎ }}id $message_exim_id${if def:received_for {
+p1235 ╎ for $received_for}}
+p1235 ╎├──expanding: $sender_ident
+p1235 ╎├─────result:
+p1235 ╎╰───skipping: result is not used
+p1235 ├───scanning: }}${if def:sender_helo_name {(helo=$sender_helo_name)
+p1235 }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1235 }}(Exim $version_number)
+p1235 ${if def:sender_address {(envelope-from <$sender_address>)
+p1235 }}id $message_exim_id${if def:received_for {
+p1235 for $received_for}}
+p1235 ├───────text:
+p1235 ├───scanning: }}${if def:sender_helo_name {(helo=$sender_helo_name)
+p1235 }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1235 }}(Exim $version_number)
+p1235 ${if def:sender_address {(envelope-from <$sender_address>)
+p1235 }}id $message_exim_id${if def:received_for {
+p1235 for $received_for}}
+p1235 ├──expanding: from ${quote_local_part:$sender_ident}
+p1235 ├─────result: from
+p1235 ╰───skipping: result is not used
+p1235 ├───item-res:
+p1235 ├───scanning: ${if def:sender_helo_name {(helo=$sender_helo_name)
+p1235 }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1235 }}(Exim $version_number)
+p1235 ${if def:sender_address {(envelope-from <$sender_address>)
+p1235 }}id $message_exim_id${if def:received_for {
+p1235 for $received_for}}
+p1235 ├──condition: def:sender_helo_name
+p1235 ├─────result: false
+p1235 ╭───scanning: (helo=$sender_helo_name)
+p1235 }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1235 }}(Exim $version_number)
+p1235 ${if def:sender_address {(envelope-from <$sender_address>)
+p1235 }}id $message_exim_id${if def:received_for {
+p1235 for $received_for}}
+p1235 ├───────text: (helo=
+p1235 ├───scanning: $sender_helo_name)
+p1235 }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1235 }}(Exim $version_number)
+p1235 ${if def:sender_address {(envelope-from <$sender_address>)
+p1235 }}id $message_exim_id${if def:received_for {
+p1235 for $received_for}}
+p1235 ├───scanning: )
+p1235 }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1235 }}(Exim $version_number)
+p1235 ${if def:sender_address {(envelope-from <$sender_address>)
+p1235 }}id $message_exim_id${if def:received_for {
+p1235 for $received_for}}
+p1235 ├───────text: )
+p1235
+p1235 ├───scanning: }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1235 }}(Exim $version_number)
+p1235 ${if def:sender_address {(envelope-from <$sender_address>)
+p1235 }}id $message_exim_id${if def:received_for {
+p1235 for $received_for}}
+p1235 ├──expanding: (helo=$sender_helo_name)
+p1235
+p1235 ├─────result: (helo=)
+p1235
+p1235 ╰───skipping: result is not used
+p1235 ├───item-res:
+p1235 ├───scanning: }}by $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1235 }}(Exim $version_number)
+p1235 ${if def:sender_address {(envelope-from <$sender_address>)
+p1235 }}id $message_exim_id${if def:received_for {
+p1235 for $received_for}}
+p1235 ├──expanding: ${if def:sender_ident {from ${quote_local_part:$sender_ident} }}${if def:sender_helo_name {(helo=$sender_helo_name)
+p1235 }}
+p1235 ├─────result:
+p1235 ╰───skipping: result is not used
+p1235 ├───item-res: from [127.0.0.1] (helo=test.ex)
+p1235
+p1235 ╰──(tainted)
+p1235 ├considering: by $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1235 }}(Exim $version_number)
+p1235 ${if def:sender_address {(envelope-from <$sender_address>)
+p1235 }}id $message_exim_id${if def:received_for {
+p1235 for $received_for}}
+p1235 ├───────text: by
+p1235 ├considering: $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1235 }}(Exim $version_number)
+p1235 ${if def:sender_address {(envelope-from <$sender_address>)
+p1235 }}id $message_exim_id${if def:received_for {
+p1235 for $received_for}}
+p1235 ├considering: ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1235 }}(Exim $version_number)
+p1235 ${if def:sender_address {(envelope-from <$sender_address>)
+p1235 }}id $message_exim_id${if def:received_for {
+p1235 for $received_for}}
+p1235 ├───────text:
+p1235 ├considering: ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1235 }}(Exim $version_number)
+p1235 ${if def:sender_address {(envelope-from <$sender_address>)
+p1235 }}id $message_exim_id${if def:received_for {
+p1235 for $received_for}}
+p1235 ├──condition: def:received_protocol
+p1235 ├─────result: true
+p1235 ╭considering: with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1235 }}(Exim $version_number)
+p1235 ${if def:sender_address {(envelope-from <$sender_address>)
+p1235 }}id $message_exim_id${if def:received_for {
+p1235 for $received_for}}
+p1235 ├───────text: with
+p1235 ├considering: $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1235 }}(Exim $version_number)
+p1235 ${if def:sender_address {(envelope-from <$sender_address>)
+p1235 }}id $message_exim_id${if def:received_for {
+p1235 for $received_for}}
+p1235 ├considering: }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1235 }}(Exim $version_number)
+p1235 ${if def:sender_address {(envelope-from <$sender_address>)
+p1235 }}id $message_exim_id${if def:received_for {
+p1235 for $received_for}}
+p1235 ├───────text:
+p1235 ├considering: }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1235 }}(Exim $version_number)
+p1235 ${if def:sender_address {(envelope-from <$sender_address>)
+p1235 }}id $message_exim_id${if def:received_for {
+p1235 for $received_for}}
+p1235 ├──expanding: with $received_protocol
+p1235 ╰─────result: with smtp
+p1235 ├───item-res: with smtp
+p1235 ╰──(tainted)
+p1235 ├considering: ${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1235 }}(Exim $version_number)
+p1235 ${if def:sender_address {(envelope-from <$sender_address>)
+p1235 }}id $message_exim_id${if def:received_for {
+p1235 for $received_for}}
+p1235 }}id $message_exim_id${if def:received_for {
+p1235 for $received_for}}
+p1235 ├──expanding: ($tls_in_ver)
+p1235 ├─────result: ()
+p1235 ╰───skipping: result is not used
+p1235 ├───item-res:
+p1235 ╰──(tainted)
+p1235 ├considering: ${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1235 }}(Exim $version_number)
+p1235 ${if def:sender_address {(envelope-from <$sender_address>)
+p1235 }}id $message_exim_id${if def:received_for {
+p1235 for $received_for}}
+p1235 ├──condition: def:tls_in_cipher_std
+p1235 ├─────result: false
+p1235 ╭───scanning: tls $tls_in_cipher_std
+p1235 }}(Exim $version_number)
+p1235 ${if def:sender_address {(envelope-from <$sender_address>)
+p1235 }}id $message_exim_id${if def:received_for {
+p1235 for $received_for}}
+p1235 ├───────text: tls
+p1235 ├───scanning: $tls_in_cipher_std
+p1235 }}(Exim $version_number)
+p1235 ${if def:sender_address {(envelope-from <$sender_address>)
+p1235 }}id $message_exim_id${if def:received_for {
+p1235 for $received_for}}
+p1235 ├───scanning:
+p1235 }}(Exim $version_number)
+p1235 ${if def:sender_address {(envelope-from <$sender_address>)
+p1235 }}id $message_exim_id${if def:received_for {
+p1235 for $received_for}}
+p1235 ├───────text:
+p1235
+p1235 ├───scanning: }}(Exim $version_number)
+p1235 ${if def:sender_address {(envelope-from <$sender_address>)
+p1235 }}id $message_exim_id${if def:received_for {
+p1235 for $received_for}}
+p1235 ├──expanding: tls $tls_in_cipher_std
+p1235
+p1235 ├─────result: tls
+p1235
+p1235 ╰───skipping: result is not used
+p1235 ├───item-res:
+p1235 ╰──(tainted)
+p1235 ├considering: (Exim $version_number)
+p1235 ${if def:sender_address {(envelope-from <$sender_address>)
+p1235 }}id $message_exim_id${if def:received_for {
+p1235 for $received_for}}
+p1235 ├───────text: (Exim
+p1235 ├considering: $version_number)
+p1235 ${if def:sender_address {(envelope-from <$sender_address>)
+p1235 }}id $message_exim_id${if def:received_for {
+p1235 for $received_for}}
+p1235 ├considering: )
+p1235 ${if def:sender_address {(envelope-from <$sender_address>)
+p1235 }}id $message_exim_id${if def:received_for {
+p1235 for $received_for}}
+p1235 ├───────text: )
+p1235
+p1235 ├considering: ${if def:sender_address {(envelope-from <$sender_address>)
+p1235 }}id $message_exim_id${if def:received_for {
+p1235 for $received_for}}
+p1235 ├──condition: def:sender_address
+p1235 ├─────result: true
+p1235 ╭considering: (envelope-from <$sender_address>)
+p1235 }}id $message_exim_id${if def:received_for {
+p1235 for $received_for}}
+p1235 ├───────text: (envelope-from <
+p1235 ├considering: $sender_address>)
+p1235 }}id $message_exim_id${if def:received_for {
+p1235 for $received_for}}
+p1235 ├considering: >)
+p1235 }}id $message_exim_id${if def:received_for {
+p1235 for $received_for}}
+p1235 ├───────text: >)
+p1235
+p1235 ├considering: }}id $message_exim_id${if def:received_for {
+p1235 for $received_for}}
+p1235 ├──expanding: (envelope-from <$sender_address>)
+p1235
+p1235 ╰─────result: (envelope-from <CALLER@test.ex>)
+p1235
+p1235 ╰──(tainted)
+p1235 ├───item-res: (envelope-from <CALLER@test.ex>)
+p1235
+p1235 ╰──(tainted)
+p1235 ├considering: id $message_exim_id${if def:received_for {
+p1235 for $received_for}}
+p1235 ├───────text: id
+p1235 ├considering: $message_exim_id${if def:received_for {
+p1235 for $received_for}}
+p1235 ├considering: ${if def:received_for {
+p1235 for $received_for}}
+p1235 ├──condition: def:received_for
+p1235 ├─────result: true
+p1235 ╭considering:
+p1235 for $received_for}}
+p1235 ├───────text:
+p1235 for
+p1235 ├considering: $received_for}}
+p1235 ├considering: }}
+p1235 ├──expanding:
+p1235 for $received_for
+p1235 ╰─────result:
+p1235 for dest_1@test.ex
+p1235 ╰──(tainted)
+p1235 ├───item-res:
+p1235 for dest_1@test.ex
+p1235 ╰──(tainted)
+p1235 ├──expanding: Received: ${if def:sender_rcvhost {from $sender_rcvhost
+p1235 }{${if def:sender_ident {from ${quote_local_part:$sender_ident} }}${if def:sender_helo_name {(helo=$sender_helo_name)
+p1235 }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1235 }}(Exim $version_number)
+p1235 ${if def:sender_address {(envelope-from <$sender_address>)
+p1235 }}id $message_exim_id${if def:received_for {
+p1235 for $received_for}}
+p1235 ╰─────result: Received: from [127.0.0.1] (helo=test.ex)
+p1235 by myhost.test.ex with smtp (Exim x.yz)
+p1235 (envelope-from <CALLER@test.ex>)
+p1235 id 10HmaX-0005vi-00
+p1235 for dest_1@test.ex
+p1235 ╰──(tainted)
+p1235 ╭considering: ${tod_full}
+p1235 ├──expanding: ${tod_full}
+p1235 ╰─────result: Tue, 2 Mar 1999 09:44:33 +0000
+LOG: MAIN
+ <= CALLER@test.ex H=(test.ex) [127.0.0.1] P=smtp S=sss
+search_tidyup called
+Process p1235 is ready for new message
+LOG: smtp_connection MAIN
+ SMTP connection from (test.ex) [127.0.0.1] closed by QUIT
+p1234 1 SMTP accept process running
+p1234 Listening...
+p1234 daemon_notification from addr ''
+p1234 compiled caseless RE '^nomatch_list' not found in local cache
+p1234 compiling caseless RE '^nomatch_list'
+p1234 compiled RE '^nomatch_list' saved in local cache
+p1234 Listening...
+p1234 daemon_notification from addr ''
+p1234 compiled RE 'static_RE' not found in local cache
+p1234 compiling RE 'static_RE'
+p1234 compiled RE 'static_RE' saved in local cache
+p1234 Listening...
+p1234 daemon_notification from addr ''
+p1234 compiled RE 'tricky_static_RE$' not found in local cache
+p1234 compiling RE 'tricky_static_RE$'
+p1234 compiled RE 'tricky_static_RE$' saved in local cache
+p1234 Listening...
+search_tidyup called
+>>>>>>>>>>>>>>>> Exim pid=p1235 (daemon-accept) terminating with rc=0 >>>>>>>>>>>>>>>>
+p1234 child p1235 ended: status=0x0
+p1234 normal exit, 0
+p1234 0 SMTP accept processes now running
+p1234 Listening...
+p1234 Connection request from 127.0.0.1 port sssss
+p1234 search_tidyup called
+p1236 Process p1236 is handling incoming connection from [127.0.0.1]
+p1236 ╭considering: $smtp_active_hostname ESMTP Exim $version_number $tod_full
+p1236 ├considering: ESMTP Exim $version_number $tod_full
+p1236 ├───────text: ESMTP Exim
+p1236 ├considering: $version_number $tod_full
+p1236 ├considering: $tod_full
+p1236 ├───────text:
+p1236 ├considering: $tod_full
+p1236 ├──expanding: $smtp_active_hostname ESMTP Exim $version_number $tod_full
+p1236 ╰─────result: myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+p1236 Process p1236 is ready for new message
+p1236 compiled caseless RE '^nomatch_list' found in local cache
+p1236 ╭considering: ${if match {a_random_string} {static_RE}}
+p1236 ╭considering: a_random_string} {static_RE}}
+p1236 ├───────text: a_random_string
+p1236 ├considering: } {static_RE}}
+p1236 ├──expanding: a_random_string
+p1236 ╰─────result: a_random_string
+p1236 ╭considering: static_RE}}
+p1236 ├───────text: static_RE
+p1236 ├considering: }}
+p1236 ├──expanding: static_RE
+p1236 ╰─────result: static_RE
+p1236 compiled RE 'static_RE' found in local cache
+p1236 ├──condition: match {a_random_string} {static_RE}
+p1236 ├─────result: false
+p1236 ├──expanding: ${if match {a_random_string} {static_RE}}
+p1236 ╰─────result:
+p1236 ╭considering: ${if match {a_random_string} {tricky_static_RE\$}}
+p1236 ╭considering: a_random_string} {tricky_static_RE\$}}
+p1236 ├───────text: a_random_string
+p1236 ├considering: } {tricky_static_RE\$}}
+p1236 ├──expanding: a_random_string
+p1236 ╰─────result: a_random_string
+p1236 ╭considering: tricky_static_RE\$}}
+p1236 ├───────text: tricky_static_RE
+p1236 ├considering: \$}}
+p1236 ├backslashed: '\$'
+p1236 ├considering: }}
+p1236 ├──expanding: tricky_static_RE\$
+p1236 ╰─────result: tricky_static_RE$
+p1236 compiled RE 'tricky_static_RE$' found in local cache
+p1236 ├──condition: match {a_random_string} {tricky_static_RE\$}
+p1236 ├─────result: false
+p1236 ├──expanding: ${if match {a_random_string} {tricky_static_RE\$}}
+p1236 ╰─────result:
+p1236 ╭considering: ${if match {a_random_string} {pid=${pid} uncacheable_RE}}
+p1236 ╭considering: a_random_string} {pid=${pid} uncacheable_RE}}
+p1236 ├───────text: a_random_string
+p1236 ├considering: } {pid=${pid} uncacheable_RE}}
+p1236 ├──expanding: a_random_string
+p1236 ╰─────result: a_random_string
+p1236 ╭considering: pid=${pid} uncacheable_RE}}
+p1236 ├───────text: pid=
+p1236 ├considering: ${pid} uncacheable_RE}}
+p1236 ├considering: uncacheable_RE}}
+p1236 ├───────text: uncacheable_RE
+p1236 ├considering: }}
+p1236 ├──expanding: pid=${pid} uncacheable_RE
+p1236 ╰─────result: pid=p1236 uncacheable_RE
+p1236 compiling RE 'pid=p1236 uncacheable_RE'
+p1236 ├──condition: match {a_random_string} {pid=${pid} uncacheable_RE}
+p1236 ├─────result: false
+p1236 ├──expanding: ${if match {a_random_string} {pid=${pid} uncacheable_RE}}
+p1236 ╰─────result:
+p1236 search_tidyup called
+p1236 search_tidyup called
+p1236 ╭considering: ${tod_full}
+p1236 ├──expanding: ${tod_full}
+p1236 ╰─────result: Tue, 2 Mar 1999 09:44:33 +0000
+p1236 ╭considering: Received: ${if def:sender_rcvhost {from $sender_rcvhost
+p1236 }{${if def:sender_ident {from ${quote_local_part:$sender_ident} }}${if def:sender_helo_name {(helo=$sender_helo_name)
+p1236 }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1236 }}(Exim $version_number)
+p1236 ${if def:sender_address {(envelope-from <$sender_address>)
+p1236 }}id $message_exim_id${if def:received_for {
+p1236 for $received_for}}
+p1236 ├───────text: Received:
+p1236 ├considering: ${if def:sender_rcvhost {from $sender_rcvhost
+p1236 }{${if def:sender_ident {from ${quote_local_part:$sender_ident} }}${if def:sender_helo_name {(helo=$sender_helo_name)
+p1236 }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1236 }}(Exim $version_number)
+p1236 ${if def:sender_address {(envelope-from <$sender_address>)
+p1236 }}id $message_exim_id${if def:received_for {
+p1236 for $received_for}}
+p1236 ├──condition: def:sender_rcvhost
+p1236 ├─────result: true
+p1236 ╭considering: from $sender_rcvhost
+p1236 }{${if def:sender_ident {from ${quote_local_part:$sender_ident} }}${if def:sender_helo_name {(helo=$sender_helo_name)
+p1236 }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1236 }}(Exim $version_number)
+p1236 ${if def:sender_address {(envelope-from <$sender_address>)
+p1236 }}id $message_exim_id${if def:received_for {
+p1236 for $received_for}}
+p1236 ├───────text: from
+p1236 ├considering: $sender_rcvhost
+p1236 }{${if def:sender_ident {from ${quote_local_part:$sender_ident} }}${if def:sender_helo_name {(helo=$sender_helo_name)
+p1236 }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1236 }}(Exim $version_number)
+p1236 ${if def:sender_address {(envelope-from <$sender_address>)
+p1236 }}id $message_exim_id${if def:received_for {
+p1236 for $received_for}}
+p1236 ├considering:
+p1236 }{${if def:sender_ident {from ${quote_local_part:$sender_ident} }}${if def:sender_helo_name {(helo=$sender_helo_name)
+p1236 }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1236 }}(Exim $version_number)
+p1236 ${if def:sender_address {(envelope-from <$sender_address>)
+p1236 }}id $message_exim_id${if def:received_for {
+p1236 for $received_for}}
+p1236 ├───────text:
+p1236
+p1236 ├considering: }{${if def:sender_ident {from ${quote_local_part:$sender_ident} }}${if def:sender_helo_name {(helo=$sender_helo_name)
+p1236 }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1236 }}(Exim $version_number)
+p1236 ${if def:sender_address {(envelope-from <$sender_address>)
+p1236 }}id $message_exim_id${if def:received_for {
+p1236 for $received_for}}
+p1236 ├──expanding: from $sender_rcvhost
+p1236
+p1236 ╰─────result: from [127.0.0.1] (helo=test.ex)
+p1236
+p1236 ╰──(tainted)
+p1236 ╭───scanning: ${if def:sender_ident {from ${quote_local_part:$sender_ident} }}${if def:sender_helo_name {(helo=$sender_helo_name)
+p1236 }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1236 }}(Exim $version_number)
+p1236 ${if def:sender_address {(envelope-from <$sender_address>)
+p1236 }}id $message_exim_id${if def:received_for {
+p1236 for $received_for}}
+p1236 ├──condition: def:sender_ident
+p1236 ├─────result: false
+p1236 ╭───scanning: from ${quote_local_part:$sender_ident} }}${if def:sender_helo_name {(helo=$sender_helo_name)
+p1236 }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1236 }}(Exim $version_number)
+p1236 ${if def:sender_address {(envelope-from <$sender_address>)
+p1236 }}id $message_exim_id${if def:received_for {
+p1236 for $received_for}}
+p1236 ├───────text: from
+p1236 ├───scanning: ${quote_local_part:$sender_ident} }}${if def:sender_helo_name {(helo=$sender_helo_name)
+p1236 }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1236 }}(Exim $version_number)
+p1236 ${if def:sender_address {(envelope-from <$sender_address>)
+p1236 }}id $message_exim_id${if def:received_for {
+p1236 for $received_for}}
+p1236 ╎╭───scanning: $sender_ident} }}${if def:sender_helo_name {(helo=$sender_helo_name)
+p1236 ╎ }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1236 ╎ }}(Exim $version_number)
+p1236 ╎ ${if def:sender_address {(envelope-from <$sender_address>)
+p1236 ╎ }}id $message_exim_id${if def:received_for {
+p1236 ╎ for $received_for}}
+p1236 ╎├───scanning: } }}${if def:sender_helo_name {(helo=$sender_helo_name)
+p1236 ╎ }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1236 ╎ }}(Exim $version_number)
+p1236 ╎ ${if def:sender_address {(envelope-from <$sender_address>)
+p1236 ╎ }}id $message_exim_id${if def:received_for {
+p1236 ╎ for $received_for}}
+p1236 ╎├──expanding: $sender_ident
+p1236 ╎├─────result:
+p1236 ╎╰───skipping: result is not used
+p1236 ├───scanning: }}${if def:sender_helo_name {(helo=$sender_helo_name)
+p1236 }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1236 }}(Exim $version_number)
+p1236 ${if def:sender_address {(envelope-from <$sender_address>)
+p1236 }}id $message_exim_id${if def:received_for {
+p1236 for $received_for}}
+p1236 ├───────text:
+p1236 ├───scanning: }}${if def:sender_helo_name {(helo=$sender_helo_name)
+p1236 }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1236 }}(Exim $version_number)
+p1236 ${if def:sender_address {(envelope-from <$sender_address>)
+p1236 }}id $message_exim_id${if def:received_for {
+p1236 for $received_for}}
+p1236 ├──expanding: from ${quote_local_part:$sender_ident}
+p1236 ├─────result: from
+p1236 ╰───skipping: result is not used
+p1236 ├───item-res:
+p1236 ├───scanning: ${if def:sender_helo_name {(helo=$sender_helo_name)
+p1236 }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1236 }}(Exim $version_number)
+p1236 ${if def:sender_address {(envelope-from <$sender_address>)
+p1236 }}id $message_exim_id${if def:received_for {
+p1236 for $received_for}}
+p1236 ├──condition: def:sender_helo_name
+p1236 ├─────result: false
+p1236 ╭───scanning: (helo=$sender_helo_name)
+p1236 }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1236 }}(Exim $version_number)
+p1236 ${if def:sender_address {(envelope-from <$sender_address>)
+p1236 }}id $message_exim_id${if def:received_for {
+p1236 for $received_for}}
+p1236 ├───────text: (helo=
+p1236 ├───scanning: $sender_helo_name)
+p1236 }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1236 }}(Exim $version_number)
+p1236 ${if def:sender_address {(envelope-from <$sender_address>)
+p1236 }}id $message_exim_id${if def:received_for {
+p1236 for $received_for}}
+p1236 ├───scanning: )
+p1236 }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1236 }}(Exim $version_number)
+p1236 ${if def:sender_address {(envelope-from <$sender_address>)
+p1236 }}id $message_exim_id${if def:received_for {
+p1236 for $received_for}}
+p1236 ├───────text: )
+p1236
+p1236 ├───scanning: }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1236 }}(Exim $version_number)
+p1236 ${if def:sender_address {(envelope-from <$sender_address>)
+p1236 }}id $message_exim_id${if def:received_for {
+p1236 for $received_for}}
+p1236 ├──expanding: (helo=$sender_helo_name)
+p1236
+p1236 ├─────result: (helo=)
+p1236
+p1236 ╰───skipping: result is not used
+p1236 ├───item-res:
+p1236 ├───scanning: }}by $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1236 }}(Exim $version_number)
+p1236 ${if def:sender_address {(envelope-from <$sender_address>)
+p1236 }}id $message_exim_id${if def:received_for {
+p1236 for $received_for}}
+p1236 ├──expanding: ${if def:sender_ident {from ${quote_local_part:$sender_ident} }}${if def:sender_helo_name {(helo=$sender_helo_name)
+p1236 }}
+p1236 ├─────result:
+p1236 ╰───skipping: result is not used
+p1236 ├───item-res: from [127.0.0.1] (helo=test.ex)
+p1236
+p1236 ╰──(tainted)
+p1236 ├considering: by $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1236 }}(Exim $version_number)
+p1236 ${if def:sender_address {(envelope-from <$sender_address>)
+p1236 }}id $message_exim_id${if def:received_for {
+p1236 for $received_for}}
+p1236 ├───────text: by
+p1236 ├considering: $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1236 }}(Exim $version_number)
+p1236 ${if def:sender_address {(envelope-from <$sender_address>)
+p1236 }}id $message_exim_id${if def:received_for {
+p1236 for $received_for}}
+p1236 ├considering: ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1236 }}(Exim $version_number)
+p1236 ${if def:sender_address {(envelope-from <$sender_address>)
+p1236 }}id $message_exim_id${if def:received_for {
+p1236 for $received_for}}
+p1236 ├───────text:
+p1236 ├considering: ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1236 }}(Exim $version_number)
+p1236 ${if def:sender_address {(envelope-from <$sender_address>)
+p1236 }}id $message_exim_id${if def:received_for {
+p1236 for $received_for}}
+p1236 ├──condition: def:received_protocol
+p1236 ├─────result: true
+p1236 ╭considering: with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1236 }}(Exim $version_number)
+p1236 ${if def:sender_address {(envelope-from <$sender_address>)
+p1236 }}id $message_exim_id${if def:received_for {
+p1236 for $received_for}}
+p1236 ├───────text: with
+p1236 ├considering: $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1236 }}(Exim $version_number)
+p1236 ${if def:sender_address {(envelope-from <$sender_address>)
+p1236 }}id $message_exim_id${if def:received_for {
+p1236 for $received_for}}
+p1236 ├considering: }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1236 }}(Exim $version_number)
+p1236 ${if def:sender_address {(envelope-from <$sender_address>)
+p1236 }}id $message_exim_id${if def:received_for {
+p1236 for $received_for}}
+p1236 ├───────text:
+p1236 ├considering: }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1236 }}(Exim $version_number)
+p1236 ${if def:sender_address {(envelope-from <$sender_address>)
+p1236 }}id $message_exim_id${if def:received_for {
+p1236 for $received_for}}
+p1236 ├──expanding: with $received_protocol
+p1236 ╰─────result: with smtp
+p1236 ├───item-res: with smtp
+p1236 ╰──(tainted)
+p1236 ├considering: ${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1236 }}(Exim $version_number)
+p1236 ${if def:sender_address {(envelope-from <$sender_address>)
+p1236 }}id $message_exim_id${if def:received_for {
+p1236 for $received_for}}
+p1236 }}id $message_exim_id${if def:received_for {
+p1236 for $received_for}}
+p1236 ├──expanding: ($tls_in_ver)
+p1236 ├─────result: ()
+p1236 ╰───skipping: result is not used
+p1236 ├───item-res:
+p1236 ╰──(tainted)
+p1236 ├considering: ${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1236 }}(Exim $version_number)
+p1236 ${if def:sender_address {(envelope-from <$sender_address>)
+p1236 }}id $message_exim_id${if def:received_for {
+p1236 for $received_for}}
+p1236 ├──condition: def:tls_in_cipher_std
+p1236 ├─────result: false
+p1236 ╭───scanning: tls $tls_in_cipher_std
+p1236 }}(Exim $version_number)
+p1236 ${if def:sender_address {(envelope-from <$sender_address>)
+p1236 }}id $message_exim_id${if def:received_for {
+p1236 for $received_for}}
+p1236 ├───────text: tls
+p1236 ├───scanning: $tls_in_cipher_std
+p1236 }}(Exim $version_number)
+p1236 ${if def:sender_address {(envelope-from <$sender_address>)
+p1236 }}id $message_exim_id${if def:received_for {
+p1236 for $received_for}}
+p1236 ├───scanning:
+p1236 }}(Exim $version_number)
+p1236 ${if def:sender_address {(envelope-from <$sender_address>)
+p1236 }}id $message_exim_id${if def:received_for {
+p1236 for $received_for}}
+p1236 ├───────text:
+p1236
+p1236 ├───scanning: }}(Exim $version_number)
+p1236 ${if def:sender_address {(envelope-from <$sender_address>)
+p1236 }}id $message_exim_id${if def:received_for {
+p1236 for $received_for}}
+p1236 ├──expanding: tls $tls_in_cipher_std
+p1236
+p1236 ├─────result: tls
+p1236
+p1236 ╰───skipping: result is not used
+p1236 ├───item-res:
+p1236 ╰──(tainted)
+p1236 ├considering: (Exim $version_number)
+p1236 ${if def:sender_address {(envelope-from <$sender_address>)
+p1236 }}id $message_exim_id${if def:received_for {
+p1236 for $received_for}}
+p1236 ├───────text: (Exim
+p1236 ├considering: $version_number)
+p1236 ${if def:sender_address {(envelope-from <$sender_address>)
+p1236 }}id $message_exim_id${if def:received_for {
+p1236 for $received_for}}
+p1236 ├considering: )
+p1236 ${if def:sender_address {(envelope-from <$sender_address>)
+p1236 }}id $message_exim_id${if def:received_for {
+p1236 for $received_for}}
+p1236 ├───────text: )
+p1236
+p1236 ├considering: ${if def:sender_address {(envelope-from <$sender_address>)
+p1236 }}id $message_exim_id${if def:received_for {
+p1236 for $received_for}}
+p1236 ├──condition: def:sender_address
+p1236 ├─────result: true
+p1236 ╭considering: (envelope-from <$sender_address>)
+p1236 }}id $message_exim_id${if def:received_for {
+p1236 for $received_for}}
+p1236 ├───────text: (envelope-from <
+p1236 ├considering: $sender_address>)
+p1236 }}id $message_exim_id${if def:received_for {
+p1236 for $received_for}}
+p1236 ├considering: >)
+p1236 }}id $message_exim_id${if def:received_for {
+p1236 for $received_for}}
+p1236 ├───────text: >)
+p1236
+p1236 ├considering: }}id $message_exim_id${if def:received_for {
+p1236 for $received_for}}
+p1236 ├──expanding: (envelope-from <$sender_address>)
+p1236
+p1236 ╰─────result: (envelope-from <CALLER@test.ex>)
+p1236
+p1236 ╰──(tainted)
+p1236 ├───item-res: (envelope-from <CALLER@test.ex>)
+p1236
+p1236 ╰──(tainted)
+p1236 ├considering: id $message_exim_id${if def:received_for {
+p1236 for $received_for}}
+p1236 ├───────text: id
+p1236 ├considering: $message_exim_id${if def:received_for {
+p1236 for $received_for}}
+p1236 ├considering: ${if def:received_for {
+p1236 for $received_for}}
+p1236 ├──condition: def:received_for
+p1236 ├─────result: true
+p1236 ╭considering:
+p1236 for $received_for}}
+p1236 ├───────text:
+p1236 for
+p1236 ├considering: $received_for}}
+p1236 ├considering: }}
+p1236 ├──expanding:
+p1236 for $received_for
+p1236 ╰─────result:
+p1236 for dest_2@test.ex
+p1236 ╰──(tainted)
+p1236 ├───item-res:
+p1236 for dest_2@test.ex
+p1236 ╰──(tainted)
+p1236 ├──expanding: Received: ${if def:sender_rcvhost {from $sender_rcvhost
+p1236 }{${if def:sender_ident {from ${quote_local_part:$sender_ident} }}${if def:sender_helo_name {(helo=$sender_helo_name)
+p1236 }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol }}${if def:tls_in_ver { ($tls_in_ver)}}${if def:tls_in_cipher_std { tls $tls_in_cipher_std
+p1236 }}(Exim $version_number)
+p1236 ${if def:sender_address {(envelope-from <$sender_address>)
+p1236 }}id $message_exim_id${if def:received_for {
+p1236 for $received_for}}
+p1236 ╰─────result: Received: from [127.0.0.1] (helo=test.ex)
+p1236 by myhost.test.ex with smtp (Exim x.yz)
+p1236 (envelope-from <CALLER@test.ex>)
+p1236 id 10HmaY-0005vi-00
+p1236 for dest_2@test.ex
+p1236 ╰──(tainted)
+p1236 ╭considering: ${tod_full}
+p1236 ├──expanding: ${tod_full}
+p1236 ╰─────result: Tue, 2 Mar 1999 09:44:33 +0000
+LOG: MAIN
+ <= CALLER@test.ex H=(test.ex) [127.0.0.1] P=smtp S=sss
+search_tidyup called
+Process p1236 is ready for new message
+LOG: smtp_connection MAIN
+ SMTP connection from (test.ex) [127.0.0.1] closed by QUIT
+p1234 1 SMTP accept process running
+p1234 Listening...
+search_tidyup called
+>>>>>>>>>>>>>>>> Exim pid=p1236 (daemon-accept) terminating with rc=0 >>>>>>>>>>>>>>>>
+p1234 child p1236 ended: status=0x0
+p1234 normal exit, 0
+p1234 0 SMTP accept processes now running
+p1234 Listening...
+p1234 SIGTERM/SIGINT seen
+p1234 search_tidyup called
+p1234 >>>>>>>>>>>>>>>> Exim pid=p1234 (daemon) terminating with rc=0 >>>>>>>>>>>>>>>>
$auth1 = userx secret
$1 = userx secret
+++MYLOGIN $1="userx secret" $2="" $3=""
+ compiled RE '^(\S+)\s+(\S+)$' not found in local cache
+ compiling RE '^(\S+)\s+(\S+)$'
+ compiled RE '^(\S+)\s+(\S+)$' saved in local cache
expanded string: yes
SMTP>> 235 Authentication succeeded
SMTP<< quit
created directory TESTSUITE/test-mail/nofile/tmp
created directory TESTSUITE/test-mail/nofile/new
created directory TESTSUITE/test-mail/nofile/cur
+compiling RE '^(?:cur|new|\..*)$'
using regex for maildir directory selection: ^(?:cur|new|\..*)$
looking for maildirsize in TESTSUITE/test-mail/nofile
TESTSUITE/test-mail/nofile/maildirsize does not exist: recalculating
created directory TESTSUITE/test-mail/userx/tmp
created directory TESTSUITE/test-mail/userx/new
created directory TESTSUITE/test-mail/userx/cur
+compiling RE '^(?:cur|new|\..*)$'
using regex for maildir directory selection: ^(?:cur|new|\..*)$
looking for maildirsize in TESTSUITE/test-mail/userx
reading quota parameters from maildirsize data
maildir_use_size_file=yes
de-tainting path 'TESTSUITE/test-mail/userx'
ensuring maildir directories exist in TESTSUITE/test-mail/userx
+compiling RE '^(?:cur|new|\..*)$'
using regex for maildir directory selection: ^(?:cur|new|\..*)$
looking for maildirsize in TESTSUITE/test-mail/userx
reading quota parameters from maildirsize data
maildir_use_size_file=yes
de-tainting path 'TESTSUITE/test-mail/userx'
ensuring maildir directories exist in TESTSUITE/test-mail/userx
+compiling RE '^(?:cur|new|\..*)$'
using regex for maildir directory selection: ^(?:cur|new|\..*)$
looking for maildirsize in TESTSUITE/test-mail/userx
reading quota parameters from maildirsize data
created directory TESTSUITE/test-mail/userx/tmp
created directory TESTSUITE/test-mail/userx/new
created directory TESTSUITE/test-mail/userx/cur
+compiling RE '^(?:cur|new|\..*)$'
using regex for maildir directory selection: ^(?:cur|new|\..*)$
looking for maildirsize in TESTSUITE/test-mail/userx
TESTSUITE/test-mail/userx/maildirsize does not exist: recalculating
├considering: }} {match{$item}{\N^250-([\w.]+)\s\N}}} {$1}}
├──expanding: .outlook.com\$
╰─────result: .outlook.com$
+ compiled RE '.outlook.com$' not found in local cache
+ compiling RE '.outlook.com$'
+ compiled RE '.outlook.com$' saved in local cache
╭───scanning: $item}{\N^250-([\w.]+)\s\N}}} {$1}}
├───scanning: }{\N^250-([\w.]+)\s\N}}} {$1}}
├──expanding: $item
├considering: }} {match{$item}{\N^250-([\w.]+)\s\N}}} {$1}}
├──expanding: .outlook.com\$
╰─────result: .outlook.com$
+ compiled RE '.outlook.com$' not found in local cache
+ compiling RE '.outlook.com$'
+ compiled RE '.outlook.com$' saved in local cache
╭───scanning: $item}{\N^250-([\w.]+)\s\N}}} {$1}}
├───scanning: }{\N^250-([\w.]+)\s\N}}} {$1}}
├──expanding: $item
├considering: }} {match{$item}{\N^250-([\w.]+)\s\N}}} {$1}}
├──expanding: .outlook.com\$
╰─────result: .outlook.com$
+ compiled RE '.outlook.com$' not found in local cache
+ compiling RE '.outlook.com$'
+ compiled RE '.outlook.com$' saved in local cache
╭───scanning: $item}{\N^250-([\w.]+)\s\N}}} {$1}}
├───scanning: }{\N^250-([\w.]+)\s\N}}} {$1}}
├──expanding: $item
├considering: }} {match{$item}{\N^250-([\w.]+)\s\N}}} {$1}}
├──expanding: .outlook.com\$
╰─────result: .outlook.com$
+ compiled RE '.outlook.com$' not found in local cache
+ compiling RE '.outlook.com$'
+ compiled RE '.outlook.com$' saved in local cache
╭───scanning: $item}{\N^250-([\w.]+)\s\N}}} {$1}}
├───scanning: }{\N^250-([\w.]+)\s\N}}} {$1}}
├──expanding: $item
├considering: }} {match{$item}{\N^250-([\w.]+)\s\N}}} {$1}}
├──expanding: .outlook.com\$
╰─────result: .outlook.com$
+ compiled RE '.outlook.com$' not found in local cache
+ compiling RE '.outlook.com$'
+ compiled RE '.outlook.com$' saved in local cache
╭───scanning: $item}{\N^250-([\w.]+)\s\N}}} {$1}}
├───scanning: }{\N^250-([\w.]+)\s\N}}} {$1}}
├──expanding: $item
├considering: }} {match{$item}{\N^250-([\w.]+)\s\N}}} {$1}}
├──expanding: .outlook.com\$
╰─────result: .outlook.com$
+ compiled RE '.outlook.com$' not found in local cache
+ compiling RE '.outlook.com$'
+ compiled RE '.outlook.com$' saved in local cache
╭───scanning: $item}{\N^250-([\w.]+)\s\N}}} {$1}}
├───scanning: }{\N^250-([\w.]+)\s\N}}} {$1}}
├──expanding: $item