Merge branch 'm_getfld2-meillo' into master
authorPhilipp Takacs <philipp@bureaucracy.de>
Fri, 22 Apr 2016 22:56:56 +0000 (00:56 +0200)
committerPhilipp Takacs <philipp@bureaucracy.de>
Fri, 22 Apr 2016 22:56:56 +0000 (00:56 +0200)
26 files changed:
h/mh.h
h/prototypes.h
sbr/Makefile.in
sbr/m_getfld.c [deleted file]
sbr/m_getfld2.c [new file with mode: 0644]
sbr/readconfig.c
sbr/seq_read.c
test/tests/bad-input/test-header
test/tests/mhparam/test-mhparam
uip/distsbr.c
uip/inc.c
uip/mhbuild.c
uip/mhl.c
uip/mhparse.c
uip/new.c
uip/pick.c
uip/prompter.c
uip/rcvdist.c
uip/rcvstore.c
uip/repl.c
uip/scan.c
uip/scansbr.c
uip/slocal.c
uip/sortm.c
uip/spost.c
uip/whom.c

diff --git a/h/mh.h b/h/mh.h
index a5a12ce..e1795ca 100644 (file)
--- a/h/mh.h
+++ b/h/mh.h
@@ -203,14 +203,24 @@ struct msgs {
                            ** terminating NULL.
                            */
 
-#define LENERR   (-2)      /* Name too long error from getfld  */
-#define FMTERR   (-3)      /* Message Format error             */
-#define FLD      0         /* Field returned                   */
-#define FLDPLUS  1         /* Field returned with more to come */
-#define BODY     3         /* Body  returned with more to come */
-#define FILEEOF  5         /* Reached end of input file        */
-
-extern int msg_count;        /* m_getfld() indicators (That's a hack!) */
+/* m_getfld2() returned data */
+struct field {
+       char name[NAMESZ];
+       size_t namelen;
+       char *value;
+       size_t valuelen;
+       size_t alloclen;
+};
+
+/* m_getfld2() states */
+enum state {
+       LENERR2 = -2,      /* Line too long */
+       FMTERR2 = -3,      /* Format error in message */
+       IOERR2 = -1,       /* Read error */
+       FLD2 = 0,          /* Header field returned */
+       BODY2,             /* Body line returned */
+       FILEEOF2,          /* Reached end of input file */
+};
 
 #define NOUSE    0        /* draft being re-used */
 
index 8455b38..69556f9 100644 (file)
@@ -65,7 +65,7 @@ int m_atoi(char *);
 char *m_backup(char *);
 int m_convert(struct msgs *, char *);
 char *m_draft(char *);
-int m_getfld(int, unsigned char *, unsigned char *, int, FILE *);
+enum state m_getfld2(enum state, struct field *, FILE *);
 int m_gmprot(void);
 char *m_name(int);
 int m_putenv(char *, char *);
index 77c0c1b..f60bd9a 100644 (file)
@@ -57,7 +57,7 @@ SRCS = addrsbr.c ambigsw.c brkstring.c  \
        getarguments.c \
        fmt_addr.c fmt_compile.c fmt_new.c fmt_rfc2047.c  \
        fmt_scan.c lock_file.c m_atoi.c \
-       m_convert.c m_draft.c m_getfld.c m_gmprot.c  \
+       m_convert.c m_draft.c m_getfld2.c m_gmprot.c  \
        m_name.c \
        makedir.c mts.c norm_charmap.c  \
        path.c pidwait.c pidstatus.c  \
diff --git a/sbr/m_getfld.c b/sbr/m_getfld.c
deleted file mode 100644 (file)
index 1ec09a4..0000000
+++ /dev/null
@@ -1,708 +0,0 @@
-/*
-** m_getfld.c -- read/parse a message
-**
-** This code is Copyright (c) 2002, 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>
-#include <ctype.h>
-#include <sysexits.h>
-
-/*
-** This module has a long and checkered history.
-**
-** [ Here had been some history of delimiter problems in MMDF maildrops ... ]
-**
-** Unfortunately the speed issue finally caught up with us since this
-** routine is at the very heart of MH.  To speed things up considerably, the
-** routine Eom() was made an auxilary function called by the macro eom().
-** Unless we are bursting a maildrop, the eom() macro returns FALSE saying
-** we aren't at the end of the message.
-**
-** [ ... and here had been some more of it. ]
-**
-**
-** ------------------------
-** (Written by Van Jacobson for the mh6 m_getfld, January, 1986):
-**
-** This routine was accounting for 60% of the cpu time used by most mh
-** programs.  I spent a bit of time tuning and it now accounts for <10%
-** of the time used.  Like any heavily tuned routine, it's a bit
-** complex and you want to be sure you understand everything that it's
-** doing before you start hacking on it.  Let me try to emphasize
-** that:  every line in this atrocity depends on every other line,
-** sometimes in subtle ways.  You should understand it all, in detail,
-** before trying to change any part.  If you do change it, test the
-** result thoroughly (I use a hand-constructed test file that exercises
-** all the ways a header name, header body, header continuation,
-** header-body separator, body line and body eom can align themselves
-** with respect to a buffer boundary).  "Minor" bugs in this routine
-** result in garbaged or lost mail.
-**
-** If you hack on this and slow it down, I, my children and my
-** children's children will curse you.
-**
-** This routine gets used on two different types of files: normal,
-** single msg files and "packed" unix mailboxs (when used by inc).
-** The biggest impact of different file types is in "eom" testing.  The
-** code has been carefully organized to test for eom at appropriate
-** times and at no other times (since the check is quite expensive).
-** I have tried to arrange things so that the eom check need only be
-** done on entry to this routine.  Since an eom can only occur after a
-** newline, this is easy to manage for header fields.  For the msg
-** body, we try to efficiently search the input buffer to see if
-** contains the eom delimiter.  If it does, we take up to the
-** delimiter, otherwise we take everything in the buffer.  (The change
-** to the body eom/copy processing produced the most noticeable
-** performance difference, particularly for "inc" and "show".)
-**
-** There are three qualitatively different things this routine busts
-** out of a message: field names, field text and msg bodies.  Field
-** names are typically short (~8 char) and the loop that extracts them
-** might terminate on a colon, newline or max width.  I considered
-** using a Vax "scanc" to locate the end of the field followed by a
-** "bcopy" but the routine call overhead on a Vax is too large for this
-** to work on short names.  If Berkeley ever makes "inline" part of the
-** C optimiser (so things like "scanc" turn into inline instructions) a
-** change here would be worthwhile.
-**
-** Field text is typically 60 - 100 characters so there's (barely)
-** a win in doing a routine call to something that does a "locc"
-** followed by a "bmove".  About 30% of the fields have continuations
-** (usually the 822 "received:" lines) and each continuation generates
-** another routine call.  "Inline" would be a big win here, as well.
-**
-** Messages, as of this writing, seem to come in two flavors: small
-** (~1K) and long (>2K).  Most messages have 400 - 600 bytes of headers
-** so message bodies average at least a few hundred characters.
-** Assuming your system uses reasonably sized stdio buffers (1K or
-** more), this routine should be able to remove the body in large
-** (>500 byte) chunks.  The makes the cost of a call to "bcopy"
-** small but there is a premium on checking for the eom in packed
-** maildrops.  The eom pattern is always a simple string so we can
-** construct an efficient pattern matcher for it (e.g., a Vax "matchc"
-** instruction).  Some thought went into recognizing the start of
-** an eom that has been split across two buffers.
-**
-** This routine wants to deal with large chunks of data so, rather
-** than "getc" into a local buffer, it uses stdio's buffer.  If
-** you try to use it on a non-buffered file, you'll get what you
-** deserve.  This routine "knows" that struct FILEs have a _ptr
-** and a _cnt to describe the current state of the buffer and
-** it knows that _filbuf ignores the _ptr & _cnt and simply fills
-** the buffer.  If stdio on your system doesn't work this way, you
-** may have to make small changes in this routine.
-**
-** This routine also "knows" that an EOF indication on a stream is
-** "sticky" (i.e., you will keep getting EOF until you reposition the
-** stream).  If your system doesn't work this way it is broken and you
-** should complain to the vendor.  As a consequence of the sticky
-** EOF, this routine will never return any kind of EOF status when
-** there is data in "name" or "buf").
-*/
-
-
-/*
-** static prototypes
-*/
-static int m_Eom(int, FILE *);
-static unsigned char *matchc(int, char *, int, char *);
-static unsigned char *locc(int, unsigned char *, unsigned char);
-
-#define eom(c,iob)  (ismbox && \
-       (((c) == *msg_delim && m_Eom(c,iob)) ||\
-       (eom_action && (*eom_action)(c))))
-
-static unsigned char **pat_map;
-
-/*
-** This is a disgusting hack for "inc" so it can know how many
-** characters were stuffed in the buffer on the last call
-** (see comments in uip/scansbr.c).
-*/
-int msg_count = 0;
-
-int ismbox = FALSE;
-
-/*
-** The "full" delimiter string for a packed maildrop consists
-** of a newline followed by the actual delimiter.  E.g., the
-** full string for a Unix maildrop would be: "\n\nFrom ".
-** "Fdelim" points to the start of the full string and is used
-** in the BODY case of the main routine to search the buffer for
-** a possible eom.  Msg_delim points to the first character of
-** the actual delim. string (i.e., fdelim+1).  Edelim
-** points to the 2nd character of actual delimiter string.  It
-** is used in m_Eom because the first character of the string
-** has been read and matched before m_Eom is called.
-*/
-static char *msg_delim = "";
-
-static unsigned char *fdelim;
-static unsigned char *delimend;
-static int fdelimlen;
-static unsigned char *edelim;
-static int edelimlen;
-
-static int (*eom_action)(int) = NULL;
-
-#ifdef _FSTDIO
-# define _ptr _p  /* Gag   */
-# define _cnt _r  /* Retch */
-# define _filbuf __srget  /* Puke  */
-# define DEFINED__FILBUF_TO_SOMETHING_SPECIFIC
-#endif
-
-#ifndef DEFINED__FILBUF_TO_SOMETHING_SPECIFIC
-extern int  _filbuf(FILE*);
-#endif
-
-
-int
-m_getfld(int state, unsigned char *name, unsigned char *buf,
-       int bufsz, FILE *iob)
-{
-       unsigned char  *bp, *cp, *ep, *sp;
-       int cnt, c, i, j;
-
-       if ((c = getc(iob)) < 0) {
-               msg_count = 0;
-               *buf = 0;
-               return FILEEOF;
-       }
-       if (eom(c, iob)) {
-               if (! eom_action) {
-                       /* flush null messages */
-                       while ((c = getc(iob)) >= 0 && eom(c, iob))
-                               ;
-                       if (c >= 0)
-                               ungetc(c, iob);
-               }
-               msg_count = 0;
-               *buf = 0;
-               return FILEEOF;
-       }
-
-       switch (state) {
-       case FLD:
-               if (c == '\n' || c == '-') {
-                       /* we hit the header/body separator */
-                       while (c != '\n' && (c = getc(iob)) >= 0)
-                               ;
-
-                       if (c < 0 || (c = getc(iob)) < 0 || eom(c, iob)) {
-                               if (!eom_action) {
-                                       /* flush null messages */
-                                       while ((c = getc(iob)) >= 0 && eom(c, iob))
-                                               ;
-                                       if (c >= 0)
-                                               ungetc(c, iob);
-                               }
-                               msg_count = 0;
-                               *buf = 0;
-                               return FILEEOF;
-                       }
-                       state = BODY;
-                       goto body;
-               }
-               /*
-               ** get the name of this component.  take characters up
-               ** to a ':', a newline or NAMESZ-1 characters,
-               ** whichever comes first.
-               */
-               cp = name;
-               i = NAMESZ - 1;
-               for (;;) {
-#ifdef LINUX_STDIO
-                       bp = sp = (unsigned char *) iob->_IO_read_ptr - 1;
-                       j = (cnt = ((long) iob->_IO_read_end -
-                               (long) iob->_IO_read_ptr)  + 1) < i ? cnt : i;
-#elif defined(__DragonFly__)
-                       bp = sp = (unsigned char *) ((struct __FILE_public *)iob)->_p - 1;
-                       j = (cnt = ((struct __FILE_public *)iob)->_r+1) < i ? cnt : i;
-#else
-                       bp = sp = (unsigned char *) iob->_ptr - 1;
-                       j = (cnt = iob->_cnt+1) < i ? cnt : i;
-#endif
-                       while (--j >= 0 && (c = *bp++) != ':' && c != '\n')
-                               *cp++ = c;
-
-                       j = bp - sp;
-                       if ((cnt -= j) <= 0) {
-#ifdef LINUX_STDIO
-                               iob->_IO_read_ptr = iob->_IO_read_end;
-                               if (__underflow(iob) == EOF) {
-#elif defined(__DragonFly__)
-                               if (__srget(iob) == EOF) {
-#else
-                               if (_filbuf(iob) == EOF) {
-#endif
-                                       *cp = *buf = 0;
-                                       advise(NULL, "eof encountered in field \"%s\"", name);
-                                       return FMTERR;
-                               }
-#ifdef LINUX_STDIO
-                               iob->_IO_read_ptr++; /* NOT automatic in __underflow()! */
-#endif
-                       } else {
-#ifdef LINUX_STDIO
-                               iob->_IO_read_ptr = bp + 1;
-#elif defined(__DragonFly__)
-                               ((struct __FILE_public *)iob)->_p = bp + 1;
-                               ((struct __FILE_public *)iob)->_r = cnt - 1;
-#else
-                               iob->_ptr = bp + 1;
-                               iob->_cnt = cnt - 1;
-#endif
-                       }
-                       if (c == ':')
-                               break;
-
-                       /*
-                       ** something went wrong.  possibilities are:
-                       **  . hit a newline (error)
-                       **  . got more than namesz chars. (error)
-                       **  . hit the end of the buffer. (loop)
-                       */
-                       if (c == '\n') {
-                               /*
-                               ** We hit the end of the line without
-                               ** seeing ':' to terminate the field name.
-                               ** This is usually (always?)  spam.  But,
-                               ** blowing up is lame, especially when
-                               ** scan(1)ing a folder with such messages.
-                               ** Pretend such lines are the first of
-                               ** the body (at least mutt also handles
-                               ** it this way).
-                               */
-
-                               /*
-                               ** See if buf can hold this line, since we
-                               ** were assuming we had a buffer of NAMESZ,
-                               ** not bufsz.
-                               */
-                               /* + 1 for the newline */
-                               if (bufsz < j + 1) {
-                                       /*
-                                       ** No, it can't.  Oh well,
-                                       ** guess we'll blow up.
-                                       */
-                                       *cp = *buf = 0;
-                                       advise(NULL, "eol encountered in field \"%s\"", name);
-                                       state = FMTERR;
-                                       goto finish;
-                               }
-                               memcpy(buf, name, j - 1);
-                               buf[j - 1] = '\n';
-                               buf[j] = '\0';
-                               /*
-                               ** mhparse.c:get_content wants to find
-                               ** the position of the body start, but
-                               ** it thinks there's a blank line between
-                               ** the header and the body (naturally!),
-                               ** so seek back so that things line up
-                               ** even though we don't have that blank
-                               ** line in this case.  Simpler parsers
-                               ** (e.g. mhl) get extra newlines, but
-                               ** that should be harmless enough, right?
-                               ** This is a corrupt message anyway.
-                               */
-                               fseek(iob, ftell(iob) - 2, SEEK_SET);
-                               return BODY;
-                       }
-                       if ((i -= j) <= 0) {
-                               *cp = *buf = 0;
-                               advise(NULL, "field name \"%s\" exceeds %d bytes", name, NAMESZ - 2);
-                               state = LENERR;
-                               goto finish;
-                       }
-               }
-
-               while (isspace(*--cp) && cp >= name)
-                       ;
-               *++cp = 0;
-               /* fall through */
-
-       case FLDPLUS:
-               /*
-               ** get (more of) the text of a field.  take
-               ** characters up to the end of this field (newline
-               ** followed by non-blank) or bufsz-1 characters.
-               */
-               cp = buf; i = bufsz-1;
-               for (;;) {
-#ifdef LINUX_STDIO
-                       cnt = (long) iob->_IO_read_end - (long) iob->_IO_read_ptr;
-                       bp = (unsigned char *) --iob->_IO_read_ptr;
-#elif defined(__DragonFly__)
-                       cnt = ((struct __FILE_public *)iob)->_r++;
-                       bp = (unsigned char *) --((struct __FILE_public *)iob)->_p;
-#else
-                       cnt = iob->_cnt++;
-                       bp = (unsigned char *) --iob->_ptr;
-#endif
-                       c = cnt < i ? cnt : i;
-                       while ((ep = locc( c, bp, '\n' ))) {
-                               /*
-                               ** if we hit the end of this field,
-                               ** return.
-                               */
-                               if ((j = *++ep) != ' ' && j != '\t') {
-#ifdef LINUX_STDIO
-                                       j = ep - (unsigned char *) iob->_IO_read_ptr;
-                                       memcpy(cp, iob->_IO_read_ptr, j);
-                                       iob->_IO_read_ptr = ep;
-#elif defined(__DragonFly__)
-                                       j = ep - (unsigned char *) ((struct __FILE_public *)iob)->_p;
-                                       memcpy(cp, ((struct __FILE_public *)iob)->_p, j);
-                                       ((struct __FILE_public *)iob)->_p = ep;
-                                       ((struct __FILE_public *)iob)->_r -= j;
-#else
-                                       j = ep - (unsigned char *) iob->_ptr;
-                                       memcpy(cp, iob->_ptr, j);
-                                       iob->_ptr = ep;
-                                       iob->_cnt -= j;
-#endif
-                                       cp += j;
-                                       state = FLD;
-                                       goto finish;
-                               }
-                               c -= ep - bp;
-                               bp = ep;
-                       }
-                       /*
-                       ** end of input or dest buffer - copy what
-                       ** we've found.
-                       */
-#ifdef LINUX_STDIO
-                       c += bp - (unsigned char *) iob->_IO_read_ptr;
-                       memcpy(cp, iob->_IO_read_ptr, c);
-#elif defined(__DragonFly__)
-                       c += bp - (unsigned char *) ((struct __FILE_public *)iob)->_p;
-                       memcpy(cp, ((struct __FILE_public *)iob)->_p, c);
-#else
-                       c += bp - (unsigned char *) iob->_ptr;
-                       memcpy(cp, iob->_ptr, c);
-#endif
-                       i -= c;
-                       cp += c;
-                       if (i <= 0) {
-                               /* the dest buffer is full */
-#ifdef LINUX_STDIO
-                               iob->_IO_read_ptr += c;
-#elif defined(__DragonFly__)
-                               ((struct __FILE_public *)iob)->_r -= c;
-                               ((struct __FILE_public *)iob)->_p += c;
-#else
-                               iob->_cnt -= c;
-                               iob->_ptr += c;
-#endif
-                               state = FLDPLUS;
-                               break;
-                       }
-                       /*
-                       ** There's one character left in the input
-                       ** buffer.  Copy it & fill the buffer.
-                       ** If the last char was a newline and the
-                       ** next char is not whitespace, this is
-                       ** the end of the field.  Otherwise loop.
-                       */
-                       --i;
-#ifdef LINUX_STDIO
-                       *cp++ = j = *(iob->_IO_read_ptr + c);
-                       iob->_IO_read_ptr = iob->_IO_read_end;
-                       c = __underflow(iob);
-                       iob->_IO_read_ptr++;  /* NOT automatic! */
-#elif defined(__DragonFly__)
-                       *cp++ =j = *(((struct __FILE_public *)iob)->_p + c);
-                       c = __srget(iob);
-#else
-                       *cp++ = j = *(iob->_ptr + c);
-                       c = _filbuf(iob);
-#endif
-                       if (c == EOF || ((j == '\0' || j == '\n')
-                                       && c != ' ' && c != '\t')) {
-                               if (c != EOF) {
-#ifdef LINUX_STDIO
-                                       --iob->_IO_read_ptr;
-#elif defined(__DragonFly__)
-                                       --((struct __FILE_public *)iob)->_p;
-                                       ++((struct __FILE_public *)iob)->_r;
-#else
-                                       --iob->_ptr;
-                                       ++iob->_cnt;
-#endif
-                               }
-                               state = FLD;
-                               break;
-                       }
-               }
-               break;
-
-       case BODY:
-       body:
-               /*
-               ** get the message body up to bufsz characters or
-               ** the end of the message.  Sleazy hack: if bufsz
-               ** is negative we assume that we were called to
-               ** copy directly into the output buffer and we
-               ** don't add an eos.
-               */
-               i = (bufsz < 0) ? -bufsz : bufsz-1;
-#ifdef LINUX_STDIO
-               bp = (unsigned char *) --iob->_IO_read_ptr;
-               cnt = (long) iob->_IO_read_end - (long) iob->_IO_read_ptr;
-#elif defined(__DragonFly__)
-               bp = (unsigned char *) --((struct __FILE_public *)iob)->_p;
-               cnt = ++((struct __FILE_public *)iob)->_r;
-#else
-               bp = (unsigned char *) --iob->_ptr;
-               cnt = ++iob->_cnt;
-#endif
-               c = (cnt < i ? cnt : i);
-               if (ismbox && c > 1) {
-                       /*
-                       ** packed maildrop - only take up to the (possible)
-                       ** start of the next message.  This "matchc" should
-                       ** probably be a Boyer-Moore matcher for non-vaxen,
-                       ** particularly since we have the alignment table
-                       ** all built for the end-of-buffer test (next).
-                       ** But our vax timings indicate that the "matchc"
-                       ** instruction is 50% faster than a carefully coded
-                       ** B.M. matcher for most strings.  (So much for
-                       ** elegant algorithms vs. brute force.)  Since I
-                       ** (currently) run MH on a vax, we use the matchc
-                       ** instruction. --vj
-                       */
-                       if ((ep = matchc( fdelimlen, fdelim, c, bp )))
-                               c = ep - bp + 1;
-                       else {
-                               /*
-                               ** There's no delim in the buffer but
-                               ** there may be a partial one at the end.
-                               ** If so, we want to leave it so the "eom"
-                               ** check on the next call picks it up.  Use a
-                               ** modified Boyer-Moore matcher to make this
-                               ** check relatively cheap.  The first "if"
-                               ** figures out what position in the pattern
-                               ** matches the last character in the buffer.
-                               ** The inner "while" matches the pattern
-                               ** against the buffer, backwards starting
-                               ** at that position.  Note that unless the
-                               ** buffer ends with one of the characters
-                               ** in the pattern (excluding the first
-                               ** and last), we do only one test.
-                               */
-                               ep = bp + c - 1;
-                               if ((sp = pat_map[*ep])) {
-                                       do {
-                                               /*
-                                               ** This if() is true unless
-                                               ** (a) the buffer is too
-                                               ** small to contain this
-                                               ** delimiter prefix,
-                                               ** or (b) it contains
-                                               ** exactly enough chars for
-                                               ** the delimiter prefix.
-                                               ** For case (a) obviously we
-                                               ** aren't going to match.
-                                               ** For case (b), if the
-                                               ** buffer really contained
-                                               ** exactly a delim prefix,
-                                               ** then the m_eom call
-                                               ** at entry should have
-                                               ** found it.  Thus it's
-                                               ** not a delim and we know
-                                               ** we won't get a match.
-                                               */
-                                               if (((sp - fdelim) + 2) <= c) {
-                                                       cp = sp;
-                                                       /*
-                                                       ** Unfortunately although fdelim has a preceding NUL
-                                                       ** we can't use this as a sentinel in case the buffer
-                                                       ** contains a NUL in exactly the wrong place (this
-                                                       ** would cause us to run off the front of fdelim).
-                                                       */
-                                                       while (*--ep == *--cp)
-                                                               if (cp < fdelim)
-                                                                       break;
-                                                       if (cp < fdelim) {
-                                                               /* we matched the entire delim prefix,
-                                                               ** so only take the buffer up to there.
-                                                               ** we know ep >= bp -- check above prevents underrun
-                                                               */
-                                                               c = (ep - bp) + 2;
-                                                               break;
-                                                       }
-                                               }
-                                               /* try matching one less char of delim string */
-                                               ep = bp + c - 1;
-                                       } while (--sp > fdelim);
-                               }
-                       }
-               }
-               memcpy( buf, bp, c );
-#ifdef LINUX_STDIO
-               iob->_IO_read_ptr += c;
-#elif defined(__DragonFly__)
-               ((struct __FILE_public *)iob)->_r -= c;
-               ((struct __FILE_public *)iob)->_p += c;
-#else
-               iob->_cnt -= c;
-               iob->_ptr += c;
-#endif
-               if (bufsz < 0) {
-                       msg_count = c;
-                       return (state);
-               }
-               cp = buf + c;
-               break;
-
-       default:
-               adios(EX_SOFTWARE, NULL, "m_getfld() called with bogus state of %d", state);
-       }
-finish:
-       *cp = 0;
-       msg_count = cp - buf;
-       return (state);
-}
-
-
-void
-thisisanmbox(FILE *iob)
-{
-       int c;
-       char text[10];
-       char *cp;
-       char *delimstr;
-
-       c = getc(iob); 
-       if (feof(iob)) {
-               return;
-       }
-       ungetc(c, iob);
-
-       /*
-       ** Figure out what the message delimitter string is for this
-       ** maildrop.  (This used to be part of m_Eom but I didn't like
-       ** the idea of an "if" statement that could only succeed on the
-       ** first call to m_Eom getting executed on each call, i.e., at
-       ** every newline in the message).
-       **
-       ** If the first line of the maildrop is a Unix "From " line, we
-       ** say the style is MBOX and eat the rest of the line.  Otherwise
-       ** abort.
-       */
-
-       if (fread(text, sizeof(*text), 5, iob) != 5) {
-               adios(EX_IOERR, NULL, "Read error");
-       }
-       if (strncmp(text, "From ", 5)!=0) {
-               adios(EX_USAGE, NULL, "No Unix style (mbox) maildrop.");
-       }
-       ismbox = TRUE;
-       delimstr = "\nFrom ";
-       while ((c = getc(iob)) != '\n' && c >= 0) {
-               continue;
-       }
-       c = strlen(delimstr);
-       fdelim = mh_xcalloc(c + 3, sizeof(char));
-       *fdelim++ = '\0';
-       *fdelim = '\n';
-       msg_delim = (char *)fdelim+1;
-       edelim = (unsigned char *)msg_delim+1;
-       fdelimlen = c + 1;
-       edelimlen = c - 1;
-       strcpy(msg_delim, delimstr);
-       delimend = (unsigned char *)msg_delim + edelimlen;
-       if (edelimlen <= 1)
-               adios(EX_DATAERR, NULL, "maildrop delimiter must be at least 2 bytes");
-       /*
-       ** build a Boyer-Moore end-position map for the matcher in m_getfld.
-       ** N.B. - we don't match just the first char (since it's the newline
-       ** separator) or the last char (since the matchc would have found it
-       ** if it was a real delim).
-       */
-       pat_map = mh_xcalloc(256, sizeof(unsigned char *));
-
-       for (cp = (char *) fdelim + 1; cp < (char *) delimend; cp++ )
-               pat_map[(unsigned char)*cp] = (unsigned char *) cp;
-}
-
-
-/*
-** test for msg delimiter string
-*/
-
-static int
-m_Eom(int c, FILE *iob)
-{
-       long pos = 0L;
-       int i;
-       char text[10];
-
-       pos = ftell(iob);
-       if ((i = fread(text, sizeof *text, edelimlen, iob)) != edelimlen ||
-                       (strncmp(text, (char *)edelim, edelimlen)!=0)) {
-               if (i == 0 && ismbox)
-                       /*
-                       ** the final newline in the (brain damaged) unix-format
-                       ** maildrop is part of the delimitter - delete it.
-                       */
-                       return 1;
-
-               fseek(iob, (long)(pos-1), SEEK_SET);
-               getc(iob);  /* should be OK */
-               return 0;
-       }
-
-       if (ismbox) {
-               while ((c = getc(iob)) != '\n' && c >= 0) {
-                       continue;
-               }
-       }
-
-       return 1;
-}
-
-
-static unsigned char *
-matchc(int patln, char *pat, int strln, char *str)
-{
-       char *es = str + strln - patln;
-       char *sp;
-       char *pp;
-       char *ep = pat + patln;
-       char pc = *pat++;
-
-       for(;;) {
-               while (pc != *str++)
-                       if (str > es)
-                               return 0;
-               if (str > es+1)
-                       return 0;
-               sp = str; pp = pat;
-               while (pp < ep && *sp++ == *pp)
-                       pp++;
-               if (pp >= ep)
-                       return ((unsigned char *)--str);
-       }
-}
-
-
-/*
-** Locate character "term" in the next "cnt" characters of "src".
-** If found, return its address, otherwise return 0.
-*/
-
-static unsigned char *
-locc(int cnt, unsigned char *src, unsigned char term)
-{
-       while (*src++ != term && --cnt > 0)
-               ;
-
-       return (cnt > 0 ? --src : (unsigned char *)0);
-}
diff --git a/sbr/m_getfld2.c b/sbr/m_getfld2.c
new file mode 100644 (file)
index 0000000..45172aa
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+** m_getfld2 -- replacement for m_getfld()
+**              read an RFC 822 message
+*/
+
+#define _WITH_GETLINE
+#define _POSIX_C_SOURCE 200809L
+
+#include <h/mh.h>
+#include <h/utils.h>
+#include <stdio.h>
+#include <ctype.h>
+
+
+enum threestate {
+       B_TRUE = 1,
+       B_FALSE = 0,
+       FAIL = -1,
+};
+
+/*
+** static prototypes
+*/
+static enum threestate is_falted(FILE *);
+static size_t copyname(char *, char *);
+static boolean is_separator(char *);
+
+
+/*
+** FLD2:       We read a (complete) header field
+** BODY2:      We read a body line
+** LENERR2:    Line is too long (>998, as defined by RFC 822)
+** FMTERR2:    Header field invalid
+** IOERR2:     Failure to read
+** FILEEOF2:   We're at the end of the file
+**
+** f->name is only filled in FLD2.
+**
+** In FLD2, f->value contains the field's (complete) value only;
+** in BODY2, LENERR2 and FMTERR2 f->value contains the whole line;
+** in IOERR2 and FILEEOF2 f->value is not set.
+*/
+enum state
+m_getfld2(enum state s, struct field *f, FILE *msg)
+{
+       char *tmpline = NULL;
+       size_t len = 0;
+       ssize_t nchars;
+       enum threestate falted = B_FALSE;
+       enum state ret = s;
+
+       switch (s) {
+       case FLD2:
+               nchars = getline(&tmpline, &len, msg);
+               if (nchars < 1) {
+                       free(f->value);
+                       *f = (struct field) { "\0", 0, NULL, 0, 0 };
+                       if (feof(msg)) {
+                               return FILEEOF2;
+                       } else {
+                               return IOERR2;
+                       }
+               }
+
+               if (nchars >= NAMESZ) {
+                       ret = LENERR2;
+               }
+
+               if (*(tmpline + nchars - 1) != '\n') {
+                       ret = FMTERR2;
+               }
+
+               if (ret == FLD2 && is_separator(tmpline)) {
+                       /* header/body separator found */
+                       free(tmpline);
+                       return m_getfld2(BODY2, f, msg);
+               }
+
+               f->namelen = copyname(f->name, tmpline);
+               if (f->namelen < 1) {
+                       *f->name = '\0';
+                       f->namelen = 0;
+                       ret = FMTERR2;
+               }
+
+               /* copy the field's value */
+               if (f->alloclen <= nchars - f->namelen) {
+                       f->value = mh_xrealloc(f->value, f->alloclen + len);
+                       f->alloclen += len;
+               }
+               if (f->namelen != 0) {
+                       strcpy(f->value, tmpline + f->namelen + 1);
+                       f->valuelen = nchars - f->namelen - 1;
+               } else {
+                       strcpy(f->value, tmpline);
+                       f->valuelen = nchars;
+               }
+
+               while (ret == FLD2 && (falted = is_falted(msg)) == B_TRUE) {
+                       nchars = getline(&tmpline, &len, msg);
+                       if (nchars <= 0) {
+                               free(tmpline);
+                               return IOERR2;
+                       }
+
+                       if (nchars >= NAMESZ) {
+                               ret = LENERR2;
+                       }
+
+                       if (*(tmpline + nchars - 1) != '\n') {
+                               ret = FMTERR2;
+                       }
+
+                       if (f->alloclen - f->valuelen <= nchars) {
+                               f->value = mh_xrealloc(f->value,
+                                               f->alloclen + len);
+                               f->alloclen += len;
+                       }
+                       strcpy(f->value + f->valuelen, tmpline);
+                       f->valuelen += nchars;
+
+               }
+
+               if (falted == FAIL) {
+                       ret = IOERR2;
+               }
+
+               free(tmpline);
+               return ret;
+
+       case BODY2:
+               *f->name = '\0';
+               f->namelen = 0;
+
+               nchars = getline(&tmpline, &len, msg);
+               if (nchars < 1) {
+                       free(f->value);
+                       f->value = NULL;
+                       f->valuelen = 0;
+                       f->alloclen = 0;
+                       if (feof(msg)) {
+                               return FILEEOF2;
+                       } else {
+                               return IOERR2;
+                       }
+               }
+
+               if (nchars >= NAMESZ) {
+                       ret = LENERR2;
+               }
+
+               free(f->value);
+               f->value = tmpline;
+               f->valuelen = nchars;
+               f->alloclen = len;
+               return ret;
+
+       default:
+               /* give error states back as received */
+               return s;
+       }
+}
+
+static enum threestate
+is_falted(FILE *msg)
+{
+       enum threestate ret;
+       int c;
+
+       if ((c = getc(msg)) < 0) {
+               if (feof(msg)) {
+                       clearerr(msg);
+                       return B_FALSE;
+               } else {
+                       return FAIL;
+               }
+       }
+       if (isblank(c)) {
+               ret = B_TRUE;
+       } else {
+               ret = B_FALSE;
+       }
+       if (ungetc(c, msg) != c) {
+               return FAIL;
+       }
+       return ret;
+}
+
+static size_t
+copyname(char *dst, char *src)
+{
+       size_t len;
+       char *cp, *sep;
+
+       if (!(sep = strchr(src, ':'))) {
+               return 0;
+       }
+       /* whitespace is forbidden in name */
+       for (cp=src; cp<sep; cp++) {
+               if (isspace(*cp)) {
+                       return 0;
+               }
+       }
+
+       len = sep - src;
+       if (len >= NAMESZ - 1) {
+               return 0;
+       }
+
+       src[len] = '\0';
+       strcpy(dst, src);
+
+       return strlen(dst);
+}
+
+static boolean
+is_separator(char *line)
+{
+       /*
+       ** In MH, lines that are consists of dashes only are
+       ** separators as well ... not so in RFC 822.
+       */
+       while (*line == '-') {
+               line++;
+       }
+       if (strcmp("\n", line) == 0 || strcmp("\r\n", line) == 0 ) {
+               return TRUE;
+       }
+       return FALSE;
+}
index 2fe2d7d..6975d72 100644 (file)
@@ -36,9 +36,8 @@ static struct node **opp = NULL;
 void
 readconfig(struct node **npp, FILE *ib, char *file, int ctx)
 {
-       int state;
-       char *cp;
-       char name[NAMESZ], field[BUFSIZ];
+       enum state state;
+       struct field f = {{0}};
        struct node *np;
        struct procstr *ps;
 
@@ -47,46 +46,34 @@ readconfig(struct node **npp, FILE *ib, char *file, int ctx)
                return;
        }
 
-       for (state = FLD;;) {
-               switch (state = m_getfld(state, name, field, sizeof(field),
-                               ib)) {
-               case FLD:
-               case FLDPLUS:
+       for (state = FLD2;;) {
+               switch (state = m_getfld2(state, &f, ib)) {
+               case FLD2:
                        np = mh_xcalloc(1, sizeof(*np));
                        *npp = np;
                        *(npp = &np->n_next) = NULL;
-                       np->n_name = mh_xstrdup(name);
-                       if (state == FLDPLUS) {
-                               cp = mh_xstrdup(field);
-                               while (state == FLDPLUS) {
-                                       state = m_getfld(state, name, field,
-                                                       sizeof(field), ib);
-                                       cp = add(field, cp);
-                               }
-                               np->n_field = trimcpy(cp);
-                               mh_free0(&cp);
-                       } else {
-                               np->n_field = trimcpy(field);
-                       }
+                       np->n_name = mh_xstrdup(f.name);
+                       np->n_field = trimcpy(f.value);
                        np->n_context = ctx;
 
                        /*
                        ** Now scan the list of `procs' and link in
                        ** the field value to the global variable.
                        */
-                       for (ps = procs; ps->procname; ps++)
+                       for (ps = procs; ps->procname; ps++) {
                                if (mh_strcasecmp(np->n_name,
                                                ps->procname) == 0) {
                                        *ps->procnaddr = np->n_field;
                                        break;
                                }
+                       }
                        continue;
 
-               case BODY:
+               case BODY2:
                        adios(EX_CONFIG, NULL, "no blank lines are permitted in %s",
                                        file);
 
-               case FILEEOF:
+               case FILEEOF2:
                        break;
 
                default:
index e76bcc6..1fdccf9 100644 (file)
@@ -55,9 +55,9 @@ seq_read(struct msgs *mp)
 static void
 seq_public(struct msgs *mp)
 {
-       int state;
-       char *cp, seqfile[PATH_MAX];
-       char name[NAMESZ], field[BUFSIZ];
+       enum state state;
+       struct field f = {{0}};
+       char seqfile[PATH_MAX];
        FILE *fp;
 
        /*
@@ -74,37 +74,24 @@ seq_public(struct msgs *mp)
                return;
 
        /* Use m_getfld to scan sequence file */
-       for (state = FLD;;) {
-               switch (state = m_getfld(state, name, field, sizeof(field),
-                               fp)) {
-               case FLD:
-               case FLDPLUS:
-                       if (state == FLDPLUS) {
-                               cp = mh_xstrdup(field);
-                               while (state == FLDPLUS) {
-                                       state = m_getfld(state, name, field,
-                                                       sizeof(field), fp);
-                                       cp = add(field, cp);
-                               }
-                               seq_init(mp, mh_xstrdup(name), trimcpy(cp));
-                               mh_free0(&cp);
-                       } else {
-                               seq_init(mp, mh_xstrdup(name), trimcpy(field));
-                       }
+       for (state = FLD2;;) {
+               switch (state = m_getfld2(state, &f, fp)) {
+               case FLD2:
+                       seq_init(mp, mh_xstrdup(f.name), trimcpy(f.value));
                        continue;
 
-               case BODY:
+               case BODY2:
                        adios(EX_CONFIG, NULL, "no blank lines are permitted in %s",
                                        seqfile);
-                       /* fall */
+                       /* FALL */
 
-               case FILEEOF:
+               case FILEEOF2:
                        break;
 
                default:
                        adios(EX_CONFIG, NULL, "%s is poorly formatted", seqfile);
                }
-               break;  /* break from for loop */
+               break;
        }
 
        lkfclose(fp, seqfile);
index 6b826a0..e152e0e 100644 (file)
@@ -1,19 +1,17 @@
 #!/bin/sh
-######################################################
 #
-# Test bogus headers (no blank line before body, etc.)
-#
-######################################################
+# Test bogus and strange headers
+
 
 . "$MH_TEST_COMMON"
 
 expected=$MH_TEST_DIR/$$.expected
 
 # Write message with bogus header field (missing blank line, really).
-msgfile="$(mhpath b)"
-msgnum="$(basename $msgfile)"
 
-cat > $msgfile <<EOF
+msgfile="`mhpath b`"
+msgnum="${msgfile##*/}"
+cat >"$msgfile" <<!
 Date: Sun, 18 Dec 2005 00:52:39 +0100
 From: foo@example.edu
 To: bar@example.edu
@@ -21,90 +19,213 @@ Subject: test
 This is a multi-part message in MIME format.
 
 I am a stupid spammer.
-EOF
-
+!
 
-# check scan
 runandcheck "scan $msgnum" <<!
-  11  2005-12-18 00:52  foo@example.edu    test
+??Format error (message $msgnum) in component 5
+  $msgnum  2005-12-18 00:52  foo@example.edu    test
 !
 
-
-# check show
 runandcheck "show $msgnum" <<!
-Date:    Sun, 18 Dec 2005 00:52:39 +0100
-From:    foo@example.edu
-To:      bar@example.edu
-Subject: test
-
-part       text/plain                  70
-
-This is a multi-part message in MIME format.
-
-I am a stupid spammer.
+show: message format error in component #5
 !
 
 
 
 # check m_getfld() handling of empty header field
+
 msgfile="`mhpath b`"
+msgnum="${msgfile##*/}"
 printf 'Date: Sat, 12 Jan 2013 09:07:01 -0600\nReceived:' >"$msgfile"
+
 runandcheck "scan l" <<!
-scan: eof encountered in field "Received"
-??Format error (message 12) in component 2
-  12  2013-01-12 09:07                     
+??Format error (message $msgnum) in component 2
+  $msgnum  2013-01-12 09:07                     
 !
 
 
 
 # check m_getfld() handling of excessively long header field name
 
-msgfile="$MH_TEST_DIR/Mail/inbox/13"
-cat >"$msgfile" <<EOF
+msgfile="`mhpath b`"
+msgnum="${msgfile##*/}"
+cat >"$msgfile" <<!
 Date: Tue, 15 Jan 2013 21:13:12 -0600
 ThisHeaderFieldNameIsWaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaayTooLong: OK
-EOF
+!
+
 runandcheck "scan l" <<!
-scan: field name "ThisHeaderFieldNameIsWaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaayTooLong" exceeds 997 bytes
-??Format error (message 13) in component 2
-  13  2013-01-15 21:13                     
+scan: line "ThisHeaderFieldNameIsWaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaayTooLong: OK" too long
+??Format error (message $msgnum) in component 2
+  $msgnum  2013-01-15 21:13                     
 !
 
 
 
-# # Cygwin has a BUFSIZ of 1024 so the error message gets truncated.
-# # Deal with that by grepping to verify that scan showed the proper error.
-# verify_string_in_file() {
-#   if grep "$1" "$2" >/dev/null; then
-#     :
-#   else
-#     echo "$0: did not receive expected error message \"$1\""
-#     failed=`expr ${failed:-0} + 1`
-#   fi
-# }
-# verify_string_in_file 'scan: field name "ThisHeaderFieldNameIsWa' "$actual_err"
-# verify_string_in_file 'exceeds 997' "$actual_err"
-# verify_string_in_file '??Format error (message 13) in component 2' "$actual_err"
-# rm -f "$actual_err"
+# check m_getfld() handling of header field name with whitespace
+
+msgfile="`mhpath b`"
+msgnum="${msgfile##*/}"
+cat >"$msgfile" <<!
+Date: Thu, 17 Jan 2013 19:33:46 -0600
+A header field name with whitespace: foo
+Subject: Will this be printed?
+
+Test
+
+!
 
+runandcheck "scan l" <<!
+??Format error (message $msgnum) in component 2
+  $msgnum  2013-01-17 19:33                     
+!
 
 
 
-# check m_getfld() handling of long header field name without a colon
+# check m_getfld() handling of header field name without a colon
 
-msgfile="$MH_TEST_DIR/Mail/inbox/14"
-cat >"$msgfile" <<EOF
+msgfile="`mhpath b`"
+msgnum="${msgfile##*/}"
+cat >"$msgfile" <<!
 Date: Thu, 17 Jan 2013 19:33:46 -0600
-If a header field name has at least 512 characters without a newline or colon, it will raise a format error in m_getfld().  Here is a test of that.  01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901
+A_header_field_name_without_a_colon_..._or_is_this_the_first_line_of_the_body_question-mark
+Subject: Will this be printed?
 
 Test
 
+!
 
-EOF
+runandcheck "scan l" <<!
+??Format error (message $msgnum) in component 2
+  $msgnum  2013-01-17 19:33                     
+!
+
+
+
+# check m_getfld() handling of empty field name
+
+msgfile="`mhpath b`"
+msgnum="${msgfile##*/}"
+cat >"$msgfile" <<!
+Date: Thu, 17 Jan 2013 19:33:46 -0600
+: foo
+Subject: Will this be printed?
+
+Test
+
+!
 
 runandcheck "scan l" <<!
-scan: eol encountered in field "If a header field name has at least 512 characters without a newline or colon, it will raise a format error in m_getfld().  Here is a test of that.  01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901"
-??Format error (message 14) in component 2
-  14  2013-01-17 19:33                     
+??Format error (message $msgnum) in component 2
+  $msgnum  2013-01-17 19:33                     
 !
 
+
+
+
+# check m_getfld() handling of dashed body separator (as in drafts)
+
+msgfile="`mhpath b`"
+msgnum="${msgfile##*/}"
+cat >"$msgfile" <<!
+Date: Thu, 17 Jan 2013 19:33:46 -0600
+----------
+Subject: Will this be printed?
+
+Test
+
+!
+
+runandcheck "scan l" <<!
+  $msgnum  2013-01-17 19:33                     
+!
+
+
+msgfile="`mhpath b`"
+msgnum="${msgfile##*/}"
+cat >"$msgfile" <<!
+Date: Thu, 17 Jan 2013 19:33:46 -0600
+-
+Subject: Will this be printed?
+
+Test
+
+!
+
+runandcheck "scan l" <<!
+  $msgnum  2013-01-17 19:33                     
+!
+
+
+msgfile="`mhpath b`"
+msgnum="${msgfile##*/}"
+cat >"$msgfile" <<!
+Date: Thu, 17 Jan 2013 19:33:46 -0600
+-----foo
+Subject: Will this be printed?
+
+Test
+
+!
+
+runandcheck "scan l" <<!
+??Format error (message $msgnum) in component 2
+  $msgnum  2013-01-17 19:33                     
+!
+
+
+msgfile="`mhpath b`"
+msgnum="${msgfile##*/}"
+cat >"$msgfile" <<!
+Date: Thu, 17 Jan 2013 19:33:46 -0600
+-foo
+Subject: Will this be printed?
+
+Test
+
+!
+
+runandcheck "scan l" <<!
+??Format error (message $msgnum) in component 2
+  $msgnum  2013-01-17 19:33                     
+!
+
+
+msgfile="`mhpath b`"
+msgnum="${msgfile##*/}"
+cat >"$msgfile" <<!
+Date: Thu, 17 Jan 2013 19:33:46 -0600
+--- --- ---
+Subject: Will this be printed?
+
+Test
+
+!
+
+runandcheck "scan l" <<!
+??Format error (message $msgnum) in component 2
+  $msgnum  2013-01-17 19:33                     
+!
+
+
+# valid headers that might be treated as body separators but should not
+
+msgfile="`mhpath b`"
+msgnum="${msgfile##*/}"
+cat >"$msgfile" <<!
+Date: Thu, 17 Jan 2013 19:33:46 -0600
+-: strange but valid header name
+-------: also a valid header name
+-dash: nothing special if it start with a dash
+-------dash: or with many dashes
+-..|.-|...|....: could even be morse code ;-)
+sort</etc/passwd|lp&&date: ... o ar command lins *eek*
+Subject: This will be printed!
+
+Test
+
+!
+
+runandcheck "scan l" <<!
+  $msgnum  2013-01-17 19:33                     This will be printed!
+!
index c2fc5de..7f21be3 100755 (executable)
@@ -120,10 +120,22 @@ runandcheck "mhparam -debug >/dev/null; echo \$?" <<!
 0
 !
 
+# check with folded header
+cat >>"$MMHP" <<!
+Alternate-Mailboxes: alice@example.org,
+  bob@example.net,
+       charly@example.comp
+!
+runandcheck 'mhparam alternate-mailboxes' <<!
+alice@example.org,   bob@example.net,  charly@example.comp
+!
+
+
 # check with text file that does not end with newline
+# in mmh this is invalid
 printf 'Editor: emacs' >>"$MMHP"
 runandcheck 'mhparam -nocomponent editor' <<!
-emacs
+mhparam: `cat test-temp-dir`/.mmh/profile2 is poorly formatted
 !
 
 
index a600b77..058875c 100644 (file)
@@ -24,10 +24,10 @@ static int ready_msg(char *);
 int
 distout(char *drft, char *msgnam, char *backup)
 {
-       int state;
+       enum state state;
+       struct field f = {{0}};
        unsigned char *dp;
-       char *resent;
-       char name[NAMESZ], buffer[BUFSIZ];
+       int resent = 0;
        FILE *ifp, *ofp;
 
        strcpy(backup, m_mktemp(toabsdir(invo_name), NULL, NULL));
@@ -52,43 +52,32 @@ distout(char *drft, char *msgnam, char *backup)
        lseek(hdrfd, (off_t) 0, SEEK_SET); /* msgnam not accurate */
        cpydata(hdrfd, fileno(ofp), msgnam, drft);
 
-       state = FLD;
-       resent = NULL;
+       state = FLD2;
        while (1) {
-               switch (state = m_getfld(state, name, buffer, sizeof buffer,
-                               ifp)) {
-               case FLD:
-               case FLDPLUS:
-                       if (!uprf(name, "resent")) {
-                               advise(NULL, "Please re-edit draft to remove the ``%s'' header.", name);
+               switch (state = m_getfld2(state, &f, ifp)) {
+               case FLD2:
+                       if (!uprf(f.name, "resent")) {
+                               advise(NULL, "Please re-edit draft to remove the ``%s'' header.", f.name);
                                goto leave_bad;
                        }
-                       if (state == FLD) {
-                               resent = add(":", add(name, resent));
-                       }
-                       resent = add(buffer, resent);
-                       fprintf(ofp, "%s: %s", name, buffer);
-                       while (state == FLDPLUS) {
-                               state = m_getfld(state, name, buffer,
-                                               sizeof buffer, ifp);
-                               resent = add(buffer, resent);
-                               fputs(buffer, ofp);
-                       }
+                       resent = 1;
+                       fprintf(ofp, "%s: %s", f.name, f.value);
                        break;
 
-               case BODY:
-                       for (dp = buffer; *dp; dp++) {
+               case BODY2:
+                       for (dp = f.value; *dp; dp++) {
                                if (!isspace(*dp)) {
                                        advise(NULL, "Please re-edit draft to consist of headers only.");
                                        goto leave_bad;
                                }
                        }
 
-               case FILEEOF:
+               case FILEEOF2:
                        goto process;
 
-               case LENERR:
-               case FMTERR:
+               case LENERR2:
+               case FMTERR2:
+               case IOERR2:
                        advise(NULL, "Please re-edit draft and fix that header.");
 leave_bad: ;
                        fclose(ifp);
@@ -118,7 +107,6 @@ process: ;
                }
                return NOTOK;
        }
-       mh_free0(&resent);
 
        if (txtfd != NOTOK) {
                lseek(txtfd, (off_t) 0, SEEK_SET);  /* msgnam not accurate */
@@ -134,8 +122,10 @@ process: ;
 static int
 ready_msg(char *msgnam)
 {
-       int state, out;
-       char name[NAMESZ], buffer[BUFSIZ], tmpfil[BUFSIZ];
+       enum state state;
+       struct field f = {{0}};
+       char tmpfil[BUFSIZ];
+       int out;
        FILE *ifp, *ofp;
        char *cp = NULL;
 
@@ -165,24 +155,18 @@ ready_msg(char *msgnam)
        }
        unlink(tmpfil);
 
-       state = FLD;
+       state = FLD2;
        while (1) {
-               state = m_getfld(state, name, buffer, sizeof buffer, ifp);
+               state = m_getfld2(state, &f, ifp);
                switch (state) {
-               case FLD:
-               case FLDPLUS:
-                       if (uprf(name, "resent")) {
+               case FLD2:
+                       if (uprf(f.name, "resent")) {
                                fprintf(ofp, "Prev-");
                        }
-                       fprintf(ofp, "%s: %s", name, buffer);
-                       while (state == FLDPLUS) {
-                               state = m_getfld(state, name, buffer,
-                                               sizeof buffer, ifp);
-                               fputs(buffer, ofp);
-                       }
+                       fprintf(ofp, "%s: %s", f.name, f.value);
                        break;
 
-               case BODY:
+               case BODY2:
                        fclose(ofp);
 
                        cp = m_mktemp2(NULL, "dist", &txtfd, NULL);
@@ -198,17 +182,19 @@ ready_msg(char *msgnam)
                                return NOTOK;
                        }
                        unlink(tmpfil);
-                       fprintf(ofp, "\n%s", buffer);
-                       while (state == BODY) {
-                               state = m_getfld(state, name, buffer,
-                                               sizeof buffer, ifp);
-                               fputs(buffer, ofp);
+                       fputs("\n", ofp);
+                       while (state == BODY2) {
+                               fputs(f.value, ofp);
+                               state = m_getfld2(state, &f, ifp);
                        }
-               case FILEEOF:
+                       /* FALL */
+
+               case FILEEOF2:
                        goto process;
 
-               case LENERR:
-               case FMTERR:
+               case LENERR2:
+               case FMTERR2:
+               case IOERR2:
                        advise(NULL, "format error in message %s", msgnam);
                        return NOTOK;
 
index 36e0ab1..0cb2a5e 100644 (file)
--- a/uip/inc.c
+++ b/uip/inc.c
@@ -162,17 +162,16 @@ main(int argc, char **argv)
                adios(EX_OSERR, NULL, "atexit failed");
        }
 
-/*
-** absolutely the first thing we do is save our privileges,
-** and drop them if we can.
-*/
+       /*
+       ** absolutely the first thing we do is save our privileges,
+       ** and drop them if we can.
+       */
        SAVEGROUPPRIVS();
        TRYDROPGROUPPRIVS();
 
        setlocale(LC_ALL, "");
        invo_name = mhbasename(argv[0]);
 
-       /* read user profile/context */
        context_read();
 
        arguments = getarguments(invo_name, argc, argv, 1);
@@ -311,7 +310,6 @@ main(int argc, char **argv)
        if (chdir(maildir) == NOTOK)
                adios(EX_OSERR, maildir, "unable to change directory to");
 
-       /* read folder and create message structure */
        if (!(mp = folder_read(folder)))
                adios(EX_IOERR, NULL, "unable to read folder %s", folder);
 
@@ -360,10 +358,25 @@ main(int argc, char **argv)
                fflush(stdout);
        }
 
+       /* check if readable and nonempty */
+       if (!fgets(buf, sizeof(buf), in)) {
+               if (ferror(in)) {
+                       advise("read", "unable to");
+                       incerr = SCNFAT;
+               } else {
+                       incerr = SCNEOF;
+               }
+               goto giveup;
+       }
+       if (strncmp("From ", buf, 5)!=0) {
+               advise(NULL, "not in mbox format");
+               incerr = SCNFAT;
+               goto giveup;
+       }
+
        /*
        ** Get the mail from file (usually mail spool)
        */
-       thisisanmbox(in);
        hghnum = msgnum = mp->hghmsg;
        for (;;) {
                /*
@@ -431,6 +444,7 @@ main(int argc, char **argv)
                */
                break;
        }
+giveup:;
        mh_free0(&maildir_copy);
 
        if (incerr < 0) {  /* error */
@@ -494,9 +508,9 @@ main(int argc, char **argv)
                fclose(in); in = NULL;
        }
 
-       seq_setunseen(mp, 1);  /* add new msgs to unseen sequences */
-       seq_save(mp);  /* synchronize sequences   */
-       context_save();  /* save the context file   */
+       seq_setunseen(mp, 1);
+       seq_save(mp);
+       context_save();
        return 0;
 }
 
index 0f77f33..fe3e946 100644 (file)
@@ -312,8 +312,10 @@ unlink_done()
 static CT
 build_mime(char *infile)
 {
-       int compnum, state;
-       char buf[BUFSIZ], name[NAMESZ];
+       enum state state;
+       struct field f = {{0}};
+       int compnum;
+       char buf[BUFSIZ];
        char *cp, *np, *vp;
        struct multipart *m;
        struct part **pp;
@@ -324,8 +326,9 @@ build_mime(char *infile)
        umask(~m_gmprot());
 
        /* open the composition draft */
-       if ((in = fopen(infile, "r")) == NULL)
+       if ((in = fopen(infile, "r")) == NULL) {
                adios(EX_IOERR, infile, "unable to open for reading");
+       }
 
        /*
        ** Allocate space for primary (outside) content
@@ -344,57 +347,45 @@ build_mime(char *infile)
        ** draft into the linked list of header fields for
        ** the new MIME message.
        */
-       for (compnum = 1, state = FLD;;) {
-               switch (state = m_getfld(state, name, buf, sizeof(buf), in)) {
-               case FLD:
-               case FLDPLUS:
+       for (compnum = 1, state = FLD2;;) {
+               switch (state = m_getfld2(state, &f, in)) {
+               case FLD2:
                        compnum++;
 
                        /* abort if draft has Mime-Version header field */
-                       if (!mh_strcasecmp(name, VRSN_FIELD))
+                       if (!mh_strcasecmp(f.name, VRSN_FIELD)) {
                                adios(EX_CONFIG, NULL, "draft shouldn't contain %s: field", VRSN_FIELD);
+                       }
 
                        /*
                        ** abort if draft has Content-Transfer-Encoding
                        ** header field
                        */
-                       if (!mh_strcasecmp(name, ENCODING_FIELD))
+                       if (!mh_strcasecmp(f.name, ENCODING_FIELD)) {
                                adios(EX_CONFIG, NULL, "draft shouldn't contain %s: field", ENCODING_FIELD);
+                       }
 
                        /* ignore any Content-Type fields in the header */
-                       if (!mh_strcasecmp(name, TYPE_FIELD)) {
-                               while (state == FLDPLUS)
-                                       state = m_getfld(state, name, buf,
-                                                       sizeof(buf), in);
+                       if (!mh_strcasecmp(f.name, TYPE_FIELD)) {
                                continue;
                        }
 
-                       /* get copies of the buffers */
-                       np = mh_xstrdup(name);
-                       vp = mh_xstrdup(buf);
-
-                       /* if necessary, get rest of field */
-                       while (state == FLDPLUS) {
-                               state = m_getfld(state, name, buf,
-                                               sizeof(buf), in);
-                               vp = add(buf, vp);  /* add to prev value */
-                       }
-
-                       /* Now add the header data to the list */
-                       add_header(ct, np, vp);
+                       /* add the header data to the list */
+                       add_header(ct, mh_xstrdup(f.name), mh_xstrdup(f.value));
 
                        continue;
 
-               case FILEEOF:
+               case BODY2:
+                       fseek(in, (long) (-strlen(f.value)), SEEK_CUR);
+                       break;
+
+               case FILEEOF2:
                        adios(EX_CONFIG, NULL, "draft has empty body -- no directives!");
                        /* NOTREACHED */
 
-               case BODY:
-                       fseek(in, (long) (-strlen(buf)), SEEK_CUR);
-                       break;
-
-               case LENERR:
-               case FMTERR:
+               case LENERR2:
+               case FMTERR2:
+               case IOERR2:
                        adios(EX_CONFIG, NULL, "message format error in component #%d",
                                        compnum);
 
@@ -434,7 +425,7 @@ build_mime(char *infile)
        ct->c_subtype = MULTI_MIXED;
        ct->c_file = mh_xstrdup(infile);
 
-       m = mh_xcalloc(1, sizeof(*m));
+       m = (struct multipart *) mh_xcalloc(1, sizeof(*m));
        ct->c_ctparams = (void *) m;
        pp = &m->mp_parts;
 
index e4e8dbf..c089d8e 100644 (file)
--- a/uip/mhl.c
+++ b/uip/mhl.c
@@ -597,16 +597,18 @@ process(char *fname, int ofilen, int ofilec)
 static void
 mhlfile(FILE *fp, char *mname, int ofilen, int ofilec)
 {
-       int state;
+       enum state state;
+       struct field f = {{0}};
        struct mcomp *c1, *c2, *c3;
-       char **ip, name[NAMESZ], buf[BUFSIZ];
+       char **ip;
 
        if (forwall) {
                printf("\n-------");
-               if (ofilen == 1)
+               if (ofilen == 1) {
                        printf(" Forwarded Message%s", ofilec > 1 ? "s" : "");
-               else
+               } else {
                        printf(" Message %d", ofilen);
+               }
                printf("\n\n");
        } else if (ofilec > 1) {
                if (ofilen > 1) {
@@ -615,84 +617,86 @@ mhlfile(FILE *fp, char *mname, int ofilen, int ofilec)
                printf(">>> %s\n\n", mname);
        }
 
-       for (state = FLD;!eflag;) {
-               switch (state = m_getfld(state, name, buf, sizeof(buf), fp)) {
-               case FLD:
-               case FLDPLUS:
+       for (state = FLD2; !eflag; ) {
+               switch (state = m_getfld2(state, &f, fp)) {
+               case FLD2:
                        for (ip = ignores; *ip; ip++)
-                               if (!mh_strcasecmp(name, *ip)) {
-                                       while (state == FLDPLUS)
-                                               state = m_getfld(state, name, buf, sizeof(buf), fp);
+                               if (mh_strcasecmp(f.name, *ip)==0) {
                                        break;
                                }
-                       if (*ip)
+                       if (*ip) {
                                continue;
+                       }
 
                        for (c2 = fmthd; c2; c2 = c2->c_next)
-                               if (!mh_strcasecmp(c2->c_name, name))
+                               if (mh_strcasecmp(c2->c_name, f.name)==0) {
                                        break;
+                               }
                        c1 = NULL;
                        if (!((c3 = c2 ? c2 : &global)->c_flags & SPLIT))
                                for (c1 = msghd; c1; c1 = c1->c_next)
-                                       if (!mh_strcasecmp(c1->c_name,
-                                                       c3->c_name)) {
-                                               c1->c_text = mcomp_add(c1->c_flags, buf, c1->c_text);
+                                       if (mh_strcasecmp(c1->c_name,
+                                                       c3->c_name)==0) {
+                                               c1->c_text = mcomp_add(c1->c_flags, f.value, c1->c_text);
                                                break;
                                        }
-                       if (c1 == NULL)
-                               c1 = add_queue(&msghd, &msgtl, name, buf, 0);
-                       while (state == FLDPLUS) {
-                               state = m_getfld(state, name, buf,
-                                               sizeof(buf), fp);
-                               c1->c_text = add(buf, c1->c_text);
+                       if (c1 == NULL) {
+                               c1 = add_queue(&msghd, &msgtl, f.name, f.value, 0);
                        }
-                       if (c2 == NULL)
+                       if (c2 == NULL) {
                                c1->c_flags |= EXTRA;
+                       }
                        continue;
 
-               case BODY:
-               case FILEEOF:
+               case BODY2:
+               case FILEEOF2:
                        column = 0;
                        for (c1 = fmthd; c1; c1 = c1->c_next) {
                                if (c1->c_flags & CLEARTEXT) {
                                        putcomp(c1, c1, ONECOMP);
                                        continue;
                                }
-                               if (!mh_strcasecmp(c1->c_name, "messagename")) {
+                               if (mh_strcasecmp(c1->c_name, "messagename")==0) {
                                        holder.c_text = concat("(Message ",
                                                        mname, ")\n", NULL);
                                        putcomp(c1, &holder, ONECOMP);
                                        mh_free0(&(holder.c_text));
                                        continue;
                                }
-                               if (!mh_strcasecmp(c1->c_name, "extras")) {
-                                       for (c2 = msghd; c2; c2 = c2->c_next)
-                                               if (c2->c_flags & EXTRA)
+                               if (mh_strcasecmp(c1->c_name, "extras")==0) {
+                                       for (c2 = msghd; c2; c2 = c2->c_next) {
+                                               if (c2->c_flags & EXTRA) {
                                                        putcomp(c1, c2, TWOCOMP);
+                                               }
+                                       }
                                        continue;
                                }
-                               if (dobody && !mh_strcasecmp(c1->c_name, "body")) {
-                                       holder.c_text = mh_xcalloc(sizeof(buf), sizeof(char));
-                                       strncpy(holder.c_text, buf, sizeof(buf));
-                                       while (state == BODY) {
+                               if (dobody && mh_strcasecmp(c1->c_name, "body")==0) {
+                                       holder.c_text = mh_xstrdup(f.value);
+                                       while (state == BODY2) {
                                                putcomp(c1, &holder, BODYCOMP);
-                                               state = m_getfld(state, name, holder.c_text, sizeof(buf), fp);
+                                               state = m_getfld2(state, &f, fp);
+                                               free(holder.c_text);
+                                               holder.c_text = mh_xstrdup(f.value);
                                        }
                                        mh_free0(&(holder.c_text));
                                        continue;
                                }
-                               for (c2 = msghd; c2; c2 = c2->c_next)
-                                       if (!mh_strcasecmp(c2->c_name,
-                                                       c1->c_name)) {
+                               for (c2 = msghd; c2; c2 = c2->c_next) {
+                                       if (mh_strcasecmp(c2->c_name,
+                                                       c1->c_name)==0) {
                                                putcomp(c1, c2, ONECOMP);
-                                               if (!(c1->c_flags & SPLIT))
+                                               if (!(c1->c_flags & SPLIT)) {
                                                        break;
+                                               }
                                        }
+                               }
                        }
                        return;
 
-               case LENERR:
-               case FMTERR:
+               case LENERR2:
+               case FMTERR2:
+               case IOERR2:
                        advise(NULL, "format error in message %s", mname);
                        exitstat++;
                        return;
index 71c1e8e..67d769c 100644 (file)
@@ -231,9 +231,9 @@ parse_mime(char *file)
 static CT
 get_content(FILE *in, char *file, int toplevel)
 {
-       int compnum, state;
-       char buf[BUFSIZ], name[NAMESZ];
-       char *np, *vp;
+       enum state state;
+       struct field f = {{0}};
+       int compnum;
        CT ct;
        HF hp;
 
@@ -248,47 +248,34 @@ get_content(FILE *in, char *file, int toplevel)
        ** Parse the header fields for this
        ** content into a linked list.
        */
-       for (compnum = 1, state = FLD;;) {
-               switch (state = m_getfld(state, name, buf, sizeof(buf), in)) {
-               case FLD:
-               case FLDPLUS:
+       for (compnum = 1, state = FLD2;;) {
+               switch (state = m_getfld2(state, &f, in)) {
+               case FLD2:
                        compnum++;
 
-                       /* get copies of the buffers */
-                       np = mh_xstrdup(name);
-                       vp = mh_xstrdup(buf);
-
-                       /* if necessary, get rest of field */
-                       while (state == FLDPLUS) {
-                               state = m_getfld(state, name, buf,
-                                               sizeof(buf), in);
-                               vp = add(buf, vp);  /* add to previous value */
-                       }
-
-                       /* Now add the header data to the list */
-                       add_header(ct, np, vp);
+                       /* add the header data to the list */
+                       add_header(ct, mh_xstrdup(f.name), mh_xstrdup(f.value));
 
                        ct->c_begin = ftell(in) + 1;
                        continue;
 
-               case BODY:
-                       ct->c_begin = ftell(in) - strlen(buf);
+               case BODY2:
+                       ct->c_begin = ftell(in) - strlen(f.value);
                        break;
 
-               case FILEEOF:
+               case FILEEOF2:
                        ct->c_begin = ftell(in);
                        break;
 
-               case LENERR:
-               case FMTERR:
+               case LENERR2:
+               case FMTERR2:
+               case IOERR2:
                        adios(EX_DATAERR, NULL, "message format error in component #%d",
                                        compnum);
 
                default:
                        adios(EX_SOFTWARE, NULL, "getfld() returned %d", state);
                }
-
-               /* break out of the loop */
                break;
        }
 
index 5bc7136..4335892 100644 (file)
--- a/uip/new.c
+++ b/uip/new.c
@@ -95,11 +95,10 @@ seq_in_list(char *name, char *sequences[])
 static char *
 get_msgnums(char *folder, char *sequences[])
 {
+       enum state state;
+       struct field f = {{0}};
        char *seqfile = concat(toabsdir(folder), "/", mh_seq, (void *)NULL);
        FILE *fp = fopen(seqfile, "r");
-       int state;
-       char name[NAMESZ], field[BUFSIZ];
-       char *cp;
        char *msgnums = NULL, *this_msgnums, *old_msgnums;
 
        /* no sequences file -> no messages */
@@ -107,67 +106,39 @@ get_msgnums(char *folder, char *sequences[])
                return NULL;
        }
 
-       /* copied from seq_read.c:seq_public */
-       for (state = FLD;;) {
-               switch (state = m_getfld(state, name, field, sizeof(field),
-                               fp)) {
-               case FLD:
-               case FLDPLUS:
-                       if (state == FLDPLUS) {
-                               cp = mh_xstrdup(field);
-                               while (state == FLDPLUS) {
-                                       state = m_getfld(state, name, field,
-                                                       sizeof(field), fp);
-                                       cp = add(field, cp);
-                               }
-
-                               /*
-                               ** Here's where we differ from
-                               ** seq_public: if it's in a
-                               ** sequence we want, save the list
-                               ** of messages.
-                               */
-                               if (seq_in_list(name, sequences)) {
-                                       this_msgnums = trimcpy(cp);
-                                       if (msgnums == NULL) {
-                                               msgnums = this_msgnums;
-                                       } else {
-                                               old_msgnums = msgnums;
-                                               msgnums = concat(old_msgnums, " ", this_msgnums, (void *)NULL);
-                                               mh_free0(&old_msgnums);
-                                               mh_free0(&this_msgnums);
-                                       }
-                               }
-                               mh_free0(&cp);
-                       } else {
-                               /* and here */
-                               if (seq_in_list(name, sequences)) {
-                                       this_msgnums = trimcpy(field);
-                                       if (msgnums == NULL) {
-                                               msgnums = this_msgnums;
-                                       } else {
-                                               old_msgnums = msgnums;
-                                               msgnums = concat(old_msgnums, " ", this_msgnums, (void *)NULL);
-                                               mh_free0(&old_msgnums);
-                                               mh_free0(&this_msgnums);
-                                       }
+       for (state = FLD2;;) {
+               switch (state = m_getfld2(state, &f, fp)) {
+               case FLD2:
+                       /*
+                       ** if it's in a sequence we want,
+                       ** save the list of messages.
+                       */
+                       if (seq_in_list(f.name, sequences)) {
+                               this_msgnums = trimcpy(f.value);
+                               if (msgnums == NULL) {
+                                       msgnums = this_msgnums;
+                               } else {
+                                       old_msgnums = msgnums;
+                                       msgnums = concat(old_msgnums, " ",
+                                                       this_msgnums,
+                                                       NULL);
+                                       mh_free0(&old_msgnums);
+                                       mh_free0(&this_msgnums);
                                }
                        }
-
                        continue;
 
-               case BODY:
-                       adios(EX_DATAERR, NULL, "no blank lines are permitted in %s",
-                                       seqfile);
-                       /* fall */
+               case BODY2:
+                       adios(EX_DATAERR, NULL, "no blank lines are permitted in %s", seqfile);
+                       /* FALL */
 
-               case FILEEOF:
+               case FILEEOF2:
                        break;
 
                default:
                        adios(EX_SOFTWARE, NULL, "%s is poorly formatted", seqfile);
                }
-               break;  /* break from for loop */
+               break;
        }
 
        fclose(fp);
index 1df59b1..5df2861 100644 (file)
@@ -1241,37 +1241,33 @@ static int
 TWSaction(params)
 plist
 {
-       int state;
+       enum state state;
+       struct field f = {{0}};
        char *bp;
-       char buf[BUFSIZ], name[NAMESZ];
        struct tws *tw;
 
        fseek(fp, start, SEEK_SET);
-       for (state = FLD, bp = NULL;;) {
-               switch (state = m_getfld(state, name, buf, sizeof buf, fp)) {
-               case FLD:
-               case FLDPLUS:
-                       if (bp != NULL) {
+       for (state = FLD2, bp = NULL;;) {
+               switch (state = m_getfld2(state, &f, fp)) {
+               case FLD2:
+                       if (bp) {
                                mh_free0(&bp);
                        }
-                       bp = mh_xstrdup(buf);
-                       while (state == FLDPLUS) {
-                               state = m_getfld(state, name, buf,
-                                               sizeof buf, fp);
-                               bp = add(buf, bp);
-                       }
-                       if (!mh_strcasecmp(name, n->n_datef))
+                       bp = mh_xstrdup(f.value);
+                       if (mh_strcasecmp(f.name, n->n_datef)==0) {
                                break;
+                       }
                        continue;
 
-               case BODY:
-               case FILEEOF:
-               case LENERR:
-               case FMTERR:
-                       if (state == LENERR || state == FMTERR)
-                               advise(NULL, "format error in message %d", msgnum);
-                       if (bp != NULL)
-                               mh_free0(&bp);
+               case LENERR2:
+               case FMTERR2:
+               case IOERR2:
+                       advise(NULL, "format error in message %d", msgnum);
+                       /* FALL */
+
+               case BODY2:
+               case FILEEOF2:
+                       mh_free0(&bp);
                        return 0;
 
                default:
index 2adbd48..c7eb957 100644 (file)
@@ -54,9 +54,10 @@ int
 main(int argc, char **argv)
 {
        int qbody = 1, prepend = 1, rapid = 0;
-       int fdi, fdo, i, state;
+       int fdi, fdo, i;
        char *cp, *drft = NULL;
-       char name[NAMESZ], field[BUFSIZ];
+       enum state state;
+       struct field f = {{0}};
        char buffer[BUFSIZ], tmpfil[BUFSIZ];
        char **arguments, **argp;
        FILE *in, *out;
@@ -137,58 +138,53 @@ main(int argc, char **argv)
        /*
        ** Loop through the lines of the draft skeleton.
        */
-       for (state = FLD;;) {
-               switch (state = m_getfld(state, name, field, sizeof(field),
-                               in)) {
-               case FLD:
-               case FLDPLUS:
+       for (state = FLD2;;) {
+               switch (state = m_getfld2(state, &f, in)) {
+               case FLD2:
                        /*
                        ** Check if the value of field contains
                        ** anything other than space or tab.
                        */
-                       for (cp = field; *cp; cp++)
-                               if (*cp != ' ' && *cp != '\t')
+                       for (cp = f.value; *cp; cp++) {
+                               if (*cp != ' ' && *cp != '\t') {
                                        break;
+                               }
+                       }
 
                        /* If so, just add header line to draft */
                        if (*cp++ != '\n' || *cp) {
-                               printf("%s:%s", name, field);
-                               fprintf(out, "%s:%s", name, field);
-                               while (state == FLDPLUS) {
-                                       state = m_getfld(state, name, field,
-                                                       sizeof(field), in);
-                                       printf("%s", field);
-                                       fprintf(out, "%s", field);
-                               }
+                               printf("%s:%s", f.name, f.value);
+                               fprintf(out, "%s:%s", f.name, f.value);
                        } else {
                                /* Else, get value of header field */
-                               printf("%s: ", name);
+                               printf("%s: ", f.name);
                                fflush(stdout);
-                               i = getln(field, sizeof(field));
+                               i = getln(buffer, sizeof(buffer));
                                if (i == -1) {
 abort:
                                        unlink(tmpfil);
                                        exit(EX_DATAERR);
                                }
-                               if (i || (field[0]!='\n' && field[0]!='\0')) {
-                                       fprintf(out, "%s:", name);
+                               if (i || (buffer[0]!='\n' && buffer[0]!='\0')) {
+                                       fprintf(out, "%s:", f.name);
                                        do {
-                                               if (field[0] != ' ' && field[0] != '\t')
+                                               if (buffer[0] != ' ' && buffer[0] != '\t') {
                                                        putc(' ', out);
-                                               fprintf(out, "%s", field);
-                                       } while (i == 1 && (i = getln(field, sizeof(field))) >= 0);
-                                       if (i == -1)
+                                               }
+                                               fprintf(out, "%s", buffer);
+                                       } while (i == 1 && (i = getln(buffer, sizeof(buffer))) >= 0);
+                                       if (i == -1) {
                                                goto abort;
+                                       }
                                }
                        }
-
                        continue;
 
-               case BODY:
-               case FILEEOF:
+               case BODY2:
+               case FILEEOF2:
                        fprintf(out, "--------\n");
                        if (qbody) {
-                               if (!*field) {
+                               if (f.value == NULL) {
                                        printf("--------\n");
                                        goto has_no_body;
                                }
@@ -198,8 +194,9 @@ abort:
                                        fflush(stdout);
                                        for (;;) {
                                                getln(buffer, sizeof(buffer));
-                                               if (!*buffer)
+                                               if (!*buffer) {
                                                        break;
+                                               }
                                                fprintf(out, "%s", buffer);
                                        }
                                } else {
@@ -207,25 +204,29 @@ abort:
                                }
                        }
 
-                       do {
-                               fprintf(out, "%s", field);
-                               if (!rapid && !sigint)
-                                       printf("%s", field);
-                       } while (state == BODY &&
-                                       (state = m_getfld(state, name,
-                                       field, sizeof(field), in)));
+                       if (state == BODY2) {
+                               do {
+                                       fprintf(out, "%s", f.value);
+                                       if (!rapid && !sigint) {
+                                               printf("%s", f.value);
+                                       }
+                               } while ((state = m_getfld2(state, &f, in))
+                                               ==BODY2);
+                       }
 
-                       if (prepend || !qbody)
+                       if (prepend || !qbody) {
                                break;
+                       }
 
                        printf("--------Enter additional text\n");
 has_no_body:
                        fflush(stdout);
                        for (;;) {
-                               getln(field, sizeof(field));
-                               if (!*field)
+                               getln(buffer, sizeof(buffer));
+                               if (!*buffer) {
                                        break;
-                               fprintf(out, "%s", field);
+                               }
+                               fprintf(out, "%s", buffer);
                        }
                        break;
 
@@ -235,8 +236,9 @@ has_no_body:
                break;
        }
 
-       if (qbody)
+       if (qbody) {
                printf("--------\n");
+       }
 
        fflush(stdout);
        fclose(in);
@@ -254,7 +256,7 @@ has_no_body:
        close(fdo);
        unlink(tmpfil);
 
-       context_save();  /* save the context file */
+       context_save();
        return EX_OK;
 }
 
index f3caa50..d08058b 100644 (file)
@@ -126,13 +126,9 @@ main(int argc, char **argv)
 
 /* very similar to routine in replsbr.c */
 
-#define SBUFSIZ 256
-
 static struct format *fmt;
 
 static int ncomps = 0;
-static char **compbuffers = 0;
-static struct comp **used_buf = 0;
 
 static int dat[5];
 
@@ -156,10 +152,12 @@ static char *addrcomps[] = {
 static void
 rcvdistout(FILE *inb, char *form, char *addrs)
 {
-       int char_read = 0, format_len, i, state;
-       char *tmpbuf, **nxtbuf, **ap;
-       char *cp, *scanl, name[NAMESZ];
-       struct comp *cptr, **savecomp;
+       int char_read = 0, format_len, i;
+       enum state state;
+       struct field f = {{0}};
+       char **ap;
+       char *cp, *scanl;
+       struct comp *cptr;
        FILE *out;
 
        if (!(out = fopen(drft, "w"))) {
@@ -170,16 +168,6 @@ rcvdistout(FILE *inb, char *form, char *addrs)
        cp = new_fs(form ? form : rcvdistcomps, NULL);
        format_len = strlen(cp);
        ncomps = fmt_compile(cp, &fmt) + 1;
-       nxtbuf = compbuffers = mh_xcalloc(ncomps, sizeof(char *));
-       savecomp = used_buf = mh_xcalloc(ncomps + 1, sizeof(struct comp *));
-       savecomp += ncomps + 1;
-       *--savecomp = 0;
-
-       for (i = ncomps; i--;) {
-               *nxtbuf++ = mh_xcalloc(SBUFSIZ, sizeof(char));
-       }
-       nxtbuf = compbuffers;
-       tmpbuf = *nxtbuf++;
 
        for (ap = addrcomps; *ap; ap++) {
                FINDCOMP(cptr, *ap);
@@ -192,22 +180,19 @@ rcvdistout(FILE *inb, char *form, char *addrs)
        if (cptr) {
                cptr->c_text = addrs;
        }
-       state = FLD;
+       state = FLD2;
        while (1) {
-               state = m_getfld(state, name, tmpbuf, SBUFSIZ, inb);
+               state = m_getfld2(state, &f, inb);
                switch (state) {
-               case FLD:
-               case FLDPLUS:
-                       if ((cptr = wantcomp[CHASH(name)])) {
+               case FLD2:
+                       if ((cptr = wantcomp[CHASH(f.name)])) {
                                do {
-                                       if (mh_strcasecmp(name, cptr->c_name)!=0) {
+                                       if (mh_strcasecmp(f.name, cptr->c_name)!=0) {
                                                continue;
                                        }
-                                       char_read += msg_count;
+                                       char_read += strlen(f.value);
                                        if (!cptr->c_text) {
-                                               cptr->c_text = tmpbuf;
-                                               *--savecomp = cptr;
-                                               tmpbuf = *nxtbuf++;
+                                               cptr->c_text = mh_xstrdup(f.value);
                                        } else {
                                                cp = cptr->c_text;
                                                i = strlen(cp) - 1;
@@ -219,27 +204,18 @@ rcvdistout(FILE *inb, char *form, char *addrs)
                                                                cp = add("\t", cp);
                                                        }
                                                }
-                                               cptr->c_text = add(tmpbuf, cp);
-                                       }
-                                       while (state == FLDPLUS) {
-                                               state = m_getfld(state, name, tmpbuf, SBUFSIZ, inb);
-                                               cptr->c_text = add(tmpbuf, cptr->c_text);
-                                               char_read += msg_count;
+                                               cptr->c_text = add(f.value, cp);
                                        }
                                        break;
                                } while ((cptr = cptr->c_next));
                        }
-
-                       while (state == FLDPLUS) {
-                               state = m_getfld(state, name, tmpbuf,
-                                               SBUFSIZ, inb);
-                       }
                        break;
 
-               case LENERR:
-               case FMTERR:
-               case BODY:
-               case FILEEOF:
+               case LENERR2:
+               case FMTERR2:
+               case IOERR2:
+               case BODY2:
+               case FILEEOF2:
                        goto finished;
 
                default:
@@ -261,15 +237,6 @@ finished: ;
        fclose(out);
 
        mh_free0(&scanl);
-       for (nxtbuf = compbuffers, i = ncomps; (cptr = *savecomp++);
-                       nxtbuf++, i--) {
-               mh_free0(&(cptr->c_text));
-       }
-       while (i-- > 0) {
-               mh_free0(nxtbuf++);
-       }
-       mh_free0(&compbuffers);
-       mh_free0(&used_buf);
 }
 
 
index 5fd9ae0..83c5150 100644 (file)
@@ -50,6 +50,7 @@ static struct swit switches[] = {
 static char *tmpfilenam = NULL;
 
 void unlink_done();
+static void fix_mbox(int out, char *ofile);
 
 int
 main(int argc, char **argv)
@@ -179,6 +180,9 @@ main(int argc, char **argv)
        }
        chmod(tmpfilenam, m_gmprot());
 
+       /* check if incoming mail is in mbox-format */
+       fix_mbox(fd, tmpfilenam);
+
        /* copy the message from stdin into temp file */
        cpydata(fileno(stdin), fd, "standard input", tmpfilenam);
 
@@ -230,6 +234,35 @@ main(int argc, char **argv)
        return EX_OK;
 }
 
+static void
+fix_mbox(int out, char *outfile)
+{
+       char mbox[5];
+       int ret;
+
+       if ((ret = read(fileno(stdin), mbox, sizeof(mbox))) != sizeof(mbox)) {
+               if (ret == -1) {
+                       adios(EX_IOERR, "standard input", "error reading");
+               }
+               return;
+       }
+
+       if (strncmp(mbox, "From ", sizeof(mbox))==0) {
+               do {
+                       if ((ret = read(fileno(stdin), mbox, 1)) != 1) {
+                               if (ret == -1) {
+                                       adios(EX_IOERR, "standard input", "error reading");
+                               }
+                               return;
+                       }
+               } while (*mbox != '\n');
+       } else {
+               if (write(out, mbox, sizeof(mbox)) != sizeof(mbox)) {
+                       adios(EX_IOERR, outfile, "error writing");
+               }
+       }
+}
+
 /*
 ** Clean up and exit
 */
index e3028fa..9006dec 100644 (file)
@@ -72,15 +72,6 @@ static struct swit ccswitches[] = {
        { NULL, 0 }
 };
 
-/*
-** Buffer size for content part of header fields.
-** We want this to be large enough so that we don't
-** do a lot of extra FLDPLUS calls on m_getfld but
-** small enough so that we don't snarf the entire
-** message body when we're not going to use any of it.
-*/
-#define SBUFSIZ 256
-
 static short ccto = -1;
 static short cccc = -1;
 static short ccme = -1;
@@ -102,8 +93,6 @@ static struct mailname mq;
 static struct format *fmt;
 
 static int ncomps = 0;  /* # of interesting components */
-static char **compbuffers = NULL;  /* buffers for component text */
-static struct comp **used_buf = NULL;  /* stack for comp that use buffers */
 
 static int dat[5];  /* aux. data for format routine */
 
@@ -388,14 +377,13 @@ static void
 replout(FILE *inb, char *drft, struct msgs *mp,
        int mime, char *form, char *filter)
 {
-       int state, i;
+       enum state state;
+       struct field f = {{0}};
+       int i;
        struct comp *cptr;
-       char *tmpbuf;
-       char **nxtbuf;
        char **ap;
-       struct comp **savecomp;
        int char_read = 0, format_len, mask;
-       char name[NAMESZ], *scanl;
+       char *scanl;
        unsigned char *cp;
        FILE *out;
 
@@ -412,17 +400,6 @@ replout(FILE *inb, char *drft, struct msgs *mp,
        /* compile format string */
        ncomps = fmt_compile(cp, &fmt) + 1;
 
-       nxtbuf = compbuffers = mh_xcalloc(ncomps, sizeof(char *));
-       savecomp = used_buf = mh_xcalloc(ncomps+1, sizeof(struct comp *));
-       savecomp += ncomps + 1;
-       *--savecomp = NULL;  /* point at zero'd end minus 1 */
-
-       for (i = ncomps; i--; )
-               *nxtbuf++ = mh_xcalloc(SBUFSIZ, sizeof(char));
-
-       nxtbuf = compbuffers;  /* point at start */
-       tmpbuf = *nxtbuf++;
-
        for (ap = addrcomps; *ap; ap++) {
                FINDCOMP(cptr, *ap);
                if (cptr)
@@ -453,11 +430,10 @@ replout(FILE *inb, char *drft, struct msgs *mp,
        /*
        ** pick any interesting stuff out of msg "inb"
        */
-       for (state = FLD;;) {
-               state = m_getfld(state, name, tmpbuf, SBUFSIZ, inb);
+       for (state = FLD2;;) {
+               state = m_getfld2(state, &f, inb);
                switch (state) {
-               case FLD:
-               case FLDPLUS:
+               case FLD2:
                        /*
                        ** if we're interested in this component, save
                        ** a pointer to the component text, then start
@@ -465,47 +441,41 @@ replout(FILE *inb, char *drft, struct msgs *mp,
                        ** temp buffer (buffer switching saves an extra
                        ** copy of the component text).
                        */
-                       if ((cptr = wantcomp[CHASH(name)]))
+                       if ((cptr = wantcomp[CHASH(f.name)])) {
                                do {
-                                       if (!mh_strcasecmp(name, cptr->c_name)) {
-                                               char_read += msg_count;
-                                               if (! cptr->c_text) {
-                                                       i = strlen(cptr->c_text = tmpbuf) - 1;
-                                                       if (tmpbuf[i] == '\n')
-                                                               tmpbuf[i] = '\0';
-                                                       *--savecomp = cptr;
-                                                       tmpbuf = *nxtbuf++;
-                                               } else {
-                                                       i = strlen(cp = cptr->c_text) - 1;
-                                                       if (cp[i] == '\n') {
-                                                               if (cptr->c_type & CT_ADDR) {
-                                                                       cp[i] = '\0';
-                                                                       cp = add(",\n\t", cp);
-                                                               } else {
-                                                                       cp = add("\t", cp);
-                                                               }
-                                                       }
-                                                       cptr->c_text = add(tmpbuf, cp);
+                                       if (mh_strcasecmp(f.name, cptr->c_name)!=0) {
+                                               continue;
+                                       }
+                                       char_read += strlen(f.value);
+                                       if (!cptr->c_text) {
+                                               cptr->c_text = mh_xstrdup(f.value);
+                                               i = strlen(cptr->c_text) - 1;
+                                               if (cptr->c_text[i] == '\n') {
+                                                       cptr->c_text[i] = '\0';
                                                }
-                                               while (state == FLDPLUS) {
-                                                       state = m_getfld(state, name, tmpbuf,
-                                                                                         SBUFSIZ, inb);
-                                                       cptr->c_text = add(tmpbuf, cptr->c_text);
-                                                       char_read += msg_count;
+                                       } else {
+                                               cp = cptr->c_text;
+                                               i = strlen(cp) - 1;
+                                               if (cp[i] == '\n') {
+                                                       if (cptr->c_type & CT_ADDR) {
+                                                               cp[i] = '\0';
+                                                               cp = add(",\n\t", cp);
+                                                       } else {
+                                                               cp = add("\t", cp);
+                                                       }
                                                }
-                                               break;
+                                               cptr->c_text = add(f.value, cp);
                                        }
+                                       break;
                                } while ((cptr = cptr->c_next));
-
-                       while (state == FLDPLUS)
-                               state = m_getfld(state, name, tmpbuf,
-                                               SBUFSIZ, inb);
+                       }
                        break;
 
-               case LENERR:
-               case FMTERR:
-               case BODY:
-               case FILEEOF:
+               case LENERR2:
+               case FMTERR2:
+               case IOERR2:
+               case BODY2:
+               case FILEEOF2:
                        goto finished;
 
                default:
@@ -583,13 +553,6 @@ finished:
 
        /* return dynamically allocated buffers */
        mh_free0(&scanl);
-       for (nxtbuf = compbuffers, i = ncomps; (cptr = *savecomp++);
-                       nxtbuf++, i--)
-               mh_free0(&(cptr->c_text));  /* if not nxtbuf, nxtbuf already freed */
-       while ( i-- > 0)
-               mh_free0(nxtbuf++);  /* free unused nxtbufs */
-       mh_free0(&compbuffers);
-       mh_free0(&used_buf);
 }
 
 static char *buf;  /* our current working buffer */
index 671509a..a735b31 100644 (file)
@@ -124,7 +124,6 @@ main(int argc, char **argv)
                        adios(EX_IOERR, file, "unable to open");
                }
 
-               thisisanmbox(in);
                for (msgnum = 1; ; ++msgnum) {
                        state = scan(in, msgnum, SCN_MBOX, fmtstr, width, 0, 0);
                        if (state != SCNMSG)
@@ -147,7 +146,6 @@ main(int argc, char **argv)
        if (chdir(maildir) == NOTOK)
                adios(EX_OSERR, maildir, "unable to change directory to");
 
-       /* read folder and create message structure */
        if (!(mp = folder_read(folder)))
                adios(EX_IOERR, NULL, "unable to read folder %s", folder);
 
@@ -159,11 +157,11 @@ main(int argc, char **argv)
        for (msgnum = 0; msgnum < msgs.size; msgnum++)
                if (!m_convert(mp, msgs.msgs[msgnum]))
                        exit(EX_USAGE);
-       seq_setprev(mp);  /* set the Previous-Sequence */
+       seq_setprev(mp);
 
-       context_replace(curfolder, folder);  /* update current folder */
-       seq_save(mp);  /* synchronize message sequences */
-       context_save();  /* save the context file */
+       context_replace(curfolder, folder);
+       seq_save(mp);
+       context_save();
 
        /*
        ** Get the sequence number for each `unseen' sequence
@@ -186,42 +184,43 @@ main(int argc, char **argv)
        }
 
        for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
-               if (is_selected(mp, msgnum)) {
-                       if ((in = fopen(cp = m_name(msgnum), "r")) == NULL) {
-                               admonish(cp, "unable to open message");
-                               continue;
-                       }
+               if (!is_selected(mp, msgnum)) {
+                       continue;
+               }
 
-                       /*
-                       ** Check if message is in any sequence given
-                       ** by Unseen-Sequence profile entry.
-                       */
-                       unseen = 0;
-                       for (i = 0; i < num_unseen_seq; i++) {
-                               if (in_sequence(mp, seqnum[i], msgnum)) {
-                                       unseen = 1;
-                                       break;
-                               }
-                       }
+               if ((in = fopen(cp = m_name(msgnum), "r")) == NULL) {
+                       admonish(cp, "unable to open message");
+                       continue;
+               }
 
-                       switch (state = scan(in, msgnum, SCN_FOLD, fmtstr,
-                                       width, msgnum==mp->curmsg, unseen)) {
-                       case SCNMSG:
-                       case SCNERR:
+               /*
+               ** Check if message is in any sequence given
+               ** by Unseen-Sequence profile entry.
+               */
+               unseen = 0;
+               for (i = 0; i < num_unseen_seq; i++) {
+                       if (in_sequence(mp, seqnum[i], msgnum)) {
+                               unseen = 1;
                                break;
+                       }
+               }
 
-                       default:
-                               adios(EX_SOFTWARE, NULL, "scan() botch(%d)", state);
+               switch (state = scan(in, msgnum, SCN_FOLD, fmtstr,
+                               width, msgnum==mp->curmsg, unseen)) {
+               case SCNMSG:
+               case SCNERR:
+                       break;
 
-                       case SCNEOF:
-                               advise(NULL, "message %d: empty", msgnum);
-                               break;
-                       }
-                       fclose(in);
+               default:
+                       adios(EX_SOFTWARE, NULL, "scan() botch(%d)", state);
+
+               case SCNEOF:
+                       advise(NULL, "message %d: empty", msgnum);
+                       break;
                }
+               fclose(in);
        }
-
-       folder_free(mp);  /* free folder/message structure */
+       folder_free(mp);
 
        return 0;
 }
index 877bdef..feef5c0 100644 (file)
 #include <sys/stat.h>
 #include <sysexits.h>
 
-#ifdef _FSTDIO
-# define _ptr _p  /* Gag */
-# define _cnt _w  /* Wretch */
-#endif
-
 #define MAXSCANL 256  /* longest possible scan line */
 
-/*
-** Buffer size for content part of header fields.  We want this
-** to be large enough so that we don't do a lot of extra FLDPLUS
-** calls on m_getfld.
-*/
-#define SBUFSIZ 512
-
 static struct format *fmt;
 
 static struct comp *datecomp;  /* pntr to "date" comp */
 static int ncomps = 0;  /* # of interesting components */
-static char **compbuffers = NULL;  /* buffers for component text */
-static struct comp **used_buf = NULL;  /* stack for comp that use buffers */
 
 static int dat[5];  /* aux. data for format routine */
 
@@ -62,18 +48,18 @@ scan(FILE *inb, int innum, int outnum, char *fmtstr, int width, int curflg,
        int unseen)
 {
        static int slwidth;
-       int i, compnum, state;
-       unsigned char *cp, *tmpbuf;
-       char **nxtbuf;
+       int compnum, i;
+       enum state state;
+       struct field f = {{0}};
+       char *cp;
        struct comp *cptr;
-       struct comp **savecomp;
        char *scnmsg = NULL;
        FILE *scnout = NULL;
-       char name[NAMESZ];
        int incing = (outnum != SCN_MBOX && outnum != SCN_FOLD);
        int scanfolder = (outnum == SCN_FOLD);
        long fpos;
        struct stat st;
+       int blankline;
 
        /* first-time only initialization */
        if (!scanl) {
@@ -96,41 +82,20 @@ scan(FILE *inb, int innum, int outnum, char *fmtstr, int width, int curflg,
                        ncomps = 1;
                        datecomp = NULL;
                }
+       }
 
-               nxtbuf = compbuffers = mh_xcalloc(ncomps, sizeof(char *));
-               used_buf = mh_xcalloc(ncomps+1, sizeof(struct comp *));
-               /* NULL-terminate array */
-               used_buf += ncomps;
-               *used_buf = NULL;
-               /* allocate space for the items */
-               for (i = ncomps; i--; )
-                       *nxtbuf++ = mh_xcalloc(SBUFSIZ, sizeof(char));
+       if (feof(inb)) {
+               return SCNEOF;
        }
 
        /*
        ** each-message initialization
        */
-       nxtbuf = compbuffers;
-       savecomp = used_buf;
-       tmpbuf = *nxtbuf++;
        dat[0] = innum ? innum : outnum;
        dat[1] = curflg;
        dat[4] = unseen;
        fpos = ftell(inb);
 
-       /*
-       ** Get the first field.  If the message is non-empty
-       ** and we're doing an "inc", open the output file.
-       */
-       if ((state = m_getfld(FLD, name, tmpbuf, SBUFSIZ, inb)) == FILEEOF) {
-               if (ferror(inb)) {
-                       advise("read", "unable to"); /* "read error" */
-                       return SCNFAT;
-               } else {
-                       return SCNEOF;
-               }
-       }
-
        if (incing) {
                scnmsg = m_name(outnum);
                if (*scnmsg == '?')  /* msg num out of range */
@@ -138,92 +103,123 @@ scan(FILE *inb, int innum, int outnum, char *fmtstr, int width, int curflg,
                if (!(scnout = fopen(scnmsg, "w")))
                        adios(EX_IOERR, scnmsg, "unable to write");
        }
-
        /* scan - main loop */
-       for (compnum = 1; ;
-                       state = m_getfld(state, name, tmpbuf, SBUFSIZ, inb)) {
+       for (compnum = 1, state = FLD2; ; ) {
+               state = m_getfld2(state, &f, inb);
                switch (state) {
-               case FLD:
-               case FLDPLUS:
+               case FLD2:
                        compnum++;
                        if (incing) {
-                               FPUTS(name);
+                               FPUTS(f.name);
                                FPUTS(":");
-                               FPUTS(tmpbuf);
+                               FPUTS(f.value);
                        }
-                       /*
-                       ** if we're interested in this component, save
-                       ** a pointer to the component text, then start
-                       ** using our next free buffer as the component
-                       ** temp buffer (buffer switching saves an extra
-                       ** copy of the component text).
-                       */
-                       if (fmtstr && (cptr = wantcomp[CHASH(name)])) {
+                       if (fmtstr && (cptr = wantcomp[CHASH(f.name)])) {
+                               /*
+                               ** we're interested in this component,
+                               ** but find the right one in the hash
+                               ** collision chain ...
+                               */
                                do {
-                                       if (mh_strcasecmp(name, cptr->c_name)!=0) {
+                                       if (mh_strcasecmp(f.name, cptr->c_name)!=0) {
                                                continue;
                                        }
-                                       if (!cptr->c_text) {
-                                               cptr->c_text = tmpbuf;
-                                               cp = tmpbuf+strlen(tmpbuf)-1;
-                                               for (; cp >= tmpbuf; cp--) {
-                                                       if (isspace(*cp))
-                                                               *cp = '\0';
-                                                       else
-                                                               break;
+                                       if (cptr->c_text) {
+                                               free(cptr->c_text);
+                                               cptr->c_text = NULL;
+                                       }
+                                       cptr->c_text = mh_xstrdup(f.value);
+                                       cp = cptr->c_text + strlen(cptr->c_text) - 1;
+                                       for (; cp >= cptr->c_text; cp--) {
+                                               if (isspace(*cp)) {
+                                                       *cp = '\0';
+                                               } else {
+                                                       break;
                                                }
-                                               *--savecomp = cptr;
-                                               tmpbuf = *nxtbuf++;
                                        }
                                        break;
                                } while ((cptr = cptr->c_next));
                        }
-
-                       while (state == FLDPLUS) {
-                               state = m_getfld(state, name, tmpbuf, SBUFSIZ,
-                                               inb);
-                               if (incing)
-                                       FPUTS(tmpbuf);
-                       }
                        break;
 
-               case BODY:
+               case BODY2:
                        compnum = -1;
                        if (scanfolder) {
                                /* stop here if we scan a msg in a folder */
-                               state = FILEEOF;
+                               state = FILEEOF2;
                                goto finished;
                        }
                        /* otherwise (mbox): snarf the body */
+                       if (strncmp("From ", f.value, 5)==0) {
+                               state = FILEEOF2;
+                               goto finished;
+                       }
                        if (incing) {
                                FPUTS("\n");
-                               FPUTS(tmpbuf);
+                               FPUTS(f.value);
                        }
 body:;
-                       while (state == BODY) {
-                               state = m_getfld(state, name, tmpbuf, SBUFSIZ,
-                                               inb);
+                       blankline = 0;
+                       while ((state = m_getfld2(state, &f, inb)) == BODY2) {
+                               /*
+                               ** recognize From lines without blank lines
+                               ** before them as well.
+                               */
+                               if (strncmp("From ", f.value, 5)==0) {
+                                       state = FILEEOF2;
+                                       goto finished;
+                               }
+                               /*
+                               ** delay the printing of blank lines
+                               ** because if it's the end of the message,
+                               ** then we must omit the blank line,
+                               ** as it is not part of the message but
+                               ** part of the mbox format
+                               */
+                               if (blankline) {
+                                       /* print the delayed blank line */
+                                       FPUTS("\n");
+                                       blankline = 0;
+                               }
+                               if (strcmp(f.value, "\n")==0) {
+                                       blankline = 1;
+                                       continue;
+                               }
                                if (incing) {
-                                       FPUTS(tmpbuf);
+                                       FPUTS(f.value);
                                }
                        }
                        goto finished;
 
-               case LENERR:
-               case FMTERR:
-                       fprintf(stderr, innum ? "??Format error (message %d) in " : "??Format error in ", outnum ? outnum : innum);
+               case LENERR2:
+                       advise(NULL, "line \"%s\" too long", trim(f.value));
+                       goto handleerror;
+
+               case FMTERR2:
+                       if (strncmp("From ", f.value, 5)==0) {
+                               state = FILEEOF2;
+                               goto finished;
+                       }
+                       /* FALL */
+
+               case IOERR2:
+handleerror:;
+                       fprintf(stderr, innum ?
+                                       "??Format error (message %d) in " :
+                                       "??Format error in ",
+                                       outnum ? outnum : innum);
                        fprintf(stderr, "component %d\n", compnum);
 
                        if (incing) {
                                FPUTS("\n\nBAD MSG:\n");
-                               FPUTS(name);
+                               FPUTS(f.name);  /* XXX use f.field? */
                                FPUTS("\n");
-                               state = BODY;
+                               state = BODY2;
                                goto body;
                        }
                        /* fall through if we scan only */
 
-               case FILEEOF:
+               case FILEEOF2:
                        goto finished;
 
                default:
@@ -232,7 +228,6 @@ body:;
        }
 
 finished:
-
        /* Format and output the scan line. */
        if (ferror(inb)) {
                advise("read", "unable to");
@@ -271,15 +266,18 @@ finished:
                fputs(scanl, stdout);
        }
 
-       /* return dynamically allocated buffers to pool */
-       while ((cptr = *savecomp++)) {
-               *--nxtbuf = cptr->c_text;
-               cptr->c_text = NULL;
+       /* clean up old values */
+        for (i=0; i < sizeof(wantcomp)/sizeof(wantcomp[0]); i++) {
+               for (cptr=wantcomp[i]; cptr; cptr=cptr->c_next) {
+                       if (cptr->c_text) {
+                               free(cptr->c_text);
+                               cptr->c_text = NULL;
+                       }
+               }
        }
-       *--nxtbuf = tmpbuf;
 
        if (incing && (ferror(scnout) || fclose(scnout) == EOF))
                adios(EX_IOERR, scnmsg, "write error on");
 
-       return (state != FILEEOF ? SCNERR : SCNMSG);
+       return (state == FILEEOF2 ? SCNMSG : SCNERR);
 }
index 18c4a58..f8f9d95 100644 (file)
@@ -724,10 +724,10 @@ split(char *cp, char **vec)
 static int
 parse(int fd)
 {
-       int i, state;
-       int fd1;
+       enum state state;
+       struct field f = {{0}};
+       int i, fd1;
        char *cp, *dp, *lp;
-       char name[NAMESZ], field[BUFSIZ];
        struct pair *p, *q;
        FILE  *in;
 
@@ -756,19 +756,12 @@ parse(int fd)
        /*
        ** Scan the headers of the message and build a lookup table.
        */
-       for (i = 0, state = FLD;;) {
-               switch (state = m_getfld(state, name, field, sizeof(field),
-                               in)) {
-               case FLD:
-               case FLDPLUS:
-                       lp = mh_xstrdup(field);
-                       while (state == FLDPLUS) {
-                               state = m_getfld(state, name, field,
-                                               sizeof(field), in);
-                               lp = add(field, lp);
-                       }
+       for (i = 0, state = FLD2;;) {
+               switch (state = m_getfld2(state, &f, in)) {
+               case FLD2:
+                       lp = mh_xstrdup(f.value);
                        for (p = hdrs; p->p_name; p++) {
-                               if (mh_strcasecmp(p->p_name, name)!=0) {
+                               if (mh_strcasecmp(p->p_name, f.name)!=0) {
                                        if (!(p->p_flags & P_HID)) {
                                                if ((cp = p->p_value)) {
                                                        if (p->p_flags & P_ADR) {
@@ -788,7 +781,7 @@ parse(int fd)
                                }
                        }
                        if (!p->p_name && i < NVEC) {
-                               p->p_name = mh_xstrdup(name);
+                               p->p_name = mh_xstrdup(f.name);
                                p->p_value = lp;
                                p->p_flags = P_NIL;
                                p++, i++;
@@ -796,12 +789,13 @@ parse(int fd)
                        }
                        continue;
 
-               case BODY:
-               case FILEEOF:
+               case BODY2:
+               case FILEEOF2:
                        break;
 
-               case LENERR:
-               case FMTERR:
+               case LENERR2:
+               case FMTERR2:
+               case IOERR2:
                        advise(NULL, "format error in message");
                        break;
 
index 0c5511d..56fa7cb 100644 (file)
@@ -317,9 +317,10 @@ read_hdrs(struct msgs *mp, char *datesw)
 static int
 get_fields(char *datesw, int msg, struct smsg *smsg)
 {
-       int state;
+       enum state state;
+       struct field f = {{0}};
        int compnum;
-       char *msgnam, buf[BUFSIZ], nam[NAMESZ];
+       char *msgnam;
        struct tws *tw;
        char *datecomp = NULL, *subjcomp = NULL;
        FILE *in;
@@ -328,49 +329,37 @@ get_fields(char *datesw, int msg, struct smsg *smsg)
                admonish(msgnam, "unable to read message");
                return (0);
        }
-       for (compnum = 1, state = FLD;;) {
-               switch (state = m_getfld(state, nam, buf, sizeof(buf), in)) {
-               case FLD:
-               case FLDPLUS:
-                       compnum++;
-                       if (!mh_strcasecmp(nam, datesw)) {
-                               datecomp = add(buf, datecomp);
-                               while (state == FLDPLUS) {
-                                       state = m_getfld(state, nam, buf,
-                                                       sizeof(buf), in);
-                                       datecomp = add(buf, datecomp);
-                               }
-                               if (!subjsort || subjcomp)
+       for (compnum = 1, state = FLD2;; compnum++) {
+               switch (state = m_getfld2(state, &f, in)) {
+               case FLD2:
+                       if (mh_strcasecmp(f.name, datesw)==0) {
+                               datecomp = mh_xstrdup(f.value);
+                               if (!subjsort || subjcomp) {
                                        break;
-                       } else if (subjsort && !mh_strcasecmp(nam, subjsort)) {
-                               subjcomp = add(buf, subjcomp);
-                               while (state == FLDPLUS) {
-                                       state = m_getfld(state, nam, buf,
-                                                       sizeof(buf), in);
-                                       subjcomp = add(buf, subjcomp);
                                }
-                               if (datecomp)
+                       } else if (subjsort && mh_strcasecmp(f.name,
+                                       subjsort)==0) {
+                               subjcomp = mh_xstrdup(f.value);
+                               if (datecomp) {
                                        break;
-                       } else {
-                               /* just flush this guy */
-                               while (state == FLDPLUS)
-                                       state = m_getfld(state, nam, buf,
-                                                       sizeof(buf), in);
+                               }
                        }
                        continue;
 
-               case BODY:
-               case FILEEOF:
+               case BODY2:
+               case FILEEOF2:
                        break;
 
-               case LENERR:
-               case FMTERR:
-                       if (state == LENERR || state == FMTERR)
-                               admonish(NULL, "format error in message %d (header #%d)", msg, compnum);
-                       if (datecomp)
+               case LENERR2:
+               case FMTERR2:
+               case IOERR2:
+                       admonish(NULL, "format error in message %d (header #%d)", msg, compnum);
+                       if (datecomp) {
                                mh_free0(&datecomp);
-                       if (subjcomp)
+                       }
+                       if (subjcomp) {
                                mh_free0(&subjcomp);
+                       }
                        fclose(in);
                        return (0);
 
index ce3e684..53ae86a 100644 (file)
@@ -144,9 +144,11 @@ static size_t do_aliasing(struct mailname *, struct mailname **);
 int
 main(int argc, char **argv)
 {
-       int state, compnum;
+       enum state state;
+       struct field f = {{0}};
+       int compnum;
        char *cp, *msg = NULL, **argp, **arguments;
-       char **sargv, buf[BUFSIZ], name[NAMESZ];
+       char **sargv, buf[BUFSIZ];
        FILE *in;
 
        setlocale(LC_ALL, "");
@@ -231,37 +233,28 @@ main(int argc, char **argv)
 
        hdrtab = (msgstate == normal) ? NHeaders : RHeaders;
 
-       for (compnum = 1, state = FLD;;) {
-               switch (state = m_getfld(state, name, buf, sizeof(buf), in)) {
-               case FLD:
-               case FLDPLUS:
+       for (compnum = 1, state = FLD2;;) {
+               switch (state = m_getfld2(state, &f, in)) {
+               case FLD2:
                        compnum++;
-                       cp = mh_xstrdup(buf);
-                       while (state == FLDPLUS) {
-                               state = m_getfld(state, name, buf,
-                                               sizeof(buf), in);
-                               cp = add(buf, cp);
-                       }
-                       putfmt(name, cp, out);
-                       mh_free0(&cp);
+                       putfmt(f.name, f.value, out);
                        continue;
 
-               case BODY:
+               case BODY2:
                        finish_headers(out);
-                       fprintf(out, "\n%s", buf);
-                       while (state == BODY) {
-                               state = m_getfld(state, name, buf,
-                                               sizeof(buf), in);
-                               fputs(buf, out);
+                       fprintf(out, "\n%s", f.value);
+                       while ((state = m_getfld2(state, &f, in)) == BODY2) {
+                               fputs(f.value, out);
                        }
                        break;
 
-               case FILEEOF:
+               case FILEEOF2:
                        finish_headers(out);
                        break;
 
-               case LENERR:
-               case FMTERR:
+               case LENERR2:
+               case FMTERR2:
+               case IOERR2:
                        adios(EX_DATAERR, NULL, "message format error in component #%d",
                                        compnum);
 
index b987356..daca343 100644 (file)
@@ -203,9 +203,9 @@ main(int argc, char **argv)
 static int
 process(char *file)
 {
-        int state, compnum;
-       char *cp = NULL;
-       char buf[BUFSIZ], name[NAMESZ];
+       enum state state;
+       struct field f = {{0}};
+       int compnum;
        FILE *in;
 
 
@@ -213,31 +213,19 @@ process(char *file)
                adios(EX_IOERR, file, "unable to open");
        }
 
-       for (compnum = 1, state = FLD;;) {
-               switch (state = m_getfld(state, name, buf, sizeof(buf), in)) {
-               case FLD:
-                       compnum++;
-                       proc_hdr(name, buf);
+       for (compnum=1, state=FLD2;; compnum++) {
+               switch (state = m_getfld2(state, &f, in)) {
+               case FLD2:
+                       proc_hdr(f.name, f.value);
                        continue;
 
-               case FLDPLUS:
-                       compnum++;
-                       cp = mh_xstrdup(buf);
-                       while (state == FLDPLUS) {
-                               state = m_getfld(state, name, buf,
-                                               sizeof(buf), in);
-                               cp = add(buf, cp);
-                       }
-                       proc_hdr(name, cp);
-                       mh_free0(&cp);
-                       continue;
-
-               case BODY:
-               case FILEEOF:
+               case BODY2:
+               case FILEEOF2:
                        break;
 
-               case LENERR:
-               case FMTERR:
+               case LENERR2:
+               case FMTERR2:
+               case IOERR2:
                        adios(EX_DATAERR, NULL, "message format error in component #%d",
                                        compnum);