From: Lyndon Nerenberg Date: Fri, 1 Feb 2013 12:44:29 +0000 (-0800) Subject: Merge branch 'master' into savannah X-Git-Url: https://diplodocus.org/git/nmh/commitdiff_plain/afee8ed17a56617618fb7f963b111d7cf0fb56e7?hp=b78be76b63889ea7973369a8fddc42ec5389726a Merge branch 'master' into savannah --- diff --git a/.gitignore b/.gitignore index 0be1cc28..af04fac2 100644 --- a/.gitignore +++ b/.gitignore @@ -103,6 +103,7 @@ a.out.dSYM/ /test/fakepop /test/getfullname /test/getfqdn +/test/getcwidth # Removed by mostlyclean: *.o diff --git a/Makefile.am b/Makefile.am index b79e930d..c1c90d03 100644 --- a/Makefile.am +++ b/Makefile.am @@ -52,6 +52,7 @@ TESTS = test/ali/test-ali test/anno/test-anno \ test/format/test-dp test/format/test-fmtdump \ test/format/test-localmbox test/format/test-myname \ test/format/test-myhost test/format/test-mymbox \ + test/format/test-rightjustify \ test/forw/test-forw-digest test/forw/test-forw-format \ test/inc/test-deb359167 test/inc/test-eom-align \ test/inc/test-inc-scanout test/inc/test-msgchk \ @@ -61,8 +62,8 @@ TESTS = test/ali/test-ali test/anno/test-anno \ test/mhlist/test-mhlist test/mhmail/test-mhmail \ test/mhparam/test-mhparam test/mhpath/test-mhpath \ test/mhshow/test-cte-binary test/mhshow/test-qp \ - test/mhshow/test-subpart test/mhstore/test-mhstore \ - test/new/test-basic \ + test/mhshow/test-subpart test/mhshow/test-msg-buffer-boundaries \ + test/mhstore/test-mhstore test/new/test-basic \ test/pick/test-pick test/pick/test-stderr \ test/post/test-post-aliases test/post/test-post-basic \ test/post/test-post-multiple test/post/test-post-bcc \ @@ -83,7 +84,8 @@ TESTS = test/ali/test-ali test/anno/test-anno \ test/cleanup ## The "cleanup" test should always be last. check_SCRIPTS = test/common.sh -check_PROGRAMS = test/getfullname test/getfqdn test/fakepop test/fakesmtp +check_PROGRAMS = test/getfullname test/getfqdn test/fakepop test/fakesmtp \ + test/getcwidth DISTCHECK_CONFIGURE_FLAGS = DISABLE_SETGID_MAIL=1 ## @@ -506,7 +508,7 @@ sbr_libmh_a_SOURCES = sbr/addrsbr.c sbr/ambigsw.c sbr/atooi.c sbr/arglist.c \ sbr/showfile.c sbr/signals.c sbr/smatch.c \ sbr/snprintb.c sbr/ssequal.c sbr/strcasecmp.c \ sbr/strindex.c sbr/trimcpy.c sbr/uprf.c sbr/vfgets.c \ - sbr/fmt_def.c sbr/m_msgdef.c sbr/mf.c sbr/utils.c \ + sbr/fmt_def.c sbr/mf.c sbr/utils.c \ sbr/m_mktemp.c sbr/getansreadline.c config/config.c \ config/version.c diff --git a/configure.ac b/configure.ac index 3bb692ef..a4cfffd2 100644 --- a/configure.ac +++ b/configure.ac @@ -8,7 +8,7 @@ AC_PREREQ([2.68]) AC_INIT([nmh], m4_normalize(m4_include([VERSION])), [nmh-workers@nongnu.org]) AC_CONFIG_SRCDIR([h/nmh.h]) AC_CONFIG_HEADER([config.h]) -AM_INIT_AUTOMAKE([-Wall foreign serial-tests subdir-objects 1.12]) +AM_INIT_AUTOMAKE([-Wall color-tests foreign serial-tests subdir-objects 1.12]) AC_CANONICAL_HOST @@ -271,7 +271,7 @@ dnl AC_CHECK_PROGS([MD5SUM], [md5sum md5], [missing]) AS_CASE(["${MD5SUM}"], [md5sum], [MD5FMT="cat"], - [md5], [[MD5FMT="${SED} -e 's/MD5 *(\(.*\)) *= \([0-9a-f]*\)/\2 \1/'"]], + [md5], [[MD5FMT="${SED} -e 's/MD5 *(.*) *= \([0-9a-f]*\)/\1/'"]], [MD5FMT="missing"]) AC_SUBST([MD5FMT]) @@ -407,15 +407,6 @@ AC_HEADER_TIOCGWINSZ AC_CHECK_HEADERS([fcntl.h ncurses/termcap.h termcap.h langinfo.h \ wchar.h wctype.h sys/param.h sys/time.h sys/stream.h]) -dnl -dnl Checks for _IO_write_ptr. A Linuxism used by nmh on linux. We -dnl really use a whole set of them, but this check should be -dnl sufficient. -dnl -AC_CHECK_HEADER(libio.h, [ - AC_EGREP_HEADER(_IO_write_ptr, libio.h, [ - AC_DEFINE(LINUX_STDIO,1,[Use the Linux _IO_*_ptr defines from .]) ]) ]) - AC_CHECK_HEADER([sys/ptem.h], AC_DEFINE(WINSIZE_IN_PTEM,1, [Define to 1 if `struct winsize' requires .]),, [[#if HAVE_SYS_STREAM_H diff --git a/docs/README.manpages b/docs/README.manpages index 77584983..6d6111df 100644 --- a/docs/README.manpages +++ b/docs/README.manpages @@ -1,6 +1,6 @@ NMH MANPAGE STYLE GUIDE -nmh manpages should be in this general form: +nmh manpages should be in this general form and section order: .TH COMP %manext1% "DATE" "%nmhversion%" .\" @@ -8,6 +8,7 @@ nmh manpages should be in this general form: .\" .SH NAME comp \- compose a message +.\" .SH SYNOPSIS .B comp .RI [ +folder ] @@ -20,13 +21,7 @@ comp \- compose a message .SH DESCRIPTION .B Comp is used to create a new message to be mailed. It copies something. -.SH FILES -.TP -filename1 -description of filename1 -.TP -filename2 -description of filename2 +.\" .SH "PROFILE COMPONENTS" .TP Path @@ -34,13 +29,7 @@ Location of the user's MH folder directory .TP moreproc The pager command name -.SH "SEE ALSO" -.IR dist (1), -.IR forw (1), -.IR repl (1), -.IR send (1), -.IR whatnow (1), -.IR mh-profile (5) +.\" .SH DEFAULTS .TP .RI + folder @@ -48,6 +37,22 @@ defaults to the current folder .\" .SH CONTEXT None +.\" +.SH FILES +.TP +filename1 +description of filename1 +.TP +filename2 +description of filename2 +.\" +.SH "SEE ALSO" +.IR dist (1), +.IR forw (1), +.IR repl (1), +.IR send (1), +.IR whatnow (1), +.IR mh-profile (5) .\" Leave out the BUGS section if there are none worth describing. .SH BUGS None @@ -68,7 +73,7 @@ Don't abbreviate the month. In the FILES section, prefer the default .TP indent. The pathnames are variable and long, so any indentation value that works for you won't -work for someone else. +work for someone using a different directory layout. Source files @@ -199,7 +204,8 @@ Pointer manpages CONTEXT - Don't include a CONTEXT section when contexts are out of context. + Don't include a CONTEXT section when contexts are not + applicable. AUTHOR and HISTORY sections @@ -209,4 +215,4 @@ AUTHOR and HISTORY sections BUGS - The BUGS section goes last. + The BUGS section goes last. diff --git a/docs/contrib/build_nmh b/docs/contrib/build_nmh index f0b0c56c..f17b240f 100755 --- a/docs/contrib/build_nmh +++ b/docs/contrib/build_nmh @@ -273,17 +273,19 @@ if [ $status -eq 0 ]; then fi [ $verbose -ge 1 ] && echo testing . . . - checkoutput=`make $check 2>>"$logfile"` + checkoutput=`make $check AM_COLOR_TESTS=always 2>>"$logfile"` status=$? tests_summary=`echo "$checkoutput" | grep tests` #### If multiple tests not run, that line will be caught by the #### "grep tests" above. test_not_run=`echo "$checkoutput" | grep 'test was not run'` + fails=`echo "$checkoutput" | grep FAIL` if [ "$tests_summary" ]; then echo '===================' >>"$logfile" - echo "$tests_summary" >>"$logfile" [ "$test_not_run" ] && echo "$test_not_run" >>"$logfile" + [ "$fails" ] && echo "$fails" >>"$logfile" + echo "$tests_summary" >>"$logfile" echo '===================' >>"$logfile" [ "$check" = distcheck ] && \ echo "$checkoutput" | tail -n 4 >>"$logfile" diff --git a/docs/pending-release-notes b/docs/pending-release-notes index 9b280927..a6ae19c5 100644 --- a/docs/pending-release-notes +++ b/docs/pending-release-notes @@ -34,6 +34,8 @@ NEW FEATURES - pick(1) now decodes MIME-encoded header fields before searching. - The VISUAL and EDITOR environment variables are now supported as fallbacks if the user does not configure an editor entry in their profile. +- The format engine (mh_format(5)) now properly accounts for multibyte + characters when accounting for column widths. ---------------------------- @@ -58,6 +60,7 @@ OBSOLETE/DEPRECATED FEATURES http://smtpfilter.sourceforge.net/esmtp.html - conflict(8) is deprecated and will be removed from the next release. - mhtest(8) is deprecated and will be removed from the next release. +- msh(1) is deprecated and will be removed from the next release. - spost(8) has been merged into post(8). Its functionality is enabled by selecting the sendmail/pipe mail transport method, described in the mh-tailor(5) man page. The spost -noalias, -backup/-nobackup, diff --git a/h/mh.h b/h/mh.h index 2cd546b1..253af9cb 100644 --- a/h/mh.h +++ b/h/mh.h @@ -288,11 +288,12 @@ struct msgs { #define FMTERR (-3) /* Message Format error */ #define FLD 0 /* Field returned */ #define FLDPLUS 1 /* Field returned with more to come */ -#define FLDEOF 2 /* Field returned ending at eom */ #define BODY 3 /* Body returned with more to come */ -#define BODYEOF 4 /* Body returned ending at eom */ #define FILEEOF 5 /* Reached end of input file */ +struct m_getfld_state; +typedef struct m_getfld_state *m_getfld_state_t; + /* * Maildrop styles */ @@ -302,10 +303,6 @@ struct msgs { #define MS_MMDF 3 /* string mmdlm2 */ #define MS_MSH 4 /* whacko msh */ -extern int msg_count; /* m_getfld() indicators */ -extern int msg_style; /* .. */ -extern char *msg_delim; /* .. */ - #define NOUSE 0 /* draft being re-used */ #define TFOLDER 0 /* path() given a +folder */ diff --git a/h/prototypes.h b/h/prototypes.h index 443479f6..d4fc6eb0 100644 --- a/h/prototypes.h +++ b/h/prototypes.h @@ -27,6 +27,8 @@ void adios (char *, char *, ...) NORETURN; void admonish (char *, char *, ...); void advertise (char *, char *, char *, va_list); void advise (char *, char *, ...); +char **argsplit (char *, char **, int *); +void arglist_free (char *, char **); void ambigsw (char *, struct swit *); int atooi(char *); char **brkstring (char *, char *, char *); @@ -76,8 +78,11 @@ int m_atoi (char *); char *m_backup (char *); int m_convert (struct msgs *, char *); char *m_draft (char *, char *, int, int *); -void m_eomsbr (int (*)(int)); -int m_getfld (int, unsigned char *, unsigned char *, int, FILE *); +void m_eomsbr (m_getfld_state_t, int (*)(int)); +void m_getfld_state_reset (m_getfld_state_t *); +void m_getfld_state_destroy (m_getfld_state_t *); +void m_getfld_track_filepos (m_getfld_state_t *, FILE *); +int m_getfld (m_getfld_state_t *, unsigned char[NAMESZ], unsigned char *, int *, FILE *); int m_gmprot (void); char *m_maildir (char *); char *m_mailpath (char *); @@ -86,7 +91,7 @@ int m_putenv (char *, char *); int m_rand (unsigned char *, size_t); char *m_mktemp(const char *, int *, FILE **); char *m_mktemp2(const char *, const char *, int *, FILE **); -void m_unknown(FILE *); +void m_unknown(m_getfld_state_t *, FILE *); int makedir (char *); char *message_id (time_t, int); char *nmh_getpass(const char *); @@ -107,6 +112,10 @@ void readconfig (struct node **, FILE *, char *, int); int refile (char **, char *); void ruserpass(char *, char **, char **); int remdir (char *); +void scan_detect_mbox_style (FILE *); +void scan_finished (); +void scan_eom_action (int (*)()); +void scan_reset_m_getfld_state (); int seq_addmsg (struct msgs *, char *, int, int, int); int seq_addsel (struct msgs *, char *, int, int); char *seq_bits (struct msgs *); diff --git a/man/msh.man b/man/msh.man index 57770b52..66e29fbe 100644 --- a/man/msh.man +++ b/man/msh.man @@ -1,4 +1,4 @@ -.TH MSH %manext1% "November 6, 2012" "%nmhversion%" +.TH MSH %manext1% "January 26, 2013" "%nmhversion%" .\" .\" %nmhwarning% .\" @@ -16,12 +16,14 @@ msh \- nmh shell (and BBoard reader) .RB [ \-version ] .RB [ \-help ] .ad +.SH STATUS +.B msh is deprecated and will be removed from the next nmh release. .SH DESCRIPTION .B msh is an interactive program that implements a subset of the normal .B nmh commands operating on a single file in -.BR packf 'd +.BR mmdf format. That is, .B msh diff --git a/mts/smtp/smtp.c b/mts/smtp/smtp.c index b1d57dd6..6fd178bc 100755 --- a/mts/smtp/smtp.c +++ b/mts/smtp/smtp.c @@ -798,9 +798,19 @@ sm_end (int type) if (sm_mts == MTS_SMTP) smtalk (SM_QUIT, "QUIT"); else { + /* The SIGPIPE block replaces old calls to discard (). + We're not sure what the discard () calls were for, + maybe to prevent deadlock on old systems. In any + case, blocking SIGPIPE should be harmless. + Because the file handles are closed below, leave it + blocked. */ + sigset_t set, oset; + sigemptyset (&set); + sigaddset (&set, SIGPIPE); + sigprocmask (SIG_BLOCK, &set, &oset); + kill (sm_child, SIGKILL); - discard (sm_rfp); - discard (sm_wfp); + sm_child = NOTOK; } if (type == NOTOK) { sm_reply.code = sm_note.code; @@ -840,9 +850,11 @@ sm_end (int type) if (sasl_inbuffer) free(sasl_inbuffer); #endif /* CYRUS_SASL */ - } else { + } else if (sm_child != NOTOK) { status = pidwait (sm_child, OK); sm_child = NOTOK; + } else { + status = OK; } sm_rfp = sm_wfp = NULL; diff --git a/sbr/arglist.c b/sbr/arglist.c index 1f85b7b2..8749a4b9 100644 --- a/sbr/arglist.c +++ b/sbr/arglist.c @@ -25,10 +25,10 @@ * * - If there are no spaces or shell metacharacters in "command", then * take it as-is. - * - If there are spaces in command, space-split command string and - * append an argument list to it. + * - If there are spaces in command, space-split command string. * - If we have shell metacharacters, run the command using - * /bin/sh -c 'command "${@}"'. + * /bin/sh -c 'command "$@"'. In this case, any additional arguments + * appended to the arglist will be expanded by "$@". * * In all cases additional arguments can be added to the argv[] array. */ @@ -123,3 +123,22 @@ argsplit(char *command, char **file, int *argp) return argvarray; } + +/* + * Free our argument array + */ + +void +arglist_free(char *command, char **argvarray) +{ + int i; + + if (command != NULL) + free(command); + + if (argvarray != NULL) { + for (i = 0; argvarray[i] != NULL; i++) + free(argvarray[i]); + free(argvarray); + } +} diff --git a/sbr/discard.c b/sbr/discard.c index a1efa488..83b0bfbc 100644 --- a/sbr/discard.c +++ b/sbr/discard.c @@ -20,15 +20,7 @@ discard (FILE *io) tcflush (fileno(io), TCOFLUSH); -#if defined(_FSTDIO) || defined(__DragonFly__) - fpurge (io); -#else -# ifdef LINUX_STDIO - io->_IO_write_ptr = io->_IO_write_base; -# else - if ((io->_ptr = io->_base)) - io->_cnt = 0; -# endif -#endif + /* There used to be an fpurge() here on some platforms, stdio + hackery on others. But it didn't seem necessary. */ } diff --git a/sbr/fmt_scan.c b/sbr/fmt_scan.c index 879f7716..b1370fb7 100644 --- a/sbr/fmt_scan.c +++ b/sbr/fmt_scan.c @@ -114,8 +114,8 @@ cpnumber(char **dest, int num, unsigned int wid, char fill, size_t n) { * no more than n bytes are copied */ static void -cptrimmed(char **dest, char *str, unsigned int wid, char fill, size_t n, - size_t max) { +cptrimmed(char **dest, char **ep, char *str, unsigned int wid, char fill, + char *epmax) { int remaining; /* remaining output width available */ int c, ljust; int end; /* number of input bytes remaining in str */ @@ -126,8 +126,6 @@ cptrimmed(char **dest, char *str, unsigned int wid, char fill, size_t n, #endif char *sp; /* current position in source string */ char *cp = *dest; /* current position in destination string */ - char *ep = cp + n; /* end of destination buffer based on desired width */ - char *epmax = cp + max; /* true end of destination buffer */ int prevCtrl = 1; /* get alignment */ @@ -137,19 +135,29 @@ cptrimmed(char **dest, char *str, unsigned int wid, char fill, size_t n, ljust++; } if ((sp = (str))) { +#ifdef MULTIBYTE_SUPPORT mbtowc(NULL, NULL, 0); /* reset shift state */ +#endif end = strlen(str); while (*sp && remaining > 0 && end > 0) { #ifdef MULTIBYTE_SUPPORT char_len = mbtowc(&wide_char, sp, end); - /* Account for multibyte characters taking only one character's - width of output. */ - if (char_len > 1 && epmax - ep >= char_len - 1) { - ep += char_len - 1; + if (char_len <= 0) + break; + + w = wcwidth(wide_char); + + /* + * Multibyte characters can have a variable number of column + * widths, so use the column width to bump the end pointer when + * appropriate. + */ + if (char_len > 1 && epmax - *ep >= char_len - w) { + *ep += char_len - w; } - if (char_len <= 0 || (cp + char_len > ep)) + if (cp + w > *ep) break; end -= char_len; @@ -176,7 +184,6 @@ cptrimmed(char **dest, char *str, unsigned int wid, char fill, size_t n, prevCtrl = 0; #ifdef MULTIBYTE_SUPPORT - w = wcwidth(wide_char); if (w >= 0 && remaining >= w) { strncpy(cp, sp, char_len); cp += char_len; @@ -191,9 +198,10 @@ cptrimmed(char **dest, char *str, unsigned int wid, char fill, size_t n, } if (ljust) { - if (cp + remaining > ep) - remaining = ep - cp; - ep = cp + remaining; + char *endfield; + if (cp + remaining > *ep) + remaining = *ep - cp; + endfield = cp + remaining; if (remaining > 0) { /* copy string to the right */ while (--cp >= *dest) @@ -203,22 +211,22 @@ cptrimmed(char **dest, char *str, unsigned int wid, char fill, size_t n, for (c=remaining; c>0; c--) *cp-- = fill; } - *dest = ep; + *dest = endfield; } else { /* pad remaining space */ - while (remaining-- > 0 && cp < ep) + while (remaining-- > 0 && cp < *ep) *cp++ = fill; *dest = cp; } } static void -cpstripped (char **dest, char *end, char *max, char *str) +cpstripped (char **dest, char **end, char *max, char *str) { int prevCtrl = 1; /* This is 1 so we strip out leading spaces */ int len; #ifdef MULTIBYTE_SUPPORT - int char_len; + int char_len, w; wchar_t wide_char; #endif /* MULTIBYTE_SUPPORT */ @@ -236,17 +244,21 @@ cpstripped (char **dest, char *end, char *max, char *str) * then deal with that here. */ - while (*str != '\0' && len > 0 && *dest < end) { + while (*str != '\0' && len > 0 && *dest < *end) { #ifdef MULTIBYTE_SUPPORT char_len = mbtowc(&wide_char, str, len); - - /* Account for multibyte characters taking only one character's - width of output. */ - if (char_len > 1 && max - end >= char_len - 1) { - end += char_len - 1; + w = wcwidth(wide_char); + + /* + * Account for multibyte characters, and increment the end pointer + * by the number of "extra" bytes in this character. That's the + * character length (char_len) minus the column width (w). + */ + if (char_len > 1 && max - *end >= char_len - w) { + *end += char_len - w; } - if (char_len <= 0 || *dest + char_len > end) + if (char_len <= 0 || *dest + char_len > *end) break; len -= char_len; @@ -384,11 +396,11 @@ fmt_scan (struct format *format, char *scanl, size_t max, int width, int *dat) switch (fmt->f_type) { case FT_COMP: - cpstripped (&cp, ep, scanl + max - 1, fmt->f_comp->c_text); + cpstripped (&cp, &ep, scanl + max - 1, fmt->f_comp->c_text); break; case FT_COMPF: - cptrimmed (&cp, fmt->f_comp->c_text, fmt->f_width, fmt->f_fill, - ep - cp, scanl - cp + max - 1); + cptrimmed (&cp, &ep, fmt->f_comp->c_text, fmt->f_width, fmt->f_fill, + scanl + max - 1); break; case FT_LIT: @@ -411,11 +423,11 @@ fmt_scan (struct format *format, char *scanl, size_t max, int width, int *dat) break; case FT_STR: - cpstripped (&cp, ep, scanl + max - 1, str); + cpstripped (&cp, &ep, scanl + max - 1, str); break; case FT_STRF: - cptrimmed (&cp, str, fmt->f_width, fmt->f_fill, ep - cp, - scanl - cp + max - 1); + cptrimmed (&cp, &ep, str, fmt->f_width, fmt->f_fill, + scanl + max - 1); break; case FT_STRLIT: sp = str; @@ -939,7 +951,7 @@ fmt_scan (struct format *format, char *scanl, size_t max, int width, int *dat) *cp++ = ' '; } } - cpstripped (&cp, ep, scanl + max - 1, lp); + cpstripped (&cp, &ep, scanl + max - 1, lp); } break; diff --git a/sbr/folder_delmsgs.c b/sbr/folder_delmsgs.c index c1416a6f..671ecc7c 100644 --- a/sbr/folder_delmsgs.c +++ b/sbr/folder_delmsgs.c @@ -24,7 +24,7 @@ folder_delmsgs (struct msgs *mp, int unlink_msgs, int nohook) { pid_t pid; int msgnum, vecp, retval = 0; - char buf[100], *dp, **vec; + char buf[100], *dp, **vec, *prog; char msgpath[BUFSIZ]; /* @@ -40,10 +40,18 @@ folder_delmsgs (struct msgs *mp, int unlink_msgs, int nohook) /* Mark that the sequence information has changed */ mp->msgflags |= SEQMOD; - vec = (char **) calloc ((size_t) (mp->numsel + 2), sizeof(*vec)); + vec = argsplit(rmmproc, &prog, &vecp); + + /* + * argsplit allocates a MAXARGS vector by default, If we need + * something bigger, allocate it ourselves + */ + + if (mp->numsel + vecp + 1 > MAXARGS) + vec = (char **) realloc (vec, (size_t) ((mp->numsel + vecp + 1) * + sizeof(*vec))); if (vec == NULL) adios (NULL, "unable to allocate exec vector"); - vecp = 1; for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) { if (is_selected (mp, msgnum) && !(vec[vecp++] = strdup (m_name (msgnum)))) @@ -52,7 +60,6 @@ folder_delmsgs (struct msgs *mp, int unlink_msgs, int nohook) vec[vecp] = NULL; fflush (stdout); - vec[0] = r1bindex (rmmproc, '/'); switch (pid = vfork()) { case -1: @@ -60,12 +67,13 @@ folder_delmsgs (struct msgs *mp, int unlink_msgs, int nohook) return -1; case 0: - execvp (rmmproc, vec); + execvp (prog, vec); fprintf (stderr, "unable to exec "); perror (rmmproc); _exit (-1); default: + arglist_free(prog, vec); return (pidwait (pid, -1)); } } diff --git a/sbr/m_getfld.c b/sbr/m_getfld.c index e139505a..af44f09a 100644 --- a/sbr/m_getfld.c +++ b/sbr/m_getfld.c @@ -11,6 +11,75 @@ #include #include +/* + Purpose + ======= + Reads an Internet message (RFC 5322), or one or more messages + stored in a maildrop in mbox (RFC 4155) or MMDF format, from a file + stream. Each call to m_getfld() reads one header field, or a + portion of the body, in sequence. + + Inputs + ====== + gstate: opaque parse state + bufsz: maximum number of characters to load into buf + iob: input file stream + + Outputs + ======= + name: header field name (array of size NAMESZ=999) + buf: either a header field body or message body + bufsz: number of characters loaded into buf + (return value): message parse state on return from function + + Functions + ========= + void m_getfld_state_destroy (m_getfld_state_t *gstate): destroys + the parse state pointed to by the gstate argument. + + m_getfld_state_reset (m_getfld_state_t *gstate): resets the parse + state to FLD. + + void m_unknown(FILE *iob): Determines the message delimiter string + for the maildrop. Called by inc, scan, and msh when reading from a + maildrop file. + + void m_eomsbr (int (*action)(int)): Sets the hook to check for end + of message in a maildrop. Called only by msh. + + State variables + =============== + m_getfld() retains state internally between calls in the + m_getfld_state_t variable. These are used for detecting the end of + each message when reading maildrops: + + unsigned char **pat_map + unsigned char *fdelim + unsigned char *delimend + int fdelimlen + unsigned char *edelim + int edelimlen + char *msg_delim + int msg_style + int (*eom_action)(int) + + Usage + ===== + m_getfld_state_t gstate = 0; + ... + int state = m_getfld (&gstate, ...); + ... + m_getfld_state_destroy (&gstate); + + The state is retained internally by gstate. To reset its state to FLD: + m_getfld_state_reset (&gstate); +*/ + +/* The following described the old implementation. The high-level + structure hasn't changed, but some of the details have. I'm + leaving this as-is, though, for posterity. + */ + /* This module has a long and checkered history. First, it didn't burst maildrops correctly because it considered two CTRL-A:s in a row to be an inter-message delimiter. It really is four CTRL-A:s followed by a @@ -125,7 +194,7 @@ 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 @@ -134,358 +203,463 @@ there is data in "name" or "buf"). */ - /* * static prototypes */ -static int m_Eom (int, FILE *); +struct m_getfld_state; +static int m_Eom (m_getfld_state_t, int); static unsigned char *matchc(int, char *, int, char *); -static unsigned char *locc(int, unsigned char *, unsigned char); - -#define Getc(iob) getc(iob) -#define eom(c,iob) (msg_style != MS_DEFAULT && \ - (((c) == *msg_delim && m_Eom(c,iob)) ||\ - (eom_action && (*eom_action)(c)))) -static unsigned char **pat_map; +#define eom(c,s) (s->msg_style != MS_DEFAULT && \ + (((c) == *s->msg_delim && m_Eom(s,c)) || \ + (s->eom_action && (*s->eom_action)(c)))) -/* - * defined in sbr/m_msgdef.c = 0 - * 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). +/* This replaces the old approach, with its direct access to stdio + * internals. It uses one fread() to load a buffer that we manage. + * + * MSG_INPUT_SIZE is the size of the buffer. + * MAX_DELIMITER_SIZE is the maximum size of the delimiter used to + * separate messages in a maildrop, such as mbox "From ". + * + * Some of the tests in the test suite assume a MSG_INPUT_SIZE + * of 4096. */ -extern int msg_count; +#define MSG_INPUT_SIZE 4096 +#define MAX_DELIMITER_SIZE 5 + +struct m_getfld_state { + unsigned char msg_buf[2 * MSG_INPUT_SIZE + MAX_DELIMITER_SIZE]; + unsigned char *readpos; + unsigned char *end; /* One past the last character read in. */ + /* The following support tracking of the read position in the + input file stream so that callers can interleave m_getfld() + calls with ftell() and fseek(). ytes_read replaces the old + m_getfld() msg_count global. last_caller_pos is stored when + leaving m_getfld()/m_unknown(), then checked on the next entry. + last_internal_pos is used to remember the position used + internally by m_getfld() (read_more(), actually). */ + off_t bytes_read; + off_t total_bytes_read; /* by caller, not necessarily from input file */ + off_t last_caller_pos; + off_t last_internal_pos; + FILE *iob; + + unsigned char **pat_map; + int msg_style; + /* + * 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. + */ + char *msg_delim; + unsigned char *fdelim; + unsigned char *delimend; + int fdelimlen; + unsigned char *edelim; + int edelimlen; + int (*eom_action)(int); + int state; + int track_filepos; +}; + +static +void +m_getfld_state_init (m_getfld_state_t *gstate, FILE *iob) { + m_getfld_state_t s; + + s = *gstate = (m_getfld_state_t) mh_xmalloc(sizeof (struct m_getfld_state)); + s->readpos = s->end = s->msg_buf; + s->bytes_read = s->total_bytes_read = 0; + s->last_caller_pos = s->last_internal_pos = 0; + s->iob = iob; + s->pat_map = NULL; + s->msg_style = MS_DEFAULT; + s->msg_delim = ""; + s->fdelim = s->delimend = s->edelim = NULL; + s->fdelimlen = s->edelimlen = 0; + s->eom_action = NULL; + s->state = FLD; + s->track_filepos = 0; +} -/* - * defined in sbr/m_msgdef.c = MS_DEFAULT - */ -extern int msg_style; +/* scan() needs to force a state an initial state of FLD for each message. */ +void +m_getfld_state_reset (m_getfld_state_t *gstate) { + if (*gstate) { + (*gstate)->state = FLD; + } +} + +/* If the caller interleaves ftell*()/fseek*() calls with m_getfld() + calls, m_getfld() must keep track of the file position. The caller + must use this function to inform m_getfld(). */ +void +m_getfld_track_filepos (m_getfld_state_t *gstate, FILE *iob) { + if (! *gstate) { + m_getfld_state_init (gstate, iob); + } + + (*gstate)->track_filepos = 1; +} + +void m_getfld_state_destroy (m_getfld_state_t *gstate) { + m_getfld_state_t s = *gstate; + + if (s) { + if (s->fdelim) free (s->fdelim-1); + free (s); + *gstate = 0; + } +} /* - * 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. - */ -extern char *msg_delim; /* defined in sbr/m_msgdef.c = "" */ -static unsigned char *fdelim; -static unsigned char *delimend; -static int fdelimlen; -static unsigned char *edelim; -static int edelimlen; + Summary of file and message input buffer positions: + + input file -------------------------------------------EOF + | | + last_caller_pos last_internal_pos + + + msg_buf --------------------EOF + | | | + msg_buf readpos end + + |<>|=retained characters, difference + between last_internal_pos and + first readpos value after reading + in new chunk in read_more() -static int (*eom_action)(int) = NULL; + When returning from m_getfld()/m_unknown(): + 1) Save the internal file position in last_internal_pos. That's the + m_getfld() position reference in the input file. + 2) Set file stream position so that callers can use ftell(). -#ifdef _FSTDIO -# define _ptr _p /* Gag */ -# define _cnt _r /* Retch */ -# define _filbuf __srget /* Puke */ -# define DEFINED__FILBUF_TO_SOMETHING_SPECIFIC + When entering m_getfld()/m_unknown(): + Check to see if the call had changed the file position. If so, + adjust the internal position reference accordingly. If not, restore + the internal file position from last_internal_pos. +*/ -# if defined __CYGWIN__ - /* Cygwin's stdio.h does not declare __srget(). */ - int __srget(FILE *); -# endif /* __CYGWIN__ */ -#endif -#ifndef DEFINED__FILBUF_TO_SOMETHING_SPECIFIC -extern int _filbuf(FILE*); -#endif +static void +enter_getfld (m_getfld_state_t *gstate, FILE *iob) { + m_getfld_state_t s; + off_t pos = ftello (iob); + + if (! *gstate) { + m_getfld_state_init (gstate, iob); + } + s = *gstate; + s->bytes_read = 0; + + /* This is ugly and no longer necessary, but is retained just in + case it's needed again. The parser used to open the input file + multiple times, so we had to always use the FILE * that's + passed to m_getfld(). Now the parser inits a new + m_getfld_state for each file. See comment below about the + readpos shift code being currently unused. */ + s->iob = iob; + + if (s->track_filepos && (pos != 0 || s->last_internal_pos != 0)) { + if (s->last_internal_pos == 0) { + s->total_bytes_read = pos; + } else { + off_t pos_movement = pos - s->last_caller_pos; /* Can be < 0. */ + + if (pos_movement == 0) { + pos = s->last_internal_pos; + } else { + /* The current file stream position differs from the + last one, so caller must have called ftell/o(). + Or, this is the first call and the file position + was not at 0. */ + + if (s->readpos + pos_movement >= s->msg_buf && + s->readpos + pos_movement < s->end) { + /* This is currently unused. It could be used by + parse_mime() if it was changed to use a global + m_getfld_state. */ + /* We can shift readpos and remain within the + bounds of msg_buf. */ + s->readpos += pos_movement; + s->total_bytes_read += pos_movement; + pos = s->last_internal_pos; + } else { + size_t num_read; + + /* This seek skips past an integral number of + chunks of size MSG_INPUT_SIZE. */ + fseeko (iob, pos/MSG_INPUT_SIZE * MSG_INPUT_SIZE, SEEK_SET); + num_read = fread (s->msg_buf, 1, MSG_INPUT_SIZE, iob); + s->readpos = s->msg_buf + pos % MSG_INPUT_SIZE; + s->end = s->msg_buf + num_read; + s->total_bytes_read = pos; + } + } + + fseeko (iob, pos, SEEK_SET); + } + } +} + +static void +leave_getfld (m_getfld_state_t s) { + s->total_bytes_read += s->bytes_read; + + if (s->track_filepos) { + /* Save the internal file position that we use for the input buffer. */ + s->last_internal_pos = ftello (s->iob); + + /* Set file stream position so that callers can use ftell(). */ + fseeko (s->iob, s->total_bytes_read, SEEK_SET); + s->last_caller_pos = ftello (s->iob); + } +} + +static size_t +read_more (m_getfld_state_t s) { + /* Retain at least edelimlen characters that have already been + read so that we can back up to them in m_Eom(). */ + ssize_t retain = s->edelimlen; + size_t num_read; + + if (retain < s->end - s->readpos) retain = s->end - s->readpos; + /* assert (retain <= s->readpos - s->msg_buf <= sizeof msg_buf); */ + + /* Move what we want to retain at end of the buffer to the beginning. */ + memmove (s->msg_buf, s->readpos - retain, retain); + + s->readpos = s->msg_buf + retain; + num_read = fread (s->readpos, 1, MSG_INPUT_SIZE, s->iob); + s->end = s->readpos + num_read; + + return num_read; +} + +static int +Getc (m_getfld_state_t s) { + if (s->end - s->readpos < 1) { + if (read_more (s) == 0) { + /* Pretend that we read a character. That's what stdio does. */ + ++s->readpos; + return EOF; + } + } + + ++s->bytes_read; + return s->readpos < s->end ? *s->readpos++ : EOF; +} + +static int +Peek (m_getfld_state_t s) { + if (s->end - s->readpos < 1) { + if (read_more (s) == 0) { + /* Pretend that we read a character. That's what stdio does. */ + ++s->readpos; + return EOF; + } + } + + return s->readpos < s->end ? *s->readpos : EOF; +} + +static int +Ungetc (int c, m_getfld_state_t s) { + if (s->readpos == s->msg_buf) { + return EOF; + } else { + --s->bytes_read; + return *--s->readpos = c; + } +} int -m_getfld (int state, unsigned char *name, unsigned char *buf, - int bufsz, FILE *iob) +m_getfld (m_getfld_state_t *gstate, unsigned char name[NAMESZ], + unsigned char *buf, int *bufsz, FILE *iob) { - register unsigned char *bp, *cp, *ep, *sp; - register int cnt, c, i, j; + m_getfld_state_t s; + register unsigned char *cp; + register int max, n, c; - if ((c = Getc(iob)) < 0) { - msg_count = 0; - *buf = 0; - return FILEEOF; + enter_getfld (gstate, iob); + s = *gstate; + + if ((c = Getc(s)) < 0) { + *bufsz = *buf = 0; + leave_getfld (s); + return s->state = FILEEOF; } - if (eom (c, iob)) { - if (! eom_action) { + if (eom (c, s)) { + if (! s->eom_action) { /* flush null messages */ - while ((c = Getc(iob)) >= 0 && eom (c, iob)) + while ((c = Getc(s)) >= 0 && eom (c, s)) ; + if (c >= 0) - ungetc(c, iob); + Ungetc(c, s); } - msg_count = 0; - *buf = 0; - return FILEEOF; + *bufsz = *buf = 0; + leave_getfld (s); + return s->state = FILEEOF; } - switch (state) { - case FLDEOF: - case BODYEOF: - case FLD: + switch (s->state) { + case FLD: if (c == '\n' || c == '-') { /* we hit the header/body separator */ - while (c != '\n' && (c = Getc(iob)) >= 0) - ; + while (c != '\n' && (c = Getc(s)) >= 0) continue; - if (c < 0 || (c = Getc(iob)) < 0 || eom (c, iob)) { - if (! eom_action) { + if (c < 0 || (c = Getc(s)) < 0 || eom (c, s)) { + if (! s->eom_action) { /* flush null messages */ - while ((c = Getc(iob)) >= 0 && eom (c, iob)) + while ((c = Getc(s)) >= 0 && eom (c, s)) ; if (c >= 0) - ungetc(c, iob); + Ungetc(c, s); } - msg_count = 0; - *buf = 0; - return FILEEOF; + *bufsz = *buf = 0; + leave_getfld (s); + return s->state = FILEEOF; } - state = BODY; + s->state = BODY; goto body; } /* * get the name of this component. take characters up * to a ':', a newline or NAMESZ-1 characters, whichever - * comes first. + * 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; + max = NAMESZ - 1; + /* Get the field name. The first time through the loop, + this copies out the first character, which was loaded + into c prior to loop entry. Initialize n to 1 to + account for that. */ + for (n = 1; + c != ':' && c != '\n' && c != EOF && n < max; + ++n, c = Getc (s)) { + *cp++ = c; + } - /* - * 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; + /* Check for next character, which is either the space after + the ':' or the first folded whitespace. */ + { + int next_char; + if (c == EOF || (next_char = Peek (s)) == EOF) { + *bufsz = *cp = *buf = 0; + advise (NULL, "eof encountered in field \"%s\"", name); + leave_getfld (s); + return s->state = FMTERR; } - if ((i -= j) <= 0) { - *cp = *buf = 0; - advise (NULL, "field name \"%s\" exceeds %d bytes", name, NAMESZ - 2); - state = LENERR; - goto finish; + } + + /* If c isn't ':' here, something went wrong. Possibilities are: + * . hit a newline (error) + * . got more than namesz chars. (error) + */ + if (c == ':') { + /* Finished header name, fall through to FLDPLUS below. */ + } else 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 < n + 1) { + /* No, it can't. Oh well, guess we'll blow up. */ + *bufsz = *cp = *buf = 0; + advise (NULL, "eol encountered in field \"%s\"", name); + s->state = FMTERR; + break; } + memcpy (buf, name, n - 1); + buf[n - 1] = '\n'; + buf[n] = '\0'; + /* The last character read was '\n'. s->bytes_read + (and n) include that, but it was not put into the + name array in the for loop above. So subtract 1. */ + *bufsz = --s->bytes_read; /* == n - 1 */ + leave_getfld (s); + return s->state = BODY; + } else if (max <= n) { + /* By design, the loop above discards the last character + it had read. It's in c, use it. */ + *cp++ = c; + *bufsz = *cp = *buf = 0; + advise (NULL, "field name \"%s\" exceeds %d bytes", name, + NAMESZ - 2); + s->state = LENERR; + break; } - while (isspace (*--cp) && cp >= name) - ; + /* Trim any trailing spaces from the end of name. */ + while (isspace (*--cp) && cp >= name) continue; *++cp = 0; + /* readpos points to the first character of the field body. */ /* fall through */ - case FLDPLUS: + case FLDPLUS: { /* - * get (more of) the text of a field. take + * 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; + int finished; + + cp = buf; + max = *bufsz-1; + n = 0; + for (finished = 0; ! finished; ) { + while (c != '\n' && c != EOF && n++ < max) { + *cp++ = c = Getc (s); } - /* - * 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) { + + if (c != EOF) c = Peek (s); + if (max < n) { /* 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; + s->state = FLDPLUS; + finished = 1; + } else if (c != ' ' && c != '\t') { + /* The next character is not folded whitespace, so + prepare to move on to the next field. It's OK + if c is EOF, it will be handled on the next + call to m_getfld (). */ + s->state = FLD; + finished = 1; + } else { + /* Folded header field, continues on the next line. */ } } + *bufsz = s->bytes_read; break; + } - case BODY: body: + case 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. + * end of the message. */ - 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 (msg_style != MS_DEFAULT && c > 1) { + unsigned char *bp; + + max = *bufsz-1; + /* Back up and store the current position. */ + bp = --s->readpos; + c = s->end - s->readpos < max ? s->end - s->readpos : max; + if (s->msg_style != MS_DEFAULT && c > 1) { /* * packed maildrop - only take up to the (possible) * start of the next message. This "matchc" should @@ -498,7 +672,9 @@ m_getfld (int state, unsigned char *name, unsigned char *buf, * 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 ))) + unsigned char *ep; + + if ((ep = matchc( s->fdelimlen, s->fdelim, c, bp ))) c = ep - bp + 1; else { /* @@ -514,8 +690,10 @@ m_getfld (int state, unsigned char *name, unsigned char *buf, * ends with one of the characters in the pattern * (excluding the first and last), we do only one test. */ + unsigned char *sp; + ep = bp + c - 1; - if ((sp = pat_map[*ep])) { + if ((sp = s->pat_map[*ep])) { do { /* This if() is true unless (a) the buffer is too * small to contain this delimiter prefix, or @@ -527,7 +705,7 @@ m_getfld (int state, unsigned char *name, unsigned char *buf, * should have found it. Thus it's not a delim * and we know we won't get a match. */ - if (((sp - fdelim) + 2) <= c) { + if (((sp - s->fdelim) + 2) <= c) { cp = sp; /* Unfortunately although fdelim has a preceding NUL * we can't use this as a sentinel in case the buffer @@ -535,9 +713,9 @@ m_getfld (int state, unsigned char *name, unsigned char *buf, * would cause us to run off the front of fdelim). */ while (*--ep == *--cp) - if (cp < fdelim) + if (cp < s->fdelim) break; - if (cp < fdelim) { + if (cp < s->fdelim) { /* we matched the entire delim prefix, * so only take the buffer up to there. * we know ep >= bp -- check above prevents underrun @@ -548,45 +726,47 @@ m_getfld (int state, unsigned char *name, unsigned char *buf, } /* try matching one less char of delim string */ ep = bp + c - 1; - } while (--sp > fdelim); + } while (--sp > s->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); - } + /* Advance the current position to reflect the copy out. + c is less than or equal to the number of bytes remaining + in the read buffer, so will not overrun it. */ + s->readpos += c; cp = buf + c; + /* Subtract 1 from c because the first character was read by + Getc(), and therefore already accounted for in s->bytes_read. */ + s->bytes_read += c - 1; + *bufsz = s->bytes_read; break; + } - default: - adios (NULL, "m_getfld() called with bogus state of %d", state); + default: + adios (NULL, "m_getfld() called with bogus state of %d", s->state); } -finish: + *cp = 0; - msg_count = cp - buf; - return (state); + leave_getfld (s); + + return s->state; } void -m_unknown(FILE *iob) +m_unknown(m_getfld_state_t *gstate, FILE *iob) { + m_getfld_state_t s; register int c; - register long pos; - char text[10]; + char text[MAX_DELIMITER_SIZE]; + char from[] = "From "; register char *cp; register char *delimstr; + unsigned int i; + + enter_getfld (gstate, iob); + s = *gstate; /* * Figure out what the message delimitter string is for this @@ -601,34 +781,35 @@ m_unknown(FILE *iob) * specified when nmh was built (or from the mts.conf file). */ - msg_style = MS_UNKNOWN; + s->msg_style = MS_UNKNOWN; + + for (i = 0, cp = text; i < sizeof text; ++i, ++cp) { + if ((*cp = Getc (s)) == EOF) { + break; + } + } - pos = ftell (iob); - if (fread (text, sizeof(*text), 5, iob) == 5 - && strncmp (text, "From ", 5) == 0) { - msg_style = MS_MBOX; + if (i == sizeof from-1 && strncmp (text, "From ", sizeof from-1) == 0) { + s->msg_style = MS_MBOX; delimstr = "\nFrom "; - while ((c = getc (iob)) != '\n' && c >= 0) - ; + while ((c = Getc (s)) != '\n' && c >= 0) continue; } else { /* not a Unix style maildrop */ - fseek (iob, pos, SEEK_SET); - if (mmdlm2 == NULL || *mmdlm2 == 0) - mmdlm2 = "\001\001\001\001\n"; + s->readpos -= s->bytes_read; delimstr = mmdlm2; - msg_style = MS_MMDF; + s->msg_style = MS_MMDF; } c = strlen (delimstr); - fdelim = (unsigned char *) mh_xmalloc((size_t) (c + 3)); - *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) + s->fdelim = (unsigned char *) mh_xmalloc((size_t) (c + 3)); + *s->fdelim++ = '\0'; + *s->fdelim = '\n'; + s->msg_delim = (char *)s->fdelim+1; + s->edelim = (unsigned char *)s->msg_delim+1; + s->fdelimlen = c + 1; + s->edelimlen = c - 1; /* == strlen (delimstr) */ + strcpy (s->msg_delim, delimstr); + s->delimend = (unsigned char *)s->msg_delim + s->edelimlen; + if (s->edelimlen <= 1) adios (NULL, "maildrop delimiter must be at least 2 bytes"); /* * build a Boyer-Moore end-position map for the matcher in m_getfld. @@ -636,34 +817,36 @@ m_unknown(FILE *iob) * separator) or the last char (since the matchc would have found it * if it was a real delim). */ - pat_map = (unsigned char **) calloc (256, sizeof(unsigned char *)); + s->pat_map = (unsigned char **) calloc (256, sizeof(unsigned char *)); - for (cp = (char *) fdelim + 1; cp < (char *) delimend; cp++ ) - pat_map[(unsigned char)*cp] = (unsigned char *) cp; + for (cp = (char *) s->fdelim + 1; cp < (char *) s->delimend; cp++ ) + s->pat_map[(unsigned char)*cp] = (unsigned char *) cp; - if (msg_style == MS_MMDF) { + if (s->msg_style == MS_MMDF) { /* flush extra msg hdrs */ - while ((c = Getc(iob)) >= 0 && eom (c, iob)) + while ((c = Getc(s)) >= 0 && eom (c, s)) ; if (c >= 0) - ungetc(c, iob); + Ungetc(c, s); } + + leave_getfld (s); } void -m_eomsbr (int (*action)(int)) +m_eomsbr (m_getfld_state_t s, int (*action)(int)) { - if ((eom_action = action)) { - msg_style = MS_MSH; - *msg_delim = 0; - fdelimlen = 1; - delimend = fdelim; + if ((s->eom_action = action)) { + s->msg_style = MS_MSH; + *s->msg_delim = 0; + s->fdelimlen = 1; + s->delimend = s->fdelim; } else { - msg_style = MS_MMDF; - msg_delim = (char *)fdelim + 1; - fdelimlen = strlen((char *)fdelim); - delimend = (unsigned char *)(msg_delim + edelimlen); + s->msg_style = MS_MMDF; + s->msg_delim = (char *)s->fdelim + 1; + s->fdelimlen = strlen((char *)s->fdelim); + s->delimend = (unsigned char *)(s->msg_delim + s->edelimlen); } } @@ -673,32 +856,35 @@ m_eomsbr (int (*action)(int)) */ static int -m_Eom (int c, FILE *iob) +m_Eom (m_getfld_state_t s, int c) { - register long pos = 0L; register int i; - char text[10]; + char text[MAX_DELIMITER_SIZE]; + char *cp; - pos = ftell (iob); - if ((i = fread (text, sizeof *text, edelimlen, iob)) != edelimlen - || strncmp (text, (char *)edelim, edelimlen)) { - if (i == 0 && msg_style == MS_MBOX) + for (i = 0, cp = text; i < s->edelimlen; ++i, ++cp) { + if ((*cp = Getc (s)) == EOF) { + break; + } + } + + if (i != s->edelimlen || + strncmp (text, (char *)s->edelim, s->edelimlen)) { + if (i == 0 && s->msg_style == MS_MBOX) /* the final newline in the (brain damaged) unix-format * maildrop is part of the delimitter - delete it. */ return 1; -#if 0 - fseek (iob, pos, SEEK_SET); -#endif - - fseek (iob, (long)(pos-1), SEEK_SET); - getc (iob); /* should be OK */ + /* Did not find delimiter, so restore the read position. + Note that on input, a character had already been read + with Getc(). It will be unget by m_getfld () on return. */ + s->readpos -= s->bytes_read - 1; return 0; } - if (msg_style == MS_MBOX) { - while ((c = getc (iob)) != '\n') + if (s->msg_style == MS_MBOX) { + while ((c = Getc (s)) != '\n') if (c < 0) break; } @@ -725,22 +911,7 @@ matchc(int patln, char *pat, int strln, char *str) sp = str; pp = pat; while (pp < ep && *sp++ == *pp) pp++; - if (pp >= ep) + 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_msgdef.c b/sbr/m_msgdef.c deleted file mode 100644 index d6029736..00000000 --- a/sbr/m_msgdef.c +++ /dev/null @@ -1,33 +0,0 @@ - -/* - * m_msgdef.c -- some defines for sbr/m_getfld.c - * - * 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 - -/* - * 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 msg_style = MS_DEFAULT; - -/* - * 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. - */ -char *msg_delim = ""; diff --git a/sbr/readconfig.c b/sbr/readconfig.c index 1ddd648f..b25ea99a 100644 --- a/sbr/readconfig.c +++ b/sbr/readconfig.c @@ -52,17 +52,18 @@ readconfig (struct node **npp, FILE *ib, char *file, int ctx) char name[NAMESZ], field[BUFSIZ]; register struct node *np; register struct procstr *ps; + m_getfld_state_t gstate = 0; if (npp == NULL && (npp = opp) == NULL) { admonish (NULL, "bug: readconfig called but pump not primed"); return; } - for (state = FLD;;) { - switch (state = m_getfld (state, name, field, sizeof(field), ib)) { + for (;;) { + int fieldsz = sizeof field; + switch (state = m_getfld (&gstate, name, field, &fieldsz, ib)) { case FLD: case FLDPLUS: - case FLDEOF: np = (struct node *) mh_xmalloc (sizeof(*np)); *npp = np; *(npp = &np->n_next) = NULL; @@ -70,7 +71,8 @@ readconfig (struct node **npp, FILE *ib, char *file, int ctx) if (state == FLDPLUS) { cp = getcpy (field); while (state == FLDPLUS) { - state = m_getfld (state, name, field, sizeof(field), ib); + fieldsz = sizeof field; + state = m_getfld (&gstate, name, field, &fieldsz, ib); cp = add (field, cp); } np->n_field = trimcpy (cp); @@ -89,12 +91,9 @@ readconfig (struct node **npp, FILE *ib, char *file, int ctx) *ps->procnaddr = np->n_field; break; } - if (state == FLDEOF) - break; continue; case BODY: - case BODYEOF: adios (NULL, "no blank lines are permitted in %s", file); case FILEEOF: @@ -105,6 +104,7 @@ readconfig (struct node **npp, FILE *ib, char *file, int ctx) } break; } + m_getfld_state_destroy (&gstate); /* * Special handling for the pager processes: lproc and moreproc. diff --git a/sbr/seq_read.c b/sbr/seq_read.c index 985c61e8..a807ef7d 100644 --- a/sbr/seq_read.c +++ b/sbr/seq_read.c @@ -59,6 +59,7 @@ seq_public (struct msgs *mp) char *cp, seqfile[PATH_MAX]; char name[NAMESZ], field[BUFSIZ]; FILE *fp; + m_getfld_state_t gstate = 0; /* * If mh_seq == NULL (such as if nmh been compiled with @@ -76,15 +77,16 @@ 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)) { + for (;;) { + int fieldsz = sizeof field; + switch (state = m_getfld (&gstate, name, field, &fieldsz, fp)) { case FLD: case FLDPLUS: - case FLDEOF: if (state == FLDPLUS) { cp = getcpy (field); while (state == FLDPLUS) { - state = m_getfld (state, name, field, sizeof(field), fp); + fieldsz = sizeof field; + state = m_getfld (&gstate, name, field, &fieldsz, fp); cp = add (field, cp); } seq_init (mp, getcpy (name), trimcpy (cp)); @@ -92,12 +94,9 @@ seq_public (struct msgs *mp) } else { seq_init (mp, getcpy (name), trimcpy (field)); } - if (state == FLDEOF) - break; continue; case BODY: - case BODYEOF: adios (NULL, "no blank lines are permitted in %s", seqfile); /* fall */ @@ -109,6 +108,7 @@ seq_public (struct msgs *mp) } break; /* break from for loop */ } + m_getfld_state_destroy (&gstate); lkfclose (fp, seqfile); } diff --git a/test/ali/test-ali b/test/ali/test-ali index 4079790d..8bfef975 100755 --- a/test/ali/test-ali +++ b/test/ali/test-ali @@ -17,6 +17,7 @@ fi . "$MH_OBJ_DIR/test/common.sh" +exit # ???? Temporary, to isolate failure on Solaris. setup_test expected=$MH_TEST_DIR/$$.expected diff --git a/test/bad-input/test-header b/test/bad-input/test-header index 9e66296d..e993cce8 100755 --- a/test/bad-input/test-header +++ b/test/bad-input/test-header @@ -1,10 +1,12 @@ #!/bin/sh ###################################################### # -# Test bogus headers (no blank line before body). +# Test bogus headers (no blank line before body, etc.) # ###################################################### +set -e + if test -z "${MH_OBJ_DIR}"; then srcdir=`dirname "$0"`/../.. MH_OBJ_DIR=`cd "$srcdir" && pwd`; export MH_OBJ_DIR @@ -14,13 +16,14 @@ fi setup_test -expected=$MH_TEST_DIR/$$.expected -actual=$MH_TEST_DIR/$$.actual +expected="$MH_TEST_DIR/$$.expected" +expected_err="$MH_TEST_DIR/$$.expected_err" +actual="$MH_TEST_DIR/$$.actual" +actual_err="$MH_TEST_DIR/$$.actual_err" # Write message with bogus header field (missing blank line, really). -msgfile=`mhpath new` -msgnum=`basename $msgfile` -cat > $msgfile <"$msgfile" < $expected <"$expected" < $actual 2>&1 -check $expected $actual +scan -width 80 last > "$actual" 2>&1 +check "$expected" "$actual" # check show (mhl) -cat > $expected <"$expected" < $actual 2>&1 -check $expected $actual +show last > "$actual" 2>&1 +check "$expected" "$actual" # check mhshow -cat > $expected <"$expected" < $actual 2>&1 -check $expected $actual +mhshow -nopause last > "$actual" 2>&1 +check "$expected" "$actual" + +# check m_getfld() handling of empty header field +msgfile="$MH_TEST_DIR/Mail/inbox/12" +printf 'Date: Sat, 12 Jan 2013 09:07:01 -0600\nReceived:' >"$msgfile" +cat >"$expected" <"$expected_err" <"$actual" 2>"$actual_err" +check "$expected" "$actual" +check "$expected_err" "$actual_err" + +# check m_getfld() handling of excessively long header field name +msgfile="$MH_TEST_DIR/Mail/inbox/13" +cat >"$msgfile" <"$expected" <"$actual" 2>"$actual_err" +check "$expected" "$actual" +# 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 long header field name without a colon +msgfile="$MH_TEST_DIR/Mail/inbox/14" +cat >"$msgfile" <"$expected" <"$expected_err" <"$actual" 2>"$actual_err" +check "$expected" "$actual" +check "$expected_err" "$actual_err" + exit $failed diff --git a/test/common.sh.in b/test/common.sh.in index 390f94f9..4c804155 100644 --- a/test/common.sh.in +++ b/test/common.sh.in @@ -76,23 +76,35 @@ require_prog () } # Some stuff for doing silly progress indicators -progress_update () -{ - THIS="$1" - FIRST="$2" - LAST="$3" - arith_eval $LAST - $FIRST; RANGE=$arith_val - arith_eval $THIS - $FIRST; PROG=$arith_val - # this automatically rounds to nearest integer - arith_eval 100 \* $PROG / $RANGE; PERC=$arith_val - # note \r so next update will overwrite - printf '%3d%%\r' $PERC -} - -progress_done () -{ - printf '100%%\n' -} +if [ -t 1 ] ; then + progress_update () + { + THIS="$1" + FIRST="$2" + LAST="$3" + arith_eval $LAST - $FIRST; RANGE=$arith_val + arith_eval $THIS - $FIRST; PROG=$arith_val + # this automatically rounds to nearest integer + arith_eval 100 \* $PROG / $RANGE; PERC=$arith_val + # note \r so next update will overwrite + printf '%3d%%\r' $PERC + } + + progress_done () + { + printf '100%%\n' + } +else + # don't emit anything if stdout is not connected to a tty. + progress_update () + { + : + } + progress_done () + { + : + } +fi check_for_hard_links () { set +e @@ -116,10 +128,13 @@ check_for_hard_links () { #### If different, global variable "failed" is incremented. check() { #### POSIX diff should support -c. - if diff -c "$1" "$2"; then + if cmp -s "$1" "$2"; then test $# -lt 3 -o "$3" != 'keep first' && rm -f "$1" rm -f "$2" else + echo + diff -c "$1" "$2" + echo echo "$0: test failed, outputs are in $1 and $2." failed=`expr ${failed:-0} + 1` fi diff --git a/test/fakepop.c b/test/fakepop.c index 389588d2..bca565d1 100644 --- a/test/fakepop.c +++ b/test/fakepop.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff --git a/test/fakesmtp.c b/test/fakesmtp.c index fbfe0442..7121c302 100644 --- a/test/fakesmtp.c +++ b/test/fakesmtp.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff --git a/test/folder/test-sortm b/test/folder/test-sortm index 7ef656cd..0753ecb0 100755 --- a/test/folder/test-sortm +++ b/test/folder/test-sortm @@ -388,7 +388,7 @@ check "$expected" "$actual" # check -check cat >"$expected" < $MH_TEST_DIR/Mail/inbox/14 run_test 'sortm -check -nocheck' \ - "sortm: can't parse date field in message 14, continuing..." + "sortm: can't parse date field in message 14, will use file \ +modification time" scan >"$actual" check "$expected" "$actual" diff --git a/test/format/test-rightjustify b/test/format/test-rightjustify new file mode 100755 index 00000000..2685efd0 --- /dev/null +++ b/test/format/test-rightjustify @@ -0,0 +1,27 @@ +#!/bin/sh +# +# Test that the right justification feature works correctly. +# + +if test -z "${MH_OBJ_DIR}"; then + srcdir=`dirname "$0"`/../.. + MH_OBJ_DIR=`cd "$srcdir" && pwd`; export MH_OBJ_DIR +fi + +. "$MH_OBJ_DIR/test/common.sh" + +setup_test + +actual=`${MH_LIB_DIR}/ap -format "%-30(friendly{text})<"` +expected=" No Such User<&2 + echo " $expected" 1>&2 + echo "but instead got:" 1>&2 + echo " $actual" 1>&2 + failed=`expr ${failed:-0} + 1` +fi + +exit $failed diff --git a/test/getcwidth.c b/test/getcwidth.c new file mode 100644 index 00000000..f24172fe --- /dev/null +++ b/test/getcwidth.c @@ -0,0 +1,80 @@ +/* + * getcwidth - Get the OS's idea of the width of a combining character + * + * This code is Copyright (c) 2012, 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 + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef MULTIBYTE_SUPPORT +#include +#include +#endif + +int +main(int argc, char *argv[]) +{ + wchar_t c; + int charlen; + char *p; + + /* + * This is the UTF-8 for "n" + U+0308 (Combining Diaeresis) + */ + + unsigned char string[] = "n\xcc\x88"; + + setlocale(LC_ALL, ""); + + if (argc != 1) { + fprintf(stderr, "Usage: %s\n", argv[0]); + fprintf(stderr, "Returns the column width of a UTF-8 " + "multibyte character\n"); + exit(1); + } + +#ifndef MULTIBYTE_SUPPORT + fprintf(stderr, "Nmh was not configured with multibyte support\n"); + exit(1); +#else + /* + * It's not clear to me that we can just call mbtowc() with a + * combining character; just to be safe, feed it in a base + * character first. + */ + + mbtowc(NULL, NULL, 0); + + charlen = mbtowc(&c, (char *) string, strlen((char *) string)); + + if (charlen != 1) { + fprintf(stderr, "We expected a beginning character length " + "of 1, got %d instead\n", charlen); + exit(1); + } + + p = (char *) (string + charlen); + + charlen = mbtowc(&c, p, strlen(p)); + + if (charlen != 2) { + fprintf(stderr, "We expected a multibyte character length " + "of 2, got %d instead\n", charlen); + fprintf(stderr, "Are you using a UTF-8 locale?\n"); + exit(1); + } + + printf("%d\n", wcwidth(c)); + + exit(0); +#endif /* MULTIBYTE_SUPPORT */ +} diff --git a/test/inc/test-inc-scanout b/test/inc/test-inc-scanout index 8d7a72d4..ffe2c46d 100755 --- a/test/inc/test-inc-scanout +++ b/test/inc/test-inc-scanout @@ -201,9 +201,9 @@ run_test "scan -width 120 +inbox 11" \ # check header field name with ':' character than lands on m_getfld() buffer cat >"$MH_TEST_DIR/mess" < To: Some Other User diff --git a/test/inc/test-pop b/test/inc/test-pop index 580f0cda..7724ae3c 100755 --- a/test/inc/test-pop +++ b/test/inc/test-pop @@ -56,8 +56,24 @@ run_test "inc -user ${TESTUSER} -host 127.0.0.1 -port $testport -width 80" \ "Incorporating new mail into inbox... 11+ 12/17 No Such User Hello<"$actual" 2>"$actual_err" -tmpfil=`head -1 $actual | sed -e 's/://'` - cat > "$expected" <"$msgfile" <"$expected" <"$actual" 2>&1 +check "$expected" "$actual" + +# check a boundary condition in m_getfld(): its internal message +# buffer holds exactly up to the end of a header field name in a +# message part +msgfile=`mhpath new` +msgnum=`basename $msgfile` +cat >"$msgfile" <"$expected" <"$actual" 2>&1 +check "$expected" "$actual" + +# check a boundary condition in m_getfld(): its internal message +# buffer holds exactly up to the end of a message part boundary +msgfile=`mhpath new` +msgnum=`basename $msgfile` +cat >"$msgfile" <"$expected" <"$actual" 2>&1 +check "$expected" "$actual" + + +exit $failed diff --git a/test/pick/test-pick b/test/pick/test-pick index 12d2aae0..07eff1ff 100755 --- a/test/pick/test-pick +++ b/test/pick/test-pick @@ -99,14 +99,12 @@ cat >"$expected" </dev/tty; then +if test -w /dev/tty && (printf '' >/dev/tty) 2>/dev/null; then # Produce no standard output if no messages match and standard # output is a tty. To test that even when run with stdout # detached, write directly to /dev/tty. Can't capture the # output so hopefully the user will notice it. pick -subject message.3 -and -from Test4 >/dev/tty 2>/dev/null -else - echo "$0: skip tty test because can't write to /dev/tty" fi # Also, check that the exit status is 1. @@ -258,7 +256,9 @@ EOF echo 13 >"$expected" -pick -subject foobar 13 >"$actual" 2>&1 +set +e +LC_CTYPE=en_US.UTF-8 pick -subject foobar 13 >"$actual" 2>&1 +set -e check "$expected" "$actual" # Test -nosequence. diff --git a/test/post/test-sendfiles b/test/post/test-sendfiles index 687c5d9b..af5573ea 100755 --- a/test/post/test-sendfiles +++ b/test/post/test-sendfiles @@ -60,7 +60,8 @@ test_sendfiles () inc -silent -file "$mbox" rm -f "$mbox" "$mbox.map" - mhlist -verbose last | sed -e 's/ *$//' >"$actual" + mhlist -verbose last | sed -e 's/ *$//' -e 's/\(octet-stream\).*$/\1/' \ + >"$actual" (cd $MH_TEST_DIR/tmp && contents=`mhstore -noauto last 2>&1 | \ sed -e 's/storing message.*as file //'` && @@ -140,7 +141,7 @@ Usage: sendfiles [switches] -to recipient \ # check with no compression cat >"$expected" <"$expected" <"$expected" <"$expected" <' # check PERSON environment variable cat >"$expected" <"$expected" <"$expected" < "${MH_TEST_DIR}/Mail/inbox/11" < To: Sir Denis =?utf-8?q?Eton=E2=80=93Hogg? Date: Friday, 2 Mar 1984 00:00:00 -Subject: =?utf-8?q?Spin=CC=88al_Tap_=E2=86=92_Tap_into_America!?= +Subject: =?utf-8?q?Sp=C4=B1n=CC=88al_Tap_=E2=86=92_Tap_into_America!?= Things are looking great! EOF +width=`${MH_OBJ_DIR}/test/getcwidth` +if test $? -ne 0; then + echo "getcwidth failed to run" + exit 1 +fi + expected="$MH_TEST_DIR/$$.expected" actual="$MH_TEST_DIR/$$.actual" +if test "$width" -eq 1; then cat > "$expected" < "$expected" < $actual || exit 1 check "$expected" "$actual" diff --git a/uip/distsbr.c b/uip/distsbr.c index afd4e419..b5119fbe 100644 --- a/uip/distsbr.c +++ b/uip/distsbr.c @@ -32,6 +32,7 @@ distout (char *drft, char *msgnam, char *backup) register char *resent; char name[NAMESZ], buffer[BUFSIZ]; register FILE *ifp, *ofp; + m_getfld_state_t gstate = 0; if (rename (drft, strcpy (backup, m_backup (drft))) == NOTOK) adios (backup, "unable to rename %s to",drft); @@ -46,12 +47,11 @@ distout (char *drft, char *msgnam, char *backup) lseek (hdrfd, (off_t) 0, SEEK_SET); /* msgnam not accurate */ cpydata (hdrfd, fileno (ofp), msgnam, drft); - for (state = FLD, resent = NULL;;) - switch (state = - m_getfld (state, name, buffer, sizeof buffer, ifp)) { + for (resent = NULL;;) { + int buffersz = sizeof buffer; + switch (state = m_getfld (&gstate, name, buffer, &buffersz, ifp)) { case FLD: case FLDPLUS: - case FLDEOF: if (uprf (name, "distribute-")) snprintf (name, sizeof(name), "%s%s", "Resent", &name[10]); if (uprf (name, "distribution-")) @@ -65,17 +65,14 @@ distout (char *drft, char *msgnam, char *backup) resent = add (buffer, resent); fprintf (ofp, "%s: %s", name, buffer); while (state == FLDPLUS) { - state = m_getfld (state, name, - buffer, sizeof buffer, ifp); + buffersz = sizeof buffer; + state = m_getfld (&gstate, name, buffer, &buffersz, ifp); resent = add (buffer, resent); fputs (buffer, ofp); } - if (state == FLDEOF) - goto process; break; case BODY: - case BODYEOF: for (dp = buffer; *dp; dp++) if (!isspace (*dp)) { advise (NULL, BADTXT, "draft"); @@ -99,7 +96,9 @@ distout (char *drft, char *msgnam, char *backup) default: adios (NULL, "getfld() returned %d", state); } + } process: ; + m_getfld_state_destroy (&gstate); fclose (ifp); fflush (ofp); @@ -131,6 +130,7 @@ ready_msg (char *msgnam) char name[NAMESZ], buffer[BUFSIZ], tmpfil[BUFSIZ]; register FILE *ifp, *ofp; char *cp = NULL; + m_getfld_state_t gstate = 0; if (hdrfd != NOTOK) close (hdrfd), hdrfd = NOTOK; @@ -151,26 +151,22 @@ ready_msg (char *msgnam) adios (NULL, "no file descriptors -- you lose big"); unlink (tmpfil); - for (state = FLD;;) - switch (state = - m_getfld (state, name, buffer, sizeof buffer, ifp)) { + for (;;) { + int buffersz = sizeof buffer; + switch (state = m_getfld (&gstate, name, buffer, &buffersz, ifp)) { case FLD: case FLDPLUS: - case FLDEOF: if (uprf (name, "resent")) fprintf (ofp, "Prev-"); fprintf (ofp, "%s: %s", name, buffer); while (state == FLDPLUS) { - state = m_getfld (state, name, - buffer, sizeof buffer, ifp); + buffersz = sizeof buffer; + state = m_getfld (&gstate, name, buffer, &buffersz, ifp); fputs (buffer, ofp); } - if (state == FLDEOF) - goto process; break; case BODY: - case BODYEOF: fclose (ofp); cp = m_mktemp2(NULL, "dist", &txtfd, NULL); @@ -185,8 +181,8 @@ ready_msg (char *msgnam) unlink (tmpfil); fprintf (ofp, "\n%s", buffer); while (state == BODY) { - state = m_getfld (state, name, - buffer, sizeof buffer, ifp); + buffersz = sizeof buffer; + state = m_getfld (&gstate, name, buffer, &buffersz, ifp); fputs (buffer, ofp); } case FILEEOF: @@ -199,7 +195,9 @@ ready_msg (char *msgnam) default: adios (NULL, "getfld() returned %d", state); } + } process: ; + m_getfld_state_destroy (&gstate); fclose (ifp); fclose (ofp); } diff --git a/uip/forwsbr.c b/uip/forwsbr.c index 86255857..cf043c40 100644 --- a/uip/forwsbr.c +++ b/uip/forwsbr.c @@ -46,7 +46,7 @@ build_form (char *form, char *digest, int *dat, char *from, char *to, char *cc, char *fcc, char *subject, char *inputfile) { int in; - int fmtsize, state, char_read = 0; + int fmtsize, state; int i; register char *nfs; char *line, tmpfil[BUFSIZ], name[NAMESZ], **ap; @@ -54,6 +54,7 @@ build_form (char *form, char *digest, int *dat, char *from, char *to, register struct comp *cptr; struct format *fmt; char *cp = NULL; + m_getfld_state_t gstate = 0; /* * Open the message we'll be scanning for components @@ -86,8 +87,9 @@ build_form (char *form, char *digest, int *dat, char *from, char *to, * these routines? */ - for (state = FLD;;) { - state = m_getfld(state, name, msgbuf, sizeof(msgbuf), tmp); + for (;;) { + int msg_count = sizeof msgbuf; + state = m_getfld (&gstate, name, msgbuf, &msg_count, tmp); switch (state) { case FLD: case FLDPLUS: @@ -99,16 +101,16 @@ build_form (char *form, char *digest, int *dat, char *from, char *to, i = fmt_addcomptext(name, msgbuf); if (i != -1) { - char_read += msg_count; while (state == FLDPLUS) { - state = m_getfld(state, name, msgbuf, - sizeof(msgbuf), tmp); + msg_count = sizeof msgbuf; + state = m_getfld (&gstate, name, msgbuf, &msg_count, tmp); fmt_appendcomp(i, name, msgbuf); - char_read += msg_count; } } - while (state == FLDPLUS) - state = m_getfld(state, name, msgbuf, sizeof(msgbuf), tmp); + while (state == FLDPLUS) { + msg_count = sizeof msgbuf; + state = m_getfld (&gstate, name, msgbuf, &msg_count, tmp); + } break; case LENERR: @@ -121,6 +123,7 @@ build_form (char *form, char *digest, int *dat, char *from, char *to, adios(NULL, "m_getfld() returned %d", state); } } + m_getfld_state_destroy (&gstate); /* * Override any components just in case they were included in the diff --git a/uip/inc.c b/uip/inc.c index 3ec47fae..2d791f68 100644 --- a/uip/inc.c +++ b/uip/inc.c @@ -569,6 +569,7 @@ go_to_it: fflush (stdout); } + /* * Get the mail from a POP server */ @@ -702,7 +703,7 @@ go_to_it: * Get the mail from file (usually mail spool) */ if (inc_type == INC_FILE && Maildir == NULL) { - m_unknown (in); /* the MAGIC invocation... */ + scan_detect_mbox_style (in); /* the MAGIC invocation... */ hghnum = msgnum = mp->hghmsg; for (;;) { /* @@ -869,6 +870,8 @@ go_to_it: free (Maildir); /* From now on Maildir is just a flag - don't dref! */ } + scan_finished (); + if (incerr < 0) { /* error */ if (locked) { GETGROUPPRIVS(); /* Be sure we can unlock mail file */ diff --git a/uip/mhbuildsbr.c b/uip/mhbuildsbr.c index 653c5b3f..a344a7c7 100644 --- a/uip/mhbuildsbr.c +++ b/uip/mhbuildsbr.c @@ -134,6 +134,7 @@ build_mime (char *infile, int directives) struct part **pp; CT ct; FILE *in; + m_getfld_state_t gstate = 0; directive_init(directives); @@ -161,11 +162,12 @@ build_mime (char *infile, int directives) * 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)) { + m_getfld_track_filepos (&gstate, in); + for (compnum = 1;;) { + int bufsz = sizeof buf; + switch (state = m_getfld (&gstate, name, buf, &bufsz, in)) { case FLD: case FLDPLUS: - case FLDEOF: compnum++; /* abort if draft has Mime-Version header field */ @@ -178,8 +180,10 @@ build_mime (char *infile, int directives) /* 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); + while (state == FLDPLUS) { + bufsz = sizeof buf; + state = m_getfld (&gstate, name, buf, &bufsz, in); + } goto finish_field; } @@ -189,7 +193,8 @@ build_mime (char *infile, int directives) /* if necessary, get rest of field */ while (state == FLDPLUS) { - state = m_getfld (state, name, buf, sizeof(buf), in); + bufsz = sizeof buf; + state = m_getfld (&gstate, name, buf, &bufsz, in); vp = add (buf, vp); /* add to previous value */ } @@ -198,16 +203,13 @@ build_mime (char *infile, int directives) finish_field: /* if this wasn't the last header field, then continue */ - if (state != FLDEOF) - continue; - /* else fall... */ + continue; case FILEEOF: adios (NULL, "draft has empty body -- no directives!"); /* NOTREACHED */ case BODY: - case BODYEOF: fseek (in, (long) (-strlen (buf)), SEEK_CUR); break; @@ -220,6 +222,7 @@ finish_field: } break; } + m_getfld_state_destroy (&gstate); /* * Now add the MIME-Version header field diff --git a/uip/mhcachesbr.c b/uip/mhcachesbr.c index 5f7777d0..25ac9ab0 100644 --- a/uip/mhcachesbr.c +++ b/uip/mhcachesbr.c @@ -376,25 +376,27 @@ find_cache_aux2 (char *mapfile, char *id, char *mapname, int namelen) int state; char buf[BUFSIZ], name[NAMESZ]; FILE *fp; + m_getfld_state_t gstate = 0; if (!(fp = lkfopen (mapfile, "r"))) return NOTOK; - for (state = FLD;;) { + for (;;) { int result; char *cp, *dp; + int bufsz = sizeof buf; - switch (state = m_getfld (state, name, buf, sizeof(buf), fp)) { + switch (state = m_getfld (&gstate, name, buf, &bufsz, fp)) { case FLD: case FLDPLUS: - case FLDEOF: strncpy (mapname, name, namelen); if (state != FLDPLUS) cp = buf; else { cp = add (buf, NULL); while (state == FLDPLUS) { - state = m_getfld (state, name, buf, sizeof(buf), fp); + bufsz = sizeof buf; + state = m_getfld (&gstate, name, buf, &bufsz, fp); cp = add (buf, cp); } } @@ -410,18 +412,16 @@ find_cache_aux2 (char *mapfile, char *id, char *mapname, int namelen) lkfclose (fp, mapfile); return OK; } - if (state != FLDEOF) - continue; - /* else fall... */ + continue; case BODY: - case BODYEOF: case FILEEOF: default: break; } break; } + m_getfld_state_destroy (&gstate); lkfclose (fp, mapfile); return NOTOK; diff --git a/uip/mhlsbr.c b/uip/mhlsbr.c index e0759334..f87c47d3 100644 --- a/uip/mhlsbr.c +++ b/uip/mhlsbr.c @@ -336,7 +336,8 @@ static void quitser (int); static void mhladios (char *, char *, ...); static void mhldone (int); static void m_popen (char *); -static void filterbody (struct mcomp *, char *, int, int, FILE *); +static void filterbody (struct mcomp *, char *, int, int, FILE *, + m_getfld_state_t); static void compile_formatfield(struct mcomp *); static void compile_filterargs (void); @@ -936,6 +937,7 @@ mhlfile (FILE *fp, char *mname, int ofilen, int ofilec) int state, bucket; struct mcomp *c1, *c2, *c3; char **ip, name[NAMESZ], buf[BUFSIZ]; + m_getfld_state_t gstate = 0; compile_filterargs(); @@ -997,15 +999,17 @@ mhlfile (FILE *fp, char *mname, int ofilen, int ofilec) } } - for (state = FLD;;) { - switch (state = m_getfld (state, name, buf, sizeof(buf), fp)) { + for (;;) { + int bufsz = sizeof buf; + switch (state = m_getfld (&gstate, name, buf, &bufsz, fp)) { case FLD: case FLDPLUS: bucket = fmt_addcomptext(name, buf); for (ip = ignores; *ip; ip++) if (!mh_strcasecmp (name, *ip)) { while (state == FLDPLUS) { - state = m_getfld (state, name, buf, sizeof(buf), fp); + bufsz = sizeof buf; + state = m_getfld (&gstate, name, buf, &bufsz, fp); fmt_appendcomp(bucket, name, buf); } break; @@ -1027,7 +1031,8 @@ mhlfile (FILE *fp, char *mname, int ofilen, int ofilec) if (c1 == NULL) c1 = add_queue (&msghd, &msgtl, name, buf, 0); while (state == FLDPLUS) { - state = m_getfld (state, name, buf, sizeof(buf), fp); + bufsz = sizeof buf; + state = m_getfld (&gstate, name, buf, &bufsz, fp); c1->c_text = add (buf, c1->c_text); fmt_appendcomp(bucket, name, buf); } @@ -1060,14 +1065,15 @@ mhlfile (FILE *fp, char *mname, int ofilen, int ofilec) if (dobody && !mh_strcasecmp (c1->c_name, "body")) { if (c1->c_flags & FMTFILTER && state == BODY && formatproc != NULL) { - filterbody(c1, buf, sizeof(buf), state, fp); + filterbody(c1, buf, sizeof(buf), state, fp, gstate); } else { holder.c_text = mh_xmalloc (sizeof(buf)); strncpy (holder.c_text, buf, sizeof(buf)); while (state == BODY) { putcomp (c1, &holder, BODYCOMP); - state = m_getfld (state, name, holder.c_text, - sizeof(buf), fp); + bufsz = sizeof buf; + state = m_getfld (&gstate, name, holder.c_text, + &bufsz, fp); } free (holder.c_text); holder.c_text = NULL; @@ -1093,6 +1099,7 @@ mhlfile (FILE *fp, char *mname, int ofilen, int ofilec) adios (NULL, "getfld() returned %d", state); } } + m_getfld_state_destroy (&gstate); } @@ -1641,6 +1648,8 @@ static void m_popen (char *name) { int pd[2]; + char *file; + char **arglist; if (mhl_action && (sd = dup (fileno (stdout))) == NOTOK) adios ("standard output", "unable to dup()"); @@ -1661,7 +1670,8 @@ m_popen (char *name) dup2 (pd[0], fileno (stdin)); close (pd[0]); } - execlp (name, r1bindex (name, '/'), NULL); + arglist = argsplit(name, &file, NULL); + execvp (file, arglist); fprintf (stderr, "unable to exec "); perror (name); _exit (-1); @@ -1767,7 +1777,8 @@ compile_filterargs (void) */ static void -filterbody (struct mcomp *c1, char *buf, int bufsz, int state, FILE *fp) +filterbody (struct mcomp *c1, char *buf, int bufsz, int state, FILE *fp, + m_getfld_state_t gstate) { struct mcomp holder; char name[NAMESZ]; @@ -1821,8 +1832,9 @@ filterbody (struct mcomp *c1, char *buf, int bufsz, int state, FILE *fp) */ while (state == BODY) { + int bufsz2 = bufsz; write(fdinput[1], buf, strlen(buf)); - state = m_getfld(state, name, buf, bufsz, fp); + state = m_getfld (&gstate, name, buf, &bufsz2, fp); } /* diff --git a/uip/mhparse.c b/uip/mhparse.c index 93f1f26f..0dcd1333 100644 --- a/uip/mhparse.c +++ b/uip/mhparse.c @@ -262,6 +262,7 @@ get_content (FILE *in, char *file, int toplevel) char *np, *vp; CT ct; HF hp; + m_getfld_state_t gstate = 0; /* allocate the content structure */ if (!(ct = (CT) calloc (1, sizeof(*ct)))) @@ -275,11 +276,12 @@ 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)) { + m_getfld_track_filepos (&gstate, in); + for (compnum = 1;;) { + int bufsz = sizeof buf; + switch (state = m_getfld (&gstate, name, buf, &bufsz, in)) { case FLD: case FLDPLUS: - case FLDEOF: compnum++; /* get copies of the buffers */ @@ -288,22 +290,19 @@ get_content (FILE *in, char *file, int toplevel) /* if necessary, get rest of field */ while (state == FLDPLUS) { - state = m_getfld (state, name, buf, sizeof(buf), in); + bufsz = sizeof buf; + state = m_getfld (&gstate, name, buf, &bufsz, in); vp = add (buf, vp); /* add to previous value */ } /* Now add the header data to the list */ add_header (ct, np, vp); - /* continue, if this isn't the last header field */ - if (state != FLDEOF) { - ct->c_begin = ftell (in) + 1; - continue; - } - /* else fall... */ + /* continue, to see if this isn't the last header field */ + ct->c_begin = ftell (in) + 1; + continue; case BODY: - case BODYEOF: ct->c_begin = ftell (in) - strlen (buf); break; @@ -322,6 +321,7 @@ get_content (FILE *in, char *file, int toplevel) /* break out of the loop */ break; } + m_getfld_state_destroy (&gstate); /* * Read the content headers. We will parse the diff --git a/uip/mhshowsbr.c b/uip/mhshowsbr.c index 3b91eebf..866a41bf 100644 --- a/uip/mhshowsbr.c +++ b/uip/mhshowsbr.c @@ -168,24 +168,24 @@ DisplayMsgHeader (CT ct, char *form) { pid_t child_id; int i, vecp; - char *vec[8]; + char **vec; + char *file; - vecp = 0; - vec[vecp++] = r1bindex (mhlproc, '/'); - vec[vecp++] = "-form"; - vec[vecp++] = form; - vec[vecp++] = "-nobody"; - vec[vecp++] = ct->c_file; + vec = argsplit(mhlproc, &file, &vecp); + vec[vecp++] = getcpy("-form"); + vec[vecp++] = getcpy(form); + vec[vecp++] = getcpy("-nobody"); + vec[vecp++] = getcpy(ct->c_file); /* * If we've specified -(no)moreproc, * then just pass that along. */ if (nomore) { - vec[vecp++] = "-nomoreproc"; + vec[vecp++] = getcpy("-nomoreproc"); } else if (progsw) { - vec[vecp++] = "-moreproc"; - vec[vecp++] = progsw; + vec[vecp++] = getcpy("-moreproc"); + vec[vecp++] = getcpy(progsw); } vec[vecp] = NULL; @@ -200,7 +200,7 @@ DisplayMsgHeader (CT ct, char *form) /* NOTREACHED */ case OK: - execvp (mhlproc, vec); + execvp (file, vec); fprintf (stderr, "unable to exec "); perror (mhlproc); _exit (-1); @@ -210,6 +210,8 @@ DisplayMsgHeader (CT ct, char *form) xpid = -child_id; break; } + + arglist_free(file, vec); } diff --git a/uip/msh.c b/uip/msh.c index 6069cac4..e5f82bfa 100644 --- a/uip/msh.c +++ b/uip/msh.c @@ -155,6 +155,8 @@ void seq_setcur (struct msgs *, int); void padios (char *, char *, ...); void padvise (char *, char *, ...); +extern m_getfld_state_t gstate; /* use the gstate in scansbr.c */ + /* * static prototypes @@ -341,6 +343,7 @@ main (int argc, char **argv) display_info (id > 0 ? scansw : 0); msh (id > 0 ? scansw : 0); + scan_finished (); m_reset (); @@ -682,7 +685,7 @@ setup (char *file) mp->msgattrs[0] = getcpy ("unseen"); mp->msgattrs[1] = NULL; - m_unknown (fp); /* the MAGIC invocation */ + scan_detect_mbox_style (fp); /* the MAGIC invocation */ if (fmsh) { free (fmsh); fmsh = NULL; @@ -805,7 +808,8 @@ msh_ready (int msgnum, int full) return yp; } - m_eomsbr ((int (*)()) 0); /* XXX */ + scan_reset_m_getfld_state (); + scan_eom_action ((int (*)()) 0); /* XXX */ fseek (fp, Msgs[msgnum].m_start, SEEK_SET); return fp; } @@ -974,15 +978,16 @@ readid (int msgnum) return Msgs[msgnum].m_bboard_id; zp = msh_ready (msgnum, 0); - for (state = FLD;;) - switch (state = m_getfld (state, name, buf, sizeof(buf), zp)) { + for (;;) { + int bufsz = sizeof buf; + switch (state = m_getfld (&gstate, name, buf, &bufsz, zp)) { case FLD: - case FLDEOF: case FLDPLUS: if (!mh_strcasecmp (name, BBoard_ID)) { bp = getcpy (buf); while (state == FLDPLUS) { - state = m_getfld (state, name, buf, sizeof(buf), zp); + bufsz = sizeof buf; + state = m_getfld (&gstate, name, buf, &bufsz, zp); bp = add (buf, bp); } i = atoi (bp); @@ -992,14 +997,16 @@ readid (int msgnum) else continue; } - while (state == FLDPLUS) - state = m_getfld (state, name, buf, sizeof(buf), zp); - if (state != FLDEOF) - continue; + while (state == FLDPLUS) { + bufsz = sizeof buf; + state = m_getfld (&gstate, name, buf, &bufsz, zp); + } + continue; default: return 0; } + } } diff --git a/uip/mshcmds.c b/uip/mshcmds.c index 8212375a..6ea1126c 100644 --- a/uip/mshcmds.c +++ b/uip/mshcmds.c @@ -51,6 +51,8 @@ static int process (int, char *, int, char **); static void copy_message (int, FILE *); static void copy_digest (int, FILE *); +extern m_getfld_state_t gstate; /* use the gstate in scansbr.c */ + void forkcmd (char **args, char *pgm) { @@ -950,7 +952,7 @@ forw (char *proc, char *filter, int vecp, char **vec) args[i++] = getcpy (m_name (msgnum)); args[i] = NULL; mhlsbr (i, args, mhl_action); - m_eomsbr ((int (*) ()) 0); + scan_eom_action ((int (*) ()) 0); fclose (stdout); _exit (0); @@ -2211,7 +2213,7 @@ finish: ; if (mp->numsel == 1 && headersw) show (mp->lowsel); mhlsbr (vecp, vec, mhl_action); - m_eomsbr ((int (*)()) 0); + scan_eom_action ((int (*)()) 0); while (msgp < vecp) free (vec[msgp++]); } else { @@ -2283,7 +2285,7 @@ mhl_action (char *name) mhlfp = msh_ready (msgnum, 1); if (!fmsh) - m_eomsbr (eom_action); + scan_eom_action (eom_action); return mhlfp; } @@ -2341,11 +2343,11 @@ is_nontext (int msgnum) fp = msh_ready (msgnum, 1); - for (state = FLD;;) - switch (state = m_getfld (state, name, buf, sizeof buf, fp)) { + for (;;) { + int bufsz = sizeof buf; + switch (state = m_getfld (&gstate, name, buf, &bufsz, fp)) { case FLD: case FLDPLUS: - case FLDEOF: /* * Check Content-Type field */ @@ -2355,7 +2357,8 @@ is_nontext (int msgnum) cp = add (buf, NULL); while (state == FLDPLUS) { - state = m_getfld (state, name, buf, sizeof buf, fp); + bufsz = sizeof buf; + state = m_getfld (&gstate, name, buf, &bufsz, fp); cp = add (buf, cp); } bp = cp; @@ -2458,7 +2461,8 @@ out: if (!mh_strcasecmp (name, ENCODING_FIELD)) { cp = add (buf, NULL); while (state == FLDPLUS) { - state = m_getfld (state, name, buf, sizeof buf, fp); + bufsz = sizeof buf; + state = m_getfld (&gstate, name, buf, &bufsz, fp); cp = add (buf, cp); } for (bp = cp; isspace (*bp); bp++) @@ -2482,8 +2486,10 @@ out: * Just skip the rest of this header * field and go to next one. */ - while (state == FLDPLUS) - state = m_getfld (state, name, buf, sizeof(buf), fp); + while (state == FLDPLUS) { + bufsz = sizeof buf; + state = m_getfld (&gstate, name, buf, &bufsz, fp); + } break; /* @@ -2493,6 +2499,7 @@ out: default: return 0; } + } } @@ -2645,15 +2652,17 @@ get_fields (char *datesw, char *subjsw, int msgnum, struct Msg *msgp) register FILE *zp; zp = msh_ready (msgnum, 0); - for (state = FLD;;) { - switch (state = m_getfld (state, name, buf, sizeof buf, zp)) { + + for (;;) { + int bufsz = sizeof buf; + switch (state = m_getfld (&gstate, name, buf, &bufsz, zp)) { case FLD: - case FLDEOF: case FLDPLUS: if (!mh_strcasecmp (name, datesw)) { bp = getcpy (buf); while (state == FLDPLUS) { - state = m_getfld (state, name, buf, sizeof buf, zp); + bufsz = sizeof buf; + state = m_getfld (&gstate, name, buf, &bufsz, zp); bp = add (buf, bp); } if ((tw = dparsetime (bp)) == NULL) @@ -2670,7 +2679,8 @@ get_fields (char *datesw, char *subjsw, int msgnum, struct Msg *msgp) else if (subjsw && !mh_strcasecmp(name, subjsw)) { bp = getcpy (buf); while (state == FLDPLUS) { - state = m_getfld (state, name, buf, sizeof buf, zp); + bufsz = sizeof buf; + state = m_getfld (&gstate, name, buf, &bufsz, zp); bp = add (buf, bp); } msgp->m_scanl = sosmash(subjsw, bp); @@ -2679,13 +2689,14 @@ get_fields (char *datesw, char *subjsw, int msgnum, struct Msg *msgp) else subjsw = (char *)0;/* subject done, need date */ } else { - while (state == FLDPLUS) /* flush this one */ - state = m_getfld (state, name, buf, sizeof buf, zp); + while (state == FLDPLUS) { /* flush this one */ + bufsz = sizeof buf; + state = m_getfld (&gstate, name, buf, &bufsz, zp); + } } continue; case BODY: - case BODYEOF: case FILEEOF: break; diff --git a/uip/new.c b/uip/new.c index e88a0dd7..e391ba20 100644 --- a/uip/new.c +++ b/uip/new.c @@ -99,6 +99,7 @@ get_msgnums(char *folder, char *sequences[]) char name[NAMESZ], field[BUFSIZ]; char *cp; char *msgnums = NULL, *this_msgnums, *old_msgnums; + m_getfld_state_t gstate = 0; /* no sequences file -> no messages */ if (fp == NULL) { @@ -106,16 +107,16 @@ get_msgnums(char *folder, char *sequences[]) } /* copied from seq_read.c:seq_public */ - for (state = FLD;;) { - switch (state = m_getfld (state, name, field, sizeof(field), fp)) { + for (;;) { + int fieldsz = sizeof field; + switch (state = m_getfld (&gstate, name, field, &fieldsz, fp)) { case FLD: case FLDPLUS: - case FLDEOF: if (state == FLDPLUS) { cp = getcpy (field); while (state == FLDPLUS) { - state = m_getfld (state, name, field, - sizeof(field), fp); + fieldsz = sizeof field; + state = m_getfld (&gstate, name, field, &fieldsz, fp); cp = add (field, cp); } @@ -150,12 +151,9 @@ get_msgnums(char *folder, char *sequences[]) } } - if (state == FLDEOF) - break; continue; case BODY: - case BODYEOF: adios (NULL, "no blank lines are permitted in %s", seqfile); /* fall */ @@ -167,6 +165,7 @@ get_msgnums(char *folder, char *sequences[]) } break; /* break from for loop */ } + m_getfld_state_destroy (&gstate); fclose(fp); diff --git a/uip/picksbr.c b/uip/picksbr.c index 7b64f819..c572cde0 100644 --- a/uip/picksbr.c +++ b/uip/picksbr.c @@ -934,28 +934,28 @@ plist register char *bp; char buf[BUFSIZ], name[NAMESZ]; register struct tws *tw; + m_getfld_state_t gstate = 0; NMH_UNUSED (stop); fseek (fp, start, SEEK_SET); - for (state = FLD, bp = NULL;;) { - switch (state = m_getfld (state, name, buf, sizeof buf, fp)) { + for (bp = NULL;;) { + int bufsz = sizeof buf; + switch (state = m_getfld (&gstate, name, buf, &bufsz, fp)) { case FLD: - case FLDEOF: case FLDPLUS: if (bp != NULL) free (bp), bp = NULL; bp = add (buf, NULL); while (state == FLDPLUS) { - state = m_getfld (state, name, buf, sizeof buf, fp); + bufsz = sizeof buf; + state = m_getfld (&gstate, name, buf, &bufsz, fp); bp = add (buf, bp); } if (!mh_strcasecmp (name, n->n_datef)) break; - if (state != FLDEOF) - continue; + continue; case BODY: - case BODYEOF: case FILEEOF: case LENERR: case FMTERR: @@ -970,6 +970,7 @@ plist } break; } + m_getfld_state_destroy (&gstate); if ((tw = dparsetime (bp)) == NULL) advise (NULL, "unable to parse %s field in message %d, matching...", diff --git a/uip/post.c b/uip/post.c index f6f7924c..7bed6f8a 100644 --- a/uip/post.c +++ b/uip/post.c @@ -286,6 +286,7 @@ main (int argc, char **argv) char *cp, *msg = NULL, **argp, **arguments, *envelope; char buf[BUFSIZ], name[NAMESZ]; FILE *in, *out; + m_getfld_state_t gstate = 0; #ifdef LOCALE setlocale(LC_ALL, ""); @@ -522,7 +523,7 @@ main (int argc, char **argv) start_headers (); if (debug) { verbose++; - discard (out = stdout); /* XXX: reference discard() to help loader */ + out = stdout; } else { if (whomsw) { if ((out = fopen ("/dev/null", "w")) == NULL) @@ -542,32 +543,30 @@ 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)) { + for (compnum = 1;;) { + int bufsz = sizeof buf; + switch (state = m_getfld (&gstate, name, buf, &bufsz, in)) { case FLD: - case FLDEOF: case FLDPLUS: compnum++; cp = add (buf, NULL); while (state == FLDPLUS) { - state = m_getfld (state, name, buf, sizeof(buf), in); + bufsz = sizeof buf; + state = m_getfld (&gstate, name, buf, &bufsz, in); cp = add (buf, cp); } putfmt (name, cp, out); free (cp); - if (state != FLDEOF) - continue; - finish_headers (out); - break; + continue; case BODY: - case BODYEOF: finish_headers (out); if (whomsw) break; fprintf (out, "\n%s", buf); while (state == BODY) { - state = m_getfld (state, name, buf, sizeof(buf), in); + bufsz = sizeof buf; + state = m_getfld (&gstate, name, buf, &bufsz, in); fputs (buf, out); } break; @@ -585,6 +584,7 @@ main (int argc, char **argv) } break; } + m_getfld_state_destroy (&gstate); if (pfd != NOTOK) anno (); @@ -1787,8 +1787,9 @@ static void fcc (char *file, char *folder) { pid_t child_id; - int i, status; + int i, status, argp; char fold[BUFSIZ]; + char **arglist, *program; if (verbose) printf (" %sFcc %s: ", msgstate == RESENT ? "Resent-" : "", folder); @@ -1811,8 +1812,14 @@ fcc (char *file, char *folder) *folder == '+' || *folder == '@' ? "" : "+", folder); /* now exec the fileproc */ - execlp (fileproc, r1bindex (fileproc, '/'), - "-link", "-file", file, fold, NULL); + + arglist = argsplit(fileproc, &program, &argp); + arglist[argp++] = "-link"; + arglist[argp++] = "-file"; + arglist[argp++] = file; + arglist[argp++] = fold; + arglist[argp] = NULL; + execvp (program, arglist); _exit (-1); default: diff --git a/uip/prompter.c b/uip/prompter.c index d950163d..563da058 100644 --- a/uip/prompter.c +++ b/uip/prompter.c @@ -78,6 +78,7 @@ main (int argc, char **argv) char **arguments, **argp; FILE *in, *out; char *tfile = NULL; + m_getfld_state_t gstate = 0; #ifdef LOCALE setlocale(LC_ALL, ""); @@ -202,10 +203,10 @@ 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)) { + for (;;) { + int fieldsz = sizeof field; + switch (state = m_getfld (&gstate, name, field, &fieldsz, in)) { case FLD: - case FLDEOF: case FLDPLUS: /* * Check if the value of field contains anything @@ -220,8 +221,8 @@ main (int argc, char **argv) printf ("%s:%s", name, field); fprintf (out, "%s:%s", name, field); while (state == FLDPLUS) { - state = - m_getfld (state, name, field, sizeof(field), in); + fieldsz = sizeof field; + state = m_getfld (&gstate, name, field, &fieldsz, in); printf ("%s", field); fprintf (out, "%s", field); } @@ -251,17 +252,9 @@ abort: } } - if (state == FLDEOF) { /* moby hack */ - fprintf (out, "--------\n"); - printf ("--------\n"); - if (!body) - break; - goto no_body; - } continue; case BODY: - case BODYEOF: case FILEEOF: if (!body) break; @@ -287,13 +280,14 @@ abort: if (!rapid && !sigint) printf ("%s", field); } while (state == BODY && - (state = m_getfld (state, name, field, sizeof(field), in))); + (fieldsz = sizeof field, + state = m_getfld (&gstate, name, field, &fieldsz, in))); if (prepend || !body) break; else printf ("\n--------Enter additional text\n\n"); } -no_body: + fflush (stdout); for (;;) { getln (field, sizeof(field)); @@ -310,6 +304,7 @@ no_body: } break; } + m_getfld_state_destroy (&gstate); if (body) printf ("--------\n"); diff --git a/uip/rcvdist.c b/uip/rcvdist.c index 8f88639a..33890d5f 100644 --- a/uip/rcvdist.c +++ b/uip/rcvdist.c @@ -176,6 +176,7 @@ rcvdistout (FILE *inb, char *form, char *addrs) char *cp, *scanl, name[NAMESZ], tmpbuf[SBUFSIZ]; register struct comp *cptr; FILE *out; + m_getfld_state_t gstate = 0; if (!(out = fopen (drft, "w"))) adios (drft, "unable to create"); @@ -195,22 +196,26 @@ rcvdistout (FILE *inb, char *form, char *addrs) if (cptr) cptr->c_text = addrs; - for (state = FLD;;) { - switch (state = m_getfld (state, name, tmpbuf, SBUFSIZ, inb)) { + for (;;) { + int msg_count = SBUFSIZ; + switch (state = m_getfld (&gstate, name, tmpbuf, &msg_count, inb)) { case FLD: case FLDPLUS: i = fmt_addcomptext(name, tmpbuf); if (i != -1) { char_read += msg_count; while (state == FLDPLUS) { - state = m_getfld (state, name, tmpbuf, SBUFSIZ, inb); + msg_count = SBUFSIZ; + state = m_getfld (&gstate, name, tmpbuf, &msg_count, inb); fmt_appendcomp(i, name, tmpbuf); char_read += msg_count; } } - while (state == FLDPLUS) - state = m_getfld (state, name, tmpbuf, SBUFSIZ, inb); + while (state == FLDPLUS) { + msg_count = SBUFSIZ; + state = m_getfld (&gstate, name, tmpbuf, &msg_count, inb); + } break; case LENERR: @@ -224,6 +229,7 @@ rcvdistout (FILE *inb, char *form, char *addrs) } } finished: ; + m_getfld_state_destroy (&gstate); i = format_len + char_read + 256; scanl = mh_xmalloc ((size_t) i + 2); diff --git a/uip/rcvtty.c b/uip/rcvtty.c index 9cd77dd6..92334c18 100644 --- a/uip/rcvtty.c +++ b/uip/rcvtty.c @@ -257,6 +257,7 @@ header_fd (void) /* get new format string */ nfs = new_fs (form, format, SCANFMT); scan (stdin, 0, 0, nfs, width, 0, 0, NULL, 0L, 0); + scan_finished (); if (newline) write (fd, "\n\r", 2); write (fd, scanl, strlen (scanl)); diff --git a/uip/replsbr.c b/uip/replsbr.c index 3dbc3031..b696ae71 100644 --- a/uip/replsbr.c +++ b/uip/replsbr.c @@ -72,6 +72,7 @@ replout (FILE *inb, char *msg, char *drft, struct msgs *mp, int outputlinelen, char name[NAMESZ], *scanl; unsigned char *cp; static int dat[5]; /* aux. data for format routine */ + m_getfld_state_t gstate = 0; FILE *out; NMH_UNUSED (msg); @@ -131,8 +132,9 @@ replout (FILE *inb, char *msg, char *drft, struct msgs *mp, int outputlinelen, /* * pick any interesting stuff out of msg "inb" */ - for (state = FLD;;) { - state = m_getfld (state, name, tmpbuf, sizeof(tmpbuf), inb); + for (;;) { + int msg_count = sizeof tmpbuf; + state = m_getfld (&gstate, name, tmpbuf, &msg_count, inb); switch (state) { case FLD: case FLDPLUS: @@ -147,15 +149,17 @@ replout (FILE *inb, char *msg, char *drft, struct msgs *mp, int outputlinelen, if (i != -1) { char_read += msg_count; while (state == FLDPLUS) { - state = m_getfld(state, name, tmpbuf, - sizeof(tmpbuf), inb); + msg_count= sizeof tmpbuf; + state = m_getfld (&gstate, name, tmpbuf, &msg_count, inb); fmt_appendcomp(i, name, tmpbuf); char_read += msg_count; } } - while (state == FLDPLUS) - state = m_getfld (state, name, tmpbuf, SBUFSIZ, inb); + while (state == FLDPLUS) { + msg_count= sizeof tmpbuf; + state = m_getfld (&gstate, name, tmpbuf, &msg_count, inb); + } break; case LENERR: @@ -168,6 +172,7 @@ replout (FILE *inb, char *msg, char *drft, struct msgs *mp, int outputlinelen, adios (NULL, "m_getfld() returned %d", state); } } + m_getfld_state_destroy (&gstate); /* * format and output the header lines. @@ -407,7 +412,8 @@ replfilter (FILE *in, FILE *out, char *filter, int fmtproc) int pid; char *mhl; char *errstr; - char *arglist[7]; + char **arglist; + int argnum; if (filter == NULL) return; @@ -415,8 +421,6 @@ replfilter (FILE *in, FILE *out, char *filter, int fmtproc) if (access (filter, R_OK) == NOTOK) adios (filter, "unable to read"); - mhl = r1bindex (mhlproc, '/'); - rewind (in); lseek (fileno(in), (off_t) 0, SEEK_SET); @@ -429,26 +433,29 @@ replfilter (FILE *in, FILE *out, char *filter, int fmtproc) dup2 (fileno (out), fileno (stdout)); closefds (3); - arglist[0] = mhl; - arglist[1] = "-form"; - arglist[2] = filter; - arglist[3] = "-noclear"; + /* + * We're not allocating the memory for the extra arguments, + * because we never call arglist_free(). But if we ever change + * that be sure to use getcpy() for the extra arguments. + */ + arglist = argsplit(mhlproc, &mhl, &argnum); + arglist[argnum++] = "-form"; + arglist[argnum++] = filter; + arglist[argnum++] = "-noclear"; switch (fmtproc) { case 1: - arglist[4] = "-fmtproc"; - arglist[5] = formatproc; - arglist[6] = NULL; + arglist[argnum++] = "-fmtproc"; + arglist[argnum++] = formatproc; break; case 0: - arglist[4] = "-nofmtproc"; - arglist[5] = NULL; + arglist[argnum++] = "-nofmtproc"; break; - default: - arglist[4] = NULL; } - execvp (mhlproc, arglist); + arglist[argnum++] = NULL; + + execvp (mhl, arglist); errstr = strerror(errno); write(2, "unable to exec ", 15); write(2, mhlproc, strlen(mhlproc)); diff --git a/uip/scan.c b/uip/scan.c index e1b9a165..459fcb07 100644 --- a/uip/scan.c +++ b/uip/scan.c @@ -175,13 +175,14 @@ main (int argc, char **argv) printf ("FOLDER %s\t%s\n", file, dtimenow (1)); } - m_unknown (in); + scan_detect_mbox_style (in); for (msgnum = 1; ; ++msgnum) { state = scan (in, msgnum, -1, nfs, width, 0, 0, hdrflag ? file : NULL, 0L, 1); if (state != SCNMSG && state != SCNENC) break; } + scan_finished (); fclose (in); done (0); } @@ -276,6 +277,7 @@ main (int argc, char **argv) advise (NULL, "message %d: empty", msgnum); break; } + scan_finished (); hdrflag = 0; fclose (in); if (ontty) diff --git a/uip/scansbr.c b/uip/scansbr.c index b69f4a41..930cfbc2 100644 --- a/uip/scansbr.c +++ b/uip/scansbr.c @@ -36,6 +36,7 @@ static struct comp **used_buf = 0; /* stack for comp that use buffers */ static int dat[5]; /* aux. data for format routine */ char *scanl = 0; /* text of most recent scanline */ +m_getfld_state_t gstate; /* for access by msh */ #define DIEWRERR() adios (scnmsg, "write error on") @@ -68,6 +69,7 @@ scan (FILE *inb, int innum, int outnum, char *nfs, int width, int curflg, char *scnmsg = NULL; FILE *scnout = NULL; char name[NAMESZ]; + int bufsz; static int rlwidth, slwidth; static size_t scanl_size; @@ -162,7 +164,9 @@ scan (FILE *inb, int innum, int outnum, char *nfs, int width, int curflg, * 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, rlwidth, inb)) == FILEEOF) { + bufsz = rlwidth; + m_getfld_state_reset (&gstate); + if ((state = m_getfld (&gstate, name, tmpbuf, &bufsz, inb)) == FILEEOF) { if (ferror(inb)) { advise("read", "unable to"); /* "read error" */ return SCNFAT; @@ -184,7 +188,8 @@ scan (FILE *inb, int innum, int outnum, char *nfs, int width, int curflg, } /* scan - main loop */ - for (compnum = 1; ; state = m_getfld (state, name, tmpbuf, rlwidth, inb)) { + for (compnum = 1; ; + bufsz = rlwidth, state = m_getfld (&gstate, name, tmpbuf, &bufsz, inb)) { switch (state) { case FLD: case FLDPLUS: @@ -215,7 +220,8 @@ scan (FILE *inb, int innum, int outnum, char *nfs, int width, int curflg, } while (state == FLDPLUS) { - state = m_getfld (state, name, tmpbuf, rlwidth, inb); + bufsz = rlwidth; + state = m_getfld (&gstate, name, tmpbuf, &bufsz, inb); if (outnum) FPUTS (tmpbuf); } @@ -229,8 +235,8 @@ scan (FILE *inb, int innum, int outnum, char *nfs, int width, int curflg, */ if ((i = strlen(tmpbuf)) < rlwidth) { - state = m_getfld (state, name, tmpbuf + i, - rlwidth - i, inb); + bufsz = rlwidth - i; + state = m_getfld (&gstate, name, tmpbuf + i, &bufsz, inb); } if (! outnum) { @@ -264,7 +270,8 @@ body:; } while (state == BODY) { - state = m_getfld(state, name, tmpbuf, rlwidth, inb); + bufsz = rlwidth; + state = m_getfld (&gstate, name, tmpbuf, &bufsz, inb); FPUTS(tmpbuf); } goto finished; @@ -372,3 +379,23 @@ mh_fputs(char *s, FILE *stream) return (0); } +/* The following three functions allow access to the global gstate above. */ +void +scan_finished () { + m_getfld_state_destroy (&gstate); +} + +void +scan_detect_mbox_style (FILE *f) { + m_unknown (&gstate, f); +} + +void +scan_eom_action (int (*action)()) { + m_eomsbr (gstate, action); +} + +void +scan_reset_m_getfld_state () { + m_getfld_state_reset (&gstate); +} diff --git a/uip/sendsbr.c b/uip/sendsbr.c index dfd974f4..2350ccf4 100644 --- a/uip/sendsbr.c +++ b/uip/sendsbr.c @@ -591,6 +591,7 @@ splitmsg (char **vec, int vecp, char *drft, struct stat *st, int delay) char subject[BUFSIZ]; char name[NAMESZ], partnum[BUFSIZ]; FILE *in; + m_getfld_state_t gstate = 0; if ((in = fopen (drft, "r")) == NULL) adios (drft, "unable to open for reading"); @@ -602,19 +603,22 @@ splitmsg (char **vec, int vecp, char *drft, struct stat *st, int delay) * Scan through the message and examine the various header fields, * as well as locate the beginning of the message body. */ - for (compnum = 1, state = FLD;;) { - switch (state = m_getfld (state, name, buffer, sizeof(buffer), in)) { + m_getfld_track_filepos (&gstate, in); + for (compnum = 1;;) { + int bufsz = sizeof buffer; + switch (state = m_getfld (&gstate, name, buffer, &bufsz, in)) { case FLD: case FLDPLUS: - case FLDEOF: compnum++; /* * This header field is discarded. */ if (!mh_strcasecmp (name, "Message-ID")) { - while (state == FLDPLUS) - state = m_getfld (state, name, buffer, sizeof(buffer), in); + while (state == FLDPLUS) { + bufsz = sizeof buffer; + state = m_getfld (&gstate, name, buffer, &bufsz, in); + } } else if (uprf (name, XXX_FIELD_PRF) || !mh_strcasecmp (name, VRSN_FIELD) || !mh_strcasecmp (name, "Subject") @@ -638,7 +642,8 @@ splitmsg (char **vec, int vecp, char *drft, struct stat *st, int delay) dp = add (concat (name, ":", buffer, NULL), dp); while (state == FLDPLUS) { - state = m_getfld (state, name, buffer, sizeof(buffer), in); + bufsz = sizeof buffer; + state = m_getfld (&gstate, name, buffer, &bufsz, in); dp = add (buffer, dp); } } else { @@ -648,19 +653,16 @@ splitmsg (char **vec, int vecp, char *drft, struct stat *st, int delay) */ cp = add (concat (name, ":", buffer, NULL), cp); while (state == FLDPLUS) { - state = m_getfld (state, name, buffer, sizeof(buffer), in); + bufsz = sizeof buffer; + state = m_getfld (&gstate, name, buffer, &bufsz, in); cp = add (buffer, cp); } } - if (state != FLDEOF) { - start = ftell (in) + 1; - continue; - } - /* else fall... */ + start = ftell (in) + 1; + continue; case BODY: - case BODYEOF: case FILEEOF: break; @@ -674,6 +676,7 @@ splitmsg (char **vec, int vecp, char *drft, struct stat *st, int delay) break; } + m_getfld_state_destroy (&gstate); if (cp == NULL) adios (NULL, "headers missing from draft"); @@ -905,8 +908,10 @@ static void alert (char *file, int out) { pid_t child_id; - int i, in; + int i, in, argp; char buf[BUFSIZ]; + char *program; + char **arglist; for (i = 0; (child_id = fork()) == NOTOK && i < 5; i++) sleep (5); @@ -946,8 +951,14 @@ alert (char *file, int out) snprintf (buf, sizeof(buf), "send failed on %s", forwsw ? "enclosed draft" : file); - execlp (mailproc, r1bindex (mailproc, '/'), getusername (), - "-subject", buf, NULL); + arglist = argsplit(mailproc, &program, &argp); + + arglist[argp++] = getusername(); + arglist[argp++] = "-subject"; + arglist[argp++] = buf; + arglist[argp] = NULL; + + execvp (program, arglist); fprintf (stderr, "unable to exec "); perror (mailproc); _exit (-1); diff --git a/uip/show.c b/uip/show.c index 229e6edd..766aec94 100644 --- a/uip/show.c +++ b/uip/show.c @@ -336,15 +336,16 @@ is_nontext (char *msgnam) char *cp; char buf[BUFSIZ], name[NAMESZ]; FILE *fp; + m_getfld_state_t gstate = 0; if ((fp = fopen (msgnam, "r")) == NULL) return 0; - for (state = FLD;;) { - switch (state = m_getfld (state, name, buf, sizeof(buf), fp)) { + for (;;) { + int bufsz = sizeof buf; + switch (state = m_getfld (&gstate, name, buf, &bufsz, fp)) { case FLD: case FLDPLUS: - case FLDEOF: /* * Check Content-Type field */ @@ -354,7 +355,8 @@ is_nontext (char *msgnam) cp = add (buf, NULL); while (state == FLDPLUS) { - state = m_getfld (state, name, buf, sizeof(buf), fp); + bufsz = sizeof buf; + state = m_getfld (&gstate, name, buf, &bufsz, fp); cp = add (buf, cp); } bp = cp; @@ -457,7 +459,8 @@ out: if (!mh_strcasecmp (name, ENCODING_FIELD)) { cp = add (buf, NULL); while (state == FLDPLUS) { - state = m_getfld (state, name, buf, sizeof(buf), fp); + bufsz = sizeof buf; + state = m_getfld (&gstate, name, buf, &bufsz, fp); cp = add (buf, cp); } for (bp = cp; isspace (*bp); bp++) @@ -481,8 +484,10 @@ out: * Just skip the rest of this header * field and go to next one. */ - while (state == FLDPLUS) - state = m_getfld (state, name, buf, sizeof(buf), fp); + while (state == FLDPLUS) { + bufsz = sizeof buf; + state = m_getfld (&gstate, name, buf, &bufsz, fp); + } break; /* @@ -494,4 +499,5 @@ out: return 0; } } + m_getfld_state_destroy (&gstate); } diff --git a/uip/slocal.c b/uip/slocal.c index 1c30dfc5..3c5e512d 100644 --- a/uip/slocal.c +++ b/uip/slocal.c @@ -707,6 +707,7 @@ parse (int fd) char name[NAMESZ], field[BUFSIZ]; struct pair *p, *q; FILE *in; + m_getfld_state_t gstate = 0; if (parsed++) return 0; @@ -730,14 +731,15 @@ 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)) { + for (i = 0;;) { + int fieldsz = sizeof field; + switch (state = m_getfld (&gstate, name, field, &fieldsz, in)) { case FLD: - case FLDEOF: case FLDPLUS: lp = add (field, NULL); while (state == FLDPLUS) { - state = m_getfld (state, name, field, sizeof(field), in); + fieldsz = sizeof field; + state = m_getfld (&gstate, name, field, &fieldsz, in); lp = add (field, lp); } for (p = hdrs; p->p_name; p++) { @@ -766,12 +768,9 @@ parse (int fd) p++, i++; p->p_name = NULL; } - if (state != FLDEOF) - continue; - break; + continue; case BODY: - case BODYEOF: case FILEEOF: break; @@ -787,6 +786,7 @@ parse (int fd) } break; } + m_getfld_state_destroy (&gstate); fclose (in); if ((p = lookup (vars, "reply-to"))) { @@ -1405,6 +1405,7 @@ suppress_duplicates (int fd, char *file) datum key, value; DBM *db; FILE *in; + m_getfld_state_t gstate = 0; if ((fd1 = dup (fd)) == -1) return -1; @@ -1414,22 +1415,25 @@ suppress_duplicates (int fd, char *file) } rewind (in); - for (state = FLD;;) { - state = m_getfld (state, name, buf, sizeof(buf), in); + for (;;) { + int bufsz = sizeof buf; + state = m_getfld (&gstate, name, buf, &bufsz, in); switch (state) { case FLD: case FLDPLUS: - case FLDEOF: /* Search for the message ID */ if (mh_strcasecmp (name, "Message-ID")) { - while (state == FLDPLUS) - state = m_getfld (state, name, buf, sizeof(buf), in); + while (state == FLDPLUS) { + bufsz = sizeof buf; + state = m_getfld (&gstate, name, buf, &bufsz, in); + } continue; } cp = add (buf, NULL); while (state == FLDPLUS) { - state = m_getfld (state, name, buf, sizeof(buf), in); + bufsz = sizeof buf; + state = m_getfld (&gstate, name, buf, &bufsz, in); cp = add (buf, cp); } key.dptr = trimcpy (cp); @@ -1477,7 +1481,6 @@ suppress_duplicates (int fd, char *file) break; case BODY: - case BODYEOF: case FILEEOF: break; @@ -1489,6 +1492,7 @@ suppress_duplicates (int fd, char *file) break; } + m_getfld_state_destroy (&gstate); fclose (in); return 0; diff --git a/uip/sortm.c b/uip/sortm.c index 429f75f9..68132989 100644 --- a/uip/sortm.c +++ b/uip/sortm.c @@ -357,21 +357,23 @@ get_fields (char *datesw, int msg, struct smsg *smsg) register struct tws *tw; register char *datecomp = NULL, *subjcomp = NULL; register FILE *in; + m_getfld_state_t gstate = 0; if ((in = fopen (msgnam = m_name (msg), "r")) == NULL) { admonish (msgnam, "unable to read message"); return (0); } - for (compnum = 1, state = FLD;;) { - switch (state = m_getfld (state, nam, buf, sizeof(buf), in)) { + for (compnum = 1;;) { + int bufsz = sizeof buf; + switch (state = m_getfld (&gstate, nam, buf, &bufsz, in)) { case FLD: - case FLDEOF: case FLDPLUS: compnum++; if (!mh_strcasecmp (nam, datesw)) { datecomp = add (buf, datecomp); while (state == FLDPLUS) { - state = m_getfld (state, nam, buf, sizeof(buf), in); + bufsz = sizeof buf; + state = m_getfld (&gstate, nam, buf, &bufsz, in); datecomp = add (buf, datecomp); } if (!subjsort || subjcomp) @@ -379,20 +381,22 @@ get_fields (char *datesw, int msg, struct smsg *smsg) } else if (subjsort && !mh_strcasecmp (nam, subjsort)) { subjcomp = add (buf, subjcomp); while (state == FLDPLUS) { - state = m_getfld (state, nam, buf, sizeof(buf), in); + bufsz = sizeof buf; + state = m_getfld (&gstate, nam, buf, &bufsz, in); subjcomp = add (buf, subjcomp); } if (datecomp) break; } else { /* just flush this guy */ - while (state == FLDPLUS) - state = m_getfld (state, nam, buf, sizeof(buf), in); + while (state == FLDPLUS) { + bufsz = sizeof buf; + state = m_getfld (&gstate, nam, buf, &bufsz, in); + } } continue; case BODY: - case BODYEOF: case FILEEOF: break; @@ -415,6 +419,7 @@ get_fields (char *datesw, int msg, struct smsg *smsg) } break; } + m_getfld_state_destroy (&gstate); /* * If no date component, then use the modification @@ -423,7 +428,10 @@ get_fields (char *datesw, int msg, struct smsg *smsg) if (!datecomp || (tw = dparsetime (datecomp)) == NULL) { struct stat st; - admonish (NULL, "can't parse %s field in message %d", datesw, msg); + advise (NULL, + "can't parse %s field in message %d, " + "will use file modification time", + datesw, msg); fstat (fileno (in), &st); smsg->s_clock = st.st_mtime; check_failed = 1; diff --git a/uip/whatnowsbr.c b/uip/whatnowsbr.c index 9a9fec1b..c9cbf503 100644 --- a/uip/whatnowsbr.c +++ b/uip/whatnowsbr.c @@ -644,7 +644,7 @@ editfile (char **ed, char **arg, char *file, int use, struct msgs *mp, { int pid, status, vecp; char altpath[BUFSIZ], linkpath[BUFSIZ]; - char *cp, *vec[MAXARGS]; + char *cp, *prog, **vec; struct stat st; #ifdef HAVE_LSTAT @@ -712,15 +712,15 @@ editfile (char **ed, char **arg, char *file, int use, struct msgs *mp, m_putenv ("editalt", altpath); } - vecp = 0; - vec[vecp++] = r1bindex (*ed, '/'); + vec = argsplit(*ed, &prog, &vecp); + if (arg) while (*arg) vec[vecp++] = *arg++; vec[vecp++] = file; vec[vecp] = NULL; - execvp (*ed, vec); + execvp (prog, vec); fprintf (stderr, "unable to exec "); perror (*ed); _exit (-1); @@ -924,14 +924,15 @@ check_draft (char *msgnam) int state; char buf[BUFSIZ], name[NAMESZ]; FILE *fp; + m_getfld_state_t gstate = 0; if ((fp = fopen (msgnam, "r")) == NULL) return 0; - for (state = FLD;;) - switch (state = m_getfld (state, name, buf, sizeof(buf), fp)) { + for (;;) { + int bufsz = sizeof buf; + switch (state = m_getfld (&gstate, name, buf, &bufsz, fp)) { case FLD: case FLDPLUS: - case FLDEOF: /* * If draft already contains any of the * Content-XXX fields, then assume it already @@ -941,8 +942,10 @@ check_draft (char *msgnam) fclose (fp); return 0; } - while (state == FLDPLUS) - state = m_getfld (state, name, buf, sizeof(buf), fp); + while (state == FLDPLUS) { + bufsz = sizeof buf; + state = m_getfld (&gstate, name, buf, &bufsz, fp); + } break; case BODY: @@ -955,7 +958,8 @@ check_draft (char *msgnam) return 1; } - state = m_getfld (state, name, buf, sizeof(buf), fp); + bufsz = sizeof buf; + state = m_getfld (&gstate, name, buf, &bufsz, fp); } while (state == BODY); /* and fall... */ @@ -963,6 +967,8 @@ check_draft (char *msgnam) fclose (fp); return 0; } + } + m_getfld_state_destroy (&gstate); }