{ "spool_directory", vtype_stringptr, &spool_directory },
{ "spool_inodes", vtype_pinodes, (void *)TRUE },
{ "spool_space", vtype_pspace, (void *)TRUE },
-#ifdef EXPERIMENTAL_SRS_ALT
- { "srs_db_address", vtype_stringptr, &srs_db_address },
- { "srs_db_key", vtype_stringptr, &srs_db_key },
- { "srs_orig_recipient", vtype_stringptr, &srs_orig_recipient },
- { "srs_orig_sender", vtype_stringptr, &srs_orig_sender },
-#endif
-#if defined(EXPERIMENTAL_SRS_ALT) || defined(SUPPORT_SRS)
+#ifdef SUPPORT_SRS
{ "srs_recipient", vtype_stringptr, &srs_recipient },
-#endif
-#ifdef EXPERIMENTAL_SRS_ALT
- { "srs_status", vtype_stringptr, &srs_status },
#endif
{ "thisaddress", vtype_stringptr, &filter_thisaddress },
+/************************************************/
+static void
+debug_expansion_interim(const uschar * what, const uschar * value, int nchar,
+ BOOL skipping)
+{
+DEBUG(D_noutf8)
+ debug_printf_indent("|");
+else
+ debug_printf_indent(UTF8_VERT_RIGHT);
+
+for (int fill = 11 - Ustrlen(what); fill > 0; fill--)
+ DEBUG(D_noutf8)
+ debug_printf("-");
+ else
+ debug_printf(UTF8_HORIZ);
+
+debug_printf("%s: %.*s\n", what, nchar, value);
+if (is_tainted(value))
+ {
+ DEBUG(D_noutf8)
+ debug_printf_indent("%s \\__", skipping ? "| " : " ");
+ else
+ debug_printf_indent("%s",
+ skipping
+ ? UTF8_VERT " " : " " UTF8_UP_RIGHT UTF8_HORIZ UTF8_HORIZ);
+ debug_printf("(tainted)\n");
+ }
+}
+
+
/*************************************************
* Expand string *
*************************************************/
{
const uschar * t = s + 2;
for (s = t; *s ; s++) if (*s == '\\' && s[1] == 'N') break;
+
DEBUG(D_expand)
- DEBUG(D_noutf8)
- debug_printf_indent("|--protected: %.*s\n", (int)(s - t), t);
- else
- debug_printf_indent(UTF8_VERT_RIGHT UTF8_HORIZ UTF8_HORIZ
- "protected: %.*s\n", (int)(s - t), t);
+ debug_expansion_interim(US"protected", t, (int)(s - t), skipping);
yield = string_catn(yield, t, s - t);
- if (*s != 0) s += 2;
+ if (*s) s += 2;
}
-
else
{
uschar ch[1];
s++;
yield = string_catn(yield, ch, 1);
}
-
continue;
}
- /*{*/
+ /*{{*/
/* Anything other than $ is just copied verbatim, unless we are
looking for a terminating } character. */
- /*{*/
if (ket_ends && *s == '}') break;
if (*s != '$' || !honour_dollar)
{
int i = 1; /*{*/
- for(const uschar * t = s+1; *t && *t != '$' && *t != '}' && *t != '\\'; t++)
- i++;
+ for (const uschar * t = s+1;
+ *t && *t != '$' && *t != '}' && *t != '\\'; t++) i++;
- DEBUG(D_expand)
- DEBUG(D_noutf8)
- debug_printf_indent("|-------text: %.*s\n", i, s);
- else
- debug_printf_indent(UTF8_VERT_RIGHT
- UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ
- "text: %.*s\n", i, s);
+ DEBUG(D_expand) debug_expansion_interim(US"text", s, i, skipping);
yield = string_catn(yield, s, i);
s += i;
"$header_". A non-existent header yields a NULL value; nothing is
inserted. */ /*}*/
- if (isalpha((*(++s))))
+ if (isalpha(*++s))
{
const uschar * value;
- int len;
- int newsize = 0;
+ int newsize = 0, len;
gstring * g = NULL;
uschar * t;
But there is no error here - nothing gets inserted. */
if (!value)
- { /*{*/
+ { /*{*/
if (Ustrchr(name, '}')) malformed_header = TRUE;
continue;
}
/* After { there can be various things, but they all start with
an initial word, except for a number for a string match variable. */ /*}*/
- if (isdigit((*(++s))))
+ if (isdigit(*++s))
{
int n;
- s = read_cnumber(&n, s); /*{*/
+ s = read_cnumber(&n, s); /*{{*/
if (*s++ != '}')
- { /*{*/
+ {
expand_string_message = US"} expected after number";
goto EXPAND_FAILED;
}
s = read_name(name, sizeof(name), s, US"_-");
item_type = chop_match(name, item_table, nelem(item_table));
+ /* Switch on item type. All nondefault choices should "continue* when
+ skipping, but "break" otherwise so we get debug output for the item
+ expansion. */
+ {
+ int start = gstring_length(yield);
switch(item_type)
{
/* Call an ACL from an expansion. We feed data in via $acl_arg1 - $acl_arg9.
case EITEM_ACL:
/* ${acl {name} {arg1}{arg2}...} */
{
- uschar *sub[10]; /* name + arg1-arg9 (which must match number of acl_arg[]) */
- uschar *user_msg;
+ uschar * sub[10]; /* name + arg1-arg9 (which must match number of acl_arg[]) */
+ uschar * user_msg;
int rc;
switch(read_subs(sub, nelem(sub), 1, &s, skipping, TRUE, name,
debug_printf_indent("acl expansion yield: %s\n", user_msg);
if (user_msg)
yield = string_cat(yield, user_msg);
- continue;
+ break;
case DEFER:
f.expand_string_forcedfail = TRUE;
rc_names[rc], sub[0]);
goto EXPAND_FAILED;
}
+ break;
}
case EITEM_AUTHRESULTS:
/* ${authresults {mysystemname}} */
{
- uschar *sub_arg[1];
+ uschar * sub_arg[1];
switch(read_subs(sub_arg, nelem(sub_arg), 1, &s, skipping, TRUE, name,
&resetok))
#ifdef EXPERIMENTAL_ARC
yield = authres_arc(yield);
#endif
- continue;
+ break;
}
/* Handle conditionals - preserve the values of the numerical expansion
goto EXPAND_FAILED; /* message already set */
DEBUG(D_expand)
- DEBUG(D_noutf8)
- {
- debug_printf_indent("|--condition: %.*s\n", (int)(next_s - s), s);
- debug_printf_indent("|-----result: %s\n", cond ? "true" : "false");
- }
- else
- {
- debug_printf_indent(UTF8_VERT_RIGHT UTF8_HORIZ UTF8_HORIZ
- "condition: %.*s\n",
- (int)(next_s - s), s);
- debug_printf_indent(UTF8_VERT_RIGHT UTF8_HORIZ UTF8_HORIZ
- UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ
- "result: %s\n",
- cond ? "true" : "false");
- }
+ {
+ debug_expansion_interim(US"condition", s, (int)(next_s - s), skipping);
+ debug_expansion_interim(US"result",
+ cond ? US"true" : US"false", cond ? 4 : 5, skipping);
+ }
s = next_s;
restore_expand_strings(save_expand_nmax, save_expand_nstring,
save_expand_nlength);
- continue;
+ break;
}
#ifdef SUPPORT_I18N
goto EXPAND_FAILED;
}
- if (!skipping)
- {
- if (!(encoded = imap_utf7_encode(sub_arg[0], headers_charset,
- sub_arg[1][0], sub_arg[2], &expand_string_message)))
- goto EXPAND_FAILED;
- yield = string_cat(yield, encoded);
- }
- continue;
+ if (skipping) continue;
+
+ if (!(encoded = imap_utf7_encode(sub_arg[0], headers_charset,
+ sub_arg[1][0], sub_arg[2], &expand_string_message)))
+ goto EXPAND_FAILED;
+ yield = string_cat(yield, encoded);
+ break;
}
#endif
int stype, partial, affixlen, starflags;
int expand_setup = 0;
int nameptr = 0;
- uschar *key, *filename;
+ uschar * key, * filename;
const uschar * affix, * opts;
- uschar *save_lookup_value = lookup_value;
+ uschar * save_lookup_value = lookup_value;
int save_expand_nmax =
save_expand_strings(save_expand_nstring, save_expand_nlength);
goto EXPAND_FAILED;
}
}
- else
- {
- if (key)
- {
- expand_string_message = string_sprintf("a single key was given for "
- "lookup type \"%s\", which is not a single-key lookup type", name);
- goto EXPAND_FAILED;
- }
- }
+ else if (key)
+ {
+ expand_string_message = string_sprintf("a single key was given for "
+ "lookup type \"%s\", which is not a single-key lookup type", name);
+ goto EXPAND_FAILED;
+ }
/* Get the next string in brackets and expand it. It is the file name for
single-key+file lookups, and the whole query otherwise. In the case of
restore_expand_strings(save_expand_nmax, save_expand_nstring,
save_expand_nlength);
- continue;
+
+ if (skipping) continue;
+ break;
}
/* If Perl support is configured, handle calling embedded perl subroutines,
or ${perl{sub}{arg1}{arg2}} or up to a maximum of EXIM_PERL_MAX_ARGS
arguments (defined below). */
- #define EXIM_PERL_MAX_ARGS 8
+#define EXIM_PERL_MAX_ARGS 8
case EITEM_PERL:
- #ifndef EXIM_PERL
- expand_string_message = US"\"${perl\" encountered, but this facility " /*}*/
- "is not included in this binary";
- goto EXPAND_FAILED;
+#ifndef EXIM_PERL
+ expand_string_message = US"\"${perl\" encountered, but this facility " /*}*/
+ "is not included in this binary";
+ goto EXPAND_FAILED;
- #else /* EXIM_PERL */
+#else /* EXIM_PERL */
{
- uschar *sub_arg[EXIM_PERL_MAX_ARGS + 2];
- gstring *new_yield;
+ uschar * sub_arg[EXIM_PERL_MAX_ARGS + 2];
+ gstring * new_yield;
- if ((expand_forbid & RDO_PERL) != 0)
+ if (expand_forbid & RDO_PERL)
{
expand_string_message = US"Perl calls are not permitted";
goto EXPAND_FAILED;
if (!opt_perl_started)
{
- uschar *initerror;
+ uschar * initerror;
if (!opt_perl_startup)
{
expand_string_message = US"A setting of perl_startup is needed when "
f.expand_string_forcedfail = FALSE;
yield = new_yield;
- continue;
+ break;
}
- #endif /* EXIM_PERL */
+#endif /* EXIM_PERL */
/* Transform email address to "prvs" scheme to use
as BATV-signed return path */
case EITEM_PRVS:
{
- uschar *sub_arg[3];
- uschar *p,*domain;
+ uschar * sub_arg[3], * p, * domain;
switch(read_subs(sub_arg, 3, 2, &s, skipping, TRUE, name, &resetok))
{
yield = string_catn(yield, US"@", 1);
yield = string_cat (yield, domain);
- continue;
+ break;
}
/* Check a prvs-encoded address for validity */
case EITEM_PRVSCHECK:
{
- uschar *sub_arg[3];
+ uschar * sub_arg[3], * p;
gstring * g;
- const pcre2_code *re;
- uschar *p;
+ const pcre2_code * re;
/* TF: Ugliness: We want to expand parameter 1 first, then set
up expansion variables that are used in the expansion of
if (regex_match_and_setup(re,sub_arg[0],0,-1))
{
- uschar *local_part = string_copyn(expand_nstring[4],expand_nlength[4]);
- uschar *key_num = string_copyn(expand_nstring[1],expand_nlength[1]);
- uschar *daystamp = string_copyn(expand_nstring[2],expand_nlength[2]);
- uschar *hash = string_copyn(expand_nstring[3],expand_nlength[3]);
- uschar *domain = string_copyn(expand_nstring[5],expand_nlength[5]);
+ uschar * local_part = string_copyn(expand_nstring[4],expand_nlength[4]);
+ uschar * key_num = string_copyn(expand_nstring[1],expand_nlength[1]);
+ uschar * daystamp = string_copyn(expand_nstring[2],expand_nlength[2]);
+ 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);
case 3: goto EXPAND_FAILED;
}
- continue;
+ if (skipping) continue;
+ break;
}
/* Handle "readfile" to insert an entire file */
case EITEM_READFILE:
{
- FILE *f;
- uschar *sub_arg[2];
+ FILE * f;
+ uschar * sub_arg[2];
if ((expand_forbid & RDO_READFILE) != 0)
{
yield = cat_file(f, yield, sub_arg[1]);
(void)fclose(f);
- continue;
+ break;
}
/* Handle "readsocket" to insert data from a socket, either
expand_string_message = US"missing '}' closing readsocket";
goto EXPAND_FAILED_CURLY;
}
- continue;
+ if (skipping) continue;
+ break;
/* Come here on failure to create socket, connect socket, write to the
socket, or timeout on reading. If another substring follows, expand and
case EITEM_RUN:
{
- FILE *f;
- uschar *arg;
- const uschar **argv;
+ FILE * f;
+ uschar * arg;
+ const uschar ** argv;
pid_t pid;
int fd_in, fd_out;
case 2: goto EXPAND_FAILED_CURLY; /* returned value is 0 */
}
- continue;
+ if (skipping) continue;
+ break;
}
/* Handle character translation for "tr" */
{
int oldptr = gstring_length(yield);
int o2m;
- uschar *sub[3];
+ uschar * sub[3];
switch(read_subs(sub, 3, 3, &s, skipping, TRUE, name, &resetok))
{
}
}
- continue;
+ if (skipping) continue;
+ break;
}
/* Handle "hash", "length", "nhash", and "substr" when they are given with
int len;
uschar *ret;
int val[2] = { 0, -1 };
- uschar *sub[3];
+ uschar * sub[3];
/* "length" takes only 2 arguments whereas the others take 2 or 3.
Ensure that sub[2] is set in the ${length } case. */
if (!ret)
goto EXPAND_FAILED;
yield = string_catn(yield, ret, len);
- continue;
+ if (skipping) continue;
+ break;
}
/* Handle HMAC computation: ${hmac{<algorithm>}{<secret>}{<text>}}
case EITEM_HMAC:
{
- uschar *sub[3];
+ uschar * sub[3];
md5 md5_base;
hctx sha1_ctx;
- void *use_base;
+ void * use_base;
int type;
int hashlen; /* Number of octets for the hash algorithm's output */
int hashblocklen; /* Number of octets the hash algorithm processes */
- uschar *keyptr, *p;
+ uschar * keyptr, * p;
unsigned int keylen;
uschar keyhash[MAX_HASHLEN];
case 3: goto EXPAND_FAILED;
}
- if (!skipping)
+ if (skipping) continue;
+
+ if (Ustrcmp(sub[0], "md5") == 0)
{
- if (Ustrcmp(sub[0], "md5") == 0)
- {
- type = HMAC_MD5;
- use_base = &md5_base;
- hashlen = 16;
- hashblocklen = 64;
- }
- else if (Ustrcmp(sub[0], "sha1") == 0)
- {
- type = HMAC_SHA1;
- use_base = &sha1_ctx;
- hashlen = 20;
- hashblocklen = 64;
- }
- else
- {
- expand_string_message =
- string_sprintf("hmac algorithm \"%s\" is not recognised", sub[0]);
- goto EXPAND_FAILED;
- }
+ type = HMAC_MD5;
+ use_base = &md5_base;
+ hashlen = 16;
+ hashblocklen = 64;
+ }
+ else if (Ustrcmp(sub[0], "sha1") == 0)
+ {
+ type = HMAC_SHA1;
+ use_base = &sha1_ctx;
+ hashlen = 20;
+ hashblocklen = 64;
+ }
+ else
+ {
+ expand_string_message =
+ string_sprintf("hmac algorithm \"%s\" is not recognised", sub[0]);
+ goto EXPAND_FAILED;
+ }
- keyptr = sub[1];
- keylen = Ustrlen(keyptr);
+ keyptr = sub[1];
+ keylen = Ustrlen(keyptr);
- /* If the key is longer than the hash block length, then hash the key
- first */
+ /* If the key is longer than the hash block length, then hash the key
+ first */
- if (keylen > hashblocklen)
- {
- chash_start(type, use_base);
- chash_end(type, use_base, keyptr, keylen, keyhash);
- keyptr = keyhash;
- keylen = hashlen;
- }
+ if (keylen > hashblocklen)
+ {
+ chash_start(type, use_base);
+ chash_end(type, use_base, keyptr, keylen, keyhash);
+ keyptr = keyhash;
+ keylen = hashlen;
+ }
- /* Now make the inner and outer key values */
+ /* Now make the inner and outer key values */
- memset(innerkey, 0x36, hashblocklen);
- memset(outerkey, 0x5c, hashblocklen);
+ memset(innerkey, 0x36, hashblocklen);
+ memset(outerkey, 0x5c, hashblocklen);
- for (int i = 0; i < keylen; i++)
- {
- innerkey[i] ^= keyptr[i];
- outerkey[i] ^= keyptr[i];
- }
+ for (int i = 0; i < keylen; i++)
+ {
+ innerkey[i] ^= keyptr[i];
+ outerkey[i] ^= keyptr[i];
+ }
- /* Now do the hashes */
+ /* Now do the hashes */
- chash_start(type, use_base);
- chash_mid(type, use_base, innerkey);
- chash_end(type, use_base, sub[2], Ustrlen(sub[2]), innerhash);
+ chash_start(type, use_base);
+ chash_mid(type, use_base, innerkey);
+ chash_end(type, use_base, sub[2], Ustrlen(sub[2]), innerhash);
- chash_start(type, use_base);
- chash_mid(type, use_base, outerkey);
- chash_end(type, use_base, innerhash, hashlen, finalhash);
+ chash_start(type, use_base);
+ chash_mid(type, use_base, outerkey);
+ chash_end(type, use_base, innerhash, hashlen, finalhash);
- /* Encode the final hash as a hex string */
+ /* Encode the final hash as a hex string */
- p = finalhash_hex;
- for (int i = 0; i < hashlen; i++)
- {
- *p++ = hex_digits[(finalhash[i] & 0xf0) >> 4];
- *p++ = hex_digits[finalhash[i] & 0x0f];
- }
+ p = finalhash_hex;
+ for (int i = 0; i < hashlen; i++)
+ {
+ *p++ = hex_digits[(finalhash[i] & 0xf0) >> 4];
+ *p++ = hex_digits[finalhash[i] & 0x0f];
+ }
- DEBUG(D_any) debug_printf("HMAC[%s](%.*s,%s)=%.*s\n",
- sub[0], (int)keylen, keyptr, sub[2], hashlen*2, finalhash_hex);
+ DEBUG(D_any) debug_printf("HMAC[%s](%.*s,%s)=%.*s\n",
+ sub[0], (int)keylen, keyptr, sub[2], hashlen*2, finalhash_hex);
- yield = string_catn(yield, finalhash_hex, hashlen*2);
- }
- continue;
+ yield = string_catn(yield, finalhash_hex, hashlen*2);
+ break;
}
/* Handle global substitution for "sg" - like Perl's s/xxx/yyy/g operator.
PCRE2_SIZE roffset;
pcre2_match_data * md;
int err, emptyopt;
- uschar *subject;
- uschar *sub[3];
+ uschar * subject, * sub[3];
int save_expand_nmax =
save_expand_strings(save_expand_nstring, save_expand_nlength);
case 3: goto EXPAND_FAILED;
}
+ /*XXX no handling of skipping? */
/* Compile the regular expression */
if (!(re = pcre2_compile((PCRE2_SPTR)sub[1], PCRE2_ZERO_TERMINATED,
PCRE2_SIZE * ovec = pcre2_get_ovector_pointer(md);
int n = pcre2_match(re, (PCRE2_SPTR)subject, slen, moffset + moffsetextra,
PCRE_EOPT | emptyopt, md, pcre_mtc_ctx);
- uschar *insert;
+ uschar * insert;
/* No match - if we previously set PCRE_NOTEMPTY after a null match, this
is not necessarily the end. We want to repeat the match from one
/* Copy the characters before the match, plus the expanded insertion. */
- yield = string_catn(yield, subject + moffset, ovec[0] - moffset);
+ yield = string_catn(yield, subject + moffset, ovec[0] - moffset);
+
if (!(insert = expand_string(sub[2])))
goto EXPAND_FAILED;
yield = string_cat(yield, insert);
restore_expand_strings(save_expand_nmax, save_expand_nstring,
save_expand_nlength);
- continue;
+ if (skipping) continue;
+ break;
}
/* Handle keyed and numbered substring extraction. If the first argument
{
int field_number = 1;
BOOL field_number_set = FALSE;
- uschar *save_lookup_value = lookup_value;
- uschar *sub[3];
+ uschar * save_lookup_value = lookup_value, * sub[3];
int save_expand_nmax =
save_expand_strings(save_expand_nstring, save_expand_nlength);
if (skipping)
{
- for (int j = 5; j > 0 && *s == '{'; j--) /*'}'*/
+ for (int j = 5; j > 0 && *s == '{'; j--) /*'}'*/
{
if (!expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok))
goto EXPAND_FAILED; /*'{'*/
}
Uskip_whitespace(&s);
}
- if ( Ustrncmp(s, "fail", 4) == 0 /*'{'*/
+ if ( Ustrncmp(s, "fail", 4) == 0 /*'{'*/
&& (s[4] == '}' || s[4] == ' ' || s[4] == '\t' || !s[4])
)
{
s += 4;
Uskip_whitespace(&s);
- } /*'{'*/
+ } /*'{'*/
if (*s != '}')
{
expand_string_message = US"missing '}' closing extract";
else for (int i = 0, j = 2; i < j; i++) /* Read the proper number of arguments */
{
- if (Uskip_whitespace(&s) == '{') /*'}'*/
+ if (Uskip_whitespace(&s) == '{') /*'}'*/
{
if (!(sub[i] = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok)))
- goto EXPAND_FAILED; /*'{'*/
+ goto EXPAND_FAILED; /*'{'*/
if (*s++ != '}')
{
expand_string_message = string_sprintf(
{
int len;
int x = 0;
- uschar *p = sub[0];
+ uschar * p = sub[0];
Uskip_whitespace(&p);
sub[0] = p;
while (len > 0 && isspace(p[len-1])) len--;
p[len] = 0;
- if (*p == 0)
+ if (!*p)
{
expand_string_message = US"first argument of \"extract\" must "
"not be empty";
field_number = -1;
p++;
}
- while (*p != 0 && isdigit(*p)) x = x * 10 + *p++ - '0';
- if (*p == 0)
+ while (*p && isdigit(*p)) x = x * 10 + *p++ - '0';
+ if (!*p)
{
field_number *= x;
if (fmt == extract_basic) j = 3; /* Need 3 args */
restore_expand_strings(save_expand_nmax, save_expand_nstring,
save_expand_nlength);
- continue;
+ if (skipping) continue;
+ break;
}
/* return the Nth item from a list */
case EITEM_LISTEXTRACT:
{
int field_number = 1;
- uschar *save_lookup_value = lookup_value;
- uschar *sub[2];
+ uschar * save_lookup_value = lookup_value, * sub[2];
int save_expand_nmax =
save_expand_strings(save_expand_nstring, save_expand_nlength);
for (int i = 0; i < 2; i++)
{
- if (Uskip_whitespace(&s) != '{') /*'}'*/
+ if (Uskip_whitespace(&s) != '{') /*}*/
{
expand_string_message = string_sprintf(
- "missing '{' for arg %d of listextract", i+1);
+ "missing '{' for arg %d of listextract", i+1); /*}*/
goto EXPAND_FAILED_CURLY;
}
sub[i] = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok);
- if (!sub[i]) goto EXPAND_FAILED; /*{*/
+ if (!sub[i]) goto EXPAND_FAILED; /*{{*/
if (*s++ != '}')
{
expand_string_message = string_sprintf(
restore_expand_strings(save_expand_nmax, save_expand_nstring,
save_expand_nlength);
- continue;
+ if (skipping) continue;
+ break;
}
case EITEM_LISTQUOTE:
yield = string_catn(yield, sub[1], 1);
}
else yield = string_catn(yield, US" ", 1);
- continue;
+ if (skipping) continue;
+ break;
}
#ifndef DISABLE_TLS
case EITEM_CERTEXTRACT:
{
- uschar *save_lookup_value = lookup_value;
- uschar *sub[2];
+ uschar * save_lookup_value = lookup_value, * sub[2];
int save_expand_nmax =
save_expand_strings(save_expand_nstring, save_expand_nlength);
if (Uskip_whitespace(&s) != '{') /*}*/
{
expand_string_message = US"missing '{' for field arg of certextract";
- goto EXPAND_FAILED_CURLY;
+ goto EXPAND_FAILED_CURLY; /*}*/
}
sub[0] = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok);
- if (!sub[0]) goto EXPAND_FAILED; /*{*/
+ if (!sub[0]) goto EXPAND_FAILED; /*{{*/
if (*s++ != '}')
{
expand_string_message = US"missing '}' closing field arg of certextract";
if (Uskip_whitespace(&s) != '{') /*}*/
{
expand_string_message = US"missing '{' for cert variable arg of certextract";
- goto EXPAND_FAILED_CURLY;
+ goto EXPAND_FAILED_CURLY; /*}*/
}
if (*++s != '$')
{
goto EXPAND_FAILED;
}
sub[1] = expand_string_internal(s+1, TRUE, &s, skipping, FALSE, &resetok);
- if (!sub[1]) goto EXPAND_FAILED; /*{*/
+ if (!sub[1]) goto EXPAND_FAILED; /*{{*/
if (*s++ != '}')
{
expand_string_message = US"missing '}' closing cert variable arg of certextract";
restore_expand_strings(save_expand_nmax, save_expand_nstring,
save_expand_nlength);
- continue;
+ if (skipping) continue;
+ break;
}
#endif /*DISABLE_TLS*/
case EITEM_MAP:
case EITEM_REDUCE:
{
- int sep = 0;
- int save_ptr = gstring_length(yield);
+ int sep = 0, save_ptr = gstring_length(yield);
uschar outsep[2] = { '\0', '\0' };
const uschar *list, *expr, *temp;
- uschar *save_iterate_item = iterate_item;
- uschar *save_lookup_value = lookup_value;
+ uschar * save_iterate_item = iterate_item;
+ uschar * save_lookup_value = lookup_value;
Uskip_whitespace(&s);
- if (*s++ != '{') /*}*/
+ if (*s++ != '{') /*}*/
{
expand_string_message =
string_sprintf("missing '{' for first arg of %s", name);
- goto EXPAND_FAILED_CURLY;
+ goto EXPAND_FAILED_CURLY; /*}*/
}
if (!(list = expand_string_internal(s, TRUE, &s, skipping, TRUE, &resetok)))
- goto EXPAND_FAILED;
- /*{*/
+ goto EXPAND_FAILED; /*{{*/
if (*s++ != '}')
{
- /*{*/
expand_string_message =
string_sprintf("missing '}' closing first arg of %s", name);
goto EXPAND_FAILED_CURLY;
{
uschar * t;
Uskip_whitespace(&s);
- if (*s++ != '{')
+ if (*s++ != '{') /*}*/
{
expand_string_message = US"missing '{' for second arg of reduce";
- goto EXPAND_FAILED_CURLY;
+ goto EXPAND_FAILED_CURLY; /*}*/
}
t = expand_string_internal(s, TRUE, &s, skipping, TRUE, &resetok);
if (!t) goto EXPAND_FAILED;
- lookup_value = t;
+ lookup_value = t; /*{{*/
if (*s++ != '}')
{
expand_string_message = US"missing '}' closing second arg of reduce";
}
Uskip_whitespace(&s);
- if (*s++ != '{') /*}*/
+ if (*s++ != '{') /*}*/
{
expand_string_message =
string_sprintf("missing '{' for last arg of %s", name); /*}*/
goto EXPAND_FAILED;
}
- Uskip_whitespace(&s); /*{*/
+ Uskip_whitespace(&s); /*{{{*/
if (*s++ != '}')
- { /*{*/
+ {
expand_string_message = string_sprintf("missing } at end of condition "
"or expression inside \"%s\"; could be an unquoted } in the content",
name);
goto EXPAND_FAILED;
}
- Uskip_whitespace(&s); /*{*/
+ Uskip_whitespace(&s); /*{{*/
if (*s++ != '}')
- { /*{*/
+ {
expand_string_message = string_sprintf("missing } at end of \"%s\"",
name);
goto EXPAND_FAILED;
too many; backup and end the loop. Otherwise arrange to double the
separator. */
- if (temp[seglen] == '\0') { yield->ptr--; break; }
+ if (!temp[seglen]) { yield->ptr--; break; }
yield = string_catn(yield, outsep, 1);
temp += seglen + 1;
}
/* Restore preserved $item */
iterate_item = save_iterate_item;
- continue;
+ if (skipping) continue;
+ break;
}
case EITEM_SORT:
{
- int cond_type;
- int sep = 0;
- const uschar *srclist, *cmp, *xtract;
+ int sep = 0, cond_type;
+ const uschar * srclist, * cmp, * xtract;
uschar * opname, * srcitem;
- const uschar *dstlist = NULL, *dstkeylist = NULL;
- uschar * tmp;
- uschar *save_iterate_item = iterate_item;
+ const uschar * dstlist = NULL, * dstkeylist = NULL;
+ uschar * tmp, * save_iterate_item = iterate_item;
Uskip_whitespace(&s);
- if (*s++ != '{')
+ if (*s++ != '{') /*}*/
{
expand_string_message = US"missing '{' for list arg of sort";
- goto EXPAND_FAILED_CURLY;
+ goto EXPAND_FAILED_CURLY; /*}*/
}
srclist = expand_string_internal(s, TRUE, &s, skipping, TRUE, &resetok);
- if (!srclist) goto EXPAND_FAILED;
+ if (!srclist) goto EXPAND_FAILED; /*{{*/
if (*s++ != '}')
{
expand_string_message = US"missing '}' closing list arg of sort";
}
Uskip_whitespace(&s);
- if (*s++ != '{')
+ if (*s++ != '{') /*}*/
{
expand_string_message = US"missing '{' for comparator arg of sort";
- goto EXPAND_FAILED_CURLY;
+ goto EXPAND_FAILED_CURLY; /*}*/
}
cmp = expand_string_internal(s, TRUE, &s, skipping, FALSE, &resetok);
- if (!cmp) goto EXPAND_FAILED;
+ if (!cmp) goto EXPAND_FAILED; /*{{*/
if (*s++ != '}')
{
expand_string_message = US"missing '}' closing comparator arg of sort";
}
Uskip_whitespace(&s);
- if (*s++ != '{')
+ if (*s++ != '{') /*}*/
{
expand_string_message = US"missing '{' for extractor arg of sort";
- goto EXPAND_FAILED_CURLY;
+ goto EXPAND_FAILED_CURLY; /*}*/
}
xtract = s;
if (!(tmp = expand_string_internal(s, TRUE, &s, TRUE, TRUE, &resetok)))
goto EXPAND_FAILED;
xtract = string_copyn(xtract, s - xtract);
-
+ /*{{*/
if (*s++ != '}')
{
expand_string_message = US"missing '}' closing extractor arg of sort";
goto EXPAND_FAILED_CURLY;
}
- /*{*/
+ /*{{*/
if (*s++ != '}')
- { /*{*/
+ {
expand_string_message = US"missing } at end of \"sort\"";
goto EXPAND_FAILED;
}
while ((srcitem = string_nextinlist(&srclist, &sep, NULL, 0)))
{
uschar * srcfield, * dstitem;
- gstring * newlist = NULL;
- gstring * newkeylist = NULL;
+ gstring * newlist = NULL, * newkeylist = NULL;
DEBUG(D_expand) debug_printf_indent("%s: $item = \"%s\"\n", name, srcitem);
/* field for comparison */
if (!(dstfield = string_nextinlist(&dstkeylist, &sep, NULL, 0)))
- goto sort_mismatch;
+ goto SORT_MISMATCH;
/* String-comparator names start with a letter; numeric names do not */
while ((dstitem = string_nextinlist(&dstlist, &sep, NULL, 0)))
{
if (!(dstfield = string_nextinlist(&dstkeylist, &sep, NULL, 0)))
- goto sort_mismatch;
+ goto SORT_MISMATCH;
newlist = string_append_listele(newlist, sep, dstitem);
newkeylist = string_append_listele(newkeylist, sep, dstfield);
}
/* Restore preserved $item */
iterate_item = save_iterate_item;
- continue;
+ break;
- sort_mismatch:
+ SORT_MISMATCH:
expand_string_message = US"Internal error in sort (list mismatch)";
goto EXPAND_FAILED;
}
#else /* EXPAND_DLFUNC */
{
- tree_node *t;
- exim_dlfunc_t *func;
- uschar *result;
+ tree_node * t;
+ exim_dlfunc_t * func;
+ uschar * result;
int status, argc;
- uschar *argv[EXPAND_DLFUNC_MAX_ARGS + 3];
+ uschar * argv[EXPAND_DLFUNC_MAX_ARGS + 3];
- if ((expand_forbid & RDO_DLFUNC) != 0)
+ if (expand_forbid & RDO_DLFUNC)
{
expand_string_message =
US"dynamically-loaded functions are not permitted";
if (!(t = tree_search(dlobj_anchor, argv[0])))
{
- void *handle = dlopen(CS argv[0], RTLD_LAZY);
+ void * handle = dlopen(CS argv[0], RTLD_LAZY);
if (!handle)
{
expand_string_message = string_sprintf("dlopen \"%s\" failed: %s",
resetok = FALSE;
result = NULL;
- for (argc = 0; argv[argc]; argc++);
- status = func(&result, argc - 2, &argv[2]);
- if(status == OK)
- {
- if (!result) result = US"";
- yield = string_cat(yield, result);
- continue;
- }
- else
+ for (argc = 0; argv[argc]; argc++) ;
+
+ if ((status = func(&result, argc - 2, &argv[2])) != OK)
{
expand_string_message = result ? result : US"(no message)";
if (status == FAIL_FORCED)
argv[0], argv[1], status, expand_string_message);
goto EXPAND_FAILED;
}
+
+ if (result) yield = string_cat(yield, result);
+ break;
}
#endif /* EXPAND_DLFUNC */
goto EXPAND_FAILED;
key = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok);
- if (!key) goto EXPAND_FAILED; /*{*/
+ if (!key) goto EXPAND_FAILED; /*{{*/
if (*s++ != '}')
{
- expand_string_message = US"missing '{' for name arg of env"; /*}*/
+ expand_string_message = US"missing '}' for name arg of env";
goto EXPAND_FAILED_CURLY;
}
case 1: goto EXPAND_FAILED; /* when all is well, the */
case 2: goto EXPAND_FAILED_CURLY; /* returned value is 0 */
}
- continue;
+ if (skipping) continue;
+ break;
}
#ifdef SUPPORT_SRS
/* @$original_domain */
yield = string_catn(yield, US"@", 1);
yield = string_cat(yield, sub[2]);
- continue;
+
+ if (skipping) continue;
+ break;
}
#endif /*SUPPORT_SRS*/
+
+ default:
+ goto NOT_ITEM;
} /* EITEM_* switch */
+ /*NOTREACHED*/
+
+ DEBUG(D_expand)
+ if (yield && (start > 0 || *s)) /* only if not the sole expansion of the line */
+ debug_expansion_interim(US"item-res",
+ yield->s + start, yield->ptr - start, skipping);
+ continue;
+
+NOT_ITEM: ;
+ }
/* Control reaches here if the name is not recognized as one of the more
complicated expansion items. Check for the "operator" syntax (name terminated
if (*s == ':')
{
int c;
- uschar *arg = NULL;
- uschar *sub;
+ uschar * arg = NULL, * sub;
#ifndef DISABLE_TLS
- var_entry *vp = NULL;
+ var_entry * vp = NULL;
#endif
/* Owing to an historical mis-design, an underscore may be part of the
} /* EOP_* switch */
DEBUG(D_expand)
- {
- const uschar * s = yield->s + start;
- int i = yield->ptr - start;
- BOOL tainted = is_tainted(s);
-
- DEBUG(D_noutf8)
- {
- debug_printf_indent("|-----op-res: %.*s\n", i, s);
- if (tainted)
- {
- debug_printf_indent("%s \\__", skipping ? "| " : " ");
- debug_printf("(tainted)\n");
- }
- }
- else
- {
- debug_printf_indent(UTF8_VERT_RIGHT
- UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ
- "op-res: %.*s\n", i, s);
- if (tainted)
- {
- debug_printf_indent("%s",
- skipping
- ? UTF8_VERT " " : " " UTF8_UP_RIGHT UTF8_HORIZ UTF8_HORIZ);
- debug_printf("(tainted)\n");
- }
- }
- }
+ if (start > 0 || *s) /* only if not the sole expansion of the line */
+ debug_expansion_interim(US"op-res",
+ yield->s + start, yield->ptr - start, skipping);
continue;
}
}