-/* $Cambridge: exim/src/src/expand.c,v 1.39 2005/08/01 15:01:12 ph10 Exp $ */
+/* $Cambridge: exim/src/src/expand.c,v 1.53 2006/02/07 11:19:00 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2005 */
+/* Copyright (c) University of Cambridge 1995 - 2006 */
/* See the file NOTICE for conditions of use and distribution. */
/* This table must be kept in alphabetical order. */
static var_entry var_table[] = {
- { "acl_c0", vtype_stringptr, &acl_var[0] },
- { "acl_c1", vtype_stringptr, &acl_var[1] },
- { "acl_c2", vtype_stringptr, &acl_var[2] },
- { "acl_c3", vtype_stringptr, &acl_var[3] },
- { "acl_c4", vtype_stringptr, &acl_var[4] },
- { "acl_c5", vtype_stringptr, &acl_var[5] },
- { "acl_c6", vtype_stringptr, &acl_var[6] },
- { "acl_c7", vtype_stringptr, &acl_var[7] },
- { "acl_c8", vtype_stringptr, &acl_var[8] },
- { "acl_c9", vtype_stringptr, &acl_var[9] },
- { "acl_m0", vtype_stringptr, &acl_var[10] },
- { "acl_m1", vtype_stringptr, &acl_var[11] },
- { "acl_m2", vtype_stringptr, &acl_var[12] },
- { "acl_m3", vtype_stringptr, &acl_var[13] },
- { "acl_m4", vtype_stringptr, &acl_var[14] },
- { "acl_m5", vtype_stringptr, &acl_var[15] },
- { "acl_m6", vtype_stringptr, &acl_var[16] },
- { "acl_m7", vtype_stringptr, &acl_var[17] },
- { "acl_m8", vtype_stringptr, &acl_var[18] },
- { "acl_m9", vtype_stringptr, &acl_var[19] },
{ "acl_verify_message", vtype_stringptr, &acl_verify_message },
{ "address_data", vtype_stringptr, &deliver_address_data },
{ "address_file", vtype_stringptr, &address_file },
{ "sender_rcvhost", vtype_stringptr, &sender_rcvhost },
{ "sender_verify_failure",vtype_stringptr, &sender_verify_failure },
{ "smtp_active_hostname", vtype_stringptr, &smtp_active_hostname },
- { "smtp_command_argument", vtype_stringptr, &smtp_command_argument },
+ { "smtp_command", vtype_stringptr, &smtp_cmd_buffer },
+ { "smtp_command_argument", vtype_stringptr, &smtp_cmd_argument },
{ "sn0", vtype_filter_int, &filter_sn[0] },
{ "sn1", vtype_filter_int, &filter_sn[1] },
{ "sn2", vtype_filter_int, &filter_sn[2] },
uschar *decoded, *error;
while (ptr > yield && isspace(ptr[-1])) ptr--;
*ptr = 0;
- decoded = rfc2047_decode2(yield, TRUE, charset, '?', NULL, newsize, &error);
+ decoded = rfc2047_decode2(yield, check_rfc2047_length, charset, '?', NULL,
+ newsize, &error);
if (error != NULL)
{
DEBUG(D_any) debug_printf("*** error in RFC 2047 decoding: %s\n"
int first = 0;
int last = var_table_size;
+/* Handle ACL variables, which are not in the table because their number may
+vary depending on a build-time setting. If the variable's name is not of the
+form acl_mddd or acl_cddd, where the d's are digits, fall through to look for
+other names that start with acl_. */
+
+if (Ustrncmp(name, "acl_", 4) == 0)
+ {
+ uschar *endptr;
+ int offset = -1;
+ int max = 0;
+
+ if (name[4] == 'm')
+ {
+ offset = ACL_CVARS;
+ max = ACL_MVARS;
+ }
+ else if (name[4] == 'c')
+ {
+ offset = 0;
+ max = ACL_CVARS;
+ }
+
+ if (offset >= 0)
+ {
+ int n = Ustrtoul(name + 5, &endptr, 10);
+ if (*endptr == 0 && n < max)
+ return (acl_var[offset + n] == NULL)? US"" : acl_var[offset + n];
+ }
+ }
+
+/* For all other variables, search the table */
+
while (last > first)
{
uschar *s, *domain;
if (c < 0) { last = middle; continue; }
/* Found an existing variable. If in skipping state, the value isn't needed,
- and we want to avoid processing (such as looking up up the host name). */
+ and we want to avoid processing (such as looking up the host name). */
if (skipping) return US"";
return tod_stamp(tod_log_datestamp);
case vtype_reply: /* Get reply address */
- s = find_header(US"reply-to:", exists_only, newsize, FALSE,
+ s = find_header(US"reply-to:", exists_only, newsize, TRUE,
headers_charset);
+ if (s != NULL) while (isspace(*s)) s++;
if (s == NULL || *s == 0)
- s = find_header(US"from:", exists_only, newsize, FALSE, headers_charset);
+ {
+ *newsize = 0; /* For the *s==0 case */
+ s = find_header(US"from:", exists_only, newsize, TRUE, headers_charset);
+ }
+ if (s != NULL)
+ {
+ uschar *t;
+ while (isspace(*s)) s++;
+ for (t = s; *t != 0; t++) if (*t == '\n') *t = ' ';
+ while (t > s && isspace(t[-1])) t--;
+ *t = 0;
+ }
return (s == NULL)? US"" : s;
/* A recipients list is available only during system message filtering,
case ECOND_ISIP4:
case ECOND_ISIP6:
rc = string_is_ip_address(sub[0], NULL);
- *yield = ((cond_type == ECOND_ISIP)? (rc > 0) :
+ *yield = ((cond_type == ECOND_ISIP)? (rc != 0) :
(cond_type == ECOND_ISIP4)? (rc == 4) : (rc == 6)) == testfor;
break;
goto MATCHED_SOMETHING;
case ECOND_MATCH_IP: /* Match IP address in a host list */
- if (sub[0][0] != 0 && string_is_ip_address(sub[0], NULL) <= 0)
+ if (sub[0][0] != 0 && string_is_ip_address(sub[0], NULL) == 0)
{
expand_string_message = string_sprintf("\"%s\" is not an IP address",
sub[0]);
int x = eval_term(&s, decimal, error);
if (*error == NULL)
{
- while (*s == '*' || *s == '/')
+ while (*s == '*' || *s == '/' || *s == '%')
{
int op = *s++;
int y = eval_term(&s, decimal, error);
if (*error != NULL) break;
- if (op == '*') x *= y; else x /= y;
+ if (op == '*') x *= y;
+ else if (op == '/') x /= y;
+ else x %= y;
}
}
*sptr = s;
domain = Ustrrchr(sub_arg[0],'@');
if ( (domain == NULL) || (domain == sub_arg[0]) || (Ustrlen(domain) == 1) )
{
- expand_string_message = US"first parameter must be a qualified email address";
+ expand_string_message = US"prvs first argument must be a qualified email address";
+ goto EXPAND_FAILED;
+ }
+
+ /* Calculate the hash. The second argument must be a single-digit
+ key number, or unset. */
+
+ if (sub_arg[2] != NULL &&
+ (!isdigit(sub_arg[2][0]) || sub_arg[2][1] != 0))
+ {
+ expand_string_message = US"prvs second argument must be a single digit";
goto EXPAND_FAILED;
}
- /* Calculate the hash */
p = prvs_hmac_sha1(sub_arg[0],sub_arg[1],sub_arg[2],prvs_daystamp(7));
if (p == NULL)
{
- expand_string_message = US"hmac-sha1 conversion failed";
+ expand_string_message = US"prvs hmac-sha1 conversion failed";
goto EXPAND_FAILED;
}
int mysize = 0, myptr = 0;
const pcre *re;
uschar *p;
- /* Ugliness: We want to expand parameter 1 first, then set
+
+ /* TF: Ugliness: We want to expand parameter 1 first, then set
up expansion variables that are used in the expansion of
parameter 2. So we clone the string for the first
- expansion, where we only expand paramter 1. */
- uschar *s_backup = string_copy(s);
+ expansion, where we only expand parameter 1.
+
+ PH: Actually, that isn't necessary. The read_subs() function is
+ designed to work this way for the ${if and ${lookup expansions. I've
+ tidied the code.
+ */
/* Reset expansion variables */
prvscheck_result = NULL;
prvscheck_address = NULL;
prvscheck_keynum = NULL;
- switch(read_subs(sub_arg, 1, 1, &s_backup, skipping, FALSE, US"prvs"))
+ switch(read_subs(sub_arg, 1, 1, &s, skipping, FALSE, US"prvs"))
{
case 1: goto EXPAND_FAILED_CURLY;
case 2:
re = regex_must_compile(US"^prvs\\=(.+)\\/([0-9])([0-9]{3})([A-F0-9]{6})\\@(.+)$",
TRUE,FALSE);
- if (regex_match_and_setup(re,sub_arg[0],0,-1)) {
+ if (regex_match_and_setup(re,sub_arg[0],0,-1))
+ {
uschar *local_part = string_copyn(expand_nstring[1],expand_nlength[1]);
uschar *key_num = string_copyn(expand_nstring[2],expand_nlength[2]);
uschar *daystamp = string_copyn(expand_nstring[3],expand_nlength[3]);
prvscheck_address[myptr] = '\0';
prvscheck_keynum = string_copy(key_num);
- /* Now re-expand all arguments in the usual manner */
- switch(read_subs(sub_arg, 3, 3, &s, skipping, TRUE, US"prvs"))
+ /* Now expand the second argument */
+ switch(read_subs(sub_arg, 1, 1, &s, skipping, FALSE, US"prvs"))
{
case 1: goto EXPAND_FAILED_CURLY;
case 2:
case 3: goto EXPAND_FAILED;
}
- if (*sub_arg[2] == '\0')
- yield = string_cat(yield,&size,&ptr,prvscheck_address,Ustrlen(prvscheck_address));
- else
- yield = string_cat(yield,&size,&ptr,sub_arg[2],Ustrlen(sub_arg[2]));
-
/* Now we have the key and can check the address. */
- p = prvs_hmac_sha1(prvscheck_address, sub_arg[1], prvscheck_keynum, daystamp);
+
+ p = prvs_hmac_sha1(prvscheck_address, sub_arg[0], prvscheck_keynum,
+ daystamp);
+
if (p == NULL)
{
expand_string_message = US"hmac-sha1 conversion failed";
DEBUG(D_expand) debug_printf("prvscheck: received hash is %s\n", hash);
DEBUG(D_expand) debug_printf("prvscheck: own hash is %s\n", p);
+
if (Ustrcmp(p,hash) == 0)
{
/* Success, valid BATV address. Now check the expiry date. */
prvscheck_result = NULL;
DEBUG(D_expand) debug_printf("prvscheck: hash failure, $pvrs_result unset\n");
}
- }
+
+ /* 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, US"prvs"))
+ {
+ case 1: goto EXPAND_FAILED_CURLY;
+ case 2:
+ case 3: goto EXPAND_FAILED;
+ }
+
+ if (sub_arg[0] == NULL || *sub_arg[0] == '\0')
+ yield = string_cat(yield,&size,&ptr,prvscheck_address,Ustrlen(prvscheck_address));
+ else
+ yield = string_cat(yield,&size,&ptr,sub_arg[0],Ustrlen(sub_arg[0]));
+
+ /* Reset the "internal" variables afterwards, because they are in
+ dynamic store that will be reclaimed if the expansion succeeded. */
+
+ prvscheck_address = NULL;
+ prvscheck_keynum = NULL;
+ }
else
{
/* Does not look like a prvs encoded address, return the empty string.
- We need to make sure all subs are expanded first. */
- switch(read_subs(sub_arg, 3, 3, &s, skipping, TRUE, US"prvs"))
+ 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, US"prvs"))
{
case 1: goto EXPAND_FAILED_CURLY;
case 2:
continue;
}
+ /* Note that for Darwin and Cygwin, BASE_62 actually has the value 36 */
+
case EOP_BASE62D:
{
uschar buf[16];
if (t == NULL)
{
expand_string_message = string_sprintf("argument for base62d "
- "operator is \"%s\", which is not a base 62 number", sub);
+ "operator is \"%s\", which is not a base %d number", sub,
+ BASE_62);
goto EXPAND_FAILED;
}
- n = n * 62 + (t - base62_chars);
+ n = n * BASE_62 + (t - base62_chars);
}
(void)sprintf(CS buf, "%ld", n);
yield = string_cat(yield, &size, &ptr, buf, Ustrlen(buf));