]> diplodocus.org Git - nmh/commitdiff
Merge branch 'master' into savannah
authorLyndon Nerenberg <lyndon@orthanc.ca>
Fri, 1 Feb 2013 12:44:29 +0000 (04:44 -0800)
committerLyndon Nerenberg <lyndon@orthanc.ca>
Fri, 1 Feb 2013 12:44:29 +0000 (04:44 -0800)
57 files changed:
.gitignore
Makefile.am
configure.ac
docs/README.manpages
docs/contrib/build_nmh
docs/pending-release-notes
h/mh.h
h/prototypes.h
man/msh.man
mts/smtp/smtp.c
sbr/arglist.c
sbr/discard.c
sbr/fmt_scan.c
sbr/folder_delmsgs.c
sbr/m_getfld.c
sbr/m_msgdef.c [deleted file]
sbr/readconfig.c
sbr/seq_read.c
test/ali/test-ali
test/bad-input/test-header
test/common.sh.in
test/fakepop.c
test/fakesmtp.c
test/folder/test-sortm
test/format/test-rightjustify [new file with mode: 0755]
test/getcwidth.c [new file with mode: 0644]
test/inc/test-inc-scanout
test/inc/test-pop
test/mhmail/test-mhmail
test/mhshow/test-msg-buffer-boundaries [new file with mode: 0755]
test/pick/test-pick
test/post/test-sendfiles
test/scan/test-scan-multibyte
uip/distsbr.c
uip/forwsbr.c
uip/inc.c
uip/mhbuildsbr.c
uip/mhcachesbr.c
uip/mhlsbr.c
uip/mhparse.c
uip/mhshowsbr.c
uip/msh.c
uip/mshcmds.c
uip/new.c
uip/picksbr.c
uip/post.c
uip/prompter.c
uip/rcvdist.c
uip/rcvtty.c
uip/replsbr.c
uip/scan.c
uip/scansbr.c
uip/sendsbr.c
uip/show.c
uip/slocal.c
uip/sortm.c
uip/whatnowsbr.c

index 0be1cc2..af04fac 100644 (file)
@@ -103,6 +103,7 @@ a.out.dSYM/
 /test/fakepop
 /test/getfullname
 /test/getfqdn
+/test/getcwidth
 
 # Removed by mostlyclean:
 *.o
index b79e930..c1c90d0 100644 (file)
@@ -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
 
