X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/82dbd376b5de9b9d91e93e91a4e058a80a43de99..0e42da1b15894b66e3726d8ce0e41e25bdc21149:/src/src/expand.c diff --git a/src/src/expand.c b/src/src/expand.c index a929e937c..bf79a8222 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -127,6 +127,7 @@ static uschar *item_table[] = { US"reduce", US"run", US"sg", + US"sort", US"substr", US"tr" }; @@ -152,6 +153,7 @@ enum { EITEM_REDUCE, EITEM_RUN, EITEM_SG, + EITEM_SORT, EITEM_SUBSTR, EITEM_TR }; @@ -444,6 +446,8 @@ static var_entry var_table[] = { { "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 }, @@ -488,9 +492,18 @@ static var_entry var_table[] = { { "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 @@ -712,16 +725,9 @@ static var_entry var_table[] = { { "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 }, @@ -1186,10 +1192,10 @@ 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); @@ -5633,6 +5639,145 @@ while (*s != 0) continue; } + case EITEM_SORT: + { + int sep = 0; + uschar *srclist, *cmp, *xtract; + uschar *srcitem; + uschar *dstlist = NULL; + uschar *dstkeylist = NULL; + uschar * tmp; + uschar *save_iterate_item = iterate_item; + + while (isspace(*s)) s++; + if (*s++ != '{') goto EXPAND_FAILED_CURLY; + + srclist = expand_string_internal(s, TRUE, &s, skipping, TRUE, &resetok); + if (!srclist) goto EXPAND_FAILED; + if (*s++ != '}') goto EXPAND_FAILED_CURLY; + + while (isspace(*s)) s++; + if (*s++ != '{') goto EXPAND_FAILED_CURLY; + + cmp = expand_string_internal(s, TRUE, &s, skipping, FALSE, &resetok); + if (!cmp) goto EXPAND_FAILED; + if (*s++ != '}') goto EXPAND_FAILED_CURLY; + + while (isspace(*s)) s++; + if (*s++ != '{') goto EXPAND_FAILED_CURLY; + + xtract = s; + tmp = expand_string_internal(s, TRUE, &s, TRUE, TRUE, &resetok); + if (!tmp) goto EXPAND_FAILED; + xtract = string_copyn(xtract, s - xtract); + + if (*s++ != '}') goto EXPAND_FAILED_CURLY; + /*{*/ + if (*s++ != '}') + { /*{*/ + expand_string_message = US"missing } at end of \"sort\""; + goto EXPAND_FAILED; + } + + if (skipping) continue; + + while ((srcitem = string_nextinlist(&srclist, &sep, NULL, 0))) + { + uschar * dstitem; + uschar * newlist = NULL; + uschar * newkeylist = NULL; + uschar * srcfield; + + DEBUG(D_expand) debug_printf("%s: $item = \"%s\"\n", name, srcitem); + + /* extract field for comparisons */ + iterate_item = srcitem; + if ( !(srcfield = expand_string_internal(xtract, FALSE, NULL, FALSE, + TRUE, &resetok)) + || !*srcfield) + { + expand_string_message = string_sprintf( + "field-extract in sort: \"%s\"", xtract); + goto EXPAND_FAILED; + } + + /* Insertion sort */ + + /* copy output list until new-item < list-item */ + while ((dstitem = string_nextinlist(&dstlist, &sep, NULL, 0))) + { + uschar * dstfield; + uschar * expr; + BOOL before; + + /* field for comparison */ + if (!(dstfield = string_nextinlist(&dstkeylist, &sep, NULL, 0))) + goto sort_mismatch; + + /* build and run condition string */ + expr = string_sprintf("%s{%s}{%s}", cmp, srcfield, dstfield); + + DEBUG(D_expand) debug_printf("%s: cond = \"%s\"\n", name, expr); + if (!eval_condition(expr, &resetok, &before)) + { + expand_string_message = string_sprintf("comparison in sort: %s", + expr); + goto EXPAND_FAILED; + } + + if (before) + { + /* New-item sorts before this dst-item. Append new-item, + then dst-item, then remainder of dst list. */ + + newlist = string_append_listele(newlist, sep, srcitem); + newkeylist = string_append_listele(newkeylist, sep, srcfield); + srcitem = NULL; + + newlist = string_append_listele(newlist, sep, dstitem); + newkeylist = string_append_listele(newkeylist, sep, dstfield); + + while ((dstitem = string_nextinlist(&dstlist, &sep, NULL, 0))) + { + if (!(dstfield = string_nextinlist(&dstkeylist, &sep, NULL, 0))) + goto sort_mismatch; + newlist = string_append_listele(newlist, sep, dstitem); + newkeylist = string_append_listele(newkeylist, sep, dstfield); + } + + break; + } + + newlist = string_append_listele(newlist, sep, dstitem); + newkeylist = string_append_listele(newkeylist, sep, dstfield); + } + + /* If we ran out of dstlist without consuming srcitem, append it */ + if (srcitem) + { + newlist = string_append_listele(newlist, sep, srcitem); + newkeylist = string_append_listele(newkeylist, sep, srcfield); + } + + dstlist = newlist; + dstkeylist = newkeylist; + + DEBUG(D_expand) debug_printf("%s: dstlist = \"%s\"\n", name, dstlist); + DEBUG(D_expand) debug_printf("%s: dstkeylist = \"%s\"\n", name, dstkeylist); + } + + if (dstlist) + yield = string_cat(yield, &size, &ptr, dstlist, Ustrlen(dstlist)); + + /* Restore preserved $item */ + iterate_item = save_iterate_item; + continue; + + sort_mismatch: + expand_string_message = US"Internal error in sort (list mismatch)"; + goto EXPAND_FAILED; + } + /* If ${dlfunc } support is configured, handle calling dynamically-loaded functions, unless locked out at this time. Syntax is ${dlfunc{file}{func}} @@ -6996,6 +7141,67 @@ return -2; } +/* 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 *