** 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 */
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 *);
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 \
+++ /dev/null
-/*
-** 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);
-}
--- /dev/null
+/*
+** 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;
+}
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;
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:
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;
/*
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);
#!/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
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!
+!
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
!
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));
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);
}
return NOTOK;
}
- mh_free0(&resent);
if (txtfd != NOTOK) {
lseek(txtfd, (off_t) 0, SEEK_SET); /* msgnam not accurate */
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;
}
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);
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;
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);
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);
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 (;;) {
/*
*/
break;
}
+giveup:;
mh_free0(&maildir_copy);
if (incerr < 0) { /* error */
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;
}
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;
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
** 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);
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;
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) {
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;
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;
** 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;
}
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 */
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);
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:
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;
/*
** 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;
}
fflush(stdout);
for (;;) {
getln(buffer, sizeof(buffer));
- if (!*buffer)
+ if (!*buffer) {
break;
+ }
fprintf(out, "%s", buffer);
}
} else {
}
}
- 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;
break;
}
- if (qbody)
+ if (qbody) {
printf("--------\n");
+ }
fflush(stdout);
fclose(in);
close(fdo);
unlink(tmpfil);
- context_save(); /* save the context file */
+ context_save();
return EX_OK;
}
/* 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];
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"))) {
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);
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;
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:
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);
}
static char *tmpfilenam = NULL;
void unlink_done();
+static void fix_mbox(int out, char *ofile);
int
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);
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
*/
{ 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;
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 */
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;
/* 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)
/*
** 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
** 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:
/* 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 */
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)
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);
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
}
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;
}
#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 */
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) {
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 */
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:
}
finished:
-
/* Format and output the scan line. */
if (ferror(inb)) {
advise("read", "unable to");
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);
}
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;
/*
** 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) {
}
}
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++;
}
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;
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;
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);
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, "");
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);
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;
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);