X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/9ad27f49dae5a6375d7951679c90c2e26ad82b5c..958af3bdb77dc5c190b7f5117c68d2b0acd7b5bc:/src/src/expand.c diff --git a/src/src/expand.c b/src/src/expand.c index cdc914f5e..21758d832 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -3,6 +3,7 @@ *************************************************/ /* Copyright (c) University of Cambridge 1995 - 2018 */ +/* Copyright (c) The Exim Maintainers 2020 */ /* See the file NOTICE for conditions of use and distribution. */ @@ -130,7 +131,7 @@ static uschar *item_table[] = { US"run", US"sg", US"sort", -#ifdef EXPERIMENTAL_SRS_NATIVE +#ifdef SUPPORT_SRS US"srs_encode", #endif US"substr", @@ -165,7 +166,7 @@ enum { EITEM_RUN, EITEM_SG, EITEM_SORT, -#ifdef EXPERIMENTAL_SRS_NATIVE +#ifdef SUPPORT_SRS EITEM_SRS_ENCODE, #endif EITEM_SUBSTR, @@ -333,7 +334,7 @@ static uschar *cond_table[] = { US"gei", US"gt", US"gti", -#ifdef EXPERIMENTAL_SRS_NATIVE +#ifdef SUPPORT_SRS US"inbound_srs", #endif US"inlist", @@ -386,7 +387,7 @@ enum { ECOND_STR_GEI, ECOND_STR_GT, ECOND_STR_GTI, -#ifdef EXPERIMENTAL_SRS_NATIVE +#ifdef SUPPORT_SRS ECOND_INBOUND_SRS, #endif ECOND_INLIST, @@ -594,7 +595,6 @@ static var_entry var_table[] = { { "local_part_prefix_v", vtype_stringptr, &deliver_localpart_prefix_v }, { "local_part_suffix", vtype_stringptr, &deliver_localpart_suffix }, { "local_part_suffix_v", vtype_stringptr, &deliver_localpart_suffix_v }, - { "local_part_verified", vtype_stringptr, &deliver_localpart_verified }, #ifdef HAVE_LOCAL_SCAN { "local_scan_data", vtype_stringptr, &local_scan_data }, #endif @@ -752,16 +752,16 @@ static var_entry var_table[] = { { "spool_directory", vtype_stringptr, &spool_directory }, { "spool_inodes", vtype_pinodes, (void *)TRUE }, { "spool_space", vtype_pspace, (void *)TRUE }, -#ifdef EXPERIMENTAL_SRS +#ifdef EXPERIMENTAL_SRS_ALT { "srs_db_address", vtype_stringptr, &srs_db_address }, { "srs_db_key", vtype_stringptr, &srs_db_key }, { "srs_orig_recipient", vtype_stringptr, &srs_orig_recipient }, { "srs_orig_sender", vtype_stringptr, &srs_orig_sender }, #endif -#if defined(EXPERIMENTAL_SRS) || defined(EXPERIMENTAL_SRS_NATIVE) +#if defined(EXPERIMENTAL_SRS_ALT) || defined(SUPPORT_SRS) { "srs_recipient", vtype_stringptr, &srs_recipient }, #endif -#ifdef EXPERIMENTAL_SRS +#ifdef EXPERIMENTAL_SRS_ALT { "srs_status", vtype_stringptr, &srs_status }, #endif { "thisaddress", vtype_stringptr, &filter_thisaddress }, @@ -779,7 +779,7 @@ static var_entry var_table[] = { { "tls_in_ourcert", vtype_cert, &tls_in.ourcert }, { "tls_in_peercert", vtype_cert, &tls_in.peercert }, { "tls_in_peerdn", vtype_stringptr, &tls_in.peerdn }, -#ifdef EXPERIMENTAL_TLS_RESUME +#ifndef DISABLE_TLS_RESUME { "tls_in_resumption", vtype_int, &tls_in.resumption }, #endif #ifndef DISABLE_TLS @@ -797,7 +797,7 @@ static var_entry var_table[] = { { "tls_out_ourcert", vtype_cert, &tls_out.ourcert }, { "tls_out_peercert", vtype_cert, &tls_out.peercert }, { "tls_out_peerdn", vtype_stringptr, &tls_out.peerdn }, -#ifdef EXPERIMENTAL_TLS_RESUME +#ifndef DISABLE_TLS_RESUME { "tls_out_resumption", vtype_int, &tls_out.resumption }, #endif #ifndef DISABLE_TLS @@ -1172,8 +1172,8 @@ Returns: NULL if the subfield was not found, or a pointer to the subfield's data */ -static uschar * -expand_getkeyed(uschar * key, const uschar * s) +uschar * +expand_getkeyed(const uschar * key, const uschar * s) { int length = Ustrlen(key); Uskip_whitespace(&s); @@ -1708,9 +1708,9 @@ authres_iprev(gstring * g) if (sender_host_name) g = string_append(g, 3, US";\n\tiprev=pass (", sender_host_name, US")"); else if (host_lookup_deferred) - g = string_catn(g, US";\n\tiprev=temperror", 19); + g = string_cat(g, US";\n\tiprev=temperror"); else if (host_lookup_failed) - g = string_catn(g, US";\n\tiprev=fail", 13); + g = string_cat(g, US";\n\tiprev=fail"); else return g; @@ -1984,11 +1984,12 @@ switch (vp->type) ss = (uschar **)(val); if (!*ss && deliver_datafile >= 0) /* Read body when needed */ { - uschar *body; + uschar * body; off_t start_offset = SPOOL_DATA_START_OFFSET; int len = message_body_visible; + if (len > message_size) len = message_size; - *ss = body = store_malloc(len+1); + *ss = body = store_get(len+1, TRUE); body[0] = 0; if (vp->type == vtype_msgbody_end) { @@ -2003,8 +2004,7 @@ switch (vp->type) if (lseek(deliver_datafile, start_offset, SEEK_SET) < 0) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "deliver_datafile lseek: %s", strerror(errno)); - len = read(deliver_datafile, body, len); - if (len > 0) + if ((len = read(deliver_datafile, body, len)) > 0) { body[len] = 0; if (message_body_newlines) /* Separate loops for efficiency */ @@ -2066,7 +2066,8 @@ switch (vp->type) case vtype_string_func: { stringptr_fn_t * fn = (stringptr_fn_t *) val; - return fn(); + uschar* s = fn(); + return s ? s : US""; } case vtype_pspace: @@ -2438,6 +2439,7 @@ else +#ifdef SUPPORT_SRS /* Do an hmac_md5. The result is _not_ nul-terminated, and is sized as the smaller of a full hmac_md5 result (16 bytes) or the supplied output buffer. @@ -2512,6 +2514,7 @@ for (int i = 0, j = len; i < MD5_HASHLEN; i++) } return; } +#endif /*SUPPORT_SRS*/ /************************************************* @@ -3441,14 +3444,14 @@ switch(cond_type = identify_operator(&s, &opname)) return s; } -#ifdef EXPERIMENTAL_SRS_NATIVE +#ifdef SUPPORT_SRS case ECOND_INBOUND_SRS: /* ${if inbound_srs {local_part}{secret} {yes}{no}} */ { uschar * sub[2]; const pcre * re; int ovec[3*(4+1)]; - int n; + int n, quoting = 0; uschar cksum[4]; BOOL boolvalue = FALSE; @@ -3471,10 +3474,20 @@ switch(cond_type = identify_operator(&s, &opname)) goto srs_result; } - /* Side-effect: record the decoded recipient */ + if (sub[0][0] == '"') + quoting = 1; + else for (uschar * s = sub[0]; *s; s++) + if (!isalnum(*s) && Ustrchr(".!#$%&'*+-/=?^_`{|}~", *s) == NULL) + { quoting = 1; break; } + if (quoting) + DEBUG(D_expand) debug_printf_indent("auto-quoting local part\n"); + + /* Record the (quoted, if needed) decoded recipient as $srs_recipient */ - srs_recipient = string_sprintf("%.*S@%.*S", /* lowercased */ + srs_recipient = string_sprintf("%.*s%.*S%.*s@%.*S", /* lowercased */ + quoting, "\"", ovec[9]-ovec[8], sub[0] + ovec[8], /* substring 4 */ + quoting, "\"", ovec[7]-ovec[6], sub[0] + ovec[6]); /* substring 3 */ /* If a zero-length secret was given, we're done. Otherwise carry on @@ -3533,7 +3546,7 @@ srs_result: if (yield) *yield = (boolvalue == testfor); return s; } -#endif /*EXPERIMENTAL_SRS_NATIVE*/ +#endif /*SUPPORT_SRS*/ /* Unknown condition */ @@ -3927,7 +3940,7 @@ Arguments: Returns: new pointer for expandable string, terminated if non-null */ -static gstring * +gstring * cat_file(FILE *f, gstring *yield, uschar *eol) { uschar buffer[1024]; @@ -3947,7 +3960,7 @@ return yield; #ifndef DISABLE_TLS -static gstring * +gstring * cat_file_tls(void * tls_ctx, gstring * yield, uschar * eol) { int rc; @@ -4387,7 +4400,7 @@ if (is_tainted(string)) goto EXPAND_FAILED; } -while (*s != 0) +while (*s) { uschar *value; uschar name[256]; @@ -4773,7 +4786,7 @@ while (*s != 0) int save_expand_nmax = save_expand_strings(save_expand_nstring, save_expand_nlength); - if ((expand_forbid & RDO_LOOKUP) != 0) + if (expand_forbid & RDO_LOOKUP) { expand_string_message = US"lookup expansions are not permitted"; goto EXPAND_FAILED; @@ -4872,21 +4885,7 @@ while (*s != 0) file types, the query (i.e. "key") starts with a file name. */ if (!key) - { - Uskip_whitespace(&filename); - key = filename; - - if (mac_islookup(stype, lookup_querystyle)) - filename = NULL; - else - if (*filename == '/') - { - while (*key && !isspace(*key)) key++; - if (*key) *key++ = '\0'; - } - else - filename = NULL; - } + key = search_args(stype, name, filename, &filename, opts); /* If skipping, don't do the next bit - just lookup_value == NULL, as if the entry was not found. Note that there is no search_close() function. @@ -4917,7 +4916,7 @@ while (*s != 0) { expand_string_message = string_sprintf("lookup of \"%s\" gave DEFER: %s", - string_printing2(key, FALSE), search_error_message); + string_printing2(key, SP_TAB), search_error_message); goto EXPAND_FAILED; } if (expand_setup > 0) expand_nmax = expand_setup; @@ -5262,7 +5261,7 @@ while (*s != 0) if (!(f = Ufopen(sub_arg[0], "rb"))) { - expand_string_message = string_open_failed(errno, "%s", sub_arg[0]); + expand_string_message = string_open_failed("%s", sub_arg[0]); goto EXPAND_FAILED; } @@ -5276,17 +5275,8 @@ while (*s != 0) case EITEM_READSOCK: { - client_conn_ctx cctx; - int timeout = 5; - int save_ptr = gstring_length(yield); - FILE * fp = NULL; uschar * arg; uschar * sub_arg[4]; - uschar * server_name = NULL; - host_item host; - BOOL do_shutdown = TRUE; - BOOL do_tls = FALSE; /* Only set under ! DISABLE_TLS */ - blob reqstr; if (expand_forbid & RDO_READSOCK) { @@ -5304,218 +5294,80 @@ while (*s != 0) case 3: goto EXPAND_FAILED; } - /* Grab the request string, if any */ - - reqstr.data = sub_arg[1]; - reqstr.len = Ustrlen(sub_arg[1]); - - /* Sort out timeout, if given. The second arg is a list with the first element - being a time value. Any more are options of form "name=value". Currently the - only options recognised are "shutdown" and "tls". */ - - if (sub_arg[2]) - { - const uschar * list = sub_arg[2]; - uschar * item; - int sep = 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; - } - - while ((item = string_nextinlist(&list, &sep, NULL, 0))) - if (Ustrncmp(item, US"shutdown=", 9) == 0) - { if (Ustrcmp(item + 9, US"no") == 0) do_shutdown = FALSE; } -#ifndef DISABLE_TLS - else if (Ustrncmp(item, US"tls=", 4) == 0) - { if (Ustrcmp(item + 9, US"no") != 0) do_tls = TRUE; } -#endif - } - else - sub_arg[3] = NULL; /* No eol if no timeout */ - /* If skipping, we don't actually do anything. Otherwise, arrange to connect to either an IP or a Unix socket. */ if (!skipping) { - /* Handle an IP (internet) domain */ - - if (Ustrncmp(sub_arg[0], "inet:", 5) == 0) - { - int port; - uschar * port_name; - - server_name = sub_arg[0] + 5; - port_name = Ustrrchr(server_name, ':'); - - /* Sort out the port */ - - if (!port_name) - { - expand_string_message = - string_sprintf("missing port for readsocket %s", sub_arg[0]); - goto EXPAND_FAILED; - } - *port_name++ = 0; /* Terminate server name */ - - if (isdigit(*port_name)) - { - uschar *end; - port = Ustrtol(port_name, &end, 0); - if (end != port_name + Ustrlen(port_name)) - { - expand_string_message = - string_sprintf("invalid port number %s", port_name); - goto EXPAND_FAILED; - } - } - else - { - struct servent *service_info = getservbyname(CS port_name, "tcp"); - if (!service_info) - { - expand_string_message = string_sprintf("unknown port \"%s\"", - port_name); - goto EXPAND_FAILED; - } - port = ntohs(service_info->s_port); - } - - /*XXX we trust that the request is idempotent for TFO. Hmm. */ - cctx.sock = ip_connectedsocket(SOCK_STREAM, server_name, port, port, - timeout, &host, &expand_string_message, - do_tls ? NULL : &reqstr); - callout_address = NULL; - if (cctx.sock < 0) - goto SOCK_FAIL; - if (!do_tls) - reqstr.len = 0; - } - - /* Handle a Unix domain socket */ - - else - { - struct sockaddr_un sockun; /* don't call this "sun" ! */ - int rc; - - if ((cctx.sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) - { - expand_string_message = string_sprintf("failed to create socket: %s", - strerror(errno)); - goto SOCK_FAIL; - } - - sockun.sun_family = AF_UNIX; - sprintf(sockun.sun_path, "%.*s", (int)(sizeof(sockun.sun_path)-1), - sub_arg[0]); - server_name = US sockun.sun_path; - - sigalrm_seen = FALSE; - ALARM(timeout); - rc = connect(cctx.sock, (struct sockaddr *)(&sockun), sizeof(sockun)); - ALARM_CLR(0); - if (sigalrm_seen) - { - expand_string_message = US "socket connect timed out"; - goto SOCK_FAIL; - } - if (rc < 0) - { - expand_string_message = string_sprintf("failed to connect to socket " - "%s: %s", sub_arg[0], strerror(errno)); - goto SOCK_FAIL; - } - host.name = server_name; - host.address = US""; - } + int stype = search_findtype(US"readsock", 8); + gstring * g = NULL; + void * handle; + int expand_setup = -1; + uschar * s; - DEBUG(D_expand) debug_printf_indent("connected to socket %s\n", sub_arg[0]); + /* If the reqstr is empty, flag that and set a dummy */ -#ifndef DISABLE_TLS - if (do_tls) + if (!sub_arg[1][0]) { - smtp_connect_args conn_args = {.host = &host }; - tls_support tls_dummy = {.sni=NULL}; - uschar * errstr; - - if (!tls_client_start(&cctx, &conn_args, NULL, &tls_dummy, &errstr)) - { - expand_string_message = string_sprintf("TLS connect failed: %s", errstr); - goto SOCK_FAIL; - } + g = string_append_listele(g, ',', US"send=no"); + sub_arg[1] = US"DUMMY"; } -#endif - /* Allow sequencing of test actions */ - testharness_pause_ms(100); + /* Re-marshall the options */ - /* Write the request string, if not empty or already done */ - - if (reqstr.len) - { - DEBUG(D_expand) debug_printf_indent("writing \"%s\" to socket\n", - reqstr.data); - if ( ( -#ifndef DISABLE_TLS - do_tls ? tls_write(cctx.tls_ctx, reqstr.data, reqstr.len, FALSE) : -#endif - write(cctx.sock, reqstr.data, reqstr.len)) != reqstr.len) - { - expand_string_message = string_sprintf("request write to socket " - "failed: %s", strerror(errno)); - goto SOCK_FAIL; - } - } - - /* Shut down the sending side of the socket. This helps some servers to - recognise that it is their turn to do some work. Just in case some - system doesn't have this function, make it conditional. */ - -#ifdef SHUT_WR - if (!do_tls && do_shutdown) shutdown(cctx.sock, SHUT_WR); -#endif + if (sub_arg[2]) + { + const uschar * list = sub_arg[2]; + uschar * item; + int sep = 0; + + /* First option has no tag and is timeout */ + if ((item = string_nextinlist(&list, &sep, NULL, 0))) + g = string_append_listele(g, ',', + string_sprintf("timeout=%s", item)); + + /* The rest of the options from the expansion */ + while ((item = string_nextinlist(&list, &sep, NULL, 0))) + g = string_append_listele(g, ',', item); + + /* possibly plus an EOL string. Process with escapes, to protect + from list-processing. The only current user of eol= in search + options is the readsock expansion. */ + + if (sub_arg[3] && *sub_arg[3]) + g = string_append_listele(g, ',', + string_sprintf("eol=%s", + string_printing2(sub_arg[3], SP_TAB|SP_SPACE))); + } - testharness_pause_ms(100); + /* Gat a (possibly cached) handle for the connection */ - /* Now we need to read from the socket, under a timeout. The function - that reads a file can be used. */ + if (!(handle = search_open(sub_arg[0], stype, 0, NULL, NULL))) + { + if (*expand_string_message) goto EXPAND_FAILED; + expand_string_message = search_error_message; + search_error_message = NULL; + goto SOCK_FAIL; + } - if (!do_tls) - fp = fdopen(cctx.sock, "rb"); - sigalrm_seen = FALSE; - ALARM(timeout); - yield = -#ifndef DISABLE_TLS - do_tls ? cat_file_tls(cctx.tls_ctx, yield, sub_arg[3]) : -#endif - cat_file(fp, yield, sub_arg[3]); - ALARM_CLR(0); + /* Get (possibly cached) results for the lookup */ + /* sspec: sub_arg[0] req: sub_arg[1] opts: g */ -#ifndef DISABLE_TLS - if (do_tls) + if ((s = search_find(handle, sub_arg[0], sub_arg[1], -1, NULL, 0, 0, + &expand_setup, string_from_gstring(g)))) + yield = string_cat(yield, s); + else if (f.search_find_defer) { - tls_close(cctx.tls_ctx, TRUE); - close(cctx.sock); + expand_string_message = search_error_message; + search_error_message = NULL; + goto SOCK_FAIL; } else -#endif - (void)fclose(fp); - - /* After a timeout, we restore the pointer in the result, that is, - make sure we add nothing from the socket. */ - - if (sigalrm_seen) - { - if (yield) yield->ptr = save_ptr; - expand_string_message = US "socket read timed out"; - goto SOCK_FAIL; - } + { /* should not happen, at present */ + expand_string_message = search_error_message; + search_error_message = NULL; + goto SOCK_FAIL; + } } /* The whole thing has worked (or we were skipping). If there is a @@ -6334,11 +6186,12 @@ while (*s != 0) case 2: case 3: goto EXPAND_FAILED; } - for (uschar sep = *sub[0], c; c = *sub[1]; sub[1]++) + if (*sub[1]) 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); } + else yield = string_catn(yield, US" ", 1); continue; } @@ -6931,12 +6784,14 @@ while (*s != 0) continue; } -#ifdef EXPERIMENTAL_SRS_NATIVE +#ifdef SUPPORT_SRS case EITEM_SRS_ENCODE: /* ${srs_encode {secret} {return_path} {orig_domain}} */ { uschar * sub[3]; uschar cksum[4]; + gstring * g = NULL; + BOOL quoted = FALSE; switch (read_subs(sub, 3, 3, CUSS &s, skipping, TRUE, name, &resetok)) { @@ -6945,47 +6800,71 @@ while (*s != 0) case 3: goto EXPAND_FAILED; } - yield = string_catn(yield, US"SRS0=", 5); + g = string_catn(g, US"SRS0=", 5); /* ${l_4:${hmac{md5}{SRS_SECRET}{${lc:$return_path}}}}= */ hmac_md5(sub[0], string_copylc(sub[1]), cksum, sizeof(cksum)); - yield = string_catn(yield, cksum, sizeof(cksum)); - yield = string_catn(yield, US"=", 1); + g = string_catn(g, cksum, sizeof(cksum)); + g = string_catn(g, US"=", 1); /* ${base32:${eval:$tod_epoch/86400&0x3ff}}= */ { struct timeval now; unsigned long i; - gstring * g = NULL; + gstring * h = NULL; gettimeofday(&now, NULL); for (unsigned long i = (now.tv_sec / 86400) & 0x3ff; i; i >>= 5) - g = string_catn(g, &base32_chars[i & 0x1f], 1); - if (g) while (g->ptr > 0) - yield = string_catn(yield, &g->s[--g->ptr], 1); + h = string_catn(h, &base32_chars[i & 0x1f], 1); + if (h) while (h->ptr > 0) + g = string_catn(g, &h->s[--h->ptr], 1); } - yield = string_catn(yield, US"=", 1); + g = string_catn(g, US"=", 1); /* ${domain:$return_path}=${local_part:$return_path} */ { int start, end, domain; uschar * t = parse_extract_address(sub[1], &expand_string_message, &start, &end, &domain, FALSE); + uschar * s; + if (!t) goto EXPAND_FAILED; - if (domain > 0) yield = string_cat(yield, t + domain); - yield = string_catn(yield, US"=", 1); - yield = domain > 0 - ? string_catn(yield, t, domain - 1) : string_cat(yield, t); + if (domain > 0) g = string_cat(g, t + domain); + g = string_catn(g, US"=", 1); + + s = domain > 0 ? string_copyn(t, domain - 1) : t; + if ((quoted = Ustrchr(s, '"') != NULL)) + { + gstring * h = NULL; + DEBUG(D_expand) debug_printf_indent("auto-quoting local part\n"); + while (*s) /* de-quote */ + { + while (*s && *s != '"') h = string_catn(h, s++, 1); + if (*s) s++; + while (*s && *s != '"') h = string_catn(h, s++, 1); + if (*s) s++; + } + gstring_release_unused(h); + s = string_from_gstring(h); + } + g = string_cat(g, s); } + /* Assume that if the original local_part had quotes + it was for good reason */ + + if (quoted) yield = string_catn(yield, US"\"", 1); + yield = string_catn(yield, g->s, g->ptr); + if (quoted) yield = string_catn(yield, US"\"", 1); + /* @$original_domain */ yield = string_catn(yield, US"@", 1); yield = string_cat(yield, sub[2]); continue; } -#endif /*EXPERIMENTAL_SRS_NATIVE*/ +#endif /*SUPPORT_SRS*/ } /* EITEM_* switch */ /* Control reaches here if the name is not recognized as one of the more @@ -7354,9 +7233,8 @@ while (*s != 0) { int cnt = 0; int sep = 0; - uschar buffer[256]; - while (string_nextinlist(CUSS &sub, &sep, buffer, sizeof(buffer))) cnt++; + while (string_nextinlist(CUSS &sub, &sep, NULL, 0)) cnt++; yield = string_fmt_append(yield, "%d", cnt); continue; } @@ -7632,24 +7510,20 @@ while (*s != 0) uschar *t = sub - 1; if (c == EOP_QUOTE) - { - while (!needs_quote && *(++t) != 0) + while (!needs_quote && *++t) needs_quote = !isalnum(*t) && !strchr("_-.", *t); - } + else /* EOP_QUOTE_LOCAL_PART */ - { - while (!needs_quote && *(++t) != 0) - needs_quote = !isalnum(*t) && - strchr("!#$%&'*+-/=?^_`{|}~", *t) == NULL && - (*t != '.' || t == sub || t[1] == 0); - } + while (!needs_quote && *++t) + needs_quote = !isalnum(*t) + && strchr("!#$%&'*+-/=?^_`{|}~", *t) == NULL + && (*t != '.' || t == sub || !t[1]); if (needs_quote) { yield = string_catn(yield, US"\"", 1); t = sub - 1; - while (*(++t) != 0) - { + while (*++t) if (*t == '\n') yield = string_catn(yield, US"\\n", 2); else if (*t == '\r') @@ -7660,10 +7534,10 @@ while (*s != 0) yield = string_catn(yield, US"\\", 1); yield = string_catn(yield, t, 1); } - } yield = string_catn(yield, US"\"", 1); } - else yield = string_cat(yield, sub); + else + yield = string_cat(yield, sub); continue; } @@ -7718,13 +7592,10 @@ while (*s != 0) prescribed by the RFC, if there are characters that need to be encoded */ case EOP_RFC2047: - { - uschar buffer[2048]; yield = string_cat(yield, parse_quote_2047(sub, Ustrlen(sub), headers_charset, - buffer, sizeof(buffer), FALSE)); + FALSE)); continue; - } /* RFC 2047 decode */