index 3bb692e..a4cfffd 100644 (file)
@@ -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 <libio.h>.]) ]) ])
-
 AC_CHECK_HEADER([sys/ptem.h], AC_DEFINE(WINSIZE_IN_PTEM,1,
   [Define to 1 if `struct winsize' requires <sys/ptem.h>.]),,
 [[#if HAVE_SYS_STREAM_H
index 7758498..6d6111d 100644 (file)
@@ -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. 
index f0b0c56..f17b240 100755 (executable)
@@ -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"
index 9b28092..a6ae19c 100644 (file)
@@ -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 2cd546b..253af9c 100644 (file)
--- 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 */
index 443479f..d4fc6eb 100644 (file)
@@ -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 *);
index 57770b5..66e29fb 100644 (file)
@@ -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
index b1d57dd..6fd178b 100755 (executable)
@@ -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;
index 1f85b7b..8749a4b 100644 (file)
  *
  * - 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);
+    }
+}
index a1efa48..83b0bfb 100644 (file)
@@ -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. */
 }
 
index 879f771..b1370fb 100644 (file)
@@ -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;
 
index c1416a6..671ecc7 100644 (file)
@@ -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));
        }
     }
index e139505..af44f09 100644 (file)
 #include <h/mts.h>
 #include <h/utils.h>
 
+/*
+   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
    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
    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 (file)
index d602973..0000000
+++ /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 <h/mh.h>
-
-/*
- * 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 = "";
index 1ddd648..b25ea99 100644 (file)
@@ -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.
index 985c61e..a807ef7 100644 (file)
@@ -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);
 }
index 4079790..8bfef97 100755 (executable)
@@ -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
index 9e66296..e993cce 100755 (executable)
@@ -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 <<EOF
+msgfile="$MH_TEST_DIR/Mail/inbox/11"
+cat >"$msgfile" <<EOF
 Date: Sun, 18 Dec 2005 00:52:39 +0100
 From: foo@example.edu
 To: bar@example.edu
@@ -31,14 +34,14 @@ I am a stupid spammer.
 EOF
 
 # check scan
-cat > $expected <<EOF
+cat >"$expected" <<EOF
   11  12/18 foo@example.edu    test<<This is a multi-part message in MIME forma
 EOF
-scan -width 80 $msgnum > $actual 2>&1
-check $expected $actual
+scan -width 80 last > "$actual" 2>&1
+check "$expected" "$actual"
 
 # check show (mhl)
-cat > $expected <<EOF
+cat >"$expected" <<EOF
 (Message inbox:11)
 
 Date:    Sun, 18 Dec 2005 00:52:39 +0100
@@ -49,14 +52,13 @@ Subject: test
 
 This is a multi-part message in MIME format.
 
-
 I am a stupid spammer.
 EOF
-show $msgnum > $actual 2>&1
-check $expected $actual
+show last > "$actual" 2>&1
+check "$expected" "$actual"
 
 # check mhshow
-cat > $expected <<EOF
+cat >"$expected" <<EOF
 Date:    Sun, 18 Dec 2005 00:52:39 +0100
 To:      bar@example.edu
 From:    foo@example.edu
@@ -69,7 +71,72 @@ This is a multi-part message in MIME format.
 
 I am a stupid spammer.
 EOF
-mhshow -nopause $msgnum > $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" <<EOF
+  12  01/12 
+EOF
+cat >"$expected_err" <<EOF
+scan: eof encountered in field "Received"
+??Format error (message 12) in component 2
+EOF
+
+scan -width 13 last >"$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" <<EOF
+Date: Tue, 15 Jan 2013 21:13:12 -0600
+ThisHeaderFieldNameIsWaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaayTooLong: OK
+EOF
+cat >"$expected" <<EOF
+  13  01/15 
+EOF
+
+scan -width 13 last >"$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" <<EOF
+Date: Thu, 17 Jan 2013 19:33:46 -0600
+If a header field name has at least 512 characters without a newline or colon, it will raise a format error in m_getfld().  Here is a test of that.  01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901
+
+Test
+
+
+EOF
+cat >"$expected" <<EOF
+  14  01/17 
+EOF
+cat >"$expected_err" <<EOF
+scan: eol encountered in field "If a header field name has at least 512 characters without a newline or colon, it will raise a format error in m_getfld().  Here is a test of that.  01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901"
+??Format error (message 14) in component 2
+EOF
+
+scan -width 13 last >"$actual" 2>"$actual_err"
+check "$expected" "$actual"
+check "$expected_err" "$actual_err"
+
 
 exit $failed
index 390f94f..4c80415 100644 (file)
@@ -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
index 389588d..bca565d 100644 (file)
@@ -13,6 +13,7 @@
 #include <netdb.h>
 #include <errno.h>
 #include <sys/socket.h>
+#include <netinet/in.h>
 #include <sys/types.h>
 #include <sys/select.h>
 #include <sys/stat.h>
index fbfe044..7121c30 100644 (file)
@@ -13,6 +13,7 @@
 #include <netdb.h>
 #include <errno.h>
 #include <sys/socket.h>
+#include <netinet/in.h>
 #include <sys/types.h>
 #include <sys/select.h>
 #include <sys/stat.h>
index 7ef656c..0753ecb 100755 (executable)
@@ -388,7 +388,7 @@ check "$expected" "$actual"
 
 # check -check
 cat >"$expected" <<EOF
-sortm: can't parse date field in message 14, continuing...
+sortm: can't parse date field in message 14, will use file modification time
 sortm: errors found, no messages sorted
 EOF
 
@@ -437,7 +437,8 @@ EOF
 
 sed -e 's/Sep//' $MH_TEST_DIR/Mail/inbox/7 > $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 (executable)
index 0000000..2685efd
--- /dev/null
@@ -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})<<End of test" "No Such User <nosuch@user.com>"`
+expected="                  No Such User<<End of test"
+##########123456789012345678901234567890
+
+if test x"$actual" != x"$expected"; then
+    echo "$0: right justification test expected:" 1>&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 (file)
index 0000000..f24172f
--- /dev/null
@@ -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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef MULTIBYTE_SUPPORT
+#include <locale.h>
+#include <wchar.h>
+#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 */
+}
index 8d7a72d..ffe2c46 100755 (executable)
@@ -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" <<EOF
-Comments: The important characteristic of this message is that the 8193'd
+Comments: The important characteristic of this message is that the 4097'th
 Comments: byte is the ':' at the end of header field name.  That tests some
-Comments: logic in m_getfld (), assuming its MSG_INPUT_SIZE is 8192.
+Comments: logic in m_getfld (), assuming its MSG_INPUT_SIZE is 4096.
 Comments: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
 Comments: BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
 Comments: CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
@@ -252,60 +252,8 @@ Comments: ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
 Comments: tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt
 Comments: uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
 Comments: vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-Comments: wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
-Comments: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-Comments: yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
-Comments: zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
-Comments: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-Comments: BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
-Comments: CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
-Comments: DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
-Comments: EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
-Comments: FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
-Comments: GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
-Comments: HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
-Comments: IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
-Comments: JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ
-Comments: KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK
-Comments: LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
-Comments: MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
-Comments: NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
-Comments: OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
-Comments: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
-Comments: QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ
-Comments: RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
-Comments: SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
-Comments: TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
-Comments: UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU
-Comments: VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
-Comments: WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
-Comments: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-Comments: YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
-Comments: ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
-Comments: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-Comments: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-Comments: cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-Comments: dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
-Comments: eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
-Comments: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-Comments: gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
-Comments: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
-Comments: iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
-Comments: jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
-Comments: kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
-Comments: llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
-Comments: mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
-Comments: nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
-Comments: oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
-Comments: pppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppp
-Comments: qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq
-Comments: rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr
-Comments: ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
-Comments: tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt
-Comments: uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
-Comments: vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-Comments: wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
-Comments: This is it, the line with the 8193'd character of ':'.
+Comments: wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
+Comments: This is it, the line with the 4097'th character of ':'.
 Comments: From somewhere
 From: No Such User <nosuch@example.com>
 To: Some Other User <someother@example.com>
index 580f0cd..7724ae3 100755 (executable)
@@ -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<<Hey man, how's it going? . Hope you're do"
+check $testmessage `mhpath +inbox 11` 'keep first'
 
-check `mhpath +inbox 11` $testmessage
-rm -f $testmessage "$netrc"
+# check -pack
+pid=`"${MH_OBJ_DIR}/test/fakepop" "$testmessage" "$testport" \
+                       "$TESTUSER" "$TESTPASS"`
+
+touch "$MH_TEST_DIR/inc.mbox"
+run_test "inc -user ${TESTUSER} -host 127.0.0.1 -port $testport -width 80 \
+          -pack $MH_TEST_DIR/inc.mbox" \
+       "Incorporating new mail into (null)...
+
+   1  12/17 No Such User       Hello<<Hey man, how's it going? . Hope you're do"
+run_test "inc -file $MH_TEST_DIR/inc.mbox -truncate" \
+       "Incorporating new mail into inbox...
+
+  11+ 12/17 No Such User       Hello<<Hey man, how's it going? . Hope you're do"
+
+check $testmessage `mhpath +inbox 11`
+rm -f "$MH_TEST_DIR/inc.mbox" "$MH_TEST_DIR/.inc.map" "$netrc"
 
 exit ${failed:-0}
index 3745207..144a362 100755 (executable)
@@ -117,8 +117,6 @@ esac
 mhmail -nosend recipient@example.com -from sender@localhost \
   -server 127.0.0.1 -port $localport -body '' >"$actual" 2>"$actual_err"
 
-tmpfil=`head -1 $actual | sed -e 's/://'`
-
 cat > "$expected" <<EOF
 To: recipient@example.com
 From: sender@localhost
diff --git a/test/mhshow/test-msg-buffer-boundaries b/test/mhshow/test-msg-buffer-boundaries
new file mode 100755 (executable)
index 0000000..4b28fa6
--- /dev/null
@@ -0,0 +1,392 @@
+#!/bin/sh
+######################################################
+#
+# Test m_getfld() with various parts of messages
+# falling on buffer boundaries
+#
+######################################################
+
+set -e
+
+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
+
+expected="$MH_TEST_DIR/$$.expected"
+actual="$MH_TEST_DIR/$$.actual"
+
+# check a boundary condition in m_getfld():  its internal message
+# buffer holds exactly up to the end of a header field body in a
+# message part
+msgfile=`mhpath new`
+msgnum=`basename $msgfile`
+cat >"$msgfile" <<EOF
+MIME-Version: 1.0
+Content-Type: multipart/mixed; boundary="NextPart_001"
+Content-class: urn:content-classes:message
+Date: Thu, 19 May 2011 00:00:00 -0000
+From: sender@example.com
+To: recipient@example.com
+
+This is a multi-part message in MIME format.
+
+--NextPart_001
+Content-Type: multipart/related;
+    type="multipart/alternative";
+    boundary="NextPart_002"
+
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXX
+
+--NextPart_002
+Content-Type: text/plain;
+    charset="utf-8"
+
+This is the text/plain part.
+
+--NextPart_002--
+
+--NextPart_001--
+EOF
+
+# Write the expected output.
+cat >"$expected" <<EOF
+part 1.1   text/plain                  29
+This is the text/plain part.
+EOF
+
+mhshow -part 1.1 -form mhl.null -nopause $msgnum >"$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" <<EOF
+MIME-Version: 1.0
+Content-Type: multipart/mixed; boundary="NextPart_001"
+Content-class: urn:content-classes:message
+Date: Thu, 19 May 2011 00:00:00 -0000
+From: sender@example.com
+To: recipient@example.com
+
+This is a multi-part message in MIME format.
+
+--NextPart_001
+Content-Type: multipart/related;
+    type="multipart/alternative";
+    boundary="NextPart_002"
+
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+--NextPart_002
+Content-Type: text/plain;
+    charset="utf-8"
+
+This is the text/plain part.
+
+--NextPart_002--
+
+--NextPart_001--
+EOF
+
+# Write the expected output.
+cat >"$expected" <<EOF
+part 1.1   text/plain                  29
+This is the text/plain part.
+EOF
+
+mhshow -part 1.1 -form mhl.null -nopause $msgnum >"$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" <<EOF
+MIME-Version: 1.0
+Content-Type: multipart/mixed; boundary="NextPart_001"
+Content-class: urn:content-classes:message
+Date: Thu, 19 May 2011 00:00:00 -0000
+From: sender@example.com
+To: recipient@example.com
+
+This is a multi-part message in MIME format.
+
+--NextPart_001
+Content-Type: multipart/related;
+    type="multipart/alternative";
+    boundary="NextPart_002"
+
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXX
+The 4096'th character is the '2' at the end of the following NextPart_002.
+
+--NextPart_002
+Content-Type: text/plain;
+    charset="utf-8"
+
+This is the text/plain part.
+
+--NextPart_002--
+
+--NextPart_001--
+EOF
+
+# Write the expected output.
+cat >"$expected" <<EOF
+part 1.1   text/plain                  29
+This is the text/plain part.
+EOF
+
+mhshow -part 1.1 -form mhl.null -nopause $msgnum >"$actual" 2>&1
+check "$expected" "$actual"
+
+
+exit $failed
index 12d2aae..07eff1f 100755 (executable)
@@ -99,14 +99,12 @@ cat >"$expected" <<EOF
 EOF
 check "$expected" "$actual"
 
-if test -w /dev/tty && printf '' >/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.
index 687c5d9..af5573e 100755 (executable)
@@ -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" <<EOF
  msg part  type/subtype              size description
-  11       application/octet-stream   10K
+  11       application/octet-stream
             type="tar"
             (extract with cat | tar xvpf -)
 EOF
@@ -150,7 +151,7 @@ test_sendfiles cat new -compress none
 # check with no compression, -none
 cat >"$expected" <<EOF
  msg part  type/subtype              size description
-  11       application/octet-stream   10K
+  11       application/octet-stream
             type="tar"
             (extract with cat | tar xvpf -)
 EOF
@@ -160,7 +161,7 @@ test_sendfiles cat new -none
 # check old argument style (without -to and -subject)
 cat >"$expected" <<EOF
  msg part  type/subtype              size description
-  11       application/octet-stream   10K
+  11       application/octet-stream
             type="tar"
             (extract with cat | tar xvpf -)
 EOF
@@ -170,7 +171,7 @@ test_sendfiles cat old -compress none
 # check -from
 cat >"$expected" <<EOF
  msg part  type/subtype              size description
-  11       application/octet-stream   10K
+  11       application/octet-stream
             type="tar"
             (extract with cat | tar xvpf -)
 EOF
@@ -180,7 +181,7 @@ test_sendfiles cat new -compress none -from 'Sender <sender@example.com>'
 # check PERSON environment variable
 cat >"$expected" <<EOF
  msg part  type/subtype              size description
-  11       application/octet-stream   10K
+  11       application/octet-stream
             type="tar"
             (extract with cat | tar xvpf -)
 EOF
@@ -190,7 +191,7 @@ PERSON='Sender <sender@example.com>' test_sendfiles cat new -compress none
 # check -delay, though for a small file it doesn't do anything
 cat >"$expected" <<EOF
  msg part  type/subtype              size description
-  11       application/octet-stream   10K
+  11       application/octet-stream
             type="tar"
             (extract with cat | tar xvpf -)
 EOF
@@ -200,7 +201,7 @@ test_sendfiles cat new -compress none -delay 5
 # check old style -delay, though for a small file it doesn't do anything
 cat >"$expected" <<EOF
  msg part  type/subtype              size description
-  11       application/octet-stream   10K
+  11       application/octet-stream
             type="tar"
             (extract with cat | tar xvpf -)
 EOF
index e877cf2..1e9349a 100755 (executable)
@@ -31,22 +31,43 @@ LC_ALL=en_US.UTF-8; export LC_ALL
 #
 # Create a test message with RFC 2047 headers we can scan
 #
+# In this Subject header in this message is a "n" with a Combining Diaeresis
+# (U+0308).  There is different interpretation of this character with respect
+# to wcwidth() (which is supposed to return the column width of a character).
+# We use a test program to determine what the output width of U+0308 is
+# and adjust our test output appropriately.
+#
 
 cat > "${MH_TEST_DIR}/Mail/inbox/11" <<EOF
 From: David =?utf-8?q?=EF=AC=86?= Hubbins <hubbins@example.com>
 To: Sir Denis =?utf-8?q?Eton=E2=80=93Hogg? <sirdenis@example.com>
 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" <<EOF
-  11  03/02 David ï¬† Hubbins    Spin̈al Tap â†’ Tap into America!<<Things are
+  11  03/02 David ï¬† Hubbins    Spın̈al Tap â†’ Tap into America!<<Things are look
 EOF
+elif test "$width" -eq 0; then
+cat > "$expected" <<EOF
+  11  03/02 David ï¬† Hubbins    Spın̈al Tap â†’ Tap into America!<<Things are looki
+EOF
+else
+    echo "Unsupported width for combining diaeresis: $width"
+    exit 1
+fi
 
 scan -width 80 +inbox 11 > $actual || exit 1
 check "$expected" "$actual"
index afd4e41..b5119fb 100644 (file)
@@ -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);
 }
