[2023-08-28 11:53] Philipp <[email protected]>
> [2023-08-27 22:00] David Levine <[email protected]>
> > Philipp wrote:
> >
> > > [2023-08-27 09:29] David Levine <[email protected]>
> > > >
> > > > My only comment on the code itself is that I prefer functions that
> > > > just do one thing. So I would implement a fold function that just
> > > > modifies a string, and leave the fprintf/fwrite to output_headers().
> > >
> > > I have thought about this, but this would require fold() to allocate
> > > memory.
> > > Because the plan was to use fold() in output_headers() I though this could
> > > be avoided.
> >
> > I don't think that allocating memory is a drawback.
>
> I first wrote a long text about the missing string abstraction, then
> I found charstring_t. I'll adjust this a few days.
I have a version with charstring_t attached. I'm unsure if it's better
to only fold the body or include the field name. The version attached
only fold the body.
Philipp
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..d80cfe2d
--- /dev/null
+++ b/sbr/fold.c
@@ -0,0 +1,63 @@
+/* fold.c -- fold a mail header field
+ *
+ * This code is Copyright (c), 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..8d0fd6d7
--- /dev/null
+++ b/sbr/fold.h
@@ -0,0 +1,7 @@
+/* fold.h -- fold a mail header field
+ *
+ * This code is Copyright (c), 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 <[email protected]>
+To: Nobody <[email protected]>
+Subject: Test message
+References: <[email protected]> <[email protected]> <[email protected]>
+--------
+This is a test
+E
+
+cat > "$expected" <<\E
+From: Somebody <[email protected]>
+To: Nobody <[email protected]>
+Subject: Test message
+References: <[email protected]>
+ <[email protected]> <[email protected]>
+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 <[email protected]>
+To: Nobody <[email protected]>
+Subject: Test message
+References: <aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...@example.com> <aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...@example.com>
+--------
+This is a test
+E
+
+cat > "$expected" <<\E
+From: Somebody <[email protected]>
+To: Nobody <[email protected]>
+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);
}