[2023-09-17 21:51] David Levine <levin...@acm.org> > > A format-patch is attached. > > Thanks. I think that the commit message should note that only header field > bodies are folded. And because folding can only occur a > t whitespace, it is possible to end up with more than 78 bytes in a line. > How about this? > > mhbuild now folds header field bodies to avoid lines with more then 78 > bytes. > > This is required by RFC 5322 2.1.1. Line Length Limits. > > I'll add the first line of the commit message to docs/pending-release-notes. > And add the year to the copyright notice in fold.[hc].
Done, updated version is attached. Philipp
From 3157510d821db9bf62b051aeb1dcc94fac1dffcd Mon Sep 17 00:00:00 2001 From: Philipp Takacs <philipp+...@bureaucracy.de> Date: Fri, 25 Aug 2023 09:29:42 +0200 Subject: [PATCH] mhbuild implement header folding mhbuild now folds header field bodies to avoid lines with more then 78 bytes. This is required by RFC 5322 2.1.1. Line Length Limits. --- Makefile.am | 2 ++ sbr/fold.c | 63 +++++++++++++++++++++++++++++++++++++++ sbr/fold.h | 7 +++++ test/mhbuild/test-mhbuild | 53 ++++++++++++++++++++++++++++++++ uip/mhoutsbr.c | 7 ++++- 5 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 sbr/fold.c create mode 100644 sbr/fold.h diff --git a/Makefile.am b/Makefile.am index 4fc84c1d..168d9fe6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -378,6 +378,7 @@ noinst_HEADERS = \ sbr/fmt_new.h \ sbr/fmt_rfc2047.h \ sbr/fmt_scan.h \ + sbr/fold.h \ sbr/folder_addmsg.h \ sbr/folder_delmsgs.h \ sbr/folder_free.h \ @@ -1106,6 +1107,7 @@ sbr_libmh_a_SOURCES = \ sbr/fmt_new.c \ sbr/fmt_rfc2047.c \ sbr/fmt_scan.c \ + sbr/fold.c \ sbr/folder_addmsg.c \ sbr/folder_delmsgs.c \ sbr/folder_free.c \ diff --git a/sbr/fold.c b/sbr/fold.c new file mode 100644 index 00000000..f6047703 --- /dev/null +++ b/sbr/fold.c @@ -0,0 +1,63 @@ +/* fold.c -- fold a mail header field + * + * This code is Copyright (c) 2023, by the authors of nmh. See the + * COPYRIGHT file in the root directory of the nmh distribution for + * complete copyright information. */ + +#include "h/mh.h" +#include "h/mime.h" +#include "sbr/charstring.h" +#include "fold.h" + +void +fold(charstring_t dst, size_t namelen, const char *restrict body) +{ + const char *restrict body_next; + const char *restrict wsp; + const char *restrict wsp_next; + const bool crlf = strchr(body, '\r'); + charstring_clear(dst); + namelen++; + + while (*body) { + body_next = strchr(body, '\n'); + if ((unsigned long) (body_next - body) <= MAXTEXTPERLN - namelen) { + charstring_push_back_chars(dst, body, body_next - body + 1, body_next - body + 1); + namelen = 0; + body = body_next + 1; + continue; + } + wsp = body; + while (namelen == 0 && (*wsp == ' ' || *wsp == '\t')) { + wsp++; + } + wsp = wsp_next = strpbrk(wsp, " \t"); + + /* if now whitespace is in the current line just print the curret line as is */ + if (!wsp_next || wsp_next > body_next) { + charstring_push_back_chars(dst, body, body_next - body + 1, body_next - body + 1); + namelen = 0; + body = body_next + 1; + continue; + } + + while ((unsigned long)(wsp_next - body) <= MAXTEXTPERLN - namelen) { + wsp = wsp_next; + wsp_next = strpbrk(wsp+1, " \t"); + if (!wsp_next) { + break; + } + if (wsp_next > body_next) { + break; + } + } + + charstring_push_back_chars(dst, body, wsp - body, wsp - body); + if (crlf) { + charstring_push_back(dst, '\r'); + } + charstring_push_back(dst, '\n'); + namelen = 0; + body = wsp; + } +} diff --git a/sbr/fold.h b/sbr/fold.h new file mode 100644 index 00000000..40bf6a49 --- /dev/null +++ b/sbr/fold.h @@ -0,0 +1,7 @@ +/* fold.h -- fold a mail header field + * + * This code is Copyright (c) 2023, by the authors of nmh. See the + * COPYRIGHT file in the root directory of the nmh distribution for + * complete copyright information. */ + +void fold(charstring_t dst, size_t namelen, const char *restrict body); diff --git a/test/mhbuild/test-mhbuild b/test/mhbuild/test-mhbuild index 706a804a..f8d4992b 100755 --- a/test/mhbuild/test-mhbuild +++ b/test/mhbuild/test-mhbuild @@ -221,5 +221,58 @@ run_test "mhbuild $f" \ check "$f" "$expected" +start_test "Checking for correct header folding" + +cat >"`mhpath new`" <<\E +From: Somebody <someb...@example.com> +To: Nobody <nob...@example.com> +Subject: Test message +References: <aaaaaaaaaaaaaaaaaaaaaaaa...@example.com> <aaaaaaaaaaaaaaaaaaaaaaaa...@example.com> <c...@example.com> +-------- +This is a test +E + +cat > "$expected" <<\E +From: Somebody <someb...@example.com> +To: Nobody <nob...@example.com> +Subject: Test message +References: <aaaaaaaaaaaaaaaaaaaaaaaa...@example.com> + <aaaaaaaaaaaaaaaaaaaaaaaa...@example.com> <c...@example.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="us-ascii" + +This is a test +E + +run_test "mhbuild -auto `mhpath last`" +check "`mhpath last`" "$expected" + +start_test "Checking header folding with a to long line" + +cat >"`mhpath new`" <<\E +From: Somebody <someb...@example.com> +To: Nobody <nob...@example.com> +Subject: Test message +References: <aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...@example.com> <aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...@example.com> +-------- +This is a test +E + +cat > "$expected" <<\E +From: Somebody <someb...@example.com> +To: Nobody <nob...@example.com> +Subject: Test message +References: + <aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...@example.com> + <aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...@example.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="us-ascii" + +This is a test +E + +run_test "mhbuild -auto `mhpath last`" +check "`mhpath last`" "$expected" + finish_test exit $failed diff --git a/uip/mhoutsbr.c b/uip/mhoutsbr.c index 6033cad8..6f80bafc 100644 --- a/uip/mhoutsbr.c +++ b/uip/mhoutsbr.c @@ -17,6 +17,8 @@ #include "h/mhparse.h" #include "mhoutsbr.h" #include "sbr/base64.h" +#include "sbr/charstring.h" +#include "sbr/fold.h" /* @@ -199,12 +201,15 @@ static void output_headers (CT ct, FILE *out) { HF hp; + charstring_t body = charstring_create(0); hp = ct->c_first_hf; while (hp) { - fprintf (out, "%s:%s", hp->name, hp->value); + fold (body, strlen(hp->name), hp->value); + fprintf (out, "%s:%s", hp->name, charstring_buffer(body)); hp = hp->next; } + charstring_free(body); } -- 2.39.2