mhl and mhbuild ignore to long lines master
authorPhilipp Takacs <philipp@bureaucracy.de>
Sun, 17 Sep 2023 16:35:35 +0000 (18:35 +0200)
committerPhilipp Takacs <philipp@bureaucracy.de>
Sun, 24 Sep 2023 22:03:28 +0000 (00:03 +0200)
14 files changed:
h/charstring.h [new file with mode: 0644]
h/mh.h
h/prototypes.h
sbr/Makefile.in
sbr/charstring.c [new file with mode: 0644]
sbr/fold.c [new file with mode: 0644]
sbr/getthreadid.c
test/tests/mhbuild/test-folding [new file with mode: 0644]
test/tests/show/test-longlines
uip/mhbuild.c
uip/mhl.c
uip/mhoutsbr.c
uip/send.c
uip/spost.c

diff --git a/h/charstring.h b/h/charstring.h
new file mode 100644 (file)
index 0000000..b2a4fed
--- /dev/null
@@ -0,0 +1,34 @@
+/* charstring.h -- dynamically-sized char array that can report size
+ *               in both characters and bytes
+ *
+ * This code is Copyright (c) 2017, by the authors of nmh.  See the
+ * COPYRIGHT file in the root directory of the nmh distribution for
+ * complete copyright information. */
+
+/*
+ * char array that keeps track of size in both bytes and characters
+ * Usage note:
+ *    Don't store return value of charstring_buffer() and use later
+ *    after intervening push_back's; use charstring_buffer_copy()
+ *    instead.
+ */
+
+typedef struct charstring *charstring_t;
+
+charstring_t charstring_create(size_t);
+charstring_t charstring_copy(const charstring_t) NONNULL(1);
+void charstring_free(charstring_t);
+/* Append a single-byte character: */
+void charstring_push_back(charstring_t, const char) NONNULL(1);
+/* Append possibly multi-byte character(s): */
+void charstring_push_back_chars(charstring_t, const char [], size_t) NONNULL(1);
+void charstring_append(charstring_t, const charstring_t) NONNULL(2);
+void charstring_append_cstring(charstring_t, const char []) NONNULL(2);
+void charstring_clear(charstring_t) NONNULL(1);
+/* Don't store return value of charstring_buffer() and use later after
+   intervening push_back's; use charstring_buffer_copy() instead. */
+const char *charstring_buffer(const charstring_t) NONNULL(1);
+/* User is responsible for free'ing result of buffer copy. */
+char *charstring_buffer_copy(const charstring_t) NONNULL(1);
+size_t charstring_bytes(const charstring_t) NONNULL(1) PURE;
+size_t charstring_chars(const charstring_t) NONNULL(1) PURE;
diff --git a/h/mh.h b/h/mh.h
index 649582d..280249e 100644 (file)
--- a/h/mh.h
+++ b/h/mh.h
@@ -38,8 +38,26 @@ typedef unsigned char  boolean;  /* not int so we can pack in a structure */
 */
 #if __GNUC__ > 2
 # define NORETURN __attribute__((__noreturn__))
+# define CONST __attribute__((const))
+# define MALLOC __attribute__((malloc))
+# define NONNULL(...) __attribute__((nonnull(__VA_ARGS__)))
+# define PURE __attribute__((pure))
+# define ENDNULL __attribute__((sentinel))
 #else
 # define NORETURN
+# define CONST
+# define MALLOC
+# define NONNULL(...)
+# define PURE
+# define ENDNULL
+#endif
+
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
+# define ALLOC_SIZE(...) __attribute__((alloc_size(__VA_ARGS__)))
+# define CHECK_PRINTF(fmt, arg) __attribute__((format(printf, fmt, arg)))
+#else
+# define ALLOC_SIZE(...)
+# define CHECK_PRINTF(fmt, arg)
 #endif
 
 /*
@@ -203,6 +221,8 @@ struct msgs {
                            ** terminating NULL.
                            */
 