index 8625585..cf043c4 100644 (file)
@@ -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
index 3ec47fa..2d791f6 100644 (file)
--- 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 */
index 653c5b3..a344a7c 100644 (file)
@@ -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
index 5f7777d..25ac9ab 100644 (file)
@@ -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;
index e075933..f87c47d 100644 (file)
@@ -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);
        }
 
        /*
index 93f1f26..0dcd133 100644 (file)
@@ -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
index 3b91eeb..866a41b 100644 (file)
@@ -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);
 }
 
 
index 6069cac..e5f82bf 100644 (file)
--- 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;
        }
+    }
 }
 
 
index 8212375..6ea1126 100644 (file)
@@ -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;
 
index e88a0dd..e391ba2 100644 (file)
--- 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);
 
index 7b64f81..c572cde 100644 (file)
@@ -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...",
index f6f7924..7bed6f8 100644 (file)
@@ -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: 
index d950163..563da05 100644 (file)
@@ -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");
index 8f88639..33890d5 100644 (file)
@@ -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);
index 9cd77dd..92334c1 100644 (file)
@@ -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));
index 3dbc303..b696ae7 100644 (file)
@@ -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));
index e1b9a16..459fcb0 100644 (file)
@@ -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)
index b69f4a4..930cfbc 100644 (file)
@@ -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);
+}
index dfd974f..2350ccf 100644 (file)
@@ -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);
index 229e6ed..766aec9 100644 (file)
@@ -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);
 }
index 1c30dfc..3c5e512 100644 (file)
@@ -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;
index 429f75f..6813298 100644 (file)
@@ -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;
index 9a9fec1..c9cbf50 100644 (file)
@@ -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);
 }