/* Recursively called function */
-static uschar *expand_string_internal(uschar *, BOOL, uschar **, BOOL, BOOL, BOOL *);
-static int_eximarith_t expanded_string_integer(uschar *, BOOL);
+static uschar *expand_string_internal(const uschar *, BOOL, const uschar **, BOOL, BOOL, BOOL *);
+static int_eximarith_t expanded_string_integer(const uschar *, BOOL);
#ifdef STAND_ALONE
#ifndef SUPPORT_CRYPTEQ
{ "caller_uid", vtype_uid, &real_uid },
{ "compile_date", vtype_stringptr, &version_date },
{ "compile_number", vtype_stringptr, &version_cnumber },
+ { "config_dir", vtype_stringptr, &config_main_directory },
+ { "config_file", vtype_stringptr, &config_main_filename },
{ "csa_status", vtype_stringptr, &csa_status },
#ifdef EXPERIMENTAL_DCC
{ "dcc_header", vtype_stringptr, &dcc_header },
{ "dnslist_value", vtype_stringptr, &dnslist_value },
{ "domain", vtype_stringptr, &deliver_domain },
{ "domain_data", vtype_stringptr, &deliver_domain_data },
+#ifdef EXPERIMENTAL_EVENT
+ { "event_data", vtype_stringptr, &event_data },
+
+ /*XXX want to use generic vars for as many of these as possible*/
+ { "event_defer_errno", vtype_int, &event_defer_errno },
+
+ { "event_name", vtype_stringptr, &event_name },
+#endif
{ "exim_gid", vtype_gid, &exim_gid },
{ "exim_path", vtype_stringptr, &exim_path },
{ "exim_uid", vtype_uid, &exim_uid },
+ { "exim_version", vtype_stringptr, &version_string },
#ifdef WITH_OLD_DEMIME
{ "found_extension", vtype_stringptr, &found_extension },
#endif
{ "sn8", vtype_filter_int, &filter_sn[8] },
{ "sn9", vtype_filter_int, &filter_sn[9] },
#ifdef WITH_CONTENT_SCAN
+ { "spam_action", vtype_stringptr, &spam_action },
{ "spam_bar", vtype_stringptr, &spam_bar },
{ "spam_report", vtype_stringptr, &spam_report },
{ "spam_score", vtype_stringptr, &spam_score },
{ "tod_logfile", vtype_todlf, NULL },
{ "tod_zone", vtype_todzone, NULL },
{ "tod_zulu", vtype_todzulu, NULL },
-#ifdef EXPERIMENTAL_TPDA
- { "tpda_data", vtype_stringptr, &tpda_data },
-
- /*XXX want to use generic vars for as many of these as possible*/
- { "tpda_defer_errno", vtype_int, &tpda_defer_errno },
-
- { "tpda_event", vtype_stringptr, &tpda_event },
-#endif
{ "transport_name", vtype_stringptr, &transport_name },
{ "value", vtype_stringptr, &lookup_value },
+ { "verify_mode", vtype_stringptr, &verify_mode },
{ "version_number", vtype_stringptr, &version_string },
{ "warn_message_delay", vtype_stringptr, &warnmsg_delay },
{ "warn_message_recipient",vtype_stringptr, &warnmsg_recipients },
Ustrchr() yields non-NULL if the character is zero (which is not something
I expected). */
-static uschar *
-read_name(uschar *name, int max, uschar *s, uschar *extras)
+static const uschar *
+read_name(uschar *name, int max, const uschar *s, uschar *extras)
{
int ptr = 0;
while (*s != 0 && (isalnum(*s) || Ustrchr(extras, *s) != NULL))
Returns: a pointer to the first character after the header name
*/
-static uschar *
-read_header_name(uschar *name, int max, uschar *s)
+static const uschar *
+read_header_name(uschar *name, int max, const uschar *s)
{
int prelen = Ustrchr(name, '_') - name + 1;
int ptr = Ustrlen(name) - prelen;
return s;
}
+static const uschar *
+read_cnumber(int *n, const uschar *s)
+{
+*n = 0;
+while (isdigit(*s)) *n = *n * 10 + (*s++ - '0');
+return s;
+}
+
/*************************************************
*/
static uschar *
-expand_getkeyed(uschar *key, uschar *s)
+expand_getkeyed(uschar *key, const uschar *s)
{
int length = Ustrlen(key);
while (isspace(*s)) s++;
{
int dkeylength;
uschar *data;
- uschar *dkey = s;
+ const uschar *dkey = s;
while (*s != 0 && *s != '=' && !isspace(*s)) s++;
dkeylength = s - dkey;
static uschar *
-expand_getlistele(int field, uschar * list)
+expand_getlistele(int field, const uschar * list)
{
-uschar * tlist= list;
+const uschar * tlist= list;
int sep= 0;
uschar dummy;
if(field<0)
-{
+ {
for(field++; string_nextinlist(&tlist, &sep, &dummy, 1); ) field++;
sep= 0;
-}
+ }
if(field==0) return NULL;
while(--field>0 && (string_nextinlist(&list, &sep, &dummy, 1))) ;
return string_nextinlist(&list, &sep, NULL, 0);
*/
static int
-read_subs(uschar **sub, int n, int m, uschar **sptr, BOOL skipping,
+read_subs(uschar **sub, int n, int m, const uschar **sptr, BOOL skipping,
BOOL check_end, uschar *name, BOOL *resetok)
{
int i;
-uschar *s = *sptr;
+const uschar *s = *sptr;
while (isspace(*s)) s++;
for (i = 0; i < n; i++)
eval_acl(uschar ** sub, int nsub, uschar ** user_msgp)
{
int i;
-uschar *tmp;
+uschar * tmp = NULL;
int sav_narg = acl_narg;
int ret;
extern int acl_where;
NULL after an error
*/
-static uschar *
-eval_condition(uschar *s, BOOL *resetok, BOOL *yield)
+static const uschar *
+eval_condition(const uschar *s, BOOL *resetok, BOOL *yield)
{
BOOL testfor = TRUE;
BOOL tempcond, combined_cond;
int_eximarith_t num[2];
struct stat statbuf;
uschar name[256];
-uschar *sub[10];
+const uschar *sub[10];
const pcre *re;
const uschar *rerror;
case ECOND_ACL:
/* ${if acl {{name}{arg1}{arg2}...} {yes}{no}} */
{
+ uschar *sub[10];
uschar *user_msg;
BOOL cond = FALSE;
int size = 0;
case ECOND_INLIST:
case ECOND_INLISTI:
{
+ const uschar * list = sub[1];
int sep = 0;
uschar *save_iterate_item = iterate_item;
int (*compare)(const uschar *, const uschar *);
DEBUG(D_expand) debug_printf("condition: %s\n", name);
tempcond = FALSE;
- if (cond_type == ECOND_INLISTI)
- compare = strcmpic;
- else
- compare = (int (*)(const uschar *, const uschar *)) strcmp;
+ compare = cond_type == ECOND_INLISTI
+ ? strcmpic : (int (*)(const uschar *, const uschar *)) strcmp;
- while ((iterate_item = string_nextinlist(&sub[1], &sep, NULL, 0)) != NULL)
+ while ((iterate_item = string_nextinlist(&list, &sep, NULL, 0)))
if (compare(sub[0], iterate_item) == 0)
{
tempcond = TRUE;
case ECOND_FORALL:
case ECOND_FORANY:
{
+ const uschar * list;
int sep = 0;
uschar *save_iterate_item = iterate_item;
}
if (yield != NULL) *yield = !testfor;
- while ((iterate_item = string_nextinlist(&sub[0], &sep, NULL, 0)) != NULL)
+ list = sub[0];
+ while ((iterate_item = string_nextinlist(&list, &sep, NULL, 0)) != NULL)
{
DEBUG(D_expand) debug_printf("%s: $item = \"%s\"\n", name, iterate_item);
if (!eval_condition(sub[1], resetok, &tempcond))
*/
static int
-process_yesno(BOOL skipping, BOOL yes, uschar *save_lookup, uschar **sptr,
+process_yesno(BOOL skipping, BOOL yes, uschar *save_lookup, const uschar **sptr,
uschar **yieldptr, int *sizeptr, int *ptrptr, uschar *type, BOOL *resetok)
{
int rc = 0;
-uschar *s = *sptr; /* Local value */
+const uschar *s = *sptr; /* Local value */
uschar *sub1, *sub2;
/* If there are no following strings, we substitute the contents of $value for
else if (*s != '}')
{
uschar name[256];
- s = read_name(name, sizeof(name), s, US"_");
+ /* deconst cast ok here as source is s anyway */
+ s = US read_name(name, sizeof(name), s, US"_");
if (Ustrcmp(name, "fail") == 0)
{
if (!yes && !skipping)
*/
static uschar *
-expand_string_internal(uschar *string, BOOL ket_ends, uschar **left,
+expand_string_internal(const uschar *string, BOOL ket_ends, const uschar **left,
BOOL skipping, BOOL honour_dollar, BOOL *resetok_p)
{
int ptr = 0;
int size = Ustrlen(string)+ 64;
int item_type;
uschar *yield = store_get(size);
-uschar *s = string;
+const uschar *s = string;
uschar *save_expand_nstring[EXPAND_MAXN+1];
int save_expand_nlength[EXPAND_MAXN+1];
BOOL resetok = TRUE;
if (s[1] == 'N')
{
- uschar *t = s + 2;
+ const uschar * t = s + 2;
for (s = t; *s != 0; s++) if (*s == '\\' && s[1] == 'N') break;
yield = string_cat(yield, &size, &ptr, t, s - t);
if (*s != 0) s += 2;
if (isdigit(*s))
{
int n;
- s = read_number(&n, s);
+ s = read_cnumber(&n, s);
if (n >= 0 && n <= expand_nmax)
yield = string_cat(yield, &size, &ptr, expand_nstring[n],
expand_nlength[n]);
if (isdigit((*(++s))))
{
int n;
- s = read_number(&n, s); /*{*/
+ s = read_cnumber(&n, s); /*{*/
if (*s++ != '}')
{ /*{*/
expand_string_message = US"} expected after number";
case EITEM_IF:
{
BOOL cond = FALSE;
- uschar *next_s;
+ const uschar *next_s;
int save_expand_nmax =
save_expand_strings(save_expand_nstring, save_expand_nlength);
int stype, partial, affixlen, starflags;
int expand_setup = 0;
int nameptr = 0;
- uschar *key, *filename, *affix;
+ uschar *key, *filename;
+ const uschar *affix;
uschar *save_lookup_value = lookup_value;
int save_expand_nmax =
save_expand_strings(save_expand_nstring, save_expand_nlength);
{
FILE *f;
uschar *arg;
- uschar **argv;
+ const uschar **argv;
pid_t pid;
int fd_in, fd_out;
int lsize = 0;
/* Create the child process, making it a group leader. */
- pid = child_open(argv, NULL, 0077, &fd_in, &fd_out, TRUE);
+ pid = child_open(USS argv, NULL, 0077, &fd_in, &fd_out, TRUE);
if (pid < 0)
{
int sep = 0;
int save_ptr = ptr;
uschar outsep[2] = { '\0', '\0' };
- uschar *list, *expr, *temp;
+ const uschar *list, *expr, *temp;
uschar *save_iterate_item = iterate_item;
uschar *save_lookup_value = lookup_value;
if (item_type == EITEM_REDUCE)
{
+ uschar * t;
while (isspace(*s)) s++;
if (*s++ != '{') goto EXPAND_FAILED_CURLY;
- temp = expand_string_internal(s, TRUE, &s, skipping, TRUE, &resetok);
+ t = expand_string_internal(s, TRUE, &s, skipping, TRUE, &resetok);
if (temp == NULL) goto EXPAND_FAILED;
- lookup_value = temp;
+ lookup_value = t;
if (*s++ != '}') goto EXPAND_FAILED_CURLY;
}
if (temp != NULL) s = temp;
}
else
- {
temp = expand_string_internal(s, TRUE, &s, TRUE, TRUE, &resetok);
- }
if (temp == NULL)
{
else
{
- temp = expand_string_internal(expr, TRUE, NULL, skipping, TRUE, &resetok);
+ uschar * t = expand_string_internal(expr, TRUE, NULL, skipping, TRUE, &resetok);
+ temp = t;
if (temp == NULL)
{
iterate_item = save_iterate_item;
}
if (item_type == EITEM_REDUCE)
{
- lookup_value = temp; /* Update the value of $value */
+ lookup_value = t; /* Update the value of $value */
continue; /* and continue the iteration */
}
}
case EITEM_SORT:
{
int sep = 0;
- uschar *srclist, *cmp, *xtract;
+ const uschar *srclist, *cmp, *xtract;
uschar *srcitem;
- uschar *dstlist = NULL;
- uschar *dstkeylist = NULL;
+ const uschar *dstlist = NULL, *dstkeylist = NULL;
uschar * tmp;
uschar *save_iterate_item = iterate_item;
case EOP_SHA256:
if (s[1] == '$')
{
- uschar * s1 = s;
+ const uschar * s1 = s;
sub = expand_string_internal(s+2, TRUE, &s1, skipping,
FALSE, &resetok);
if (!sub) goto EXPAND_FAILED; /*{*/
uschar * cp;
uschar buffer[256];
- while (string_nextinlist(&sub, &sep, buffer, sizeof(buffer)) != NULL) cnt++;
+ while (string_nextinlist(CUSS &sub, &sep, buffer, sizeof(buffer)) != NULL) cnt++;
cp = string_sprintf("%d", cnt);
yield = string_cat(yield, &size, &ptr, cp, Ustrlen(cp));
continue;
case EOP_LISTNAMED:
{
tree_node *t = NULL;
- uschar * list;
+ const uschar * list;
int sep = 0;
uschar * item;
uschar * suffix = US"";
case EOP_RFC2047:
{
uschar buffer[2048];
- uschar *string = parse_quote_2047(sub, Ustrlen(sub), headers_charset,
+ const uschar *string = parse_quote_2047(sub, Ustrlen(sub), headers_charset,
buffer, sizeof(buffer), FALSE);
yield = string_cat(yield, &size, &ptr, string, Ustrlen(string));
continue;
case EOP_ESCAPE:
{
- uschar *t = string_printing(sub);
+ const uschar *t = string_printing(sub);
yield = string_cat(yield, &size, &ptr, t, Ustrlen(t));
continue;
}
+const uschar *
+expand_cstring(const uschar *string)
+{
+search_find_defer = FALSE;
+malformed_header = FALSE;
+return (Ustrpbrk(string, "$\\") == NULL)? string :
+ expand_string_internal(string, FALSE, NULL, FALSE, TRUE, NULL);
+}
+
+
+
/*************************************************
* Expand and copy *
*************************************************/
/* Now and again we want to expand a string and be sure that the result is in a
new bit of store. This function does that.
+Since we know it has been copied, the de-const cast is safe.
Argument: the string to be expanded
Returns: the expanded string, always in a new bit of store, or NULL
*/
uschar *
-expand_string_copy(uschar *string)
+expand_string_copy(const uschar *string)
{
-uschar *yield = expand_string(string);
+const uschar *yield = expand_cstring(string);
if (yield == string) yield = string_copy(string);
-return yield;
+return US yield;
}
*/
static int_eximarith_t
-expanded_string_integer(uschar *s, BOOL isplus)
+expanded_string_integer(const uschar *s, BOOL isplus)
{
int_eximarith_t value;
uschar *msg = US"invalid integer \"%s\"";
}
+/* These values are usually fixed boolean values, but they are permitted to be
+expanded strings.
+
+Arguments:
+ addr address being routed
+ mtype the module type
+ mname the module name
+ dbg_opt debug selectors
+ oname the option name
+ bvalue the router's boolean value
+ svalue the router's string value
+ rvalue where to put the returned value
+
+Returns: OK value placed in rvalue
+ DEFER expansion failed
+*/
+
+int
+exp_bool(address_item *addr,
+ uschar *mtype, uschar *mname, unsigned dbg_opt,
+ uschar *oname, BOOL bvalue,
+ uschar *svalue, BOOL *rvalue)
+{
+uschar *expanded;
+if (svalue == NULL) { *rvalue = bvalue; return OK; }
+
+expanded = expand_string(svalue);
+if (expanded == NULL)
+ {
+ if (expand_string_forcedfail)
+ {
+ DEBUG(dbg_opt) debug_printf("expansion of \"%s\" forced failure\n", oname);
+ *rvalue = bvalue;
+ return OK;
+ }
+ addr->message = string_sprintf("failed to expand \"%s\" in %s %s: %s",
+ oname, mname, mtype, expand_string_message);
+ DEBUG(dbg_opt) debug_printf("%s\n", addr->message);
+ return DEFER;
+ }
+
+DEBUG(dbg_opt) debug_printf("expansion of \"%s\" yields \"%s\"\n", oname,
+ expanded);
+
+if (strcmpic(expanded, US"true") == 0 || strcmpic(expanded, US"yes") == 0)
+ *rvalue = TRUE;
+else if (strcmpic(expanded, US"false") == 0 || strcmpic(expanded, US"no") == 0)
+ *rvalue = FALSE;
+else
+ {
+ addr->message = string_sprintf("\"%s\" is not a valid value for the "
+ "\"%s\" option in the %s %s", expanded, oname, mname, mtype);
+ return DEFER;
+ }
+
+return OK;
+}
+
+
+
+
/*************************************************
**************************************************
* Stand-alone test program *