From: Philipp Takacs Date: Fri, 22 Apr 2016 22:56:56 +0000 (+0200) Subject: Merge branch 'm_getfld2-meillo' into master X-Git-Tag: mmh-0.3~39 X-Git-Url: http://git.marmaro.de/?p=mmh;a=commitdiff_plain;h=04a3dfc70394a517a79340a7d3ecd9c6a23d0bee;hp=bd02210b2be64956a952f925a2dcd35fb42f6136 Merge branch 'm_getfld2-meillo' into master --- diff --git a/h/mh.h b/h/mh.h index a5a12ce..e1795ca 100644 --- 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 */ diff --git a/h/prototypes.h b/h/prototypes.h index 8455b38..69556f9 100644 --- a/h/prototypes.h +++ b/h/prototypes.h @@ -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 *); diff --git a/sbr/Makefile.in b/sbr/Makefile.in index 77c0c1b..f60bd9a 100644 --- a/sbr/Makefile.in +++ b/sbr/Makefile.in @@ -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 index 1ec09a4..0000000 --- a/sbr/m_getfld.c +++ /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 -#include -#include -#include - -/* -** 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 index 0000000..45172aa --- /dev/null +++ b/sbr/m_getfld2.c @@ -0,0 +1,230 @@ +/* +** m_getfld2 -- replacement for m_getfld() +** read an RFC 822 message +*/ + +#define _WITH_GETLINE +#define _POSIX_C_SOURCE 200809L + +#include +#include +#include +#include + + +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= 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; +} diff --git a/sbr/readconfig.c b/sbr/readconfig.c index 2fe2d7d..6975d72 100644 --- a/sbr/readconfig.c +++ b/sbr/readconfig.c @@ -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: diff --git a/sbr/seq_read.c b/sbr/seq_read.c index e76bcc6..1fdccf9 100644 --- a/sbr/seq_read.c +++ b/sbr/seq_read.c @@ -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); diff --git a/test/tests/bad-input/test-header b/test/tests/bad-input/test-header index 6b826a0..e152e0e 100644 --- a/test/tests/bad-input/test-header +++ b/test/tests/bad-input/test-header @@ -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 <"$msgfile" <"$msgfile" + runandcheck "scan l" <"$msgfile" <"$msgfile" </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" <"$msgfile" <"$msgfile" <"$msgfile" <"$msgfile" <"$msgfile" <"$msgfile" <"$msgfile" <"$msgfile" <"$msgfile" </dev/null; echo \$?" <>"$MMHP" <>"$MMHP" runandcheck 'mhparam -nocomponent editor' <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; } diff --git a/uip/mhbuild.c b/uip/mhbuild.c index 0f77f33..fe3e946 100644 --- a/uip/mhbuild.c +++ b/uip/mhbuild.c @@ -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; diff --git a/uip/mhl.c b/uip/mhl.c index e4e8dbf..c089d8e 100644 --- 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; diff --git a/uip/mhparse.c b/uip/mhparse.c index 71c1e8e..67d769c 100644 --- a/uip/mhparse.c +++ b/uip/mhparse.c @@ -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; } diff --git a/uip/new.c b/uip/new.c index 5bc7136..4335892 100644 --- 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); diff --git a/uip/pick.c b/uip/pick.c index 1df59b1..5df2861 100644 --- a/uip/pick.c +++ b/uip/pick.c @@ -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: diff --git a/uip/prompter.c b/uip/prompter.c index 2adbd48..c7eb957 100644 --- a/uip/prompter.c +++ b/uip/prompter.c @@ -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; } diff --git a/uip/rcvdist.c b/uip/rcvdist.c index f3caa50..d08058b 100644 --- a/uip/rcvdist.c +++ b/uip/rcvdist.c @@ -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); } diff --git a/uip/rcvstore.c b/uip/rcvstore.c index 5fd9ae0..83c5150 100644 --- a/uip/rcvstore.c +++ b/uip/rcvstore.c @@ -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 */ diff --git a/uip/repl.c b/uip/repl.c index e3028fa..9006dec 100644 --- a/uip/repl.c +++ b/uip/repl.c @@ -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 */ diff --git a/uip/scan.c b/uip/scan.c index 671509a..a735b31 100644 --- a/uip/scan.c +++ b/uip/scan.c @@ -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; } diff --git a/uip/scansbr.c b/uip/scansbr.c index 877bdef..feef5c0 100644 --- a/uip/scansbr.c +++ b/uip/scansbr.c @@ -16,26 +16,12 @@ #include #include -#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); } diff --git a/uip/slocal.c b/uip/slocal.c index 18c4a58..f8f9d95 100644 --- a/uip/slocal.c +++ b/uip/slocal.c @@ -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; diff --git a/uip/sortm.c b/uip/sortm.c index 0c5511d..56fa7cb 100644 --- a/uip/sortm.c +++ b/uip/sortm.c @@ -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); diff --git a/uip/spost.c b/uip/spost.c index ce3e684..53ae86a 100644 --- a/uip/spost.c +++ b/uip/spost.c @@ -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); diff --git a/uip/whom.c b/uip/whom.c index b987356..daca343 100644 --- a/uip/whom.c +++ b/uip/whom.c @@ -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);