X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fsrc%2Fheader.c;h=e2b3d8a9c2c9f92d0c5f69efe1682adc5704313d;hb=a6d90e094d4e2a84d18859cf2005d10c2020e2d4;hp=cbfc4f847e5a5ce28062f912e2d514c5b88074dc;hpb=5fcc791a74a6f6933b3fb03f36e9ea3553152cf7;p=user%2Fhenk%2Fcode%2Fexim.git diff --git a/src/src/header.c b/src/src/header.c index cbfc4f847..e2b3d8a9c 100644 --- a/src/src/header.c +++ b/src/src/header.c @@ -2,8 +2,10 @@ * Exim - an Internet mail transport agent * *************************************************/ +/* Copyright (c) The Exim Maintainers 2020 - 2023 */ /* Copyright (c) University of Cambridge 1995 - 2016 */ /* See the file NOTICE for conditions of use and distribution. */ +/* SPDX-License-Identifier: GPL-2.0-or-later */ #include "exim.h" @@ -96,12 +98,15 @@ header_add_backend(BOOL after, uschar *name, BOOL topnot, int type, header_line *h, *new = NULL; header_line **hptr; -uschar *p, *q; -uschar * buf = store_get(HEADER_ADD_BUFFER_SIZE, FALSE); -gstring gs = { .size = HEADER_ADD_BUFFER_SIZE, .ptr = 0, .s = buf }; +uschar * p, * q, * buf; +gstring gs; if (!header_last) return NULL; +gs.s = buf = store_get(HEADER_ADD_BUFFER_SIZE, GET_UNTAINTED); +gs.size = HEADER_ADD_BUFFER_SIZE; +gs.ptr = 0; + if (!string_vformat(&gs, SVFMT_REBUFFER, format, ap)) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "string too long in header_add: " "%.100s ...", string_from_gstring(&gs)); @@ -178,7 +183,7 @@ for (p = q = gs.s; *p; p = q) if (*(++q) != ' ' && *q != '\t') break; } - new = store_get(sizeof(header_line), FALSE); + new = store_get(sizeof(header_line), GET_UNTAINTED); new->text = string_copyn(p, q - p); new->slen = q - p; new->type = type; @@ -321,9 +326,8 @@ while (bot < top) if (c == 0) { - uschar *s = text + mid->len; - while (isspace(*s)) s++; - if (*s == ':') + uschar * s = text + mid->len; + if (Uskip_whitespace(&s) == ':') return (!is_resent || mid->allow_resent)? mid->htype : htype_other; c = 1; } @@ -365,15 +369,15 @@ Returns: cond if the header exists and contains one of the strings; /* First we have a local subroutine to handle a single pattern */ static BOOL -one_pattern_match(uschar *name, int slen, BOOL has_addresses, uschar *pattern) +one_pattern_match(uschar * name, int slen, BOOL has_addresses, uschar * pattern) { BOOL yield = FALSE; -const pcre *re = NULL; +const pcre2_code *re = NULL; /* If the pattern is a regex, compile it. Bomb out if compiling fails; these patterns are all constructed internally and should be valid. */ -if (*pattern == '^') re = regex_must_compile(pattern, TRUE, FALSE); +if (*pattern == '^') re = regex_must_compile(pattern, MCS_CASELESS, FALSE); /* Scan for the required header(s) and scan each one */ @@ -416,10 +420,9 @@ for (header_line * h = header_list; !yield && h; h = h->next) /* Otherwise, test for the pattern; a non-regex must be an exact match */ - yield = !re - ? (strcmpic(next, pattern) == 0) - : (pcre_exec(re, NULL, CS next, Ustrlen(next), 0, PCRE_EOPT, NULL, 0) - >= 0); + yield = re + ? regex_match(re, next, -1, NULL) + : (strcmpic(next, pattern) == 0); } } @@ -428,10 +431,9 @@ for (header_line * h = header_list; !yield && h; h = h->next) else { - yield = (re == NULL)? - (strstric(h->text, pattern, FALSE) != NULL) - : - (pcre_exec(re, NULL, CS h->text, h->slen, 0, PCRE_EOPT, NULL, 0) >= 0); + yield = re + ? regex_match(re, h->text, h->slen, NULL) + : (strstric(h->text, pattern, FALSE) != NULL); } } @@ -442,7 +444,7 @@ return yield; /* The externally visible interface */ BOOL -header_match(uschar *name, BOOL has_addresses, BOOL cond, string_item *strings, +header_match(uschar * name, BOOL has_addresses, BOOL cond, string_item * strings, int count, ...) { va_list ap; @@ -464,4 +466,85 @@ va_end(ap); return !cond; } + + +/* Wrap and truncate a string for use as a header. +Convert either the sequence "\n" or a real newline into newline plus indent. +If that still takes us past the column limit, look for the last space +and split there too. +Limit to the given max total char count. + +Return: string or NULL */ + +uschar * +wrap_header(const uschar * s, unsigned cols, unsigned maxchars, + const uschar * indent, unsigned indent_cols) +{ +gstring * g = NULL; + +if (maxchars == 0) maxchars = INT_MAX; +if (cols == 0) cols = INT_MAX; + +if (s && *s) + { + int sleft = Ustrlen(s); + for(unsigned llen = 0; ; llen = indent_cols) + { + const uschar * t; + unsigned ltail = 0, glen; + + if ((t = Ustrchr(s, '\\')) && t[1] == 'n') + ltail = 2; + else if ((t = Ustrchr(s, '\n'))) + ltail = 1; + else + t = s + sleft; + + if ((llen + t - s) > cols) /* more than a linesworth of s */ + { /* look backward for whitespace */ + for (const uschar * u = s + cols - llen; u > s + 10; --u) if (isspace(*u)) + { + llen = u - s; + while (u > s+1 && isspace(u[-1])) --u; /* find start of whitespace */ + g = string_catn(g, s, u - s); + s += ++llen; /* skip the space */ + while (*s && isspace(*s)) /* and any trailing */ + s++, llen++; + goto LDONE; + } + /* no whitespace */ + if (llen < cols) + { /* just linebreak at 80 */ + llen = cols - llen; + g = string_catn(g, s, llen); + s += llen; + } + else + llen = 0; + LDONE: + } + else /* rest of s fits in line */ + { + llen = t - s; + g = string_catn(g, s, llen); + s = t + ltail; + } + + if (!*s) + break; /* no trailing linebreak */ + if ((glen = gstring_length(g)) >= maxchars) + { + gstring_trim(g, glen - maxchars); + break; /* no trailing linebreak */ + } + sleft -= llen; + g = string_catn(g, US"\n", 1); + g = string_catn(g, indent, 1); + } + } +gstring_release_unused(g); +return string_from_gstring(g); +} + + /* End of header.c */