+#define MAXTEXTPERLN 78
+
 /* m_getfld2() returned data */
 struct field {
        char name[NAMESZ];
@@ -308,4 +328,5 @@ extern char *version;
 extern char *lib_version;
 extern char *whatnowproc;
 
+#include <h/charstring.h>
 #include <h/prototypes.h>
index fad1af4..182cf1c 100644 (file)
@@ -114,6 +114,7 @@ void unquote_string(const char *input, char *output);
 int uprf(char *, char *);
 int vfgets(FILE *, char **);
 char *write_charset_8bit(void);
+void fold(charstring_t, size_t, const char *restrict);
 
 
 
index 142a7f2..ca8b20d 100644 (file)
@@ -52,8 +52,10 @@ SRCS = addrsbr.c ambigsw.c brkstring.c  \
        context_find.c context_read.c  \
        context_replace.c context_save.c \
        cpydata.c crawl_folders.c  \
+       charstring.c \
        dtime.c dtimep.c  \
-       error.c execprog.c ext_hook.c folder_addmsg.c folder_delmsgs.c  \
+       error.c execprog.c ext_hook.c fold.c  \
+       folder_addmsg.c folder_delmsgs.c  \
        folder_free.c folder_read.c  \
        folder_realloc.c gans.c getans.c getanswer.c  \
        getarguments.c \
diff --git a/sbr/charstring.c b/sbr/charstring.c
new file mode 100644 (file)
index 0000000..ff311f1
--- /dev/null
@@ -0,0 +1,154 @@
+/* charstring.c -- dynamically-sized char array that can report size
+ *                        in both characters and bytes
+ *
+ * This code is Copyright (c) 2014, 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/utils.h>
+
+#define CHARSTRING_DEFAULT_SIZE 64
+
+struct charstring {
+       char *buffer;  /* the char array, not always null-terminated */
+       size_t max;    /* current size of the char array, in bytes */
+       char *cur;     /* size in bytes = cur - buffer, without trailing null */
+};
+
+
+static void
+charstring_reserve(charstring_t s, size_t need)
+{
+       const size_t cur = s->cur - s->buffer;
+
+       while (need >= s->max - cur) {
+               /* Insufficient capacity, so double it. */
+               s->buffer = mh_xrealloc(s->buffer, s->max *= 2);
+               s->cur = s->buffer + cur;
+       }
+}
+
+/*
+ * max is in characters
+ */
+charstring_t
+charstring_create(size_t max)
+{
+       charstring_t s = mh_xcalloc(1, sizeof(*s));
+
+       s->max = max ? max : CHARSTRING_DEFAULT_SIZE;
+       s->cur = s->buffer = mh_xcalloc(s->max, 1);
+
+       return s;
+}
+
+charstring_t
+charstring_copy(const charstring_t src)
+{
+       const size_t num = src->cur - src->buffer;
+       charstring_t s = mh_xcalloc(1, sizeof(*s));
+
+       s->max = src->max;
+       s->buffer = mh_xcalloc(s->max, 1);
+       memcpy(s->buffer, src->buffer, num);
+       s->cur = s->buffer + num;
+
+       return s;
+}
+
+/*
+ * OK to call charstring_free with a NULL argument.
+ */
+void
+charstring_free(charstring_t s)
+{
+       if (s) {
+               free(s->buffer);
+               free(s);
+       }
+}
+
+void
+charstring_push_back(charstring_t s, const char c)
+{
+       charstring_reserve(s, s->cur - s->buffer + 1);
+       *s->cur++ = c;
+}
+
+/*
+ * num is the number of bytes in c
+ */
+void
+charstring_push_back_chars(charstring_t s, const char c[], size_t num)
+{
+       charstring_reserve(s, s->cur - s->buffer + num);
+       memcpy(s->cur, c, num);
+       s->cur += num;
+}
+
+void
+charstring_append(charstring_t dest, const charstring_t src)
+{
+       const size_t num = src->cur - src->buffer;
+
+       if (num > 0) {
+               charstring_reserve(dest, dest->cur - dest->buffer + num);
+               memcpy(dest->cur, src->buffer, num);
+               dest->cur += num;
+       }
+}
+
+void
+charstring_append_cstring(charstring_t dest, const char src[])
+{
+       const size_t num = strlen(src);
+
+       if (num > 0) {
+               charstring_reserve(dest, dest->cur - dest->buffer + num);
+               memcpy(dest->cur, src, num);  /* Exclude src's trailing NUL. */
+               dest->cur += num;
+       }
+}
+
+void
+charstring_clear(charstring_t s)
+{
+       s->cur = s->buffer;
+}
+
+/*
+ * Don't store return value of charstring_buffer() and use later after
+ * intervening push_back's; use charstring_buffer_copy() instead.
+ */
+const char *
+charstring_buffer(const charstring_t s)
+{
+       charstring_reserve(s, s->cur - s->buffer + 1);
+
+       /* This is the only place that we null-terminate the buffer. */
+       *s->cur = '\0';
+       /* Don't increment cur so that more can be appended later, and so
+          that charstring_bytes() behaves as strlen() by not counting the
+          null. */
+
+       return s->buffer;
+}
+
+char *
+charstring_buffer_copy(const charstring_t s)
+{
+       char *copy = mh_xcalloc(s->cur - s->buffer + 1, 1);
+
+       /* Use charstring_buffer() to null terminate the buffer. */
+       memcpy(copy, charstring_buffer(s), s->cur - s->buffer + 1);
+
+       return copy;
+}
+
+size_t
+charstring_bytes(const charstring_t s)
+{
+       return s->cur - s->buffer;
+}
diff --git a/sbr/fold.c b/sbr/fold.c
new file mode 100644 (file)
index 0000000..0189382
--- /dev/null
@@ -0,0 +1,61 @@
+/* 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 <stdio.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 int crlf = strchr(body, '\r') != NULL;
+       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);
+                       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);
+                       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);
+               if (crlf) {
+                       charstring_push_back(dst, '\r');
+               }
+               charstring_push_back(dst, '\n');
+               namelen = 0;
+               body = wsp;
+       }
+}
index a1ad7a0..abac78d 100644 (file)
@@ -54,8 +54,11 @@ threadid(char *msgid, char *referens)
        }
 
        start = strchr(threadfrom, '<');
+       if (!start) {
+               return NULL;
+       }
        end = strchr(start, '>');
-       if (!(*start) || !(*end)) {
+       if (!end) {
                return NULL;
        }
        *end = '\0';
diff --git a/test/tests/mhbuild/test-folding b/test/tests/mhbuild/test-folding
new file mode 100644 (file)
index 0000000..366f82b
--- /dev/null
@@ -0,0 +1,35 @@
+# test mhbuild linebreak for quoted-printable
+
+. "$MH_TEST_COMMON"
+
+
+draft="$MH_TEST_DIR/mhbuild-$$.draft"
+
+cat >"$draft" <<!
+From: meillo
+To: meillo
+Date: Thursday, 28 Sep 2006 00:02:00
+Subject: mhbuild header folding
+References: <aaaaaaaaaaaaaaaaaaaaaaaaaaa@example.com> <aaaaaaaaaaaaaaaaaaaaaaaaaab@example.com> <c@example.com>
+----------------
+Das ist ein test
+!
+
+
+
+runandcheck 'mhbuild "$draft"' <<!
+!
+
+runandcheck 'sed "/^Content-ID:/s/:.*/: <TESTID>/" "$draft"' <<!
+From: meillo
+To: meillo
+Date: Thursday, 28 Sep 2006 00:02:00
+Subject: mhbuild header folding
+References: <aaaaaaaaaaaaaaaaaaaaaaaaaaa@example.com>
+ <aaaaaaaaaaaaaaaaaaaaaaaaaab@example.com> <c@example.com>
+MIME-Version: 1.0
+Content-Type: text/plain; charset="us-ascii"
+Content-ID: <TESTID>
+
+Das ist ein test
+!
index f6ae126..54e8616 100644 (file)
@@ -105,7 +105,11 @@ EOF
 
 # check it
 cat > $expected <<-EOF
