summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJeremy Harris <jgh146exb@wizmail.org>2023-03-11 17:48:28 +0000
committerJeremy Harris <jgh146exb@wizmail.org>2023-03-11 17:49:54 +0000
commita6d90e094d4e2a84d18859cf2005d10c2020e2d4 (patch)
treeedd8c087315fbc59f8c05c9e6a1f7c585958401a /src
parentca8410e981982edd16bcc8689e09c2c15d8267e7 (diff)
downloadexim4-a6d90e094d4e2a84d18859cf2005d10c2020e2d4.tar.gz
Header-wrap expansion. Bug 2843
Diffstat (limited to 'src')
-rw-r--r--src/src/deliver.c67
-rw-r--r--src/src/expand.c31
-rw-r--r--src/src/functions.h3
-rw-r--r--src/src/header.c83
4 files changed, 118 insertions, 66 deletions
diff --git a/src/src/deliver.c b/src/src/deliver.c
index 9b77b3619..e2994b116 100644
--- a/src/src/deliver.c
+++ b/src/src/deliver.c
@@ -2,7 +2,7 @@
* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) The Exim Maintainers 2020 - 2022 */
+/* Copyright (c) The Exim Maintainers 2020 - 2023 */
/* Copyright (c) University of Cambridge 1995 - 2018 */
/* See the file NOTICE for conditions of use and distribution. */
/* SPDX-License-Identifier: GPL-2.0-or-later */
@@ -5566,69 +5566,14 @@ Limit to about 1024 chars total. */
static void
dsn_put_wrapped(FILE * fp, const uschar * header, const uschar * s)
{
-const uschar * t;
-int llen = fprintf(fp, "%s", CS header), sleft = Ustrlen(s);
-int remain = 1022 - llen;
+gstring * g = string_cat(NULL, header);
-if (*s && remain > 0)
- {
- for(;;)
- {
- unsigned ltail; /* source chars to skip */
-
- /* Chop at a newline, or end of string */
-
- if ((t = Ustrchr(s, '\\')) && t[1] == 'n')
- ltail = 2;
- else if ((t = Ustrchr(s, '\n')))
- ltail = 1;
- else
- {
- t = s + sleft;
- ltail = 0;
- }
-
- /* If that is too long, search backward for a space */
-
- if ((llen + t - s) > 78)
- {
- const uschar * u;
- for (u = s + 78 - llen; u > s + 10; --u) if (*u == ' ') break;
- if (u > s + 10)
- { /* found a space to linebreak at */
- llen = u - s;
- remain -= fprintf(fp, "%.*s", (int)llen, s);
- s += ++llen; /* skip the space also */
- }
- else if (llen < 78)
- { /* just linebreak at 78 */
- llen = 78 - llen;
- remain -= fprintf(fp, "%.*s", llen, s);
- s += llen;
- }
- else /* header rather long */
- llen = 0;
- }
- else
- {
- llen = t - s;
- remain -= fprintf(fp, "%.*s", llen, s);
- s = t + ltail;
- }
+g = string_cat(g, s);
+gstring_release_unused(g);
+fprintf(fp, "%s\n", wrap_header(string_from_gstring(g), 79, 1023, US" ", 1));
+}
- sleft -= llen;
- remain -= 2;
- if (!*s || remain <= 0)
- break;
- fputs("\n ", fp);
- llen = 1; /* one for the leading space output above */
- }
- if (s[-1] != '\n') fputs("\n", fp);
- }
-else
- fputs("\n", fp);
-}
/*************************************************
diff --git a/src/src/expand.c b/src/src/expand.c
index baf7134cd..6dcd45062 100644
--- a/src/src/expand.c
+++ b/src/src/expand.c
@@ -2,7 +2,7 @@
* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) The Exim Maintainers 2020 - 2022 */
+/* Copyright (c) The Exim Maintainers 2020 - 2023 */
/* Copyright (c) University of Cambridge 1995 - 2018 */
/* See the file NOTICE for conditions of use and distribution. */
/* SPDX-License-Identifier: GPL-2.0-or-later */
@@ -237,6 +237,7 @@ static uschar *op_table_main[] = {
US"expand",
US"h",
US"hash",
+ US"headerwrap",
US"hex2b64",
US"hexquote",
US"ipv6denorm",
@@ -284,6 +285,7 @@ enum {
EOP_EXPAND,
EOP_H,
EOP_HASH,
+ EOP_HEADERWRAP,
EOP_HEX2B64,
EOP_HEXQUOTE,
EOP_IPV6DENORM,
@@ -7262,7 +7264,7 @@ NOT_ITEM: ;
{
uschar *t;
unsigned long int n = Ustrtoul(sub, &t, 10);
- if (*t != 0)
+ if (*t)
{
expand_string_message = string_sprintf("argument for base62 "
"operator is \"%s\", which is not a decimal number", sub);
@@ -7278,7 +7280,7 @@ NOT_ITEM: ;
{
uschar *tt = sub;
unsigned long int n = 0;
- while (*tt != 0)
+ while (*tt)
{
uschar *t = Ustrchr(base62_chars, *tt++);
if (!t)
@@ -7428,6 +7430,29 @@ NOT_ITEM: ;
goto EXPAND_FAILED;
#endif
+ /* Line-wrap a string as if it is a header line */
+
+ case EOP_HEADERWRAP:
+ {
+ unsigned col = 80, lim = 998;
+ uschar * s;
+
+ if (arg)
+ {
+ const uschar * list = arg;
+ int sep = '_';
+ if ((s = string_nextinlist(&list, &sep, NULL, 0)))
+ {
+ col = atoi(CS s);
+ if ((s = string_nextinlist(&list, &sep, NULL, 0)))
+ lim = atoi(CS s);
+ }
+ }
+ if ((s = wrap_header(sub, col, lim, US"\t", 8)))
+ yield = string_cat(yield, s);
+ }
+ break;
+
/* Convert hex encoding to base64 encoding */
case EOP_HEX2B64:
diff --git a/src/src/functions.h b/src/src/functions.h
index 37f0a57bc..5fbb426ec 100644
--- a/src/src/functions.h
+++ b/src/src/functions.h
@@ -2,7 +2,7 @@
* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) The Exim Maintainers 2020 - 2022 */
+/* Copyright (c) The Exim Maintainers 2020 - 2023 */
/* Copyright (c) University of Cambridge 1995 - 2018 */
/* See the file NOTICE for conditions of use and distribution. */
/* SPDX-License-Identifier: GPL-2.0-or-later */
@@ -678,6 +678,7 @@ extern void version_init(void);
extern BOOL write_chunk(transport_ctx *, uschar *, int);
extern ssize_t write_to_fd_buf(int, const uschar *, size_t);
+extern uschar *wrap_header(const uschar *, unsigned, unsigned, const uschar *, unsigned);
/******************************************************************************/
diff --git a/src/src/header.c b/src/src/header.c
index a4dd6e72e..e2b3d8a9c 100644
--- a/src/src/header.c
+++ b/src/src/header.c
@@ -2,7 +2,7 @@
* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) The Exim Maintainers 2020 - 2022 */
+/* 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 */
@@ -466,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 */