X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fsrc%2Fexpand.c;h=2128ee72c768eb72ce0b0b1973188f9f3de48b07;hb=9c5e54499afef5167bee6ecdcbf8dd5f023f51e0;hp=a7a09fa7a6207f3d729c2ea4dccb79767a4383a5;hpb=190404d75c168ce1e6dbf6ee08bdbbf62b365e4b;p=user%2Fhenk%2Fcode%2Fexim.git diff --git a/src/src/expand.c b/src/src/expand.c index a7a09fa7a..2128ee72c 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -312,7 +312,11 @@ static uschar *cond_table[] = { US"exists", US"first_delivery", US"forall", + US"forall_json", + US"forall_jsons", US"forany", + US"forany_json", + US"forany_jsons", US"ge", US"gei", US"gt", @@ -358,7 +362,11 @@ enum { ECOND_EXISTS, ECOND_FIRST_DELIVERY, ECOND_FORALL, + ECOND_FORALL_JSON, + ECOND_FORALL_JSONS, ECOND_FORANY, + ECOND_FORANY_JSON, + ECOND_FORANY_JSONS, ECOND_STR_GE, ECOND_STR_GEI, ECOND_STR_GT, @@ -2144,6 +2152,89 @@ return ret; +/* Return pointer to dewrapped string, with enclosing specified chars removed. +The given string is modified on return. Leading whitespace is skipped while +looking for the opening wrap character, then the rest is scanned for the trailing +(non-escaped) wrap character. A backslash in the string will act as an escape. + +A nul is written over the trailing wrap, and a pointer to the char after the +leading wrap is returned. + +Arguments: + s String for de-wrapping + wrap Two-char string, the first being the opener, second the closer wrapping + character +Return: + Pointer to de-wrapped string, or NULL on error (with expand_string_message set). +*/ + +static uschar * +dewrap(uschar * s, const uschar * wrap) +{ +uschar * p = s; +unsigned depth = 0; +BOOL quotesmode = wrap[0] == wrap[1]; + +while (isspace(*p)) p++; + +if (*p == *wrap) + { + s = ++p; + wrap++; + while (*p) + { + if (*p == '\\') p++; + else if (!quotesmode && *p == wrap[-1]) depth++; + else if (*p == *wrap) + if (depth == 0) + { + *p = '\0'; + return s; + } + else + depth--; + p++; + } + } +expand_string_message = string_sprintf("missing '%c'", *wrap); +return NULL; +} + + +/* Pull off the leading array or object element, returning +a copy in an allocated string. Update the list pointer. + +The element may itself be an abject or array. +Return NULL when the list is empty. +*/ + +static uschar * +json_nextinlist(const uschar ** list) +{ +unsigned array_depth = 0, object_depth = 0; +const uschar * s = *list, * item; + +while (isspace(*s)) s++; + +for (item = s; + *s && (*s != ',' || array_depth != 0 || object_depth != 0); + s++) + switch (*s) + { + case '[': array_depth++; break; + case ']': array_depth--; break; + case '{': object_depth++; break; + case '}': object_depth--; break; + } +*list = *s ? s+1 : s; +if (item == s) return NULL; +item = string_copyn(item, s - item); +DEBUG(D_expand) debug_printf_indent(" json ele: '%s'\n", item); +return US item; +} + + + /************************************************* * Read and evaluate a condition * *************************************************/ @@ -2170,6 +2261,7 @@ BOOL testfor = TRUE; BOOL tempcond, combined_cond; BOOL *subcondptr; BOOL sub2_honour_dollar = TRUE; +BOOL is_forany, is_json, is_jsons; int rc, cond_type, roffset; int_eximarith_t num[2]; struct stat statbuf; @@ -2737,7 +2829,7 @@ switch(cond_type) if (sublen == 24) { - uschar *coded = b64encode(digest, 16); + uschar *coded = b64encode(CUS digest, 16); DEBUG(D_auth) debug_printf("crypteq: using MD5+B64 hashing\n" " subject=%s\n crypted=%s\n", coded, sub[1]+5); tempcond = (Ustrcmp(coded, sub[1]+5) == 0); @@ -2774,7 +2866,7 @@ switch(cond_type) if (sublen == 28) { - uschar *coded = b64encode(digest, 20); + uschar *coded = b64encode(CUS digest, 20); DEBUG(D_auth) debug_printf("crypteq: using SHA1+B64 hashing\n" " subject=%s\n crypted=%s\n", coded, sub[1]+6); tempcond = (Ustrcmp(coded, sub[1]+6) == 0); @@ -2945,8 +3037,14 @@ switch(cond_type) /* forall/forany: iterates a condition with different values */ - case ECOND_FORALL: - case ECOND_FORANY: + case ECOND_FORALL: is_forany = FALSE; is_json = FALSE; is_jsons = FALSE; goto FORMANY; + case ECOND_FORANY: is_forany = TRUE; is_json = FALSE; is_jsons = FALSE; goto FORMANY; + case ECOND_FORALL_JSON: is_forany = FALSE; is_json = TRUE; is_jsons = FALSE; goto FORMANY; + case ECOND_FORANY_JSON: is_forany = TRUE; is_json = TRUE; is_jsons = FALSE; goto FORMANY; + case ECOND_FORALL_JSONS: is_forany = FALSE; is_json = TRUE; is_jsons = TRUE; goto FORMANY; + case ECOND_FORANY_JSONS: is_forany = TRUE; is_json = TRUE; is_jsons = TRUE; goto FORMANY; + + FORMANY: { const uschar * list; int sep = 0; @@ -2987,10 +3085,22 @@ switch(cond_type) return NULL; } - if (yield != NULL) *yield = !testfor; + if (yield) *yield = !testfor; list = sub[0]; - while ((iterate_item = string_nextinlist(&list, &sep, NULL, 0)) != NULL) + if (is_json) list = dewrap(string_copy(list), US"[]"); + while ((iterate_item = is_json + ? json_nextinlist(&list) : string_nextinlist(&list, &sep, NULL, 0))) { + if (is_jsons) + if (!(iterate_item = dewrap(iterate_item, US"\"\""))) + { + expand_string_message = + string_sprintf("%s wrapping string result for extract jsons", + expand_string_message); + iterate_item = save_iterate_item; + return NULL; + } + DEBUG(D_expand) debug_printf_indent("%s: $item = \"%s\"\n", name, iterate_item); if (!eval_condition(sub[1], resetok, &tempcond)) { @@ -3002,8 +3112,8 @@ switch(cond_type) DEBUG(D_expand) debug_printf_indent("%s: condition evaluated to %s\n", name, tempcond? "true":"false"); - if (yield != NULL) *yield = (tempcond == testfor); - if (tempcond == (cond_type == ECOND_FORANY)) break; + if (yield) *yield = (tempcond == testfor); + if (tempcond == is_forany) break; } iterate_item = save_iterate_item; @@ -3841,87 +3951,6 @@ return x; -/* Return pointer to dewrapped string, with enclosing specified chars removed. -The given string is modified on return. Leading whitespace is skipped while -looking for the opening wrap character, then the rest is scanned for the trailing -(non-escaped) wrap character. A backslash in the string will act as an escape. - -A nul is written over the trailing wrap, and a pointer to the char after the -leading wrap is returned. - -Arguments: - s String for de-wrapping - wrap Two-char string, the first being the opener, second the closer wrapping - character -Return: - Pointer to de-wrapped string, or NULL on error (with expand_string_message set). -*/ - -static uschar * -dewrap(uschar * s, const uschar * wrap) -{ -uschar * p = s; -unsigned depth = 0; -BOOL quotesmode = wrap[0] == wrap[1]; - -while (isspace(*p)) p++; - -if (*p == *wrap) - { - s = ++p; - wrap++; - while (*p) - { - if (*p == '\\') p++; - else if (!quotesmode && *p == wrap[-1]) depth++; - else if (*p == *wrap) - if (depth == 0) - { - *p = '\0'; - return s; - } - else - depth--; - p++; - } - } -expand_string_message = string_sprintf("missing '%c'", *wrap); -return NULL; -} - - -/* Pull off the leading array or object element, returning -a copy in an allocated string. Update the list pointer. - -The element may itself be an abject or array. -*/ - -uschar * -json_nextinlist(const uschar ** list) -{ -unsigned array_depth = 0, object_depth = 0; -const uschar * s = *list, * item; - -while (isspace(*s)) s++; - -for (item = s; - *s && (*s != ',' || array_depth != 0 || object_depth != 0); - s++) - switch (*s) - { - case '[': array_depth++; break; - case ']': array_depth--; break; - case '{': object_depth++; break; - case '}': object_depth--; break; - } -*list = *s ? s+1 : s; -item = string_copyn(item, s - item); -DEBUG(D_expand) debug_printf_indent(" json ele: '%s'\n", item); -return US item; -} - - - /************************************************* * Expand string * *************************************************/ @@ -5633,7 +5662,7 @@ while (*s != 0) uschar *sub[3]; int save_expand_nmax = save_expand_strings(save_expand_nstring, save_expand_nlength); - enum {extract_basic, extract_json} fmt = extract_basic; + enum {extract_basic, extract_json, extract_jsons} fmt = extract_basic; while (isspace(*s)) s++; @@ -5641,7 +5670,10 @@ while (*s != 0) if (*s != '{') /*}*/ if (Ustrncmp(s, "json", 4) == 0) - {fmt = extract_json; s += 4;} + if (*(s += 4) == 's') + {fmt = extract_jsons; s++;} + else + fmt = extract_json; /* While skipping we cannot rely on the data for expansions being available (eg. $item) hence cannot decide on numeric vs. keyed. @@ -5722,7 +5754,7 @@ while (*s != 0) if (*p == 0) { field_number *= x; - if (fmt != extract_json) j = 3; /* Need 3 args */ + if (fmt == extract_basic) j = 3; /* Need 3 args */ field_number_set = TRUE; } } @@ -5749,6 +5781,7 @@ while (*s != 0) break; case extract_json: + case extract_jsons: { uschar * s, * item; const uschar * list; @@ -5814,6 +5847,15 @@ while (*s != 0) } } } + + if (fmt == extract_jsons) + if (!(lookup_value = dewrap(lookup_value, US"\"\""))) + { + expand_string_message = + string_sprintf("%s wrapping string result for extract jsons", + expand_string_message); + goto EXPAND_FAILED_CURLY; + } } /* If no string follows, $value gets substituted; otherwise there can @@ -6843,7 +6885,7 @@ while (*s != 0) } } - enc = b64encode(sub, out - sub); + enc = b64encode(CUS sub, out - sub); yield = string_cat(yield, enc); continue; } @@ -7507,9 +7549,9 @@ while (*s != 0) #ifdef SUPPORT_TLS uschar * s = vp && *(void **)vp->value ? tls_cert_der_b64(*(void **)vp->value) - : b64encode(sub, Ustrlen(sub)); + : b64encode(CUS sub, Ustrlen(sub)); #else - uschar * s = b64encode(sub, Ustrlen(sub)); + uschar * s = b64encode(CUS sub, Ustrlen(sub)); #endif yield = string_cat(yield, s); continue;