-mhl: format error in message 13
+Date:    Sun, 15 Jul 2018 12:26:59 +0200
+From:    foo@example.edu
+To:      bar@example.edu
+Subject: 999 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+
 part       text/plain                   4
 foo
 EOF
@@ -163,7 +167,11 @@ EOF
 
 # check it
 cat > $expected <<-EOF
-mhl: format error in message 15
+Date:    Sun, 15 Jul 2018 12:26:59 +0200
+From:    foo@example.edu
+To:      bar@example.edu
+Subject: 999 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+
 part       text/plain                   4
 foo
 EOF
index a233c68..f9674a3 100644 (file)
@@ -51,7 +51,7 @@ char *version=VERSION;
 ** Directory to place tmp files.  This must
 ** be set before these routines are called.
 */
-char *tmp;
+extern char *tmp;
 
 pid_t xpid = 0;
 
@@ -350,6 +350,8 @@ build_mime(char *infile)
        */
        for (compnum = 1, state = FLD2;;) {
                switch (state = m_getfld2(state, &f, in)) {
+               case LENERR2:
+                       state = FLD2;
                case FLD2:
                        compnum++;
 
@@ -384,7 +386,6 @@ build_mime(char *infile)
                        adios(EX_CONFIG, NULL, "draft has empty body -- no directives!");
                        /* NOTREACHED */
 
-               case LENERR2:
                case FMTERR2:
                case IOERR2:
                        adios(EX_CONFIG, NULL, "message format error in component #%d",
index fa83602..dd77f5b 100644 (file)
--- a/uip/mhl.c
+++ b/uip/mhl.c
@@ -654,6 +654,8 @@ mhlfile(FILE *fp, char *mname, int ofilen, int ofilec)
 
        for (state = FLD2; !eflag; ) {
                switch (state = m_getfld2(state, &f, fp)) {
+               case LENERR2:
+                       state = FLD2;
                case FLD2:
                        for (ip = ignores; *ip; ip++)
                                if (simplematch(*ip, f.name)) {
@@ -729,7 +731,6 @@ mhlfile(FILE *fp, char *mname, int ofilen, int ofilec)
                        }
                        return;
 
-               case LENERR2:
                case FMTERR2:
                case IOERR2:
                        advise(NULL, "format error in message %s", mname);
index 87e7943..2915afe 100644 (file)
@@ -161,12 +161,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);
 }
 
 
index 148c05b..1df2fa9 100644 (file)
@@ -39,8 +39,6 @@ char *distfile = NULL;
 static char body_file_name[MAXPATHLEN + 1];
 /* name of mhbuild composition temporary file */
 static char composition_file_name[MAXPATHLEN + 1]; 
-static int field_size;  /* size of header field buffer */
-static char *field;  /* header field buffer */
 static FILE *draft_file;  /* draft file pointer */
 static FILE *body_file;  /* body file pointer */
 static FILE *composition_file;  /* composition file pointer */
@@ -54,7 +52,6 @@ static int sendaux(char **, int, char *, struct stat *);
 static int attach(char *);
 static int signandenc(char *);
 static void clean_up_temporary_files(void);
-static int get_line(void);
 static void make_mime_composition_file_entry(char *);
 static char* strexit(int status);
 
@@ -331,9 +328,12 @@ sendsbr(char **vec, int vecp, char *drft, struct stat *st)
 static int
 attach(char *draft_file_name)
 {
+       enum state state;
+       struct field f = {{0}};
+       int compnum;
+       int finished_header = 0;
        char buf[MAXPATHLEN + 6];
-       int c;
-       int length = strlen(attach_hdr);
+       size_t length = strlen(attach_hdr);
        char *p;
 
        if(distfile) {
@@ -344,9 +344,6 @@ attach(char *draft_file_name)
                adios(EX_IOERR, NULL, "can't open draft file `%s'.", draft_file_name);
        }
 
-       /* We'll grow the buffer as needed. */
-       field = mh_xcalloc(field_size = 256, sizeof(char));
-
        /*
        ** MIMEify
        */
@@ -369,28 +366,42 @@ attach(char *draft_file_name)
 
        /* Copy non-attachment header fields to the temp composition file. */
        rewind(draft_file);
-       while (get_line() != EOF && *field && *field != '-') {
-               if (strncasecmp(field, VRSN_FIELD, strlen(VRSN_FIELD))==0 &&
-                               field[strlen(VRSN_FIELD)] == ':') {
-                       /*
-                       ** The draft is already in MIME format, thus
-                       ** back out and use the original draft file.
-                       */
-                       clean_up_temporary_files();
-                       return DONE;
-               }
-
-               if (strncasecmp(field, attach_hdr, length) != 0 ||
-                               field[length] != ':') {
-                       fprintf(composition_file, "%s\n", field);
+       for (compnum = 1, state = FLD2; state == FLD2 || state == BODY2;) {
+               switch (state = m_getfld2(state, &f, draft_file)) {
+               case LENERR2:
+                       state = FLD2;
+               case FLD2:
+                       compnum++;
+                       if (strncasecmp(f.name, VRSN_FIELD, sizeof(VRSN_FIELD) - 1)==0) {
+                               /*
+                               ** The draft is already in MIME format, thus
+                               ** back out and use the original draft file.
+                               */
+                               clean_up_temporary_files();
+                               return DONE;
+                       }
+                       if (strncasecmp(f.name, attach_hdr, length) != 0 ||
+                                       f.namelen != length) {
+                               fprintf(composition_file, "%s:%s", f.name, f.value);
+                       }
+                       break;
+               case BODY2:
+                       if (!finished_header) {
+                               fputs("--------\n", composition_file);
+                               finished_header++;
+                       }
+                       fputs(f.value, body_file);
+                       break;
+               case FILEEOF2:
+                       break;
+               case FMTERR2:
+                       adios(EX_DATAERR, NULL, "message format error in component #%d", compnum);
+               case IOERR2:
+                       adios(EX_IOERR, NULL, "error reading draft file: %s", draft_file_name);
+               default:
+                       adios(EX_SOFTWARE, NULL, "getfld() returned %d", state);
                }
        }
-       fputs("--------\n", composition_file);
-
-       /* Copy the message body to the temporary file. */
-       while ((c = getc(draft_file)) != EOF) {
-               putc(c, body_file);
-       }
        fclose(body_file);
 
        /* Add a mhbuild MIME composition file line for the body */
@@ -403,17 +414,33 @@ attach(char *draft_file_name)
        ** composition file for each.
        */
        rewind(draft_file);
-       while (get_line() != EOF && *field && *field != '-') {
-               if (strncasecmp(field, attach_hdr, length) == 0 &&
-                               field[length] == ':') {
-                       p = trim(field+length+1);
-                       if (*p == '+') {
-                               /* forwarded message */
-                               fprintf(composition_file, "#forw [forwarded message(s)] %s\n", p);
-                       } else {
-                               /* regular attachment */
-                               make_mime_composition_file_entry(p);
+       for (compnum = 1, state = FLD2; state == FLD2;) {
+               switch (state = m_getfld2(state, &f, draft_file)) {
+               case LENERR2:
+                       state = FLD2;
+               case FLD2:
+                       compnum++;
+                       if (strncasecmp(f.name, attach_hdr, length) == 0 &&
+                                       f.namelen == length) {
+                               p = trim(f.value);
+                               if (*p == '+') {
+                                       /* forwarded message */
+                                       fprintf(composition_file, "#forw [forwarded message(s)] %s\n", p);
+                               } else {
+                                       /* regular attachment */
+                                       make_mime_composition_file_entry(p);
+                               }
                        }
+                       break;
+               case BODY2:
+               case FILEEOF2:
+                       break;
+               case FMTERR2:
+                       adios(EX_DATAERR, NULL, "message format error in component #%d", compnum);
+               case IOERR2:
+                       adios(EX_IOERR, NULL, "error reading draft file: %s", draft_file_name);
+               default:
+                       adios(EX_SOFTWARE, NULL, "getfld() returned %d", state);
                }
        }
        fclose(composition_file);
@@ -437,6 +464,9 @@ attach(char *draft_file_name)
 static int
 signandenc(char *draft_file_name)
 {
+       enum state state;
+       int compnum;
+       struct field f = {{0}};
        char buf[BUFSIZ];
        int dosign = 0;
        int doenc = 0;
@@ -450,20 +480,32 @@ signandenc(char *draft_file_name)
                adios(EX_IOERR, NULL, "can't open draft file `%s'.", draft_file_name);
        }
 
-       /* We'll grow the buffer as needed. */
-       field = mh_xcalloc(field_size = 256, sizeof(char));
-
        /* Scan the draft file for an attachment header field name. */
-       while (get_line() != EOF && *field != '\0' && *field != '-') {
-               if (strncasecmp(field, sign_hdr, strlen(sign_hdr))==0 &&
-                               field[strlen(sign_hdr)] == ':') {
-                       dosign = 1;
-               }
-               if (strncasecmp(field, enc_hdr, strlen(enc_hdr))==0 &&
-                               field[strlen(enc_hdr)] == ':') {
-                       doenc = 1;
+       for (compnum = 1, state = FLD2; state == FLD2;) {
+               switch (state = m_getfld2(state, &f, draft_file)) {
+               case LENERR2:
+                       state = FLD2;
+               case FLD2:
+                       compnum++;
+                       if (strcasecmp(f.name, sign_hdr)==0) {
+                               dosign = 1;
+                       }
+                       if (strcasecmp(f.name, enc_hdr)==0) {
+                               doenc = 1;
+                       }
+                       break;
+               case BODY2:
+               case FILEEOF2:
+                       break;
+               case FMTERR2:
+                       adios(EX_DATAERR, NULL, "message format error in component #%d", compnum);
+               case IOERR2:
+                       adios(EX_IOERR, NULL, "error reading draft file: %s", draft_file_name);
+               default:
+                       adios(EX_SOFTWARE, NULL, "getfld() returned %d", state);
                }
        }
+
        if (!dosign && !doenc) {
                return DONE;
        }
@@ -500,35 +542,6 @@ clean_up_temporary_files(void)
        return;
 }
 
-static int
-get_line(void)
-{
-       int c;  /* current character */
-       int n;  /* number of bytes in buffer */
-       char *p;
-
-       /*
-       ** Get a line from the input file, growing the field buffer as
-       ** needed.  We do this so that we can fit an entire line in the
-       ** buffer making it easy to do a string comparison on both the
-       ** field name and the field body which might be a long path name.
-       */
-       for (n = 0, p = field; (c = getc(draft_file)) != EOF; *p++ = c) {
-               if (c == '\n' && (c = getc(draft_file)) != ' ' && c != '\t') {
-                       ungetc(c, draft_file);
-                       c = '\n';
-                       break;
-               }
-               if (++n >= field_size - 1) {
-                       field = mh_xrealloc(field, field_size += 256);
-                       p = field + n - 1;
-               }
-       }
-       *p = '\0';
-
-       return (c);
-}
-
 static void
 make_mime_composition_file_entry(char *file_name)
 {
index fd0cbcc..ea032d2 100644 (file)
@@ -458,7 +458,7 @@ putfmt(char *name, char *str, FILE *out)
        if (hdr->flags & HTRY) {
                addr_end->m_next = recipients;
                recipients = addr_start.m_next;
-               recipientsc += i;
+               recipientsc += addrc;
        }
 }