X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/691ca88ca06899e02e77cb28fbf075de450607bc..48b30ae1141cbce9fe6f1153f368dd63a4505775:/src/src/expand.c diff --git a/src/src/expand.c b/src/src/expand.c index 4377ea1aa..6d9a1695b 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -117,6 +117,7 @@ static uschar *item_table[] = { #endif US"length", US"listextract", + US"listquote", US"lookup", US"map", US"nhash", @@ -151,6 +152,7 @@ enum { #endif EITEM_LENGTH, EITEM_LISTEXTRACT, + EITEM_LISTQUOTE, EITEM_LOOKUP, EITEM_MAP, EITEM_NHASH, @@ -1174,7 +1176,7 @@ static uschar * expand_getkeyed(uschar * key, const uschar * s) { int length = Ustrlen(key); -while (isspace(*s)) s++; +Uskip_whitespace(&s); /* Loop to search for the key */ @@ -1186,14 +1188,13 @@ while (*s) while (*s && *s != '=' && !isspace(*s)) s++; dkeylength = s - dkey; - while (isspace(*s)) s++; - if (*s == '=') while (isspace((*(++s)))); + if (Uskip_whitespace(&s) == '=') while (isspace((*(++s)))); data = string_dequote(&s); if (length == dkeylength && strncmpic(key, dkey, length) == 0) return data; - while (isspace(*s)) s++; + Uskip_whitespace(&s); } return NULL; @@ -2044,7 +2045,7 @@ switch (vp->type) s = find_header(US"reply-to:", newsize, exists_only ? FH_EXISTS_ONLY|FH_WANT_RAW : FH_WANT_RAW, headers_charset); - if (s) while (isspace(*s)) s++; + if (s) Uskip_whitespace(&s); if (!s || !*s) { *newsize = 0; /* For the *s==0 case */ @@ -2055,8 +2056,8 @@ switch (vp->type) if (s) { uschar *t; - while (isspace(*s)) s++; - for (t = s; *t != 0; t++) if (*t == '\n') *t = ' '; + Uskip_whitespace(&s); + for (t = s; *t; t++) if (*t == '\n') *t = ' '; while (t > s && isspace(t[-1])) t--; *t = 0; } @@ -2144,7 +2145,7 @@ read_subs(uschar **sub, int n, int m, const uschar **sptr, BOOL skipping, { const uschar *s = *sptr; -while (isspace(*s)) s++; +Uskip_whitespace(&s); for (int i = 0; i < n; i++) { if (*s != '{') @@ -2161,7 +2162,7 @@ for (int i = 0; i < n; i++) if (!(sub[i] = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, resetok))) return 3; if (*s++ != '}') return 1; - while (isspace(*s)) s++; + Uskip_whitespace(&s); } if (check_end && *s++ != '}') { @@ -2284,9 +2285,7 @@ uschar * p = s; unsigned depth = 0; BOOL quotesmode = wrap[0] == wrap[1]; -while (isspace(*p)) p++; - -if (*p == *wrap) +if (Uskip_whitespace(&p) == *wrap) { s = ++p; wrap++; @@ -2747,7 +2746,7 @@ switch(cond_type = identify_operator(&s, &opname)) if (*s++ != '{') goto COND_FAILED_CURLY_START; /*}*/ switch(read_subs(sub, nelem(sub), 1, - &s, yield == NULL, TRUE, US"acl", resetok)) + &s, yield == NULL, TRUE, name, resetok)) { case 1: expand_string_message = US"too few arguments or bracketing " "error for acl"; @@ -2798,7 +2797,7 @@ switch(cond_type = identify_operator(&s, &opname)) uschar *sub[4]; while (isspace(*s)) s++; if (*s++ != '{') goto COND_FAILED_CURLY_START; /* }-for-text-editors */ - switch(read_subs(sub, nelem(sub), 2, &s, yield == NULL, TRUE, US"saslauthd", + switch(read_subs(sub, nelem(sub), 2, &s, yield == NULL, TRUE, name, resetok)) { case 1: expand_string_message = US"too few arguments or bracketing " @@ -3460,7 +3459,7 @@ switch(cond_type = identify_operator(&s, &opname)) uschar cksum[4]; BOOL boolvalue = FALSE; - switch(read_subs(sub, 2, 2, CUSS &s, yield == NULL, FALSE, US"inbound_srs", resetok)) + switch(read_subs(sub, 2, 2, CUSS &s, yield == NULL, FALSE, name, resetok)) { case 1: expand_string_message = US"too few arguments or bracketing " "error for inbound_srs"; @@ -4026,8 +4025,7 @@ int c; int_eximarith_t n; uschar *s = *sptr; -while (isspace(*s)) s++; -if (isdigit((c = *s))) +if (isdigit((c = Uskip_whitespace(&s)))) { int count; (void)sscanf(CS s, (decimal? SC_EXIM_DEC "%n" : SC_EXIM_ARITH "%n"), &n, &count); @@ -4039,7 +4037,7 @@ if (isdigit((c = *s))) case 'm': n *= 1024*1024; s++; break; case 'g': n *= 1024*1024*1024; s++; break; } - while (isspace (*s)) s++; + Uskip_whitespace(&s); } else if (c == '(') { @@ -4061,7 +4059,7 @@ eval_op_unary(uschar **sptr, BOOL decimal, uschar **error) { uschar *s = *sptr; int_eximarith_t x; -while (isspace(*s)) s++; +Uskip_whitespace(&s); if (*s == '+' || *s == '-' || *s == '~') { int op = *s++; @@ -4603,7 +4601,7 @@ while (*s != 0) uschar *user_msg; int rc; - switch(read_subs(sub, nelem(sub), 1, &s, skipping, TRUE, US"acl", + switch(read_subs(sub, nelem(sub), 1, &s, skipping, TRUE, name, &resetok)) { case 1: goto EXPAND_FAILED_CURLY; @@ -4779,7 +4777,7 @@ while (*s != 0) int expand_setup = 0; int nameptr = 0; uschar *key, *filename; - const uschar *affix; + const uschar * affix, * opts; uschar *save_lookup_value = lookup_value; int save_expand_nmax = save_expand_strings(save_expand_nstring, save_expand_nlength); @@ -4819,20 +4817,19 @@ while (*s != 0) kinds. Allow everything except space or { to appear; the actual content is checked by search_findtype_partial. */ /*}*/ - while (*s != 0 && *s != '{' && !isspace(*s)) /*}*/ + while (*s && *s != '{' && !isspace(*s)) /*}*/ { if (nameptr < sizeof(name) - 1) name[nameptr++] = *s; s++; } - name[nameptr] = 0; + name[nameptr] = '\0'; while (isspace(*s)) s++; /* Now check for the individual search type and any partial or default options. Only those types that are actually in the binary are valid. */ - stype = search_findtype_partial(name, &partial, &affix, &affixlen, - &starflags); - if (stype < 0) + if ((stype = search_findtype_partial(name, &partial, &affix, &affixlen, + &starflags, &opts)) < 0) { expand_string_message = search_error_message; goto EXPAND_FAILED; @@ -4892,16 +4889,13 @@ while (*s != 0) if (mac_islookup(stype, lookup_querystyle)) filename = NULL; else - { - if (*filename != '/') - { - expand_string_message = string_sprintf( - "absolute file name expected for \"%s\" lookup", name); - goto EXPAND_FAILED; - } - while (*key != 0 && !isspace(*key)) key++; - if (*key != 0) *key++ = 0; - } + if (*filename == '/') + { + while (*key && !isspace(*key)) key++; + if (*key) *key++ = '\0'; + } + else + filename = NULL; } /* If skipping, don't do the next bit - just lookup_value == NULL, as if @@ -4928,7 +4922,7 @@ while (*s != 0) goto EXPAND_FAILED; } lookup_value = search_find(handle, filename, key, partial, affix, - affixlen, starflags, &expand_setup); + affixlen, starflags, &expand_setup, opts); if (f.search_find_defer) { expand_string_message = @@ -4988,7 +4982,7 @@ while (*s != 0) } switch(read_subs(sub_arg, EXIM_PERL_MAX_ARGS + 1, 1, &s, skipping, TRUE, - US"perl", &resetok)) + name, &resetok)) { case 1: goto EXPAND_FAILED_CURLY; case 2: @@ -5059,7 +5053,7 @@ while (*s != 0) uschar *sub_arg[3]; uschar *p,*domain; - switch(read_subs(sub_arg, 3, 2, &s, skipping, TRUE, US"prvs", &resetok)) + switch(read_subs(sub_arg, 3, 2, &s, skipping, TRUE, name, &resetok)) { case 1: goto EXPAND_FAILED_CURLY; case 2: @@ -5133,7 +5127,7 @@ while (*s != 0) prvscheck_address = NULL; prvscheck_keynum = NULL; - switch(read_subs(sub_arg, 1, 1, &s, skipping, FALSE, US"prvs", &resetok)) + switch(read_subs(sub_arg, 1, 1, &s, skipping, FALSE, name, &resetok)) { case 1: goto EXPAND_FAILED_CURLY; case 2: @@ -5165,7 +5159,7 @@ while (*s != 0) prvscheck_keynum = string_copy(key_num); /* Now expand the second argument */ - switch(read_subs(sub_arg, 1, 1, &s, skipping, FALSE, US"prvs", &resetok)) + switch(read_subs(sub_arg, 1, 1, &s, skipping, FALSE, name, &resetok)) { case 1: goto EXPAND_FAILED_CURLY; case 2: @@ -5219,7 +5213,7 @@ while (*s != 0) /* 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", &resetok)) + switch(read_subs(sub_arg, 1, 0, &s, skipping, TRUE, name, &resetok)) { case 1: goto EXPAND_FAILED_CURLY; case 2: @@ -5240,7 +5234,7 @@ while (*s != 0) 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", &resetok)) + switch(read_subs(sub_arg, 2, 1, &s, skipping, TRUE, name, &resetok)) { case 1: goto EXPAND_FAILED_CURLY; case 2: @@ -5263,7 +5257,7 @@ while (*s != 0) goto EXPAND_FAILED; } - switch(read_subs(sub_arg, 2, 1, &s, skipping, TRUE, US"readfile", &resetok)) + switch(read_subs(sub_arg, 2, 1, &s, skipping, TRUE, name, &resetok)) { case 1: goto EXPAND_FAILED_CURLY; case 2: @@ -5313,7 +5307,7 @@ while (*s != 0) /* 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, US"readsocket", &resetok)) + switch(read_subs(sub_arg, 4, 2, &s, skipping, FALSE, name, &resetok)) { case 1: goto EXPAND_FAILED_CURLY; case 2: /* Won't occur: no end check */ @@ -5335,8 +5329,9 @@ while (*s != 0) uschar * item; int sep = 0; - item = string_nextinlist(&list, &sep, NULL, 0); - if ((timeout = readconf_readtime(item, 0, FALSE)) < 0) + if ( !(item = string_nextinlist(&list, &sep, NULL, 0)) + || !*item + || (timeout = readconf_readtime(item, 0, FALSE)) < 0) { expand_string_message = string_sprintf("bad time value %s", item); goto EXPAND_FAILED; @@ -5624,7 +5619,8 @@ while (*s != 0) /* Create the child process, making it a group leader. */ - if ((pid = child_open(USS argv, NULL, 0077, &fd_in, &fd_out, TRUE)) < 0) + if ((pid = child_open(USS argv, NULL, 0077, &fd_in, &fd_out, TRUE, + US"expand-run")) < 0) { expand_string_message = string_sprintf("couldn't create child process: %s", strerror(errno)); @@ -5698,7 +5694,7 @@ while (*s != 0) int o2m; uschar *sub[3]; - switch(read_subs(sub, 3, 3, &s, skipping, TRUE, US"tr", &resetok)) + switch(read_subs(sub, 3, 3, &s, skipping, TRUE, name, &resetok)) { case 1: goto EXPAND_FAILED_CURLY; case 2: @@ -5910,7 +5906,7 @@ while (*s != 0) int save_expand_nmax = save_expand_strings(save_expand_nstring, save_expand_nlength); - switch(read_subs(sub, 3, 3, &s, skipping, TRUE, US"sg", &resetok)) + switch(read_subs(sub, 3, 3, &s, skipping, TRUE, name, &resetok)) { case 1: goto EXPAND_FAILED_CURLY; case 2: @@ -6259,7 +6255,7 @@ while (*s != 0) for (int i = 0; i < 2; i++) { - while (isspace(*s)) s++; + skip_whitespace(&s); if (*s != '{') /*'}'*/ { expand_string_message = string_sprintf( @@ -6344,6 +6340,23 @@ while (*s != 0) continue; } + case EITEM_LISTQUOTE: + { + uschar * sub[2]; + switch(read_subs(sub, 2, 2, &s, skipping, TRUE, name, &resetok)) + { + case 1: goto EXPAND_FAILED_CURLY; + case 2: + case 3: goto EXPAND_FAILED; + } + for (uschar sep = *sub[0], c; c = *sub[1]; sub[1]++) + { + if (c == sep) yield = string_catn(yield, sub[1], 1); + yield = string_catn(yield, sub[1], 1); + } + continue; + } + #ifndef DISABLE_TLS case EITEM_CERTEXTRACT: { @@ -6353,7 +6366,7 @@ while (*s != 0) save_expand_strings(save_expand_nstring, save_expand_nlength); /* Read the field argument */ - while (isspace(*s)) s++; + skip_whitespace(&s); if (*s != '{') /*}*/ { expand_string_message = US"missing '{' for field arg of certextract"; @@ -6831,7 +6844,7 @@ while (*s != 0) } switch(read_subs(argv, EXPAND_DLFUNC_MAX_ARGS + 2, 2, &s, skipping, - TRUE, US"dlfunc", &resetok)) + TRUE, name, &resetok)) { case 1: goto EXPAND_FAILED_CURLY; case 2: @@ -7451,6 +7464,8 @@ while (*s != 0) continue; } + /* quote a list-item for the given list-separator */ + /* mask applies a mask to an IP address; for example the result of ${mask:131.111.10.206/28} is 131.111.10.192/28. */