From: Ken Hornstein Date: Fri, 22 Feb 2013 03:40:48 +0000 (-0500) Subject: Merge branch 'format-test' X-Git-Url: https://diplodocus.org/git/nmh/commitdiff_plain/2e768e3cc0ce768373d3320eca4cdd08b8cf646a?hp=7344831da78eff4eac463d5ef0e3004a465f4330 Merge branch 'format-test' --- diff --git a/.gitignore b/.gitignore index ebf140c2..8d7e69d7 100644 --- a/.gitignore +++ b/.gitignore @@ -41,6 +41,7 @@ /RPM/ a.out.dSYM/ /config/version.c +/etc/gen-ctype-checked /etc/mhn.defaults /etc/mts.conf /man/*.[1578] @@ -48,6 +49,7 @@ a.out.dSYM/ /man/mh-chart.man /mts/libmts.a /sbr/*.a +/sbr/ctype-checked.* /sbr/sigmsg.h /test/testdir/ /uip/ali @@ -104,6 +106,7 @@ a.out.dSYM/ /test/fakepop /test/getfullname /test/getfqdn +/test/getcwidth # Removed by mostlyclean: *.o diff --git a/Makefile.am b/Makefile.am index 7e93a12a..3654eab7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -14,7 +14,7 @@ ACLOCAL_AMFLAGS = -I m4 ## LDADD is included in the program-specific LDADD since we want to add ## to this list of libraries, not replace it. ## -LDADD = sbr/libmh.a sbr/libdtimep.a +LDADD = sbr/libmh.a ## ## These are used to create the default mhn.defaults config file @@ -38,13 +38,14 @@ TESTS_ENVIRONMENT = MH_OBJ_DIR="@abs_builddir@" \ auxexecdir="$(auxexecdir)" bindir="$(bindir)" \ mandir="$(mandir)" sysconfdir="$(sysconfdir)" \ MULTIBYTE_ENABLED=$(MULTIBYTE_ENABLED) \ + ICONV_ENABLED=$(ICONV_ENABLED) \ $(TESTS_SHELL) ## Keep at end of TESTS_ENVIRONMENT. ## ## Important note: the "cleanup" test should always be last ## TESTS = test/ali/test-ali test/anno/test-anno \ test/bad-input/test-header \ - test/burst/test-burst \ + test/burst/test-burst test/burst/test-burst-mime \ test/comp/test-comp-format test/dist/test-dist \ test/folder/test-create test/folder/test-packf \ test/folder/test-recurse test/folder/test-sortm \ @@ -52,6 +53,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 +63,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,13 +85,15 @@ 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 ## ## Stuff that should be cleaned via "make clean" ## CLEANFILES = config/version.c sbr/sigmsg.h etc/mts.conf \ + etc/gen-ctype-checked sbr/ctype-checked.h sbr/ctype-checked.c \ etc/mhn.defaults man/man.sed man/mh-chart.man $(man_MANS) clean-local: @rm -rf RPM a.out.dSYM uip/a.out.dSYM @@ -113,7 +117,7 @@ superclean: maintainer-clean ## ## Files that need to be built before everything else ## -BUILT_SOURCES = sbr/sigmsg.h +BUILT_SOURCES = sbr/sigmsg.h sbr/ctype-checked.c ## ## This is a list of all programs that get installed in the "bin" directory @@ -139,11 +143,18 @@ auxexec_PROGRAMS = uip/ap uip/conflict uip/dp uip/fmtdump uip/mhl uip/post \ auxexec_SCRIPTS = uip/spost +## +## Programs that MAY need to get built at some point; we need to list them +## here if they don't appear in any other primary so Automake knows about +## them and can properly record dependency information. +## +EXTRA_PROGRAMS = etc/gen-ctype-checked + ## ## Internal libraries that we create as part of the build process ## but do not install ## -noinst_LIBRARIES = sbr/libmh.a sbr/libdtimep.a mts/libmts.a +noinst_LIBRARIES = sbr/libmh.a mts/libmts.a ## ## These are all of our header files. Right now we don't install any of @@ -154,7 +165,7 @@ noinst_HEADERS = h/addrsbr.h h/aliasbr.h h/crawl_folders.h h/dropsbr.h \ h/mh.h h/mhcachesbr.h h/mhparse.h h/mime.h h/msh.h \ h/mts.h h/nmh.h h/picksbr.h h/popsbr.h h/prototypes.h \ h/rcvmail.h h/scansbr.h h/signals.h h/tws.h h/utils.h \ - h/vmhsbr.h mts/smtp/smtp.h + h/vmhsbr.h mts/smtp/smtp.h sbr/ctype-checked.h ## ## Extra files we need to install in various places @@ -256,7 +267,8 @@ uip_ali_SOURCES = uip/ali.c uip/aliasbr.c uip_anno_SOURCES = uip/anno.c uip/annosbr.c -uip_burst_SOURCES = uip/burst.c +uip_burst_SOURCES = uip/burst.c uip/mhparse.c uip/mhmisc.c uip/mhfree.c \ + uip/mhcachesbr.c uip/md5.c uip_comp_SOURCES = uip/comp.c uip/whatnowproc.c uip/whatnowsbr.c uip/sendsbr.c \ uip/annosbr.c uip/distsbr.c @@ -410,6 +422,12 @@ test_fakepop_LDADD = test_fakesmtp_SOURCES = test/fakesmtp.c test_fakesmtp_LDADD = +test_getcwidth_SOURCES = test/getcwidth.c +test_getcwidth_LDADD = + +etc_gen_ctype_checked_SOURCES = etc/gen-ctype-checked.c +etc_gen_ctype_checked_LDADD = + ## ## Our rebuild rules for files that aren't built via the normal mechanisms ## @@ -419,6 +437,11 @@ config/version.c: Makefile sbr/sigmsg.h: $(srcdir)/sbr/sigmsg.awk $(SIGNAL_H) $(AWK) -f $(srcdir)/sbr/sigmsg.awk $(SIGNAL_H) > $@ +sbr/ctype-checked.h: etc/gen-ctype-checked + etc/gen-ctype-checked + +sbr/ctype-checked.c: etc/gen-ctype-checked sbr/ctype-checked.h + etc/mts.conf: $(srcdir)/etc/mts.conf.in Makefile @rm -f $@ $(SED) -e 's,%mts%,$(MTS),' \ @@ -483,7 +506,8 @@ sbr_libmh_a_SOURCES = sbr/addrsbr.c sbr/ambigsw.c sbr/atooi.c sbr/arglist.c \ sbr/context_replace.c sbr/context_save.c \ sbr/copy.c sbr/copyip.c sbr/cpydata.c \ sbr/cpydgst.c sbr/crawl_folders.c sbr/discard.c \ - sbr/done.c sbr/dtime.c sbr/escape_addresses.c \ + sbr/done.c sbr/dtimep.l sbr/dtime.c \ + sbr/escape_addresses.c \ sbr/error.c sbr/ext_hook.c sbr/fdcompare.c \ sbr/folder_addmsg.c sbr/folder_delmsgs.c \ sbr/folder_free.c sbr/folder_pack.c \ @@ -509,7 +533,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/ctype-checked.c \ sbr/m_mktemp.c sbr/getansreadline.c config/config.c \ config/version.c @@ -518,11 +542,6 @@ sbr_libmh_a_CPPFLAGS = -I./sbr -DNMHETCDIR='"$(sysconfdir)"' \ -DSENDMAILPATH='"$(sendmailpath)"' -DNMHBINDIR='"$(bindir)"' \ -DNMHLIBDIR='"$(libdir)"' -sbr_libdtimep_a_SOURCES = sbr/dtimep.l -sbr_libdtimep_a_CFLAGS = $(sbr_libmh_a_CPPFLAGS) \ - $(DISABLE_UNUSED_MACROS_WARNING) \ - $(DISABLE_SIGN_COMPARE_WARNING) - mts_libmts_a_SOURCES = mts/smtp/smtp.c ## @@ -580,8 +599,8 @@ cleanman: ## Don't include commit hashes in ChangeLog. ChangeLog: - @[ -d .git ] && git --no-pager log --abbrev-commit | \ - egrep -v '^commit [0-9a-f]+$$' > $@ || true + @[ -d $(srcdir)/.git ] && (cd $(srcdir); git --no-pager log --abbrev-commit | \ + egrep -v '^commit [0-9a-f]+$$' > $@) || true ## Make ChangeLog phony so it will always get regenerated. But don't ## fail if we don't have a git repository in order to allow ## regeneration of distribution archive or RPM. diff --git a/config/config.c b/config/config.c index 02265c0a..d29f8a2e 100644 --- a/config/config.c +++ b/config/config.c @@ -68,8 +68,13 @@ try_it: default: /* Check nmh Mail directory */ - if (access ((cp = m_mailpath (file)), R_OK) != NOTOK) + if (access ((cp = m_mailpath (file)), R_OK) != NOTOK) { + /* Will leak because caller doesn't know cp was + dynamically allocated. */ return cp; + } else { + free (cp); + } } /* Check nmh `etc' directory */ @@ -201,13 +206,6 @@ char *formatproc = NULL; char *incproc = nmhbindir (/inc); -/* - * When a user runs an nmh program for the first time, this program - * is called to create his nmh profile, and mail directory. - */ - -char *installproc = nmhlibdir (/install-mh); - /* * This is the default program invoked by a "list" response * at the "What now?" prompt. It is also used by the draft diff --git a/configure.ac b/configure.ac index 3bb692ef..238e17a4 100644 --- a/configure.ac +++ b/configure.ac @@ -8,7 +8,7 @@ AC_PREREQ([2.68]) AC_INIT([nmh], m4_normalize(m4_include([VERSION])), [nmh-workers@nongnu.org]) AC_CONFIG_SRCDIR([h/nmh.h]) AC_CONFIG_HEADER([config.h]) -AM_INIT_AUTOMAKE([-Wall foreign serial-tests subdir-objects 1.12]) +AM_INIT_AUTOMAKE([-Wall color-tests foreign serial-tests subdir-objects 1.12]) AC_CANONICAL_HOST @@ -137,43 +137,16 @@ fi AC_PROG_CC AM_PROG_CC_C_O -AC_CACHE_CHECK([whether preprocessor supports -Wunused-macros], - [nmh_cv_has_unusedmacros], - [nmh_saved_cppflags="$CPPFLAGS" - CPPFLAGS="$CPPFLAGS -Wunused-macros -Wno-unused-macros" - AC_TRY_COMPILE([],[],nmh_cv_has_unusedmacros=yes,nmh_cv_has_unusedmacros=no) - CPPFLAGS="$nmh_saved_cppflags"]) - -if test "$nmh_cv_has_unusedmacros" = 'yes'; then - test -z "$CPPFLAGS" && CPPFLAGS=-Wunused-macros \ - || CPPFLAGS="$CPPFLAGS -Wunused-macros" - DISABLE_UNUSED_MACROS_WARNING=-Wno-unused-macros -fi -AC_SUBST([DISABLE_UNUSED_MACROS_WARNING])dnl - -AC_CACHE_CHECK([whether compiler supports -Wno-sign-compare], - [nmh_cv_has_nosigncompare], - [nmh_saved_cppflags="$CPPFLAGS" - CPPFLAGS="$CPPFLAGS -Wno-sign-compare" - AC_TRY_COMPILE([],[],nmh_cv_has_nosigncompare=yes, - nmh_cv_has_nosigncompare=no) - CPPFLAGS="$nmh_saved_cppflags"]) - -if test "$nmh_cv_has_nosigncompare" = 'yes'; then - DISABLE_SIGN_COMPARE_WARNING=-Wno-sign-compare -fi -AC_SUBST([DISABLE_SIGN_COMPARE_WARNING])dnl - AC_CACHE_CHECK([whether compiler supports -Wextra], [nmh_cv_has_wextra], [nmh_saved_cflags="$CFLAGS" - CFLAGS="$CFLAGS -Wextra -Wno-clobbered" + CFLAGS="$CFLAGS -Wextra -Werror" AC_TRY_COMPILE([],[],nmh_cv_has_wextra=yes,nmh_cv_has_wextra=no) CFLAGS="$nmh_saved_cflags"]) -AC_CACHE_CHECK([whether compiler supports -Wno-pointer-sign], [nmh_cv_has_noptrsign], +AC_CACHE_CHECK([whether compiler supports -Wno-clobbered], [nmh_cv_has_noclobbered], [nmh_saved_cflags="$CFLAGS" - CFLAGS="$CFLAGS -Wno-pointer-sign" - AC_TRY_COMPILE([],[],nmh_cv_has_noptrsign=yes,nmh_cv_has_noptrsign=no) + CFLAGS="$CFLAGS -Wno-clobbered -Werror" + AC_TRY_COMPILE([],[],nmh_cv_has_noclobbered=yes,nmh_cv_has_noclobbered=no) CFLAGS="$nmh_saved_cflags"]) dnl Can't use -ansi with gcc 4.5.3 on Cygwin, at least through setup @@ -203,24 +176,16 @@ dnl We use -Wall and -Wextra if supported. If the compiler supports it we dnl also use -Wno-pointer-sign, because gcc 4 now produces a lot of new dnl warnings which are probably mostly spurious and which in any case we dnl don't want to deal with now. -if test "$nmh_cv_has_noptrsign" = "yes"; then - if test "$nmh_cv_has_dash_ansi" = "yes"; then - nmh_gcc_common_flags="-ansi -pedantic -Wall" - else - nmh_gcc_common_flags="-Wall" - fi - if test "$nmh_cv_has_wextra" = "yes"; then - nmh_gcc_warnflags="${nmh_gcc_common_flags} -Wextra -Wno-clobbered "\ -"-Wno-pointer-sign" - else - nmh_gcc_warnflags="${nmh_gcc_common_flags} -Wno-pointer-sign" - fi +if test "$nmh_cv_has_dash_ansi" = "yes"; then + nmh_gcc_warnflags="-ansi -pedantic -Wall" else - if test "$nmh_cv_has_wextra" = "yes"; then - nmh_gcc_warnflags="${nmh_gcc_common_flags} -Wextra -Wno-clobbered" - else - nmh_gcc_warnflags="${nmh_gcc_common_flags}" - fi + nmh_gcc_warnflags="-Wall" +fi +if test "$nmh_cv_has_wextra" = "yes"; then + nmh_gcc_warnflags="${nmh_gcc_warnflags} -Wextra" +fi +if test "$nmh_cv_has_noclobbered" = "yes"; then + nmh_gcc_warnflags="${nmh_gcc_warnflags} -Wno-clobbered" fi if test -n "$auto_cflags"; then @@ -246,6 +211,8 @@ if test -n "$auto_cflags"; then else test -z "$CFLAGS" && CFLAGS=-O || CFLAGS="$CFLAGS -O" fi + AC_DEFINE([NDEBUG], [1], + [Define to disable run-time debugging and asserts.]) fi fi @@ -271,7 +238,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 +374,6 @@ AC_HEADER_TIOCGWINSZ AC_CHECK_HEADERS([fcntl.h ncurses/termcap.h termcap.h langinfo.h \ wchar.h wctype.h sys/param.h sys/time.h sys/stream.h]) -dnl -dnl Checks for _IO_write_ptr. A Linuxism used by nmh on linux. We -dnl really use a whole set of them, but this check should be -dnl sufficient. -dnl -AC_CHECK_HEADER(libio.h, [ - AC_EGREP_HEADER(_IO_write_ptr, libio.h, [ - AC_DEFINE(LINUX_STDIO,1,[Use the Linux _IO_*_ptr defines from .]) ]) ]) - AC_CHECK_HEADER([sys/ptem.h], AC_DEFINE(WINSIZE_IN_PTEM,1, [Define to 1 if `struct winsize' requires .]),, [[#if HAVE_SYS_STREAM_H diff --git a/docs/README.manpages b/docs/README.manpages index 33693df3..6bb6636b 100644 --- a/docs/README.manpages +++ b/docs/README.manpages @@ -1,6 +1,6 @@ NMH MANPAGE STYLE GUIDE -nmh manpages should be in this general form: +nmh manpages should be in this general form and section order: .TH COMP %manext1% "DATE" "%nmhversion%" .\" @@ -8,6 +8,7 @@ nmh manpages should be in this general form: .\" .SH NAME comp \- compose a message +.\" .SH SYNOPSIS .HP 5 .na @@ -23,13 +24,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 @@ -37,13 +32,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 @@ -51,6 +40,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 @@ -71,7 +76,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 @@ -202,7 +207,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 @@ -212,4 +218,4 @@ AUTHOR and HISTORY sections BUGS - The BUGS section goes last. + The BUGS section goes last. diff --git a/docs/contrib/build_nmh b/docs/contrib/build_nmh index f0b0c56c..f17b240f 100755 --- a/docs/contrib/build_nmh +++ b/docs/contrib/build_nmh @@ -273,17 +273,19 @@ if [ $status -eq 0 ]; then fi [ $verbose -ge 1 ] && echo testing . . . - checkoutput=`make $check 2>>"$logfile"` + checkoutput=`make $check AM_COLOR_TESTS=always 2>>"$logfile"` status=$? tests_summary=`echo "$checkoutput" | grep tests` #### If multiple tests not run, that line will be caught by the #### "grep tests" above. test_not_run=`echo "$checkoutput" | grep 'test was not run'` + fails=`echo "$checkoutput" | grep FAIL` if [ "$tests_summary" ]; then echo '===================' >>"$logfile" - echo "$tests_summary" >>"$logfile" [ "$test_not_run" ] && echo "$test_not_run" >>"$logfile" + [ "$fails" ] && echo "$fails" >>"$logfile" + echo "$tests_summary" >>"$logfile" echo '===================' >>"$logfile" [ "$check" = distcheck ] && \ echo "$checkoutput" | tail -n 4 >>"$logfile" diff --git a/docs/pending-release-notes b/docs/pending-release-notes index 9b280927..1cd1cd76 100644 --- a/docs/pending-release-notes +++ b/docs/pending-release-notes @@ -34,7 +34,13 @@ 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. +- burst(1) now can burst MIME-formatted digests (messages that contain + message/rfc822 parts instead of messages formatted with RFC 934). +- All proc entries (showproc, moreproc, etc) can now accept entries that + contain spaces and shell metacharacters. If found, such entries will + either be space-splitted or processed by /bin/sh. ---------------------------- OBSOLETE/DEPRECATED FEATURES @@ -58,6 +64,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/etc/gen-ctype-checked.c b/etc/gen-ctype-checked.c new file mode 100644 index 00000000..60191673 --- /dev/null +++ b/etc/gen-ctype-checked.c @@ -0,0 +1,125 @@ +/* + * gen-ctype-checked.c: generates ctype-checked.h on stdout + * + * This code is Copyright (c) 2013, by the authors of nmh. + * See the COPYRIGHT file in the root directory of the nmh + * distribution for complete copyright information. + */ + +/* + * This is intended to catch any calls using a char argument to any of + * the is*(int) functions in . It does that by defining a + * macro that uses the argument as an array index, along with a + * compiler warning such as gcc -Wchar-subscripts (include with + * -Wall). This program creates sbr/ctype-checked.h and + * sbr/ctype-checked.c. The header file is put into sbr/ because h/ + * is unwritable during make distcheck. + */ + +#include +#include + +#define CTYPE_FUNCTIONS \ + X(isalnum) \ + X(isalpha) \ + X(iscntrl) \ + X(isdigit) \ + X(isgraph) \ + X(islower) \ + X(isprint) \ + X(ispunct) \ + X(isspace) \ + X(isupper) \ + X(isxdigit) \ + +#if (defined (_BSD_SOURCE) && _BSD_SOURCE) || \ + (defined (_SVID_SOURCE) && _SVID_SOURCE) || \ + (defined (_XOPEN_SOURCE) && _XOPEN_SOURCE) +# define CTYPE_FUNCTION_ISASCII X(isascii) +#else +# define CTYPE_FUNCTION_ISASCII +#endif + +#if (defined (_XOPEN_SOURCE) && _XOPEN_SOURCE >= 600) || \ + (defined (_ISOC99_SOURCE) && _ISOC99_SOURCE) || \ + (defined (_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) +# define CTYPE_FUNCTIONS_C99 X(isblank) +#else +# define CTYPE_FUNCTIONS_C99 +#endif + +struct ctype_func { const char *name; int (*function) (int); }; + +#define X(function) { #function, function }, +struct ctype_func functions[] = + { CTYPE_FUNCTIONS CTYPE_FUNCTION_ISASCII CTYPE_FUNCTIONS_C99 { NULL, 0} }; +#undef X + + +int +main () { + const char *copyright="\ +/*\n\ + * %s: checks type of arguments and argument\n\ + * values for each of the ctype functions\n\ + *\n\ + * Generated by etc/gen-ctype-checked.\n\ + *\n\ + * This code is Copyright (c) 2013, by the authors of nmh.\n\ + * See the COPYRIGHT file in the root directory of the nmh\n\ + * distribution for complete copyright information.\n\ + */\n\n"; + char headername[] = "sbr/ctype-checked.h"; + const char cfilename[] = "sbr/ctype-checked.c"; + FILE *header, *cfile; + + if ((header = fopen (headername, "w")) != 0 && + (cfile = fopen (cfilename, "w")) != 0) { + struct ctype_func *f; + + fprintf (header, copyright, headername); + fputs ("#ifndef CTYPE_CHECKED_H\n\ +#define CTYPE_CHECKED_H\n\ +#include \n\ +\n", header); + + fprintf (cfile, copyright, cfilename); + fputs ("#include \n\n", cfile); + fputs ("#ifndef NDEBUG\n", cfile); + fputs ("#include \n\n", cfile); + + for (f = functions; f->function; ++f) { + const char *cp = f->name; + unsigned int i; + + fprintf (header, "extern int %s_type_checked[];\n", cp); + fprintf (header, "#ifdef %s\n#undef %s\n#endif\n", cp, cp); + fprintf (header, "#define %s(c) %s_type_checked[(c)]\n\n", cp, cp); + + fprintf (cfile, "int %s_type_checked[] = {\n ", cp); + for (i = 0; i < 256; ++i) { + fprintf (cfile, "%d", (*f->function) (i)); + if ((i+1) % 8) { + fputs (", ", cfile); + } else { + if (i == 255) { + fputs (" };\n\n", cfile); + } else { + fputs (",\n ", cfile); + } + } + } + } + + /* Need to put a symbol in the .c file with NDEBUG so the + compilation unit isn't empty. */ + fputs ("#else /* NDEBUG */\n\nint ctype_checked;\n\n", cfile); + fputs ("#endif /* NDEBUG */\n", cfile); + fprintf (header, "#endif /* CTYPE_CHECKED_H */\n"); + } else { + perror ("fopen in sbr/"); + return -1; + } + + return 0; +} diff --git a/etc/rmmproc.messageid b/etc/rmmproc.messageid new file mode 100755 index 00000000..1bac5901 --- /dev/null +++ b/etc/rmmproc.messageid @@ -0,0 +1,61 @@ +#! /bin/sh +## + # rmmproc.messageid -- tries to back up each message/file to a file + # that's named based on Message ID + # + # This code is Copyright (c) 2013, by the authors of nmh. + # See the COPYRIGHT file in the root directory of the nmh + # distribution for complete copyright information. + # + # If called on messages, the current directory is the message folder + # and the scripts arguments are is the message filenames. If called + # on files, the arguments are the full paths to the files. + # + # The backup directory will be: + # 1) If input is messages, the folder of the messages. + # 2) If input is files, the directories of the files. + # 3) If input is standard input (-), the user's MHPATH directory. + # + # Each backup filename will be: + # 1) Message-ID with all / and \ converted to periods. + # Message-IDs should not contain \, but some filesystems can't + # handle them. Message-IDs should be unique, so there should be + # no need to backup a file with the same name, especially if the + # result of malicious action. If the backup file already + # exists, use 2). + # NOTE: conversion of some characters in the filename could + # result in an unintended name collision. If that is a concern, + # a program that uses mktemp(3) to create a temporary file might + # be the basis for a remedy. + # 2) Concatenation of BACKUP_PREFIX and input filename. + # NOTE: if a file of that name already exists in the destination + # directory, it will be overwritten by the mv below. +## + +for i in "$@"; do + if [ "$i" = - ]; then + #### Input is stdin; put backup in user's MHPATH directory. + dir=`mhparam path` + #### If Path is relative, prepend home directory. + [ `dirname "$dir"` = . ] && dir="$HOME/$dir" + else + dir=`dirname "$i"` + fi + + #### Extract first Message-Id, remove <>, substitute / and \. + messageid=`sed -n ' + /^$/q; /^[Mm][Ee][Ss][Ss][Aa][Gg][Ee]-[Ii][Dd]:/!d + s/>.*//; s/.*' \ && (c) != '@' && (c) != ',' && (c) != ';' \ && (c) != ':' && (c) != '\\' && (c) != '"' \ @@ -23,7 +25,9 @@ * Test for valid characters used in "token" * as defined in RFC2045 */ -#define istoken(c) (!isspace (c) && !iscntrl (c) && (c) != '(' \ +#define istoken(c) (isascii((unsigned char) c) \ + && !isspace ((unsigned char) c) \ + && !iscntrl ((unsigned char) c) && (c) != '(' \ && (c) != ')' && (c) != '<' && (c) != '>' \ && (c) != '@' && (c) != ',' && (c) != ';' \ && (c) != ':' && (c) != '\\' && (c) != '"' \ diff --git a/h/nmh.h b/h/nmh.h index 3b91e2c3..b2bac8f0 100644 --- a/h/nmh.h +++ b/h/nmh.h @@ -10,6 +10,10 @@ #include #include #include +#ifndef NDEBUG + /* See etc/gen-ctype-checked.c. */ +# include +#endif #include # include diff --git a/h/prototypes.h b/h/prototypes.h index 443479f6..a3263195 100644 --- a/h/prototypes.h +++ b/h/prototypes.h @@ -23,10 +23,17 @@ char *etcpath(char *); /* * prototypes from the nmh subroutine library */ + +struct msgs_array; + 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 argsplit_msgarg (struct msgs_array *, char *, char **); +void argsplit_insert (struct msgs_array *, char *, char **); +void arglist_free (char *, char **); void ambigsw (char *, struct swit *); int atooi(char *); char **brkstring (char *, char *, char *); @@ -76,8 +83,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 *, char[NAMESZ], char *, int *, FILE *); int m_gmprot (void); char *m_maildir (char *); char *m_mailpath (char *); @@ -86,7 +96,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 +117,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 *); @@ -114,7 +128,7 @@ int seq_delmsg (struct msgs *, char *, int); int seq_delsel (struct msgs *, char *, int, int); int seq_getnum (struct msgs *, char *); char *seq_list (struct msgs *, char *); -int seq_nameok (unsigned char *); +int seq_nameok (char *); void seq_print (struct msgs *, char *); void seq_printall (struct msgs *); void seq_read (struct msgs *); @@ -127,7 +141,7 @@ int smatch(char *, struct swit *); char *snprintb (char *, size_t, unsigned, char *); int ssequal (char *, char *); int stringdex (char *, char *); -char *trimcpy (unsigned char *); +char *trimcpy (char *); int unputenv (char *); int uprf (char *, char *); int vfgets (FILE *, char **); @@ -163,7 +177,7 @@ int sc_length(void); int sc_width(void); int build_form (char *, char *, int *, char *, char *, char *, char *, char *, char *); -int sendsbr (char **, int, char *, struct stat *, int, char *, int); +int sendsbr (char **, int, char *, char *, struct stat *, int, char *, int); int SOprintf (char *, ...); int what_now (char *, int, int, char *, char *, int, struct msgs *, char *, int, char *, int); diff --git a/m4/iconv.m4 b/m4/iconv.m4 index 949c746d..5ae52c87 100644 --- a/m4/iconv.m4 +++ b/m4/iconv.m4 @@ -4,7 +4,8 @@ dnl or libiconv() dnl AC_DEFUN([NMH_CHECK_ICONV], -[AC_CHECK_HEADER([iconv.h], +[ICONV_ENABLED=0 +AC_CHECK_HEADER([iconv.h], [AC_CHECK_FUNC([iconv], [dnl This is where iconv is found in the default libraries (LIBS) nmh_found_iconv=yes @@ -24,6 +25,7 @@ AC_DEFUN([NMH_CHECK_ICONV], AS_IF([test "x$nmh_found_iconv" = "xyes"], [AC_DEFINE([HAVE_ICONV], [1], [Define if you have the iconv() function.]) + ICONV_ENABLED=1 AC_CACHE_CHECK([for iconv declaration], [nmh_cv_iconv_const], [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include #include ]], @@ -40,3 +42,4 @@ AC_DEFUN([NMH_CHECK_ICONV], AC_DEFINE_UNQUOTED([ICONV_CONST], [$nmh_cv_iconv_const], [Define as const if the declaration of iconv() needs const.])])]) AC_SUBST([ICONVLIB])]) +AC_SUBST([ICONV_ENABLED]) diff --git a/man/ali.man b/man/ali.man index a67cad14..1b54e0f1 100644 --- a/man/ali.man +++ b/man/ali.man @@ -59,30 +59,33 @@ switch will be read. Each is processed as described in .IR mh\-alias (5). .SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -^/etc/passwd~^List of users -^/etc/group~^List of groups -.fi +.TP 20 +$HOME/.mh\-profile +The user's profile. .SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -^Aliasfile:~^For a default alias file -.fi +.PP +.PD 0 +.TP 20 +Path: +To determine the user's nmh directory +.TP +Aliasfile: +For a default alias file +.PD .SH "SEE ALSO" .IR mh\-alias (5) .SH DEFAULTS -.nf -.RB ` aliasfiles "' defaults to %etcdir%/MailAliases" -.RB ` \-nolist ' -.RB ` \-nonormalize ' -.RB ` \-nouser ' -.fi +.PD 0 +.TP 20 +aliasfile +%etcdir%/MailAliases +.TP +\-nolist +.TP +\-nonormalize +.TP +\-nouser +.PD .SH CONTEXT None .SH BUGS diff --git a/man/anno.man b/man/anno.man index ce1942b6..2842d40b 100644 --- a/man/anno.man +++ b/man/anno.man @@ -151,30 +151,35 @@ A matching option exists that allows time preservation to be turned off if enabled in the profile. .SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -.fi +.TP 20 +$HOME/\&.mh\(ruprofile +The user's profile. .SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -^Current\-Folder:~^To find the default current folder -.fi +.PD 0 +.TP 20 +Path: +To determine the user's nmh directory. +.TP +Current\-Folder: +To find the default current folder. +.PD .SH "SEE ALSO" .IR dist (1), .IR forw (1), .IR repl (1) .SH DEFAULTS -.nf -.RI ` +folder "' defaults to the current folder" -.RI ` msgs "' defaults to cur" -.RB ` \-inplace ' -.RB ` \-date ' -.fi +.PD 0 +.TP 20 ++folder +The current folder. +.TP +msgs +The current message. +.TP +-inplace +.TP +-date +.PD .SH CONTEXT If a folder is given, it will become the current folder. The first message annotated will become the current message. diff --git a/man/ap.man b/man/ap.man index f1b6faa4..52d6c522 100644 --- a/man/ap.man +++ b/man/ap.man @@ -78,12 +78,14 @@ which says that if an error was detected, print the error, a `:', and the address in error. Otherwise, output the 822\-proper format of the address. .SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -^%etcdir%/mts.conf~^nmh mts configuration file -.fi +.PD 0 +.TP 20 +$HOME/\&.mh\(ruprofile +The user's profile. +.TP +%etcdir%/mts.conf +The mts configuration file. +.PD .SH "PROFILE COMPONENTS" None .SH "SEE ALSO" @@ -93,10 +95,15 @@ None Standard for the Format of ARPA Internet Text Messages (RFC\-822) .SH DEFAULTS -.nf -.RB ` \-format "' defaults as described above" -.RB ` \-normalize ' -.RB ` \-width "' defaults to the width of the terminal" -.fi +.PD 0 +.TP 20 +-format +As described above. +.TP +\-normalize +.TP +\-width +The width of the terminal. +.PD .SH CONTEXT None diff --git a/man/burst.man b/man/burst.man index 4e2d0cc0..2ef0975c 100644 --- a/man/burst.man +++ b/man/burst.man @@ -11,6 +11,8 @@ burst \- explode digests into messages .RI [ +folder ] .RI [ msgs ] .RB [ \-inplace " | " \-noinplace ] +.RB [ \-mime " | " \-nomime ] +.RB [ \-automime ] .RB [ \-quiet " | " \-noquiet ] .RB [ \-verbose " | " \-noverbose ] .RB [ \-version ] @@ -36,6 +38,20 @@ is given, each digest is preserved, no table of contents is produced, and the messages contained within the digest are placed at the end of the folder. Other messages are not tampered with in any way. .PP +If +.B \-automime +is given, +.B burst +will try to determine if the message is formatted with MIME and contains MIME parts of +type \*(lqmessage/rfc822\*(rq. If it does, it will burst the message using MIME +formatting rules. The +.B \-mime +switch can be used to enforce the use of MIME formatting. The +.B \-nomime +switch will force +.B burst +to use RFC-934 rules. +.PP The .B \-quiet switch directs @@ -59,20 +75,21 @@ former two were generated by or .BR send . .SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -.fi +.TP 20 +$HOME/.mh\-profile +The user's profile. .SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -^Current\-Folder:~^To find the default current folder -^Msg\-Protect:~^To set mode when creating a new message -.fi +.PD 0 +.TP 20 +Path: +To determine the user's nmh directory. +.TP +Current\-Folder: +To find the default current folder. +.TP +Msg\-Protect: +To set mode when creating a new message. +.PD .SH "SEE ALSO" .IR inc (1), .IR msh (1), @@ -82,13 +99,22 @@ or Proposed Standard for Message Encapsulation (RFC\-934) .SH DEFAULTS -.nf -.RB ` +folder "' defaults to the current folder" -.RB ` msgs "' defaults to cur" -.RB ` \-noinplace ' -.RB ` \-noquiet ' -.RB ` \-noverbose ' -.fi +.PD 0 +.TP 20 ++folder +The current folder. +.TP +msgs +The current message. +.TP +\-noinplace +.TP +\-automime +.TP +\-noquiet +.TP +\-noverbose +.PD .SH CONTEXT If a folder is given, it will become the current folder. If .B \-inplace diff --git a/man/comp.man b/man/comp.man index bd0a762e..387ec129 100644 --- a/man/comp.man +++ b/man/comp.man @@ -231,26 +231,38 @@ program which starts the initial edit. Hence, .B \-nowhatnowproc will prevent any edit from occurring.) .SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^%etcdir%/components~^The standard message skeleton -^or /components~^Rather than the standard skeleton -^$HOME/\&.mh\(ruprofile~^The user profile -^/draft~^The draft file -.fi +.PD 0 +.TP 20 +%etcdir%/components +The standard message skeleton. +.TP +/components +An alternative to the standard skeleton. +.TP +$HOME/.mh\-profile +The user's profile. +.PD .SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -^Draft\-Folder:~^To find the default draft\-folder -^Editor:~^To override the default editor -^Msg\-Protect:~^To set mode when creating a new message (draft) -^fileproc:~^Program to refile the message -^whatnowproc:~^Program to ask the \*(lqWhat now?\*(rq questions -.fi +.PD 0 +.TP 20 +Path: +To determine the user's nmh directory. +.TP +Draft\-Folder: +To find the default draft\-folder. +.TP +Editor: +To override the default editor. +.TP +Msg\-Protect: +To set mode when creating a new message (draft). +.TP +fileproc: +Program to refile the message. +.TP +whatnowproc: +Program to ask the \*(lqWhat now?\*(rq questions +.PD .SH "SEE ALSO" .IR dist (1), .IR forw (1), @@ -259,12 +271,18 @@ will prevent any edit from occurring.) .IR whatnow (1), .IR mh-profile (5) .SH DEFAULTS -.nf -.RB ` +folder "' defaults to the current folder" -.RB ` msg "' defaults to the current message" -.RB ` \-nodraftfolder ' -.RB ` \-nouse ' -.fi +.PD 0 +.TP 20 ++folder +The current folder. +.TP +msg +The current message. +.TP +\-nodraftfolder +.TP +\-nouse +.PD .SH CONTEXT None .SH BUGS diff --git a/man/dp.man b/man/dp.man index 3f98913a..7998c2d0 100644 --- a/man/dp.man +++ b/man/dp.man @@ -62,11 +62,9 @@ which says that if an error was detected, print the error, a `:', and the date in error. Otherwise, output the 822\-proper format of the date. .SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -.fi +.TP 20 +$HOME/.mh\-profile +The user's profile. .SH "PROFILE COMPONENTS" None .SH "SEE ALSO" @@ -75,9 +73,13 @@ None .I "Standard for the Format of ARPA Internet Text Messages" (RFC\-822) .SH DEFAULTS -.nf -.RB ` \-format "' default as described above" -.RB ` \-width "' default to the width of the terminal" -.fi +.PD 0 +.TP 20 +\-format +As described above. +.TP +\-width +The width of the terminal. +.PD .SH CONTEXT None diff --git a/man/flist.man b/man/flist.man index 49b45021..a3ad8798 100644 --- a/man/flist.man +++ b/man/flist.man @@ -174,35 +174,45 @@ addressed to you personally, those about a pet project, and those about mh-related things. It places uninteresting folders at the end, and it puts everything else in the middle in alphabetical order. .SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -.fi +.TP 20 +$HOME/.mh\-profile +The user's profile. .SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -^mh-sequences:~^File that contains public sequences -^Unseen-Sequence:~^The name of the unseen message sequence -^Flist-Order:~^To sort folders by priority -.fi +.PD 0 +.TP 20 +Path: +To determine the user's nmh directory. +.TP +mh-sequences: +File that contains public sequences. +.TP +Unseen-Sequence: +The name of the unseen message sequence. +.TP +Flist-Order: +To sort folders by priority. +.PD .SH "SEE ALSO" .IR folder (1), .IR rcvstore (1), .IR slocal (1), .IR mh\-sequence (5) .SH DEFAULTS -.nf -.RB ` -sequence "' defaults to Unseen-Sequence profile entry" -.RB ` \-showzero ' -.RB ` \-noall ' -.RB ` \-norecurse ' -.RB ` \-noalpha ' -.RB ` \-nofast ' -.fi +.PD 0 +.TP 20 +-sequence +The Unseen-Sequence profile entry. +.TP +\-showzero +.TP +\-noall +.TP +\-norecurse +.TP +\-noalpha +.TP +\-nofast +.PD .SH CONTEXT If .I +folder diff --git a/man/fmtdump.man b/man/fmtdump.man index 9a71ac94..42cb3df2 100644 --- a/man/fmtdump.man +++ b/man/fmtdump.man @@ -36,19 +36,18 @@ See .IR mh-format (5) for the details. .SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -^%etcdir%/scan.default~^The default format file -.fi +.PD 0 +.TP 20 +$HOME/.mh\-profile +The user's profile. +.TP +%etcdir%/scan.default +The default format file. +.PD .SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -.fi +.TP 20 +Path: +To determine the user's nmh directory. .SH "SEE ALSO" .IR mh-format (5), .IR mh-sequences (8) diff --git a/man/folder.man b/man/folder.man index dadabbf5..401ab5b8 100644 --- a/man/folder.man +++ b/man/folder.man @@ -261,38 +261,64 @@ and switches turn off .BR \-print . .SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -.fi +.TP 20 +$HOME/.mh\-profile +The user's profile. .SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -^Current\-Folder:~^To find the default current folder -^Folder\-Protect:~^To set mode when creating a new folder -^Folder\-Stack:~^To determine the folder stack +.PD 0 +.TP 20 +Path: +To determine the user's nmh directory. +.TP +Current\-Folder: +To find the default current folder. +.TP +Folder\-Protect: +To set mode when creating a new folder. +.TP +Folder\-Stack: +To determine the folder stack. .\" ^lsproc:~^Program to list the contents of a folder -.fi +.PD .SH "SEE ALSO" .IR mhpath (1), .IR refile (1) .SH DEFAULTS -.nf -.RB ` +folder "' defaults to the current folder" -.RB ` msg "' defaults to none" -.RB ` \-nofast ' -.RB ` \-noheader ' -.RB ` \-nototal ' -.RB ` \-nopack ' -.RB ` \-norecurse ' -.RB ` \-noverbose ' -.RB ` \-print "' is the default if no " \-list ", " \-push ", or " \-pop " is specified" -.RB ` \-list "' is the default if " \-push ", or " \-pop " is specified" -.fi +.PD 0 +.TP 20 ++folder +The current folder. +.TP +msg +\*(lqnone\*(rq +.TP +\-nofast +.TP +\-noheader +.TP +\-nototal +.TP +\-nopack +.TP +\-norecurse +.TP +\-noverbose +.TP +\-print +is the default if no +.BR -list , +.BR \-push , +or +.B \-pop +is specified. +.TP +\-list +is the default if +.BR \-push , +or +.B \-pop +is specified. +.PD .SH CONTEXT If .I +folder diff --git a/man/forw.man b/man/forw.man index 2efa5413..1e0c0c39 100644 --- a/man/forw.man +++ b/man/forw.man @@ -395,32 +395,58 @@ section of the .B nmh User's Manual for more information on making digests. .SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^%etcdir%/forwcomps~^The standard message skeleton -^or /forwcomps~^Rather than the standard skeleton -^%etcdir%/digestcomps~^The message skeleton if `\-digest' is given -^or /digestcomps~^Rather than the standard skeleton -^%etcdir%/mhl.forward~^The standard message filter -^or /mhl.forward~^Rather than the standard filter -^$HOME/\&.mh\(ruprofile~^The user profile -^/draft~^The draft file -.fi +.PD 0 +.TP 25 +%etcdir%/forwcomps +The standard message skeleton. +.TP +/forwcomps +Rather than the standard skeleton. +.TP +%etcdir%/digestcomps +The message skeleton if +.B \-digest +is given. +.TP +/digestcomps +Rather than the standard skeleton. +.TP +^%etcdir%/mhl.forward +The standard message filter. +.TP +/mhl.forward +Rather than the standard filter. +.TP +^$HOME/.mh\-profile +The user's profile. +.PD .SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -^Current\-Folder:~^To find the default current folder -^Draft\-Folder:~^To find the default draft\-folder -^Editor:~^To override the default editor -^Msg\-Protect:~^To set mode when creating a new message (draft) -^fileproc:~^Program to refile the message -^mhlproc:~^Program to filter messages being forwarded -^whatnowproc:~^Program to ask the \*(lqWhat now?\*(rq questions -.fi +.PD 0 +.TP 25 +Path: +To determine the user's nmh directory. +.TP +Current\-Folder: +To find the default current folder. +.TP +Draft\-Folder: +To find the default draft\-folder. +.TP +Editor: +To override the default editor. +.TP +Msg\-Protect: +To set mode when creating a new message (draft). +.TP +fileproc: +Program to refile the message. +.TP +mhlproc: +Program to filter messages being forwarded. +.TP +whatnowproc: +Program to ask the \*(lqWhat now?\*(rq questions. +.PD .SH "SEE ALSO" .IR comp (1), .IR mhbuild (1), @@ -433,16 +459,26 @@ User's Manual for more information on making digests. Proposed Standard for Message Encapsulation (RFC\-934) .SH DEFAULTS -.nf -.RB ` +folder "' defaults to the current folder" -.RB ` msgs "' defaults to cur" -.RB ` \-noannotate ' -.RB ` \-nodraftfolder ' -.RB ` \-noformat ' -.RB ` \-inplace ' -.RB ` \-dashstuffing ' -.RB ` \-nomime ' -.fi +.PD 0 +.TP 25 ++folder +The current folder. +.TP +msgs +The current message. +.TP +\-noannotate +.TP +\-nodraftfolder +.TP +\-noformat +.TP +\-inplace +.TP +\-dashstuffing +.TP +\-nomime +.PD .SH CONTEXT If a folder is given, it will become the current folder. The first message forwarded will become the current message. diff --git a/man/inc.man b/man/inc.man index 627c20ed..b534d1b1 100644 --- a/man/inc.man +++ b/man/inc.man @@ -1,4 +1,4 @@ -.TH INC %manext1% "November 6, 2012" "%nmhversion%" +.TH INC %manext1% "February 16, 2013" "%nmhversion%" .\" .\" %nmhwarning% .\" @@ -153,6 +153,13 @@ Note that the name file will NOT be zeroed, unless the .B \-truncate switch is given. .PP +The +.B \-file +switch does not support use of standard input. Instead, +the +.B rcvstore +command can be used to incorporate mail from the standard input stream. +.PP If the environment variable .B $MAILDROP is set, then @@ -289,42 +296,73 @@ when viewing the POP transaction with the .B \-snoop switch. .SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -^%etcdir%/mts.conf~^nmh mts configuration file -^%mailspool%/$USER~^Location of mail drop -.fi +.PD 0 +.TP 20 +$HOME/.mh\-profile +The user's profile. +.TP +%etcdir%/mts.conf +mts configuration file. +.TP +%mailspool%/$USER +Location of the system mail drop. +.PD .SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -^Alternate\-Mailboxes:~^To determine the user's mailboxes -^Inbox:~^To determine the inbox, default \*(lqinbox\*(rq -^Folder\-Protect:~^To set mode when creating a new folder -^Msg\-Protect:~^To set mode when creating a new message and audit\-file -^Unseen\-Sequence:~^To name sequences denoting unseen messages -.fi +.PD 0 +.TP 20 +Path: +To determine the user's nmh directory. +.TP +Alternate\-Mailboxes: +To determine the user's mailboxes. +.TP +Inbox: +To determine the inbox. +.TP +Folder\-Protect: +To set mode when creating a new folder. +.TP +Msg\-Protect: +To set mode when creating a new message and audit\-file. +.TP +Unseen\-Sequence: +To name sequences denoting unseen messages. +.PD .SH "SEE ALSO" .IR mhmail (1), .IR scan (1), .IR mh\-mail (5), -.IR post (8) +.IR post (8), +.IR rcvstore (1) .SH DEFAULTS -.nf -.RB ` +folder "' defaulted by \*(lqInbox\*(rq above" -.RB ` \-noaudit ' -.RB ` \-changecur ' -.RB ` \-format "' defaulted as described above" -.RB ` \-nosilent ' -.RB ` \-nosasl ' -.RB ` \-truncate "' if `" \-file " name' not given, `" \-notruncate "' otherwise" -.RB ` \-width "' defaulted to the width of the terminal" -.RB ` \-nopack ' -.fi +.PD 0 +.TP 20 ++folder +defaulted by \*(lqInbox\*(rq above. +.TP +\-noaudit +.TP +\-changecur +.TP +\-format +As described above. +.TP +\-nosilent +.TP +\-nosasl +.TP +\-truncate +If +.B \-file +.I name +not given, +\-notruncate otherwise. +.TP +\-width +The width of the terminal. +.TP +\-nopack +.PD .SH CONTEXT The folder into which messages are being incorporated will become the current folder. The first message incorporated will become the current diff --git a/man/install-mh.man b/man/install-mh.man index 33262d2d..25a7fdbe 100644 --- a/man/install-mh.man +++ b/man/install-mh.man @@ -67,19 +67,18 @@ been installed. This can be used by other programs to determine whether or not nmh has been installed without their having to know the internals of nmh. .SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -^%etcdir%/mh.profile~^Used to initialize user profile -.fi +.PD 0 +.TP 20 +$HOME/.mh\-profile +The user's profile. +.TP +%etcdir%/mh.profile +Used to initialize user's profile. +.PD .SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To set the user's nmh directory -.fi +.TP 20 +Path: +To set the user's nmh directory. .SH CONTEXT With .BR \-auto , diff --git a/man/mark.man b/man/mark.man index 500fdb16..74bdfe6c 100644 --- a/man/mark.man +++ b/man/mark.man @@ -164,29 +164,44 @@ to the first or last `n' messages of the sequence `name', respectively. Constructs of the form \*(lqname1\-name2\*(rq are forbidden for user defined sequences. .SH FILES -.fc ^ ~ -.nf -.ta \w'%etcdir%/ExtraBigFileName 'u -^$HOME/\&.mh\(ruprofile~^The user profile -.fi +.TP 20 +$HOME/.mh\-profile +The user's profile. .SH "PROFILE COMPONENTS" -.fc ^ ~ -.nf -.ta 2.4i -.ta \w'ExtraBigProfileName 'u -^Path:~^To determine the user's nmh directory -^Current\-Folder:~^To find the default current folder -.fi +.PD 0 +.TP 20 +Path: +To determine the user's nmh directory. +.TP +Current\-Folder: +To find the default current folder. +.PD .SH "SEE ALSO" .IR flist (1), .IR pick (1), .IR mh-sequence (5) .SH DEFAULTS -.nf -.RB ` +folder "' defaults to the current folder" -.RB ` \-add "' if " \-sequence " is specified, " \-list " otherwise" -.RB ` msgs "' defaults to cur (or all if " \-list " is specified)" -.RB ` \-nozero ' +.PD 0 +.TP 20 ++folder +The current folder. +.TP +\-add +If +.B \-sequence +is specified, +.B \-list +otherwise. +.TP +msgs +The current message, or +.B all +if +.B \-list +is specified. +.TP +\-nozero +.PD .SH CONTEXT If a folder is given, it will become the current folder. .SH "HELPFUL HINTS" diff --git a/man/mh-profile.man b/man/mh-profile.man index d7b03841..d7afe5be 100644 --- a/man/mh-profile.man +++ b/man/mh-profile.man @@ -361,6 +361,13 @@ The .I \&.mh\(ruprofile can be used to select alternate programs if the user wishes. The default values are given in the examples. +.PP +If the profile element contains spaces, the element is split at spaces +into tokens and each token is given as a seperate argument to the +.IR execvp (2) +system call. If the element contains shell metacharacters then the entire +element is executed using +.BR /bin/sh . .RE .PP .BR buildmimeproc : @@ -410,14 +417,6 @@ to incorporate new mail when it is invoked with no arguments. .RE .PP -.BR installproc : -%libdir%/install\-mh -.RS 5 -This program is called to initialize the environment for -new users of -.BR nmh . -.RE -.PP .BR lproc : more .RS 5 diff --git a/man/mhbuild.man b/man/mhbuild.man index 57441dad..cbe2f4f5 100644 --- a/man/mhbuild.man +++ b/man/mhbuild.man @@ -28,7 +28,7 @@ a valid MIME message. .PP .B mhbuild creates multi-media messages as specified in RFC\-2045 -thru RFC\-2049. Currently +to RFC\-2049. Currently .B mhbuild only supports encodings in message bodies, and does not support the encoding of message headers as diff --git a/man/mhlist.man b/man/mhlist.man index fab619f9..f6e752ef 100644 --- a/man/mhlist.man +++ b/man/mhlist.man @@ -1,4 +1,4 @@ -.TH MHLIST %manext1% "January 9, 2001" "%nmhversion%" +.TH MHLIST %manext1% "February 12, 2013" "%nmhversion%" .\" .\" %nmhwarning% .\" @@ -38,7 +38,7 @@ MIME (multi-media) messages. .PP .B mhlist manipulates MIME (multi-media messages) as specified -in RFC\-2045 thru RFC\-2049 (See +in RFC\-2045 to RFC\-2049 (See .IR mhbuild (1)). .PP The @@ -168,10 +168,9 @@ integrity of the content. ^Current\-Folder:~^To find the default current folder .fi .SH "SEE ALSO" -,IR mhbuild (1), +.IR mhbuild (1), .IR mhshow (1), -.IR mhstore (1), -.IR sendfiles (1) +.IR mhstore (1) .SH DEFAULTS .nf .RB ` +folder "' defaults to the current folder" diff --git a/man/mhshow.man b/man/mhshow.man index 04a88c4f..b2bc6f66 100644 --- a/man/mhshow.man +++ b/man/mhshow.man @@ -38,7 +38,7 @@ message or collection of messages. .PP .B mhshow manipulates multi-media messages as specified in -RFC\-2045 thru RFC\-2049. Currently +RFC\-2045 to RFC\-2049. Currently .B mhshow only supports encodings in message bodies, and does not support the encoding of diff --git a/man/mhstore.man b/man/mhstore.man index 79be43f0..35696494 100644 --- a/man/mhstore.man +++ b/man/mhstore.man @@ -38,7 +38,7 @@ messages. .PP .B mhstore manipulates multi-media messages as specified in -RFC\-2045 thru RFC\-2049. +RFC\-2045 to RFC\-2049. .PP By default, .B mhstore diff --git a/man/msh.man b/man/msh.man index 57770b52..66e29fbe 100644 --- a/man/msh.man +++ b/man/msh.man @@ -1,4 +1,4 @@ -.TH MSH %manext1% "November 6, 2012" "%nmhversion%" +.TH MSH %manext1% "January 26, 2013" "%nmhversion%" .\" .\" %nmhwarning% .\" @@ -16,12 +16,14 @@ msh \- nmh shell (and BBoard reader) .RB [ \-version ] .RB [ \-help ] .ad +.SH STATUS +.B msh is deprecated and will be removed from the next nmh release. .SH DESCRIPTION .B msh is an interactive program that implements a subset of the normal .B nmh commands operating on a single file in -.BR packf 'd +.BR mmdf format. That is, .B msh diff --git a/man/rcvstore.man b/man/rcvstore.man index 2a64f1d0..3ed56fe3 100644 --- a/man/rcvstore.man +++ b/man/rcvstore.man @@ -1,4 +1,4 @@ -.TH RCVSTORE %manext1% "January 18, 2001" "%nmhversion%" +.TH RCVSTORE %manext1% "February 18, 2013" "%nmhversion%" .\" .\" %nmhwarning% .\" @@ -98,6 +98,17 @@ and .B \-nopublic switches may be used to force these sequences to be public or private sequences. +.SS LOCKING AND \-unseen +If you use the \*(lqUnseen-Sequence\*(rq profile entry, rcvstore could +try to read and update its sequence state while another +.B nmh +process is also trying to do so. This can cause the sequence state to +lose track. To avoid this just between asynchronous invocations of +.BR rcvstore , +do not use it without an external locking mechanism, for example, a +.IR procmailrc (5) +local lockfile, if you use the \*(lqUnseen-Sequence\*(rq profile +entry. .SH FILES .fc ^ ~ .nf @@ -119,7 +130,9 @@ to force these sequences to be public or private sequences. .IR rcvdist (1), .IR rcvpack (1), .IR rcvtty (1), -.IR mh\-sequence (5) +.IR mh\-sequence (5), +.IR procmailex (5), +.IR procmailrc (5) .SH DEFAULTS .nf .RB ` +folder "' defaults to \*(lqInbox\*(rq profile entry" diff --git a/man/rmm.man b/man/rmm.man index 75dac5fa..52ac7f4d 100644 --- a/man/rmm.man +++ b/man/rmm.man @@ -1,4 +1,4 @@ -.TH RMM %manext1% "November 9, 2010" "%nmhversion%" +.TH RMM %manext1% "February 13, 2013" "%nmhversion%" .\" .\" %nmhwarning% .\" @@ -50,6 +50,13 @@ will call the named program or script to handle the files that represent the messages to be deleted. .PP +An example of a +.I rmmproc +script that saves a message based in its Message-ID is provided in +%etcdir%/rmmproc.messageid. To enable it, simply add a +.I rmmproc +component that names it to your profile. +.PP Some users of .B csh prefer the following: diff --git a/mts/smtp/smtp.c b/mts/smtp/smtp.c index b1d57dd6..6fd178bc 100755 --- a/mts/smtp/smtp.c +++ b/mts/smtp/smtp.c @@ -798,9 +798,19 @@ sm_end (int type) if (sm_mts == MTS_SMTP) smtalk (SM_QUIT, "QUIT"); else { + /* The SIGPIPE block replaces old calls to discard (). + We're not sure what the discard () calls were for, + maybe to prevent deadlock on old systems. In any + case, blocking SIGPIPE should be harmless. + Because the file handles are closed below, leave it + blocked. */ + sigset_t set, oset; + sigemptyset (&set); + sigaddset (&set, SIGPIPE); + sigprocmask (SIG_BLOCK, &set, &oset); + kill (sm_child, SIGKILL); - discard (sm_rfp); - discard (sm_wfp); + sm_child = NOTOK; } if (type == NOTOK) { sm_reply.code = sm_note.code; @@ -840,9 +850,11 @@ sm_end (int type) if (sasl_inbuffer) free(sasl_inbuffer); #endif /* CYRUS_SASL */ - } else { + } else if (sm_child != NOTOK) { status = pidwait (sm_child, OK); sm_child = NOTOK; + } else { + status = OK; } sm_rfp = sm_wfp = NULL; diff --git a/sbr/arglist.c b/sbr/arglist.c index 1f85b7b2..f40f1e89 100644 --- a/sbr/arglist.c +++ b/sbr/arglist.c @@ -25,10 +25,10 @@ * * - If there are no spaces or shell metacharacters in "command", then * take it as-is. - * - If there are spaces in command, space-split command string and - * append an argument list to it. + * - If there are spaces in command, space-split command string. * - If we have shell metacharacters, run the command using - * /bin/sh -c 'command "${@}"'. + * /bin/sh -c 'command "$@"'. In this case, any additional arguments + * appended to the arglist will be expanded by "$@". * * In all cases additional arguments can be added to the argv[] array. */ @@ -52,7 +52,7 @@ argsplit(char *command, char **file, int *argp) } } - argvarray = (char **) mh_xmalloc((sizeof(char **) * MAXARGS)); + argvarray = (char **) mh_xmalloc((sizeof(char **) * (MAXARGS + 5))); /* * The simple case - no spaces or shell metacharacters @@ -123,3 +123,100 @@ 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); + } +} + +/* + * Similar in functionality to argsplit, but is designed to deal with + * a msgs_array. + */ + +void +argsplit_msgarg(struct msgs_array *msgs, char *command, char **program) +{ + int argp, i; + char **vec; + + vec = argsplit(command, program, &argp); + + /* + * As usual, there is lousy memory management in nmh. Nothing ever + * free's the msgs_array, and a lot of the arguments are allocated + * from static memory. I could have app_msgarg() allocate new + * memory for each pointer, but for now I decided to stick with + * the existing interface; maybe that will be revisited later. + * So we'll just copy over our pointers and free the pointer list + * (not the actual pointers themselves). Note that we don't + * include a trailing NULL, since we are expecting the application + * to take care of that. + */ + + for (i = 0; i < argp; i++) { + app_msgarg(msgs, vec[i]); + } + + free(vec); +} + +/* + * Insert a arglist vector into the beginning of an struct msgs array + * + * Uses by some programs (e.g., show) who want to decide which proc + * to use after the argument vector has been constructed + */ + +#ifndef MAXMSGS +#define MAXMSGS 256 +#endif + +void +argsplit_insert(struct msgs_array *msgs, char *command, char **program) +{ + int argp, i; + char **vec; + + vec = argsplit(command, program, &argp); + + /* + * Okay, we want to shuffle all of our arguments down so we have room + * for argp number of arguments. This means we need to know about + * msgs_array internals. If that changes, we need to change this + * code here. + */ + + if (msgs->size + argp >= msgs->max) { + msgs->max += MAXMSGS > argp ? MAXMSGS : argp; + msgs->msgs = mh_xrealloc(msgs->msgs, msgs->max * sizeof(*msgs->msgs)); + } + + for (i = msgs->size - 1; i >= 0; i--) + msgs->msgs[i + argp] = msgs->msgs[i]; + + msgs->size += argp; + + /* + * Now fill in the arguments at the beginning of the vector. + */ + + for (i = 0; i < argp; i++) + msgs->msgs[i] = vec[i]; + + free(vec); +} diff --git a/sbr/brkstring.c b/sbr/brkstring.c index 5375596d..bdc8c30a 100644 --- a/sbr/brkstring.c +++ b/sbr/brkstring.c @@ -59,7 +59,7 @@ brkstring (char *str, char *brksep, char *brkterm) if (!c || brkany (c, brkterm)) { *s = '\0'; broken[i] = NULL; - return broken; + break; } /* set next start addr */ @@ -69,7 +69,7 @@ brkstring (char *str, char *brksep, char *brkterm) ; /* empty body */ } - return broken; /* NOT REACHED */ + return broken; } diff --git a/sbr/discard.c b/sbr/discard.c index a1efa488..83b0bfbc 100644 --- a/sbr/discard.c +++ b/sbr/discard.c @@ -20,15 +20,7 @@ discard (FILE *io) tcflush (fileno(io), TCOFLUSH); -#if defined(_FSTDIO) || defined(__DragonFly__) - fpurge (io); -#else -# ifdef LINUX_STDIO - io->_IO_write_ptr = io->_IO_write_base; -# else - if ((io->_ptr = io->_base)) - io->_cnt = 0; -# endif -#endif + /* There used to be an fpurge() here on some platforms, stdio + hackery on others. But it didn't seem necessary. */ } diff --git a/sbr/dtimep.l b/sbr/dtimep.l index 29c4dd0c..bae6ac5c 100644 --- a/sbr/dtimep.l +++ b/sbr/dtimep.l @@ -126,7 +126,7 @@ static int day_map[] = { tw.tw_flags &= ~TW_SDAY; tw.tw_flags |= TW_SEXP; \ SKIPA(); } #define SETMON() { cp++; \ - tw.tw_mon = month_map[(cp[0] + cp[1]) & 0x1f]; \ + tw.tw_mon = month_map[(((unsigned char) cp[0]) + ((unsigned char) cp[1])) & 0x1f]; \ SKIPA(); } #define SETMON_NUM() { tw.tw_mon = atoi(cp)-1; \ SKIPD(); } @@ -146,17 +146,17 @@ static int day_map[] = { tw.tw_flags |= TW_SZEXP; \ SKIPD(); } #define SETDST() { tw.tw_flags |= TW_DST; } -#define SKIPD() { while ( isdigit(*cp++) ) ; \ +#define SKIPD() { while ( isdigit((unsigned char) *cp++) ) ; \ --cp; } -#define SKIPTOD() { while ( !isdigit(*cp++) ) ; \ +#define SKIPTOD() { while ( !isdigit((unsigned char) *cp++) ) ; \ --cp; } -#define SKIPA() { while ( isalpha(*cp++) ) ; \ +#define SKIPA() { while ( isalpha((unsigned char) *cp++) ) ; \ --cp; } -#define SKIPTOA() { while ( !isalpha(*cp++) ) ; \ +#define SKIPTOA() { while ( !isalpha((unsigned char) *cp++) ) ; \ --cp; } -#define SKIPSP() { while ( isspace(*cp++) ) ; \ +#define SKIPSP() { while ( isspace((unsigned char) *cp++) ) ; \ --cp; } -#define SKIPTOSP() { while ( !isspace(*cp++) ) ; \ +#define SKIPTOSP() { while ( !isspace((unsigned char) *cp++) ) ; \ --cp; } #ifdef ADJUST_NUMERIC_ONLY_TZ_OFFSETS_WRT_DST @@ -230,7 +230,7 @@ nl [ \t\n()] YY_BUFFER_STATE lexhandle; - register unsigned char *cp; + char *cp; static struct tws tw; memset(&tw,0,sizeof(struct tws)); diff --git a/sbr/ext_hook.c b/sbr/ext_hook.c index e94083b3..26f2c1c0 100644 --- a/sbr/ext_hook.c +++ b/sbr/ext_hook.c @@ -16,25 +16,27 @@ ext_hook(char *hook_name, char *message_file_name_1, char *message_file_name_2) char *hook; /* hook program from context */ pid_t pid; /* ID of child process */ int status; /* exit or other child process status */ - char *vec[4]; /* argument vector for child process */ + char **vec; /* argument vector for child process */ + int vecp; /* Vector index */ + char *program; /* Name of program to execute */ static int did_message = 0; /* set if we've already output a message */ if ((hook = context_find(hook_name)) == (char *)0) return (OK); - switch (pid = vfork()) { + switch (pid = fork()) { case -1: status = NOTOK; advise(NULL, "external database may be out-of-date."); break; case 0: - vec[0] = r1bindex(hook, '/'); - vec[1] = message_file_name_1; - vec[2] = message_file_name_2; - vec[3] = (char *)0; - execvp(hook, vec); + vec = argsplit(hook, &program, &vecp); + vec[vecp++] = message_file_name_1; + vec[vecp++] = message_file_name_2; + vec[vecp++] = NULL; + execvp(program, vec); _exit(-1); /* NOTREACHED */ diff --git a/sbr/fmt_compile.c b/sbr/fmt_compile.c index 9ef39467..0fd83d1e 100644 --- a/sbr/fmt_compile.c +++ b/sbr/fmt_compile.c @@ -270,7 +270,7 @@ static struct ftable functable[] = { #define PUTC(c) do { NEW(FT_CHAR,0,0); fp->f_char = (c); } while (0) static char *format_string; -static unsigned char *usr_fstring; /* for CERROR */ +static char *usr_fstring; /* for CERROR */ #define CERROR(str) compile_error (str, cp) @@ -321,7 +321,7 @@ compile_error(char *str, char *cp) for (i = errpos-errctx; i < errpos; i++) { #ifdef LOCALE - if (iscntrl(usr_fstring[i])) + if (iscntrl((unsigned char) usr_fstring[i])) #else if (usr_fstring[i] < 32) #endif diff --git a/sbr/fmt_scan.c b/sbr/fmt_scan.c index e654b15e..dad7a3c6 100644 --- a/sbr/fmt_scan.c +++ b/sbr/fmt_scan.c @@ -50,13 +50,24 @@ match (char *str, char *sub) #ifdef LOCALE while ((c1 = *sub)) { - c1 = (isalpha(c1) && isupper(c1)) ? tolower(c1) : c1; - while ((c2 = *str++) && c1 != ((isalpha(c2) && isupper(c2)) ? tolower(c2) : c2)) + c1 = (isascii((unsigned char) c1) && isalpha((unsigned char) c1) && + isupper((unsigned char) c1)) ? tolower((unsigned char) c1) : c1; + while ((c2 = *str++) && c1 != ((isascii((unsigned char) c2) && + isalpha((unsigned char) c2) && + isupper((unsigned char) c2)) ? + tolower((unsigned char) c2) : c2)) ; if (! c2) return 0; s1 = sub + 1; s2 = str; - while ((c1 = *s1++) && ((isalpha(c1) && isupper(c1)) ? tolower(c1) : c1) == ((isalpha(c2 =*s2++) && isupper(c2)) ? tolower(c2) : c2)) + while ((c1 = *s1++) && ((isascii((unsigned char) c1) && + isalpha((unsigned char) c1) && + isupper((unsigned char) c1)) ? + tolower(c1) : c1) == + ((isascii((unsigned char) (c2 =*s2++)) && + isalpha((unsigned char) c2) && + isupper((unsigned char) c2)) ? + tolower((unsigned char) c2) : c2)) ; if (! c1) return 1; @@ -114,8 +125,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 +137,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 +146,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; @@ -161,7 +180,7 @@ cptrimmed(char **dest, char *str, unsigned int wid, char fill, size_t n, end--; /* isnctrl(), etc., take an int argument. Cygwin's ctype.h intentionally warns if they are passed a char. */ - c = *sp; + c = (unsigned char) *sp; if (iscntrl(c) || isspace(c)) { sp++; #endif @@ -176,7 +195,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 +209,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 +222,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 +255,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); + w = wcwidth(wide_char); - /* 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; + /* + * 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; @@ -254,7 +277,7 @@ cpstripped (char **dest, char *end, char *max, char *str) if (iswcntrl(wide_char) || iswspace(wide_char)) { str += char_len; #else /* MULTIBYTE_SUPPORT */ - int c = *str; + int c = (unsigned char) *str; len--; if (iscntrl(c) || isspace(c)) { str++; @@ -331,10 +354,8 @@ struct format * fmt_scan (struct format *format, char *scanl, size_t max, int width, int *dat, struct fmt_callbacks *callbacks) { - char *cp, *ep; - unsigned char *sp; - char *savestr = NULL; - unsigned char *str = NULL; + char *cp, *ep, *sp; + char *savestr = NULL, *str = NULL; char buffer[BUFSIZ], buffer2[BUFSIZ]; int i, c, ljust, n; int value = 0; @@ -385,11 +406,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: @@ -412,11 +433,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; @@ -584,12 +605,12 @@ fmt_scan (struct format *format, char *scanl, size_t max, int width, int *dat, case FT_LS_TRIM: if (str) { - unsigned char *xp; + char *xp; strncpy(buffer, str, sizeof(buffer)); buffer[sizeof(buffer)-1] = '\0'; str = buffer; - while (isspace(*str)) + while (isspace((unsigned char) *str)) str++; ljust = 0; if ((i = fmt->f_width) < 0) { @@ -601,7 +622,7 @@ fmt_scan (struct format *format, char *scanl, size_t max, int width, int *dat, str[i] = '\0'; xp = str; xp += strlen(str) - 1; - while (xp > str && isspace(*xp)) + while (xp > str && isspace((unsigned char) *xp)) *xp-- = '\0'; if (ljust && i > 0 && (int) strlen(str) > i) str += strlen(str) - i; @@ -903,8 +924,7 @@ fmt_scan (struct format *format, char *scanl, size_t max, int width, int *dat, * (e.g., "To: ") */ { - unsigned char *lp; - char *lastb; + char *lp, *lastb; int indent, wid, len; lp = str; @@ -917,21 +937,22 @@ fmt_scan (struct format *format, char *scanl, size_t max, int width, int *dat, adios(NULL, "putaddr -- num register (%d) must be greater " "than label width (%d)", value, indent); } - while( (c = *sp++) && cp < ep) - *cp++ = c; + while( (c = (unsigned char) *sp++) && cp < ep) + *cp++ = (char) c; while (len > wid) { /* try to break at a comma; failing that, break at a * space. */ lastb = 0; sp = lp + wid; - while (sp > lp && (c = *--sp) != ',') { + while (sp > lp && (c = (unsigned char) *--sp) != ',') { if (! lastb && isspace(c)) lastb = sp - 1; } if (sp == lp) { if (! (sp = lastb)) { sp = lp + wid - 1; - while (*sp && *sp != ',' && !isspace(*sp)) + while (*sp && *sp != ',' && + !isspace((unsigned char) *sp)) sp++; if (*sp != ',') sp--; @@ -940,7 +961,7 @@ fmt_scan (struct format *format, char *scanl, size_t max, int width, int *dat, len -= sp - lp + 1; while (cp < ep && lp <= sp) *cp++ = *lp++; - while (isspace(*lp)) + while (isspace((unsigned char) *lp)) lp++, len--; if (*lp) { if (cp < ep) @@ -949,7 +970,7 @@ fmt_scan (struct format *format, char *scanl, size_t max, int width, int *dat, *cp++ = ' '; } } - cpstripped (&cp, ep, scanl + max - 1, lp); + cpstripped (&cp, &ep, scanl + max - 1, lp); } break; diff --git a/sbr/folder_delmsgs.c b/sbr/folder_delmsgs.c index c1416a6f..7431b62e 100644 --- a/sbr/folder_delmsgs.c +++ b/sbr/folder_delmsgs.c @@ -24,7 +24,7 @@ folder_delmsgs (struct msgs *mp, int unlink_msgs, int nohook) { pid_t pid; int msgnum, vecp, retval = 0; - char buf[100], *dp, **vec; + char buf[100], *dp, **vec, *prog; char msgpath[BUFSIZ]; /* @@ -40,10 +40,18 @@ folder_delmsgs (struct msgs *mp, int unlink_msgs, int nohook) /* Mark that the sequence information has changed */ mp->msgflags |= SEQMOD; - vec = (char **) calloc ((size_t) (mp->numsel + 2), sizeof(*vec)); + vec = argsplit(rmmproc, &prog, &vecp); + + /* + * argsplit allocates a MAXARGS vector by default, If we need + * something bigger, allocate it ourselves + */ + + if (mp->numsel + vecp + 1 > MAXARGS) + vec = (char **) realloc (vec, (size_t) ((mp->numsel + vecp + 1) * + sizeof(*vec))); if (vec == NULL) adios (NULL, "unable to allocate exec vector"); - vecp = 1; for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) { if (is_selected (mp, msgnum) && !(vec[vecp++] = strdup (m_name (msgnum)))) @@ -52,20 +60,20 @@ folder_delmsgs (struct msgs *mp, int unlink_msgs, int nohook) vec[vecp] = NULL; fflush (stdout); - vec[0] = r1bindex (rmmproc, '/'); - switch (pid = vfork()) { + switch (pid = fork()) { case -1: advise ("fork", "unable to"); return -1; case 0: - execvp (rmmproc, vec); + execvp (prog, vec); fprintf (stderr, "unable to exec "); perror (rmmproc); _exit (-1); default: + arglist_free(prog, vec); return (pidwait (pid, -1)); } } diff --git a/sbr/m_atoi.c b/sbr/m_atoi.c index 174c4077..f05271f7 100644 --- a/sbr/m_atoi.c +++ b/sbr/m_atoi.c @@ -16,11 +16,11 @@ int m_atoi (char *str) { int i; - unsigned char *cp; + char *cp; for (i = 0, cp = str; *cp; cp++) { #ifdef LOCALE - if (!isdigit(*cp)) + if (!isdigit((unsigned char) *cp)) #else if (*cp < '0' || *cp > '9') #endif diff --git a/sbr/m_convert.c b/sbr/m_convert.c index 496978ee..56b63233 100644 --- a/sbr/m_convert.c +++ b/sbr/m_convert.c @@ -38,8 +38,7 @@ int m_convert (struct msgs *mp, char *name) { int first, last, found, range, err; - unsigned char *bp; - char *cp; + char *bp, *cp; /* check if user defined sequence */ err = attr (mp, cp = name); @@ -141,7 +140,7 @@ rangerr: } if ((range = atoi (bp = cp)) == 0) goto badlist; - while (isdigit (*bp)) + while (isdigit ((unsigned char) *bp)) bp++; if (*bp) goto badelim; @@ -250,14 +249,14 @@ single: static int m_conv (struct msgs *mp, char *str, int call) { - register int i; - register unsigned char *cp, *bp; - unsigned char buf[16]; + int i; + char *cp, *bp; + char buf[16]; convdir = 1; cp = bp = str; - if (isdigit (*cp)) { - while (isdigit (*bp)) + if (isdigit ((unsigned char) *cp)) { + while (isdigit ((unsigned char) *bp)) bp++; delimp = bp; i = atoi (cp); @@ -274,7 +273,7 @@ m_conv (struct msgs *mp, char *str, int call) #ifdef LOCALE /* doesn't enforce lower case */ - for (bp = buf; (isalpha(*cp) || *cp == '.') + for (bp = buf; (isalpha((unsigned char) *cp) || *cp == '.') && (bp - buf < (int) sizeof(buf) - 1); ) #else for (bp = buf; ((*cp >= 'a' && *cp <= 'z') || *cp == '.') @@ -337,9 +336,9 @@ m_conv (struct msgs *mp, char *str, int call) static int attr (struct msgs *mp, char *cp) { - register unsigned char *dp; + char *dp; char *bp = NULL; - register int i, j; + int i, j; int found, inverted = 0, range = 0, /* no range */ @@ -359,7 +358,7 @@ attr (struct msgs *mp, char *cp) convdir = 1; /* convert direction */ - for (dp = cp; *dp && isalnum(*dp); dp++) + for (dp = cp; *dp && isalnum((unsigned char) *dp); dp++) continue; if (*dp == ':') { @@ -372,7 +371,7 @@ attr (struct msgs *mp, char *cp) * seq:first (or) * seq:last */ - if (isalpha (*dp)) { + if (isalpha ((unsigned char) *dp)) { if (!strcmp (dp, "prev")) { convdir = -1; first = (mp->curmsg > 0) && (mp->curmsg <= mp->hghmsg) @@ -407,7 +406,7 @@ attr (struct msgs *mp, char *cp) } if ((range = atoi(dp)) == 0) return BADLST; - while (isdigit (*dp)) + while (isdigit ((unsigned char) *dp)) dp++; if (*dp) return BADLST; diff --git a/sbr/m_getfld.c b/sbr/m_getfld.c index e139505a..c6716284 100644 --- a/sbr/m_getfld.c +++ b/sbr/m_getfld.c @@ -11,6 +11,75 @@ #include #include +/* + Purpose + ======= + Reads an Internet message (RFC 5322), or one or more messages + stored in a maildrop in mbox (RFC 4155) or MMDF format, from a file + stream. Each call to m_getfld() reads one header field, or a + portion of the body, in sequence. + + Inputs + ====== + gstate: opaque parse state + bufsz: maximum number of characters to load into buf + iob: input file stream + + Outputs + ======= + name: header field name (array of size NAMESZ=999) + buf: either a header field body or message body + bufsz: number of characters loaded into buf + (return value): message parse state on return from function + + Functions + ========= + void m_getfld_state_destroy (m_getfld_state_t *gstate): destroys + the parse state pointed to by the gstate argument. + + m_getfld_state_reset (m_getfld_state_t *gstate): resets the parse + state to FLD. + + void m_unknown(FILE *iob): Determines the message delimiter string + for the maildrop. Called by inc, scan, and msh when reading from a + maildrop file. + + void m_eomsbr (int (*action)(int)): Sets the hook to check for end + of message in a maildrop. Called only by msh. + + State variables + =============== + m_getfld() retains state internally between calls in the + m_getfld_state_t variable. These are used for detecting the end of + each message when reading maildrops: + + char **pat_map + char *fdelim + char *delimend + int fdelimlen + char *edelim + int edelimlen + char *msg_delim + int msg_style + int (*eom_action)(int) + + Usage + ===== + m_getfld_state_t gstate = 0; + ... + int state = m_getfld (&gstate, ...); + ... + m_getfld_state_destroy (&gstate); + + The state is retained internally by gstate. To reset its state to FLD: + m_getfld_state_reset (&gstate); +*/ + +/* The following described the old implementation. The high-level + structure hasn't changed, but some of the details have. I'm + leaving this as-is, though, for posterity. + */ + /* This module has a long and checkered history. First, it didn't burst maildrops correctly because it considered two CTRL-A:s in a row to be an inter-message delimiter. It really is four CTRL-A:s followed by a @@ -125,7 +194,7 @@ it knows that _filbuf ignores the _ptr & _cnt and simply fills the buffer. If stdio on your system doesn't work this way, you may have to make small changes in this routine. - + This routine also "knows" that an EOF indication on a stream is "sticky" (i.e., you will keep getting EOF until you reposition the stream). If your system doesn't work this way it is broken and you @@ -134,358 +203,466 @@ there is data in "name" or "buf"). */ - /* * static prototypes */ -static int m_Eom (int, FILE *); -static unsigned char *matchc(int, char *, int, char *); -static unsigned char *locc(int, unsigned char *, unsigned char); - -#define Getc(iob) getc(iob) -#define eom(c,iob) (msg_style != MS_DEFAULT && \ - (((c) == *msg_delim && m_Eom(c,iob)) ||\ - (eom_action && (*eom_action)(c)))) +struct m_getfld_state; +static int m_Eom (m_getfld_state_t, int); +static char *matchc(int, char *, int, char *); -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 { + char msg_buf[2 * MSG_INPUT_SIZE + MAX_DELIMITER_SIZE]; + char *readpos; + 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; + + 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; + char *fdelim; + char *delimend; + int fdelimlen; + 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; +} + +/* The return values of the following functions are a bit + subtle. They can return 0x00 - 0xff as a valid character, + but EOF is typically 0xffffffff. */ +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 ? (unsigned char) *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 ? (unsigned char) *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 = (unsigned char) c; + } +} int -m_getfld (int state, unsigned char *name, unsigned char *buf, - int bufsz, FILE *iob) +m_getfld (m_getfld_state_t *gstate, char name[NAMESZ], 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 char *cp; + register int max, n, c; + + enter_getfld (gstate, iob); + s = *gstate; - if ((c = Getc(iob)) < 0) { - msg_count = 0; - *buf = 0; - return FILEEOF; + 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 ((unsigned char) *--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) { + 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 +675,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 ))) + char *ep; + + if ((ep = matchc( s->fdelimlen, s->fdelim, c, bp ))) c = ep - bp + 1; else { /* @@ -514,8 +693,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. */ + char *sp; + ep = bp + c - 1; - if ((sp = pat_map[*ep])) { + if ((sp = s->pat_map[(unsigned char) *ep])) { do { /* This if() is true unless (a) the buffer is too * small to contain this delimiter prefix, or @@ -527,7 +708,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 +716,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 +729,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 +784,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 = mh_xmalloc (c + 3); + *s->fdelim++ = '\0'; + *s->fdelim = '\n'; + s->msg_delim = s->fdelim+1; + s->edelim = s->msg_delim+1; + s->fdelimlen = c + 1; + s->edelimlen = c - 1; /* == strlen (delimstr) */ + strcpy (s->msg_delim, delimstr); + s->delimend = 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 +820,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 = (char **) calloc (256, sizeof(char *)); - for (cp = (char *) fdelim + 1; cp < (char *) delimend; cp++ ) - pat_map[(unsigned char)*cp] = (unsigned char *) cp; + for (cp = s->fdelim + 1; cp < s->delimend; cp++ ) + s->pat_map[(unsigned char)*cp] = 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 = s->fdelim + 1; + s->fdelimlen = strlen (s->fdelim); + s->delimend = s->msg_delim + s->edelimlen; } } @@ -673,32 +859,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; + + for (i = 0, cp = text; i < s->edelimlen; ++i, ++cp) { + if ((*cp = Getc (s)) == EOF) { + break; + } + } - pos = ftell (iob); - if ((i = fread (text, sizeof *text, edelimlen, iob)) != edelimlen - || strncmp (text, (char *)edelim, edelimlen)) { - if (i == 0 && msg_style == MS_MBOX) + 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; } @@ -707,7 +896,7 @@ m_Eom (int c, FILE *iob) } -static unsigned char * +static char * matchc(int patln, char *pat, int strln, char *str) { register char *es = str + strln - patln; @@ -725,22 +914,7 @@ matchc(int patln, char *pat, int strln, char *str) sp = str; pp = pat; while (pp < ep && *sp++ == *pp) pp++; - if (pp >= ep) - return ((unsigned char *)--str); + if (pp >= ep) + return --str; } } - - -/* - * Locate character "term" in the next "cnt" characters of "src". - * If found, return its address, otherwise return 0. - */ - -static unsigned char * -locc(int cnt, unsigned char *src, unsigned char term) -{ - while (*src++ != term && --cnt > 0); - - return (cnt > 0 ? --src : (unsigned char *)0); -} - diff --git a/sbr/m_msgdef.c b/sbr/m_msgdef.c deleted file mode 100644 index d6029736..00000000 --- a/sbr/m_msgdef.c +++ /dev/null @@ -1,33 +0,0 @@ - -/* - * m_msgdef.c -- some defines for sbr/m_getfld.c - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ - -#include - -/* - * disgusting hack for "inc" so it can know how many characters - * were stuffed in the buffer on the last call (see comments - * in uip/scansbr.c) - */ -int msg_count = 0; - -int msg_style = MS_DEFAULT; - -/* - * The "full" delimiter string for a packed maildrop consists - * of a newline followed by the actual delimiter. E.g., the - * full string for a Unix maildrop would be: "\n\nFrom ". - * "Fdelim" points to the start of the full string and is used - * in the BODY case of the main routine to search the buffer for - * a possible eom. Msg_delim points to the first character of - * the actual delim. string (i.e., fdelim+1). Edelim - * points to the 2nd character of actual delimiter string. It - * is used in m_Eom because the first character of the string - * has been read and matched before m_Eom is called. - */ -char *msg_delim = ""; diff --git a/sbr/makedir.c b/sbr/makedir.c index 4337b7ce..98a5d7f3 100644 --- a/sbr/makedir.c +++ b/sbr/makedir.c @@ -85,7 +85,7 @@ makedir (char *dir) nested directories like the above code can. -- Dan Harkless */ - switch (pid = vfork()) { + switch (pid = fork()) { case -1: advise ("fork", "unable to"); return 0; @@ -94,8 +94,8 @@ makedir (char *dir) setgid (getgid ()); setuid (getuid ()); - execl ("/bin/mkdir", "mkdir", dir, NULL); - execl ("/usr/bin/mkdir", "mkdir", dir, NULL); + execl ("/bin/mkdir", "mkdir", dir, (void *) NULL); + execl ("/usr/bin/mkdir", "mkdir", dir, (void *) NULL); fprintf (stderr, "unable to exec "); perror ("mkdir"); _exit (-1); diff --git a/sbr/mf.c b/sbr/mf.c index fd92e369..37fcf7b9 100644 --- a/sbr/mf.c +++ b/sbr/mf.c @@ -16,7 +16,6 @@ * static prototypes */ static char *getcpy (char *); -static void compress (char *, unsigned char *); static int isat (char *); static int parse_address (void); static int phrase (char *); @@ -55,14 +54,16 @@ isfrom(char *string) int -lequal (unsigned char *a, unsigned char *b) +lequal (char *a, char *b) { for (; *a; a++, b++) if (*b == 0) return FALSE; else { - char c1 = islower (*a) ? toupper (*a) : *a; - char c2 = islower (*b) ? toupper (*b) : *b; + char c1 = islower ((unsigned char) *a) ? + toupper ((unsigned char) *a) : *a; + char c2 = islower ((unsigned char) *b) ? + toupper ((unsigned char) *b) : *b; if (c1 != c2) return FALSE; } @@ -71,158 +72,6 @@ lequal (unsigned char *a, unsigned char *b) } -/* - * seekadrx() is tricky. We want to cover both UUCP-style and ARPA-style - * addresses, so for each list of addresses we see if we can find some - * character to give us a hint. - */ - - -#define CHKADR 0 /* undertermined address style */ -#define UNIXDR 1 /* UNIX-style address */ -#define ARPADR 2 /* ARPAnet-style address */ - - -static char *punctuators = ";<>.()[]"; -static char *vp = NULL; -static char *tp = NULL; - -static struct adrx adrxs1; - - -struct adrx * -seekadrx (char *addrs) -{ - static int state = CHKADR; - register char *cp; - register struct adrx *adrxp; - - if (state == CHKADR) - for (state = UNIXDR, cp = addrs; *cp; cp++) - if (strchr(punctuators, *cp)) { - state = ARPADR; - break; - } - - switch (state) { - case UNIXDR: - adrxp = uucpadrx (addrs); - break; - - case ARPADR: - default: - adrxp = getadrx (addrs); - break; - } - - if (adrxp == NULL) - state = CHKADR; - - return adrxp; -} - - -/* - * uucpadrx() implements a partial UUCP-style address parser. It's based - * on the UUCP notion that addresses are separated by spaces or commas. - */ - - -struct adrx * -uucpadrx (char *addrs) -{ - register unsigned char *cp, *wp, *xp, *yp; - register char *zp; - register struct adrx *adrxp = &adrxs1; - - if (vp == NULL) { - vp = tp = getcpy (addrs); - compress (addrs, vp); - } - else - if (tp == NULL) { - free (vp); - vp = NULL; - return NULL; - } - - for (cp = tp; isspace (*cp); cp++) - continue; - if (*cp == 0) { - free (vp); - vp = tp = NULL; - return NULL; - } - - if ((wp = strchr(cp, ',')) == NULL) { - if ((wp = strchr(cp, ' ')) != NULL) { - xp = wp; - while (isspace (*xp)) - xp++; - if (*xp != 0 && isat (--xp)) { - yp = xp + 4; - while (isspace (*yp)) - yp++; - if (*yp != 0) { - if ((zp = strchr(yp, ' ')) != NULL) - *zp = 0, tp = ++zp; - else - tp = NULL; - } - else - *wp = 0, tp = ++wp; - } - else - *wp = 0, tp = ++wp; - } - else - tp = NULL; - } - else - *wp = 0, tp = ++wp; - - if (adrxp->text) - free (adrxp->text); - adrxp->text = getcpy (cp); - adrxp->mbox = cp; - adrxp->host = adrxp->path = NULL; - if ((wp = strrchr(cp, '@')) != NULL) { - *wp++ = 0; - adrxp->host = *wp ? wp : NULL; - } - else - for (wp = cp + strlen (cp) - 4; wp >= cp; wp--) - if (isat (wp)) { - *wp++ = 0; - adrxp->host = wp + 3; - } - - adrxp->pers = adrxp->grp = adrxp->note = adrxp->err = NULL; - adrxp->ingrp = 0; - - return adrxp; -} - - -static void -compress (char *fp, unsigned char *tp) -{ - register char c; - register unsigned char *cp; - - for (c = ' ', cp = tp; (*tp = *fp++) != 0;) - if (isspace (*tp)) { - if (c != ' ') - *tp++ = c = ' '; - } - else - c = *tp++; - - if (c == ' ' && cp < tp) - *--tp = 0; -} - - static int isat (char *p) { @@ -333,8 +182,8 @@ static int ingrp = 0; static int last_lex = LX_END; static char *dp = NULL; -static unsigned char *cp = NULL; -static unsigned char *ap = NULL; +static char *cp = NULL; +static char *ap = NULL; static char *pers = NULL; static char *mbox = NULL; static char *host = NULL; @@ -416,7 +265,7 @@ getadrx (char *addrs) } break; } - while (isspace (*ap)) + while (isspace ((unsigned char) *ap)) ap++; if (cp) sprintf (adr, "%.*s", (int)(cp - ap), ap); @@ -759,8 +608,7 @@ my_lex (char *buffer) { /* buffer should be at least BUFSIZ bytes long */ int i, gotat = 0; - register unsigned char c; - register char *bp; + char c, *bp; /* Add C to the buffer bp. After use of this macro *bp is guaranteed to be within the buffer. */ #define ADDCHR(C) do { *bp++ = (C); if ((bp - buffer) == (BUFSIZ-1)) goto my_lex_buffull; } while (0) @@ -772,7 +620,7 @@ my_lex (char *buffer) gotat = isat (cp); c = *cp++; - while (isspace (c)) + while (isspace ((unsigned char) c)) c = *cp++; if (c == 0) { cp = NULL; @@ -862,7 +710,7 @@ my_lex (char *buffer) if (c == special[i].lx_chr) return (last_lex = special[i].lx_val); - if (iscntrl (c)) + if (iscntrl ((unsigned char) c)) return (last_lex = LX_ERR); for (;;) { @@ -871,7 +719,7 @@ my_lex (char *buffer) for (i = 0; special[i].lx_chr != 0; i++) if (c == special[i].lx_chr) goto got_atom; - if (iscntrl (c) || isspace (c)) + if (iscntrl ((unsigned char) c) || isspace ((unsigned char) c)) break; ADDCHR(c); } diff --git a/sbr/mts.c b/sbr/mts.c index bf7d42b1..03578288 100644 --- a/sbr/mts.c +++ b/sbr/mts.c @@ -23,7 +23,7 @@ /* * static prototypes */ -static char *tailor_value (unsigned char *); +static char *tailor_value (char *); static void getuserinfo (void); static const char *get_mtsconf_pathname(void); static const char *get_mtsuserconf_pathname(void); @@ -177,7 +177,7 @@ mts_init (char *name) */ static char * -tailor_value (unsigned char *s) +tailor_value (char *s) { int i, r; char *bp; @@ -200,13 +200,13 @@ tailor_value (unsigned char *s) break; default: - if (!isdigit (*s)) { + if (!isdigit ((unsigned char) *s)) { *bp++ = QUOTE; *bp = *s; } - r = *s != '0' ? 10 : 8; - for (i = 0; isdigit (*s); s++) - i = i * r + *s - '0'; + r = ((unsigned char) *s) != '0' ? 10 : 8; + for (i = 0; isdigit ((unsigned char) *s); s++) + i = i * r + ((unsigned char) *s) - '0'; s--; *bp = toascii (i); break; @@ -359,9 +359,8 @@ getlocalmbox (void) static void getuserinfo (void) { - register unsigned char *cp; - register char *np; - register struct passwd *pw; + char *cp, *np; + struct passwd *pw; if ((pw = getpwuid (getuid ())) == NULL || pw->pw_name == NULL @@ -461,8 +460,7 @@ get_mtsuserconf_pathname (void) static void mts_read_conf_file (FILE *fp) { - unsigned char *bp; - char *cp, buffer[BUFSIZ]; + char *bp, *cp, buffer[BUFSIZ]; struct bind *b; while (fgets (buffer, sizeof(buffer), fp)) { @@ -474,7 +472,7 @@ mts_read_conf_file (FILE *fp) if (!(bp = strchr(buffer, ':'))) break; *bp++ = 0; - while (isspace (*bp)) + while (isspace ((unsigned char) *bp)) *bp++ = 0; for (b = binds; b->keyword; b++) diff --git a/sbr/readconfig.c b/sbr/readconfig.c index 1ddd648f..be458239 100644 --- a/sbr/readconfig.c +++ b/sbr/readconfig.c @@ -23,7 +23,6 @@ static struct procstr procs[] = { { "fileproc", &fileproc }, { "formatproc", &formatproc }, { "incproc", &incproc }, - { "installproc", &installproc }, { "lproc", &lproc }, { "mailproc", &mailproc }, { "mhlproc", &mhlproc }, @@ -52,17 +51,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 +70,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 +90,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 +103,7 @@ readconfig (struct node **npp, FILE *ib, char *file, int ctx) } break; } + m_getfld_state_destroy (&gstate); /* * Special handling for the pager processes: lproc and moreproc. diff --git a/sbr/refile.c b/sbr/refile.c index fc2793c6..c675500f 100644 --- a/sbr/refile.c +++ b/sbr/refile.c @@ -15,15 +15,16 @@ int refile (char **arg, char *file) { pid_t pid; - register int vecp; - char *vec[MAXARGS]; + int vecp; + char **vec; + char *program; - vecp = 0; - vec[vecp++] = r1bindex (fileproc, '/'); - vec[vecp++] = "-nolink"; /* override bad .mh_profile defaults */ - vec[vecp++] = "-nopreserve"; - vec[vecp++] = "-file"; - vec[vecp++] = file; + vec = argsplit(fileproc, &program, &vecp); + + vec[vecp++] = getcpy("-nolink"); /* override bad .mh_profile defaults */ + vec[vecp++] = getcpy("-nopreserve"); + vec[vecp++] = getcpy("-file"); + vec[vecp++] = getcpy(file); if (arg) { while (*arg) @@ -34,18 +35,19 @@ refile (char **arg, char *file) context_save(); /* save the context file */ fflush(stdout); - switch (pid = vfork()) { + switch (pid = fork()) { case -1: advise ("fork", "unable to"); return -1; case 0: - execvp (fileproc, vec); + execvp (program, vec); fprintf (stderr, "unable to exec "); perror (fileproc); _exit (-1); default: + arglist_free(program, vec); return (pidwait (pid, -1)); } } diff --git a/sbr/seq_nameok.c b/sbr/seq_nameok.c index 6887ac6a..328bd5c2 100644 --- a/sbr/seq_nameok.c +++ b/sbr/seq_nameok.c @@ -11,9 +11,9 @@ int -seq_nameok (unsigned char *s) +seq_nameok (char *s) { - unsigned char *pp; + char *pp; if (s == NULL || *s == '\0') { advise (NULL, "empty sequence name"); @@ -38,7 +38,7 @@ seq_nameok (unsigned char *s) * First character in a sequence name must be * an alphabetic character ... */ - if (!isalpha (*s)) { + if (!isalpha ((unsigned char) *s)) { advise (NULL, "illegal sequence name: %s", s); return 0; } @@ -47,7 +47,7 @@ seq_nameok (unsigned char *s) * and can be followed by zero or more alphanumeric characters */ for (pp = s + 1; *pp; pp++) - if (!isalnum (*pp)) { + if (!isalnum ((unsigned char) *pp)) { advise (NULL, "illegal sequence name: %s", s); return 0; } diff --git a/sbr/seq_read.c b/sbr/seq_read.c index 985c61e8..a807ef7d 100644 --- a/sbr/seq_read.c +++ b/sbr/seq_read.c @@ -59,6 +59,7 @@ seq_public (struct msgs *mp) char *cp, seqfile[PATH_MAX]; char name[NAMESZ], field[BUFSIZ]; FILE *fp; + m_getfld_state_t gstate = 0; /* * If mh_seq == NULL (such as if nmh been compiled with @@ -76,15 +77,16 @@ seq_public (struct msgs *mp) return; /* Use m_getfld to scan sequence file */ - for (state = FLD;;) { - switch (state = m_getfld (state, name, field, sizeof(field), fp)) { + for (;;) { + int fieldsz = sizeof field; + switch (state = m_getfld (&gstate, name, field, &fieldsz, fp)) { case FLD: case FLDPLUS: - case FLDEOF: if (state == FLDPLUS) { cp = getcpy (field); while (state == FLDPLUS) { - state = m_getfld (state, name, field, sizeof(field), fp); + fieldsz = sizeof field; + state = m_getfld (&gstate, name, field, &fieldsz, fp); cp = add (field, cp); } seq_init (mp, getcpy (name), trimcpy (cp)); @@ -92,12 +94,9 @@ seq_public (struct msgs *mp) } else { seq_init (mp, getcpy (name), trimcpy (field)); } - if (state == FLDEOF) - break; continue; case BODY: - case BODYEOF: adios (NULL, "no blank lines are permitted in %s", seqfile); /* fall */ @@ -109,6 +108,7 @@ seq_public (struct msgs *mp) } break; /* break from for loop */ } + m_getfld_state_destroy (&gstate); lkfclose (fp, seqfile); } diff --git a/sbr/showfile.c b/sbr/showfile.c index 59ae7952..1d4bd17f 100644 --- a/sbr/showfile.c +++ b/sbr/showfile.c @@ -15,7 +15,8 @@ showfile (char **arg, char *file) { pid_t pid; int isdraft, vecp; - char *vec[MAXARGS]; + char **vec, *program; + int retval = 1; context_save(); /* save the context file */ fflush(stdout); @@ -28,16 +29,15 @@ showfile (char **arg, char *file) if (!strcmp (r1bindex (lproc, '/'), "mhl")) lproc = mhlproc; - switch (pid = vfork()) { + switch (pid = fork()) { case -1: /* fork error */ advise ("fork", "unable to"); - return 1; + break; case 0: /* child */ - vecp = 0; - vec[vecp++] = r1bindex (lproc, '/'); + vec = argsplit(lproc, &program, &vecp); isdraft = 1; if (arg) { while (*arg) { @@ -53,15 +53,15 @@ showfile (char **arg, char *file) } vec[vecp] = NULL; - execvp (lproc, vec); + execvp (program, vec); fprintf (stderr, "unable to exec "); perror (lproc); _exit (-1); default: /* parent */ - return (pidwait (pid, -1) & 0377 ? 1 : 0); + retval = pidwait (pid, -1) & 0377 ? 1 : 0; } - return 1; /* NOT REACHED */ + return retval; } diff --git a/sbr/strcasecmp.c b/sbr/strcasecmp.c index 04aad7d3..c48c9d4c 100644 --- a/sbr/strcasecmp.c +++ b/sbr/strcasecmp.c @@ -24,9 +24,9 @@ mh_strcasecmp (const char *s1, const char *s2) us2 = (const unsigned char *) s2; if (!us1) - us1 = ""; + us1 = (const unsigned char *) ""; if (!us2) - us2 = ""; + us2 = (const unsigned char *) ""; while (tolower(*us1) == tolower(*us2++)) if (*us1++ == '\0') diff --git a/sbr/trimcpy.c b/sbr/trimcpy.c index b640ea6f..3a2fbd76 100644 --- a/sbr/trimcpy.c +++ b/sbr/trimcpy.c @@ -13,17 +13,17 @@ char * -trimcpy (unsigned char *cp) +trimcpy (char *cp) { - unsigned char *sp; + char *sp; /* skip over leading whitespace */ - while (isspace(*cp)) + while (isspace((unsigned char) *cp)) cp++; /* start at the end and zap trailing whitespace */ for (sp = cp + strlen(cp) - 1; sp >= cp; sp--) { - if (isspace(*sp)) + if (isspace((unsigned char) *sp)) *sp = '\0'; else break; @@ -31,7 +31,7 @@ trimcpy (unsigned char *cp) /* replace remaining whitespace with spaces */ for (sp = cp; *sp; sp++) { - if (isspace(*sp)) + if (isspace((unsigned char) *sp)) *sp = ' '; } diff --git a/test/bad-input/test-header b/test/bad-input/test-header index 9e66296d..e993cce8 100755 --- a/test/bad-input/test-header +++ b/test/bad-input/test-header @@ -1,10 +1,12 @@ #!/bin/sh ###################################################### # -# Test bogus headers (no blank line before body). +# Test bogus headers (no blank line before body, etc.) # ###################################################### +set -e + if test -z "${MH_OBJ_DIR}"; then srcdir=`dirname "$0"`/../.. MH_OBJ_DIR=`cd "$srcdir" && pwd`; export MH_OBJ_DIR @@ -14,13 +16,14 @@ fi setup_test -expected=$MH_TEST_DIR/$$.expected -actual=$MH_TEST_DIR/$$.actual +expected="$MH_TEST_DIR/$$.expected" +expected_err="$MH_TEST_DIR/$$.expected_err" +actual="$MH_TEST_DIR/$$.actual" +actual_err="$MH_TEST_DIR/$$.actual_err" # Write message with bogus header field (missing blank line, really). -msgfile=`mhpath new` -msgnum=`basename $msgfile` -cat > $msgfile <"$msgfile" < $expected <"$expected" < $actual 2>&1 -check $expected $actual +scan -width 80 last > "$actual" 2>&1 +check "$expected" "$actual" # check show (mhl) -cat > $expected <"$expected" < $actual 2>&1 -check $expected $actual +show last > "$actual" 2>&1 +check "$expected" "$actual" # check mhshow -cat > $expected <"$expected" < $actual 2>&1 -check $expected $actual +mhshow -nopause last > "$actual" 2>&1 +check "$expected" "$actual" + +# check m_getfld() handling of empty header field +msgfile="$MH_TEST_DIR/Mail/inbox/12" +printf 'Date: Sat, 12 Jan 2013 09:07:01 -0600\nReceived:' >"$msgfile" +cat >"$expected" <"$expected_err" <"$actual" 2>"$actual_err" +check "$expected" "$actual" +check "$expected_err" "$actual_err" + +# check m_getfld() handling of excessively long header field name +msgfile="$MH_TEST_DIR/Mail/inbox/13" +cat >"$msgfile" <"$expected" <"$actual" 2>"$actual_err" +check "$expected" "$actual" +# Cygwin has a BUFSIZ of 1024 so the error message gets truncated. +# Deal with that by grepping to verify that scan showed the proper error. +verify_string_in_file() { + if grep "$1" "$2" >/dev/null; then + : + else + echo "$0: did not receive expected error message \"$1\"" + failed=`expr ${failed:-0} + 1` + fi +} +verify_string_in_file 'scan: field name "ThisHeaderFieldNameIsWa' "$actual_err" +verify_string_in_file 'exceeds 997' "$actual_err" +verify_string_in_file '??Format error (message 13) in component 2' "$actual_err" +rm -f "$actual_err" + +# check m_getfld() handling of long header field name without a colon +msgfile="$MH_TEST_DIR/Mail/inbox/14" +cat >"$msgfile" <"$expected" <"$expected_err" <"$actual" 2>"$actual_err" +check "$expected" "$actual" +check "$expected_err" "$actual_err" + exit $failed diff --git a/test/burst/test-burst-mime b/test/burst/test-burst-mime new file mode 100755 index 00000000..93f6b6d6 --- /dev/null +++ b/test/burst/test-burst-mime @@ -0,0 +1,138 @@ +#!/bin/sh +# +# Tests to see if bursting MIME messages works correctly. +# + +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 + +# +# Create a one-part test message that we can burst +# + +cat > "${MH_TEST_DIR}/Mail/inbox/11" < +To: Test Recipient +Date: Friday, 29 Sep 2006 00:00:00 +Subject: Test MIME digest +MIME-Version: 1.0 +Content-type: message/rfc822 + +From: Mister Burster +To: Nobody 1 +Date: Thursday, 28 Sep 2006 00:01:00 +Subject: Message one + +- - This line should not be unstuffed + +EOF + +burst 11 + +run_test 'scan -width 80 11-last' \ +" 11 09/29 Test Burst Messag Test MIME digest< "${MH_TEST_DIR}/Mail/inbox/14" < +To: Test Recipient +Date: Friday, 29 Sep 2006 00:00:00 +Subject: Test digest +MIME-Version: 1.0 +Content-Type: multipart/digest; boundary="----- =_aaaaaaaaaa0" + +This is a preamble +------- =_aaaaaaaaaa0 +Content-Type: message/rfc822 + +From: Mister Burster +To: Nobody 1 +Date: Thursday, 28 Sep 2006 00:01:00 +Subject: Message one + +- -This is message one + +------- =_aaaaaaaaaa0 + +From: Mister Burster +To: Nobody 2 +Date: Thursday, 28 Sep 2006 00:02:00 +Subject: Message two + +This is message two +- For real. +------- =_aaaaaaaaaa0 + +From: Mister Burster +To: Nobody 3 +Date: Thursday, 28 Sep 2006 00:03:00 +Subject: Message three + +Will this one work? + + +------- =_aaaaaaaaaa0-- +EOF + +burst 14 || exit + +run_test 'scan -width 80 14-last' \ +" 14 09/29 Test Burst Messag Test digest<> + 16 09/28 Mister Burster Message two<> + 17 09/28 Mister Burster Message three<>" + +# +# Check to see if each message is what we expect +# + +run_test 'show -noheader -noshow 15' \ +"From: Mister Burster +To: Nobody 1 +Date: Thursday, 28 Sep 2006 00:01:00 +Subject: Message one + +- -This is message one" + +run_test 'show -noheader -noshow 16' \ +"From: Mister Burster +To: Nobody 2 +Date: Thursday, 28 Sep 2006 00:02:00 +Subject: Message two + +This is message two +- For real." + +# +# The CR/LF that appears right before the boundary line is considered part +# of the boundary line, so this has the practical effect of "eating" a +# blank line if it's before the boundary (RFC 2046. 5.1.1). So make sure +# a double blank line results in only one blank line at the end of a message. +# + +expected="${MH_TEST_DIR}/$$.expected" +cat > "${expected}" < +To: Nobody 3 +Date: Thursday, 28 Sep 2006 00:03:00 +Subject: Message three + +Will this one work? + +EOF + +check "${expected}" `mhpath 17` + +exit $failed diff --git a/test/common.sh.in b/test/common.sh.in index 390f94f9..2264d469 100644 --- a/test/common.sh.in +++ b/test/common.sh.in @@ -14,15 +14,20 @@ test -z "$bindir" && bindir="@bindir@" test -z "$mandir" && mandir="@mandir@" test -z "$sysconfdir" && sysconfdir="@sysconfdir@" test -z "$MULTIBYTE_ENABLED" && MULTIBYTE_ENABLED="@MULTIBYTE_ENABLED@" +test -z "$ICONV_ENABLED" && ICONV_ENABLED="@ICONV_ENABLED@" export MH_TEST_DIR auxexecdir bindir mandir sysconfdir -export MULTIBYTE_ENABLED +export MULTIBYTE_ENABLED ICONV_ENABLED test -z "$MH_INST_DIR" && MH_INST_DIR="${MH_TEST_DIR}/inst" export MH_INST_DIR -unset MHBUILD MHCONTEXT MHMTSUSERCONF MHN MHSHOW MHSTORE MHTMPDIR +unset MHBUILD MHCONTEXT MHMTSUSERCONF MHN MHSHOW MHSTORE unset MHLDEBUG MHPDEBUG MHWDEBUG MM_CHARSET PAGER +#### Use a test dir for tmp files when MHTMPDIR applies. +MHTMPDIR=$MH_TEST_DIR/Mail +export MHTMPDIR + output_md5() { #### Output just the checksum. If the filename needs to appear on @@ -76,23 +81,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 +133,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" || true + echo echo "$0: test failed, outputs are in $1 and $2." failed=`expr ${failed:-0} + 1` fi @@ -147,9 +167,8 @@ setup_test () { MH="${MH_TEST_DIR}/Mail/.mh_profile" MHMTSCONF="${MH_INST_DIR}${sysconfdir}/mts.conf" - PATH="${MH_INST_DIR}${bindir}:${PATH}" MH_LIB_DIR="${MH_INST_DIR}${auxexecdir}" - export MH MHMTSCONF MH_LIB_DIR PATH + export MH MHMTSCONF MH_LIB_DIR # # Only install once @@ -174,10 +193,14 @@ setup_test () "${MHMTSCONF}.old" >"${MHMTSCONF}" fi + #### On Solaris, must set PATH after the install! + PATH="${MH_INST_DIR}${bindir}:${PATH}" + export PATH + # clean old test data trap "rm -rf '$MH_TEST_DIR/Mail'" 0 # setup test data - mkdir "$MH_TEST_DIR/Mail" || exit 1 + mkdir -p "$MH_TEST_DIR/Mail" || exit 1 cat > "$MH" < #include #include +#include #include #include #include diff --git a/test/fakesmtp.c b/test/fakesmtp.c index fbfe0442..7121c302 100644 --- a/test/fakesmtp.c +++ b/test/fakesmtp.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff --git a/test/folder/test-sortm b/test/folder/test-sortm index 7ef656cd..0753ecb0 100755 --- a/test/folder/test-sortm +++ b/test/folder/test-sortm @@ -388,7 +388,7 @@ check "$expected" "$actual" # check -check cat >"$expected" < $MH_TEST_DIR/Mail/inbox/14 run_test 'sortm -check -nocheck' \ - "sortm: can't parse date field in message 14, continuing..." + "sortm: can't parse date field in message 14, will use file \ +modification time" scan >"$actual" check "$expected" "$actual" diff --git a/test/format/test-rightjustify b/test/format/test-rightjustify new file mode 100755 index 00000000..2685efd0 --- /dev/null +++ b/test/format/test-rightjustify @@ -0,0 +1,27 @@ +#!/bin/sh +# +# Test that the right justification feature works correctly. +# + +if test -z "${MH_OBJ_DIR}"; then + srcdir=`dirname "$0"`/../.. + MH_OBJ_DIR=`cd "$srcdir" && pwd`; export MH_OBJ_DIR +fi + +. "$MH_OBJ_DIR/test/common.sh" + +setup_test + +actual=`${MH_LIB_DIR}/ap -format "%-30(friendly{text})<"` +expected=" No Such User<&2 + echo " $expected" 1>&2 + echo "but instead got:" 1>&2 + echo " $actual" 1>&2 + failed=`expr ${failed:-0} + 1` +fi + +exit $failed diff --git a/test/getcwidth.c b/test/getcwidth.c new file mode 100644 index 00000000..a145b2d9 --- /dev/null +++ b/test/getcwidth.c @@ -0,0 +1,163 @@ +/* + * getcwidth - Get the OS's idea of the width of Unicode codepoints + * + * This code is Copyright (c) 2013, by the authors of nmh. See the + * COPYRIGHT file in the root directory of the nmh distribution for + * complete copyright information. + */ + +#include +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef MULTIBYTE_SUPPORT +#include +#include +#endif + +#ifdef MULTIBYTE_SUPPORT +static void usage(char *); +static void dumpwidth(void); +static void getwidth(const char *); +#endif /* MULTIBYTE_SUPPORT */ + +int +main(int argc, char *argv[]) +{ +#ifndef MULTIBYTE_SUPPORT + fprintf(stderr, "Nmh was not configured with multibyte support\n"); + exit(1); +#else /* MULTIBYTE_SUPPORT */ + wchar_t c; + int i; + + setlocale(LC_ALL, ""); + + if (argc < 2) + usage(argv[0]); + + if (strcmp(argv[1], "--dump") == 0) { + if (argc == 2) { + dumpwidth(); + exit(0); + } else { + fprintf(stderr, "--dump cannot be combined with " + "other arguments\n"); + exit(1); + } + } + + /* + * Process each argument. If it begins with "U+", then try to + * convert it to a Unicode codepoint. Otherwise, take each + * string and get the total width + */ + + for (i = 1; i < argc; i++) { + if (strncmp(argv[i], "U+", 2) == 0) { + /* + * We're making a big assumption here that + * wchar_t represents a Unicode codepoint. + * That technically isn't valid unless the + * C compiler defines __STDC_ISO_10646__, but + * we're going to assume now that it works. + */ + errno = 0; + c = strtoul(argv[i] + 2, NULL, 16); + if (errno) { + fprintf(stderr, "Codepoint %s invalid\n", + argv[i]); + continue; + } + printf("%d\n", wcwidth(c)); + } else { + getwidth(argv[i]); + } + } + + exit(0); +} + +static void +usage(char *argv0) +{ + fprintf(stderr, "Usage: %s [--dump]\n", argv0); + fprintf(stderr, " %s U+XXXX [...]\n", argv0); + fprintf(stderr, " %s utf-8-sequence [...]\n", argv0); + fprintf(stderr, "Returns the column width of a Unicode codepoint " + "or UTF-8 character sequence\n"); + fprintf(stderr, "\t--dump\tDump complete width table\n"); + + exit(1); +} + +static void +getwidth(const char *string) +{ + wchar_t c; + int charlen, charleft = strlen(string); + int length = 0; + + /* + * In theory we should be able to use wcswidth(), but since we're + * testing out how the format libraries behave we'll do it a character + * at a time. + */ + + mbtowc(NULL, NULL, 0); + + while (charleft > 0) { + int clen; + + charlen = mbtowc(&c, string, charleft); + + if (charlen == 0) + break; + + if (charlen < 0) { + fprintf(stderr, "Unable to convert string \"%s\"\n", + string); + return; + } + + if ((clen = wcwidth(c)) < 0) { + fprintf(stderr, "U+%04lX non-printable\n", + (unsigned long int) c); + return; + } + + length += clen; + string += charlen; + charleft -= charlen; + } + + printf("%d\n", length); +} + +static void +dumpwidth(void) +{ + wchar_t wc, low; + int width, lastwidth; + + for (wc = low = 1, lastwidth = wcwidth(wc); wc <= 0xffff; wc++) { + width = wcwidth(wc); + if (width != lastwidth) { + printf("%04lX - %04lX = %d\n", (unsigned long int) low, + (unsigned long int) (wc - 1), lastwidth); + low = wc; + } + lastwidth = width; + } + + width = wcwidth(wc - 1); + if (width == lastwidth) + printf("%04lX - %04lX = %d\n", (unsigned long int) low, + (unsigned long int) (wc - 1), width); +} +#endif /* MULTIBYTE_SUPPORT */ diff --git a/test/inc/test-eom-align b/test/inc/test-eom-align index 5acdc0eb..aa470c36 100755 --- a/test/inc/test-eom-align +++ b/test/inc/test-eom-align @@ -126,7 +126,7 @@ do_one_test_B () { # buffer size or to body size equal to buffer size. arith_eval $STDIO_BUFSZ - 16; START=$arith_val arith_eval $STDIO_BUFSZ + $HDRSZ + $FROMLINESZ + 32; FINISH=$arith_val -echo \ +[ -t 1 ] && echo \ "Testing inc of files with various alignments of eom marker with buffer size..." i="$START" while test $i -le $FINISH; do diff --git a/test/inc/test-inc-scanout b/test/inc/test-inc-scanout index 8d7a72d4..ffe2c46d 100755 --- a/test/inc/test-inc-scanout +++ b/test/inc/test-inc-scanout @@ -201,9 +201,9 @@ run_test "scan -width 120 +inbox 11" \ # check header field name with ':' character than lands on m_getfld() buffer cat >"$MH_TEST_DIR/mess" < To: Some Other User diff --git a/test/inc/test-pop b/test/inc/test-pop index 580f0cda..7724ae3c 100755 --- a/test/inc/test-pop +++ b/test/inc/test-pop @@ -56,8 +56,24 @@ run_test "inc -user ${TESTUSER} -host 127.0.0.1 -port $testport -width 80" \ "Incorporating new mail into inbox... 11+ 12/17 No Such User Hello< /dev/null 2>>"$actual" + groff -Tutf8 -mandoc $warnings "$manpage" > /dev/null 2>>"$actual" done check "$expected" "$actual" diff --git a/test/mhmail/test-mhmail b/test/mhmail/test-mhmail index 37452073..144a362e 100755 --- a/test/mhmail/test-mhmail +++ b/test/mhmail/test-mhmail @@ -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" <"$msgfile" <"$expected" <"$actual" 2>&1 +check "$expected" "$actual" + +# check a boundary condition in m_getfld(): its internal message +# buffer holds exactly up to the end of a header field name in a +# message part +msgfile=`mhpath new` +msgnum=`basename $msgfile` +cat >"$msgfile" <"$expected" <"$actual" 2>&1 +check "$expected" "$actual" + +# check a boundary condition in m_getfld(): its internal message +# buffer holds exactly up to the end of a message part boundary +msgfile=`mhpath new` +msgnum=`basename $msgfile` +cat >"$msgfile" <"$expected" <"$actual" 2>&1 +check "$expected" "$actual" + + +exit $failed diff --git a/test/pick/test-pick b/test/pick/test-pick index 12d2aae0..e1434dce 100755 --- a/test/pick/test-pick +++ b/test/pick/test-pick @@ -99,14 +99,12 @@ cat >"$expected" </dev/tty; then +if test -t 1 && (printf '' >/dev/tty) 2>/dev/null; then # Produce no standard output if no messages match and standard # output is a tty. To test that even when run with stdout # detached, write directly to /dev/tty. Can't capture the # output so hopefully the user will notice it. pick -subject message.3 -and -from Test4 >/dev/tty 2>/dev/null -else - echo "$0: skip tty test because can't write to /dev/tty" fi # Also, check that the exit status is 1. @@ -258,7 +256,9 @@ EOF echo 13 >"$expected" -pick -subject foobar 13 >"$actual" 2>&1 +set +e +LC_CTYPE=en_US.UTF-8 pick -subject foobar 13 >"$actual" 2>&1 +set -e check "$expected" "$actual" # Test -nosequence. diff --git a/test/post/test-sendfiles b/test/post/test-sendfiles index 687c5d9b..af5573ea 100755 --- a/test/post/test-sendfiles +++ b/test/post/test-sendfiles @@ -60,7 +60,8 @@ test_sendfiles () inc -silent -file "$mbox" rm -f "$mbox" "$mbox.map" - mhlist -verbose last | sed -e 's/ *$//' >"$actual" + mhlist -verbose last | sed -e 's/ *$//' -e 's/\(octet-stream\).*$/\1/' \ + >"$actual" (cd $MH_TEST_DIR/tmp && contents=`mhstore -noauto last 2>&1 | \ sed -e 's/storing message.*as file //'` && @@ -140,7 +141,7 @@ Usage: sendfiles [switches] -to recipient \ # check with no compression cat >"$expected" <"$expected" <"$expected" <"$expected" <' # check PERSON environment variable cat >"$expected" <"$expected" <"$expected" < "${MH_TEST_DIR}/Mail/inbox/11" < To: Sir Denis =?utf-8?q?Eton=E2=80=93Hogg? Date: Friday, 2 Mar 1984 00:00:00 -Subject: =?utf-8?q?Spin=CC=88al_Tap_=E2=86=92_Tap_into_America!?= +Subject: =?utf-8?q?Sp=C4=B1n=CC=88al_Tap_=E2=86=92_Tap_into_America!?= Things are looking great! EOF +width=`${MH_OBJ_DIR}/test/getcwidth "→n̈"` +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 3; then +cat > "$expected" < "$expected" < $actual || exit 1 check "$expected" "$actual" -# check decoding with an invalid multibyte sequence +# +# Check decoding with an invalid multibyte sequence. We skip this test +# if we don't have iconv support, since it requires converting from one +# character set to another. Be sure we created the test file, though, because +# it's required for the test right after it. +# + cat >`mhpath new` < To: Some User @@ -68,13 +95,34 @@ cat >"$expected" <"$actual" -check "$expected" "$actual" +if test "$ICONV_ENABLED" -eq 1; then + LC_CTYPE=ISO-8859-1 MM_CHARSET=ISO-8859-1 scan -width 75 last >"$actual" + check "$expected" "$actual" +fi + +# +# Find out the width of our Unicode apostrophe (U+2019). Some implementations +# say it has a width of 2, but that seems totally bizarre to me. +# + +width=`${MH_OBJ_DIR}/test/getcwidth U+2019` +if test $? -ne 0; then + echo "getcwidth failed to run" + exit 1 +fi # check scan width with a valid multibyte sequence -cat >"$expected" <"$expected" <"$expected" <"$actual" check "$expected" "$actual" diff --git a/uip/aliasbr.c b/uip/aliasbr.c index 49372510..a696e8a6 100644 --- a/uip/aliasbr.c +++ b/uip/aliasbr.c @@ -35,7 +35,7 @@ char *akerror (int); static char *akval (struct aka *, char *); static int aleq (char *, char *); -static char *scanp (unsigned char *); +static char *scanp (char *); static char *getp (char *); static char *seekp (char *, char *, char **); static int addfile (struct aka *, char *); @@ -313,9 +313,9 @@ akerror (int i) static char * -scanp (unsigned char *p) +scanp (char *p) { - while (isspace (*p)) + while (isspace ((unsigned char) *p)) p++; return p; } @@ -324,10 +324,10 @@ scanp (unsigned char *p) static char * getp (char *p) { - register unsigned char *cp = scanp (p); + char *cp = scanp (p); p = cp; - while (!isspace (*cp) && *cp) + while (!isspace ((unsigned char) *cp) && *cp) cp++; *cp = 0; @@ -338,10 +338,10 @@ getp (char *p) static char * seekp (char *p, char *c, char **a) { - register unsigned char *cp; + char *cp; p = cp = scanp (p); - while (!isspace (*cp) && *cp && *cp != ':' && *cp != ';') + while (!isspace ((unsigned char) *cp) && *cp && *cp != ':' && *cp != ';') cp++; *c = *cp; *cp++ = 0; @@ -456,7 +456,7 @@ addall (struct aka *ak) static char * getalias (char *addrs) { - register unsigned char *pp, *qp; + char *pp, *qp; static char *cp = NULL; if (cp == NULL) @@ -466,7 +466,7 @@ getalias (char *addrs) return (cp = NULL); /* Remove leading any space from the address. */ - for (pp = cp; isspace (*pp); pp++) + for (pp = cp; isspace ((unsigned char) *pp); pp++) continue; if (*pp == 0) return (cp = NULL); @@ -478,7 +478,7 @@ getalias (char *addrs) *qp++ = 0; for (cp = qp, qp--; qp > pp; qp--) if (*qp != 0) { - if (isspace (*qp)) + if (isspace ((unsigned char) *qp)) *qp = 0; else break; diff --git a/uip/anno.c b/uip/anno.c index 0ed6e77f..cf52021c 100644 --- a/uip/anno.c +++ b/uip/anno.c @@ -74,7 +74,7 @@ DEFINE_SWITCH_ARRAY(ANNO, switches); /* * static prototypes */ -static void make_comp (unsigned char **); +static void make_comp (char **); int @@ -83,8 +83,7 @@ main (int argc, char **argv) int inplace = 1, datesw = 1; int msgnum; char *cp, *maildir; - unsigned char *comp = NULL; - char *text = NULL, *folder = NULL, buf[BUFSIZ]; + char *comp = NULL, *text = NULL, *folder = NULL, buf[BUFSIZ]; char **argp, **arguments; struct msgs_array msgs = { 0, 0, NULL }; struct msgs *mp; @@ -275,10 +274,9 @@ main (int argc, char **argv) } static void -make_comp (unsigned char **ap) +make_comp (char **ap) { - register unsigned char *cp; - char buffer[BUFSIZ]; + char *cp, buffer[BUFSIZ]; if (*ap == NULL) { printf ("Enter component name: "); @@ -299,6 +297,6 @@ make_comp (unsigned char **ap) adios (NULL, "too large component name %s", *ap); for (cp = *ap; *cp; cp++) - if (!isalnum (*cp) && *cp != '-') + if (!isalnum ((unsigned char) *cp) && *cp != '-') adios (NULL, "invalid component name %s", *ap); } diff --git a/uip/burst.c b/uip/burst.c index 0b4a2409..e4792335 100644 --- a/uip/burst.c +++ b/uip/burst.c @@ -9,10 +9,14 @@ #include #include +#include #define BURST_SWITCHES \ X("inplace", 0, INPLSW) \ X("noinplace", 0, NINPLSW) \ + X("mime", 0, MIMESW) \ + X("nomime", 0, NMIMESW) \ + X("automime", 0, AUTOMIMESW) \ X("quiet", 0, QIETSW) \ X("noquiet", 0, NQIETSW) \ X("verbose", 0, VERBSW) \ @@ -33,12 +37,21 @@ struct smsg { off_t s_stop; }; +/* + * For the MIME parsing routines + */ + +int debugsw = 0; +pid_t xpid = 0; + /* * static prototypes */ -static int find_delim (int, struct smsg *); -static void burst (struct msgs **, int, struct smsg *, int, int, int, char *); -static void cpybrst (FILE *, FILE *, char *, char *, int); +static int find_delim (int, struct smsg *, int *); +static void find_mime_parts (CT, struct smsg *, int *); +static void burst (struct msgs **, int, struct smsg *, int, int, int, + char *, int); +static void cpybrst (FILE *, FILE *, char *, char *, int, int); /* * A macro to check to see if we have reached a message delimiter @@ -54,7 +67,7 @@ static void cpybrst (FILE *, FILE *, char *, char *, int); int main (int argc, char **argv) { - int inplace = 0, quietsw = 0, verbosw = 0; + int inplace = 0, quietsw = 0, verbosw = 0, mimesw = 1; int hi, msgnum, numburst; char *cp, *maildir, *folder = NULL, buf[BUFSIZ]; char **argp, **arguments; @@ -98,6 +111,16 @@ main (int argc, char **argv) inplace = 0; continue; + case MIMESW: + mimesw = 2; + continue; + case NMIMESW: + mimesw = 0; + continue; + case AUTOMIMESW: + mimesw = 1; + continue; + case QIETSW: quietsw++; continue; @@ -158,11 +181,12 @@ main (int argc, char **argv) /* burst all the SELECTED messages */ for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) { if (is_selected (mp, msgnum)) { - if ((numburst = find_delim (msgnum, smsgs)) >= 1) { + if ((numburst = find_delim (msgnum, smsgs, &mimesw)) >= 1) { if (verbosw) printf ("%d message%s exploded from digest %d\n", numburst, numburst > 1 ? "s" : "", msgnum); - burst (&mp, msgnum, smsgs, numburst, inplace, verbosw, maildir); + burst (&mp, msgnum, smsgs, numburst, inplace, verbosw, + maildir, mimesw); } else { if (numburst == 0) { if (!quietsw) @@ -203,18 +227,49 @@ main (int argc, char **argv) /* * Scan the message and find the beginning and * end of all the messages in the digest. + * + * If requested, see if the message is MIME-formatted and contains any + * message/rfc822 parts; if so, burst those parts. */ static int -find_delim (int msgnum, struct smsg *smsgs) +find_delim (int msgnum, struct smsg *smsgs, int *mimesw) { int wasdlm = 0, msgp; off_t pos; char c, *msgnam; char buffer[BUFSIZ]; FILE *in; + CT content; - if ((in = fopen (msgnam = m_name (msgnum), "r")) == NULL) + msgnam = m_name (msgnum); + + /* + * If mimesw is 1 or 2, try to see if it's got proper MIME formatting. + */ + + if (*mimesw > 0) { + content = parse_mime(msgnam); + if (! content && *mimesw == 2) + return 0; + else if (content) { + smsgs[0].s_start = 0; + smsgs[0].s_stop = content->c_begin - 1; + msgp = 1; + find_mime_parts(content, smsgs, &msgp); + free_content(content); + if (msgp == 1 && *mimesw == 2) { + adios (msgnam, "does not have any message/rfc822 parts"); + } else if (msgp > 1) { + *mimesw = 1; + return (msgp - 1); + } + } + } + + *mimesw = 0; + + if ((in = fopen (msgnam, "r")) == NULL) adios (msgnam, "unable to read message"); for (msgp = 0, pos = 0L; msgp <= MAXFOLDER;) { @@ -275,13 +330,51 @@ find_delim (int msgnum, struct smsg *smsgs) } +/* + * Find any MIME content in the message that is a message/rfc822 and add + * it to the list of messages to burst. + */ + +static void +find_mime_parts (CT content, struct smsg *smsgs, int *msgp) +{ + struct multipart *m; + struct part *part; + + /* + * If we have a message/rfc822, then it's easy. + */ + + if (content->c_type == CT_MESSAGE && + content->c_subtype == MESSAGE_RFC822) { + smsgs[*msgp].s_start = content->c_begin; + smsgs[*msgp].s_stop = content->c_end; + (*msgp)++; + return; + } + + /* + * Otherwise, if we do have multiparts, try all of the sub-parts. + */ + + if (content->c_type == CT_MULTIPART) { + m = (struct multipart *) content->c_ctparams; + + for (part = m->mp_parts; part; part = part->mp_next) + find_mime_parts(part->mp_part, smsgs, msgp); + } + + return; +} + + /* * Burst out the messages in the digest into the folder */ static void burst (struct msgs **mpp, int msgnum, struct smsg *smsgs, int numburst, - int inplace, int verbosw, char *maildir) + int inplace, int verbosw, char *maildir, int mimesw) { int i, j, mode; char *msgnam; @@ -380,7 +473,7 @@ burst (struct msgs **mpp, int msgnum, struct smsg *smsgs, int numburst, chmod (f2, mode); fseeko (in, smsgs[j].s_start, SEEK_SET); cpybrst (in, out, msgnam, f2, - (int) (smsgs[j].s_stop - smsgs[j].s_start)); + (int) (smsgs[j].s_stop - smsgs[j].s_start), mimesw); fclose (out); if (i == msgnum) { @@ -408,6 +501,7 @@ burst (struct msgs **mpp, int msgnum, struct smsg *smsgs, int numburst, #define S1 0 #define S2 1 #define S3 2 +#define S4 3 /* * Copy a mesage which is being burst out of a digest. @@ -415,11 +509,11 @@ burst (struct msgs **mpp, int msgnum, struct smsg *smsgs, int numburst, */ static void -cpybrst (FILE *in, FILE *out, char *ifile, char *ofile, int len) +cpybrst (FILE *in, FILE *out, char *ifile, char *ofile, int len, int mime) { register int c, state; - for (state = S1; (c = fgetc (in)) != EOF && len > 0; len--) { + for (state = mime ? S4 : S1; (c = fgetc (in)) != EOF && len > 0; len--) { if (c == 0) continue; switch (state) { @@ -460,6 +554,10 @@ cpybrst (FILE *in, FILE *out, char *ifile, char *ofile, int len) break; } break; + + case S4: + fputc (c, out); + break; } } diff --git a/uip/conflict.c b/uip/conflict.c index d8c45669..a43c70ee 100644 --- a/uip/conflict.c +++ b/uip/conflict.c @@ -366,7 +366,7 @@ setup (void) close (fd); } execlp (mailproc, r1bindex (mailproc, '/'), - mail, "-subject", invo_name, NULL); + mail, "-subject", invo_name, (void *) NULL); adios (mailproc, "unable to exec "); default: diff --git a/uip/distsbr.c b/uip/distsbr.c index afd4e419..d7a27120 100644 --- a/uip/distsbr.c +++ b/uip/distsbr.c @@ -28,10 +28,10 @@ int distout (char *drft, char *msgnam, char *backup) { int state; - register unsigned char *dp; - register char *resent; + char *dp, *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 +46,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,19 +64,16 @@ 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)) { + if (!isspace ((unsigned char) *dp)) { advise (NULL, BADTXT, "draft"); goto leave_bad; } @@ -99,7 +95,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 +129,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 +150,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 +180,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 +194,9 @@ ready_msg (char *msgnam) default: adios (NULL, "getfld() returned %d", state); } + } process: ; + m_getfld_state_destroy (&gstate); fclose (ifp); fclose (ofp); } diff --git a/uip/flist.c b/uip/flist.c index 4c0469ed..1444acaf 100644 --- a/uip/flist.c +++ b/uip/flist.c @@ -277,17 +277,17 @@ main(int argc, char **argv) void GetFolderOrder(void) { - unsigned char *p, *s; + char *p, *s; int priority = 1; struct Folder *o; if (!(p = context_find("Flist-Order"))) return; for (;;) { - while (isspace(*p)) + while (isspace((unsigned char) *p)) ++p; s = p; - while (*p && !isspace(*p)) + while (*p && !isspace((unsigned char) *p)) ++p; if (p != s) { /* Found one. */ @@ -390,7 +390,7 @@ void BuildFolderListRecurse(char *dirName, struct stat *s, int searchdepth) { char *base, name[PATH_MAX]; - unsigned char *n; + char *n; int nlinks; DIR *dir; struct dirent *dp; @@ -430,7 +430,7 @@ BuildFolderListRecurse(char *dirName, struct stat *s, int searchdepth) /* Check to see if the name of the file is a number * if it is, we assume it's a mail file and skip it */ - for (n = dp->d_name; *n && isdigit(*n); n++); + for (n = dp->d_name; *n && isdigit((unsigned char) *n); n++); if (!*n) continue; strncpy (name, base, sizeof(name) - 2); diff --git a/uip/forw.c b/uip/forw.c index 97714dc4..18a4f03b 100644 --- a/uip/forw.c +++ b/uip/forw.c @@ -496,12 +496,13 @@ mhl_draft (int out, char *digest, int volume, int issue, int i, msgnum, pd[2]; char buf1[BUFSIZ]; char buf2[BUFSIZ]; + char *program; struct msgs_array vec = { 0, 0, NULL }; if (pipe (pd) == NOTOK) adios ("pipe", "unable to create"); - app_msgarg(&vec, r1bindex (mhlproc, '/')); + argsplit_msgarg(&vec, mhlproc, &program); for (i = 0; (child_id = fork()) == NOTOK && i < 5; i++) sleep (5); @@ -548,7 +549,7 @@ mhl_draft (int out, char *digest, int volume, int issue, app_msgarg(&vec, NULL); - execvp (mhlproc, vec.msgs); + execvp (program, vec.msgs); fprintf (stderr, "unable to exec "); perror (mhlproc); _exit (-1); diff --git a/uip/forwsbr.c b/uip/forwsbr.c index 1f181fdd..48fecb17 100644 --- a/uip/forwsbr.c +++ b/uip/forwsbr.c @@ -46,7 +46,7 @@ build_form (char *form, char *digest, int *dat, char *from, char *to, char *cc, char *fcc, char *subject, char *inputfile) { int in; - int fmtsize, state, char_read = 0; + int fmtsize, state; int i; register char *nfs; char *line, tmpfil[BUFSIZ], name[NAMESZ], **ap; @@ -54,6 +54,7 @@ build_form (char *form, char *digest, int *dat, char *from, char *to, register struct comp *cptr; struct format *fmt; char *cp = NULL; + m_getfld_state_t gstate = 0; /* * Open the message we'll be scanning for components @@ -86,8 +87,9 @@ build_form (char *form, char *digest, int *dat, char *from, char *to, * these routines? */ - for (state = FLD;;) { - state = m_getfld(state, name, msgbuf, sizeof(msgbuf), tmp); + for (;;) { + int msg_count = sizeof msgbuf; + state = m_getfld (&gstate, name, msgbuf, &msg_count, tmp); switch (state) { case FLD: case FLDPLUS: @@ -99,16 +101,16 @@ build_form (char *form, char *digest, int *dat, char *from, char *to, i = fmt_addcomptext(name, msgbuf); if (i != -1) { - char_read += msg_count; while (state == FLDPLUS) { - state = m_getfld(state, name, msgbuf, - sizeof(msgbuf), tmp); + msg_count = sizeof msgbuf; + state = m_getfld (&gstate, name, msgbuf, &msg_count, tmp); fmt_appendcomp(i, name, msgbuf); - char_read += msg_count; } } - while (state == FLDPLUS) - state = m_getfld(state, name, msgbuf, sizeof(msgbuf), tmp); + while (state == FLDPLUS) { + msg_count = sizeof msgbuf; + state = m_getfld (&gstate, name, msgbuf, &msg_count, tmp); + } break; case LENERR: @@ -133,6 +135,7 @@ build_form (char *form, char *digest, int *dat, char *from, char *to, */ finished: + m_getfld_state_destroy (&gstate); cptr = fmt_findcomp ("digest"); if (cptr) { diff --git a/uip/inc.c b/uip/inc.c index 3ec47fae..2d791f68 100644 --- a/uip/inc.c +++ b/uip/inc.c @@ -569,6 +569,7 @@ go_to_it: fflush (stdout); } + /* * Get the mail from a POP server */ @@ -702,7 +703,7 @@ go_to_it: * Get the mail from file (usually mail spool) */ if (inc_type == INC_FILE && Maildir == NULL) { - m_unknown (in); /* the MAGIC invocation... */ + scan_detect_mbox_style (in); /* the MAGIC invocation... */ hghnum = msgnum = mp->hghmsg; for (;;) { /* @@ -869,6 +870,8 @@ go_to_it: free (Maildir); /* From now on Maildir is just a flag - don't dref! */ } + scan_finished (); + if (incerr < 0) { /* error */ if (locked) { GETGROUPPRIVS(); /* Be sure we can unlock mail file */ diff --git a/uip/mhbuild.c b/uip/mhbuild.c index 893ef8d6..e91e3586 100644 --- a/uip/mhbuild.c +++ b/uip/mhbuild.c @@ -87,9 +87,6 @@ int output_message_fp (CT, FILE *, char*); /* mhlistsbr.c */ int list_all_messages (CT *, int, int, int, int); -/* mhfree.c */ -void free_content (CT); - int main (int argc, char **argv) diff --git a/uip/mhbuildsbr.c b/uip/mhbuildsbr.c index 653c5b3f..d2d033f1 100644 --- a/uip/mhbuildsbr.c +++ b/uip/mhbuildsbr.c @@ -62,7 +62,6 @@ void content_error (char *, CT, char *, ...); int find_cache (CT, int, int *, char *, char *, int); /* mhfree.c */ -void free_content (CT); void free_ctinfo (CT); void free_encoding (CT, int); @@ -134,6 +133,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 +161,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 +179,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 +192,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 +202,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 +221,7 @@ finish_field: } break; } + m_getfld_state_destroy (&gstate); /* * Now add the MIME-Version header field @@ -400,8 +402,7 @@ static int user_content (FILE *in, char *file, char *buf, CT *ctp) { int extrnal, vrsn; - unsigned char *cp; - char **ap; + char *cp, **ap; char buffer[BUFSIZ]; struct multipart *m; struct part **pp; @@ -674,7 +675,7 @@ use_forw: if (ci->ci_magic) { /* check if specifies command to execute */ if (*ci->ci_magic == '|' || *ci->ci_magic == '!') { - for (cp = ci->ci_magic + 1; isspace (*cp); cp++) + for (cp = ci->ci_magic + 1; isspace ((unsigned char) *cp); cp++) continue; if (!*cp) adios (NULL, "empty pipe command for #%s directive", ci->ci_type); @@ -1093,7 +1094,7 @@ raw: if ((out = fopen (ce->ce_file, "w")) == NULL) adios (ce->ce_file, "unable to open for writing"); - for (i = 0; (child_id = vfork()) == NOTOK && i > 5; i++) + for (i = 0; (child_id = fork()) == NOTOK && i > 5; i++) sleep (5); switch (child_id) { case NOTOK: @@ -1153,7 +1154,7 @@ scan_content (CT ct) int checklinelen = 0, linelen = 0; /* check for long lines */ int checkboundary = 0, boundaryclash = 0; /* check if clashes with multipart boundary */ int checklinespace = 0, linespace = 0; /* check if any line ends with space */ - unsigned char *cp = NULL, buffer[BUFSIZ]; + char *cp = NULL, buffer[BUFSIZ]; struct text *t = NULL; FILE *in = NULL; CE ce = ct->c_cefile; @@ -1248,7 +1249,7 @@ scan_content (CT ct) */ if (check8bit) { for (cp = buffer; *cp; cp++) { - if (!isascii (*cp)) { + if (!isascii ((unsigned char) *cp)) { contains8bit = 1; check8bit = 0; /* no need to keep checking */ } @@ -1266,7 +1267,7 @@ scan_content (CT ct) /* * Check if line ends with a space. */ - if (checklinespace && (cp = buffer + strlen (buffer) - 2) > buffer && isspace (*cp)) { + if (checklinespace && (cp = buffer + strlen (buffer) - 2) > buffer && isspace ((unsigned char) *cp)) { linespace = 1; checklinespace = 0; /* no need to keep checking */ } @@ -1277,10 +1278,10 @@ scan_content (CT ct) */ if (checkboundary && buffer[0] == '-' && buffer[1] == '-') { for (cp = buffer + strlen (buffer) - 1; cp >= buffer; cp--) - if (!isspace (*cp)) + if (!isspace ((unsigned char) *cp)) break; *++cp = '\0'; - if (!strncmp(buffer + 2, prefix, len) && isdigit(buffer[2 + len])) { + if (!strncmp(buffer + 2, prefix, len) && isdigit((unsigned char) buffer[2 + len])) { boundaryclash = 1; checkboundary = 0; /* no need to keep checking */ } @@ -1639,7 +1640,8 @@ calculate_digest (CT ct, int asciiP) } /* encode the digest using base64 */ - for (dp = digest, op = outbuf, cc = sizeof(digest) / sizeof(digest[0]); + for (dp = digest, op = (char *) outbuf, + cc = sizeof(digest) / sizeof(digest[0]); cc > 0; cc -= 3, op += 4) { unsigned long bits; char *bp; diff --git a/uip/mhcachesbr.c b/uip/mhcachesbr.c index 5f7777d0..25ac9ab0 100644 --- a/uip/mhcachesbr.c +++ b/uip/mhcachesbr.c @@ -376,25 +376,27 @@ find_cache_aux2 (char *mapfile, char *id, char *mapname, int namelen) int state; char buf[BUFSIZ], name[NAMESZ]; FILE *fp; + m_getfld_state_t gstate = 0; if (!(fp = lkfopen (mapfile, "r"))) return NOTOK; - for (state = FLD;;) { + for (;;) { int result; char *cp, *dp; + int bufsz = sizeof buf; - switch (state = m_getfld (state, name, buf, sizeof(buf), fp)) { + switch (state = m_getfld (&gstate, name, buf, &bufsz, fp)) { case FLD: case FLDPLUS: - case FLDEOF: strncpy (mapname, name, namelen); if (state != FLDPLUS) cp = buf; else { cp = add (buf, NULL); while (state == FLDPLUS) { - state = m_getfld (state, name, buf, sizeof(buf), fp); + bufsz = sizeof buf; + state = m_getfld (&gstate, name, buf, &bufsz, fp); cp = add (buf, cp); } } @@ -410,18 +412,16 @@ find_cache_aux2 (char *mapfile, char *id, char *mapname, int namelen) lkfclose (fp, mapfile); return OK; } - if (state != FLDEOF) - continue; - /* else fall... */ + continue; case BODY: - case BODYEOF: case FILEEOF: default: break; } break; } + m_getfld_state_destroy (&gstate); lkfclose (fp, mapfile); return NOTOK; diff --git a/uip/mhfree.c b/uip/mhfree.c index 38b830ec..83ed5366 100644 --- a/uip/mhfree.c +++ b/uip/mhfree.c @@ -19,7 +19,6 @@ CT *cts = NULL; /* * prototypes */ -void free_content (CT); void free_header (CT); void free_ctinfo (CT); void free_encoding (CT, int); @@ -205,6 +204,8 @@ free_multi (CT ct) free (m->mp_start); if (m->mp_stop) free (m->mp_stop); + free (m->mp_content_before); + free (m->mp_content_after); for (part = m->mp_parts; part; part = next) { next = part->mp_next; diff --git a/uip/mhlist.c b/uip/mhlist.c index 1363081c..6ab50e39 100644 --- a/uip/mhlist.c +++ b/uip/mhlist.c @@ -86,7 +86,6 @@ void flush_errors (void); void list_all_messages (CT *, int, int, int, int); /* mhfree.c */ -void free_content (CT); extern CT *cts; void freects_done (int) NORETURN; @@ -358,7 +357,6 @@ static void pipeser (int i) { if (i == SIGQUIT) { - unlink ("core"); fflush (stdout); fprintf (stderr, "\n"); fflush (stderr); diff --git a/uip/mhlsbr.c b/uip/mhlsbr.c index fc0a1a10..5dbf341c 100644 --- a/uip/mhlsbr.c +++ b/uip/mhlsbr.c @@ -288,7 +288,7 @@ static unsigned int wid; static char *ovtxt; -static unsigned char *onelp; +static char *onelp; static char *parptr; @@ -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; @@ -1081,12 +1087,14 @@ mhlfile (FILE *fp, char *mname, int ofilen, int ofilec) break; } } + m_getfld_state_destroy (&gstate); return; case LENERR: case FMTERR: advise (NULL, "format error in message %s", mname); exitstat++; + m_getfld_state_destroy (&gstate); return; default: @@ -1272,7 +1280,7 @@ static void putcomp (struct mcomp *c1, struct mcomp *c2, int flag) { int count, cchdr; - unsigned char *cp; + char *cp; cchdr = 0; lm = 0; @@ -1310,8 +1318,8 @@ putcomp (struct mcomp *c1, struct mcomp *c2, int flag) if (!(c1->c_flags & HDROUTPUT) && !(c1->c_flags & NOCOMPONENT)) { if (c1->c_flags & UPPERCASE) /* uppercase component also */ for (cp = (c1->c_text ? c1->c_text : c1->c_name); *cp; cp++) - if (islower (*cp)) - *cp = toupper (*cp); + if (islower ((unsigned char) *cp)) + *cp = toupper ((unsigned char) *cp); putstr (c1->c_text ? c1->c_text : c1->c_name, c1->c_flags); if (flag != BODYCOMP) { putstr (": ", c1->c_flags); @@ -1333,8 +1341,8 @@ putcomp (struct mcomp *c1, struct mcomp *c2, int flag) && !(c2->c_flags & NOCOMPONENT)) { if (c1->c_flags & UPPERCASE) for (cp = c2->c_name; *cp; cp++) - if (islower (*cp)) - *cp = toupper (*cp); + if (islower ((unsigned char) *cp)) + *cp = toupper ((unsigned char) *cp); putstr (c2->c_name, c1->c_flags); putstr (": ", c1->c_flags); if (!(c1->c_flags & SPLIT)) @@ -1347,8 +1355,8 @@ putcomp (struct mcomp *c1, struct mcomp *c2, int flag) } if (c1->c_flags & UPPERCASE) for (cp = c2->c_text; *cp; cp++) - if (islower (*cp)) - *cp = toupper (*cp); + if (islower ((unsigned char) *cp)) + *cp = toupper ((unsigned char) *cp); count = 0; if (cchdr) { @@ -1395,7 +1403,7 @@ oneline (char *stuff, long flags) term = 0; if (flags & COMPRESS) { for (spc = 1, cp = ret; *onelp; onelp++) - if (isspace (*onelp)) { + if (isspace ((unsigned char) *onelp)) { if (*onelp == '\n' && (!onelp[1] || (flags & ADDRFMT))) { term = '\n'; *onelp++ = 0; @@ -1643,6 +1651,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()"); @@ -1650,7 +1660,7 @@ m_popen (char *name) if (pipe (pd) == NOTOK) adios ("pipe", "unable to"); - switch (m_pid = vfork()) { + switch (m_pid = fork()) { case NOTOK: adios ("fork", "unable to"); @@ -1663,7 +1673,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); @@ -1769,7 +1780,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]; @@ -1823,8 +1835,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); } /* @@ -1849,18 +1862,17 @@ filterbody (struct mcomp *c1, char *buf, int bufsz, int state, FILE *fp) */ switch (filterpid = fork()) { - char **args; + char **args, *program; struct arglist *a; - int i, dat[5], s; + int i, dat[5], s, argp; case 0: /* - * Allocate an argument array for us + * Configure an argument array for us */ - args = (char **) mh_xmalloc((filter_nargs + 2) * sizeof(char *)); - args[0] = formatproc; - args[filter_nargs + 1] = NULL; + args = argsplit(formatproc, &program, &argp); + args[argp + filter_nargs] = NULL; dat[0] = 0; dat[1] = 0; dat[2] = 0; @@ -1871,7 +1883,7 @@ filterbody (struct mcomp *c1, char *buf, int bufsz, int state, FILE *fp) * Pull out each argument and scan them. */ - for (a = arglist_head, i = 1; a != NULL; a = a->a_next, i++) { + for (a = arglist_head, i = argp; a != NULL; a = a->a_next, i++) { args[i] = mh_xmalloc(BUFSIZ); fmt_scan(a->a_fmt, args[i], BUFSIZ - 1, BUFSIZ, dat, NULL); /* diff --git a/uip/mhmail b/uip/mhmail index 2fbedccb..839b82a7 100755 --- a/uip/mhmail +++ b/uip/mhmail @@ -160,7 +160,8 @@ for arg in "$@"; do #### It's not strictly necessary to have one space after #### the : that separates the header field name from the #### body, but do it to avoid surprising someone. - add=`printf %s "$arg" | sed -e 's/:/: /' -e 's/: /: /'` + #### Solaris sed wants the trailing newline in its input. + add=`printf '%s\n' "$arg" | sed -e 's/:/: /' -e 's/: /: /'` headerfieldlist="${headerfieldlist:+$headerfieldlist}$add " headerfieldarg=0 diff --git a/uip/mhn.c b/uip/mhn.c index 5ce76222..a5a7b05e 100644 --- a/uip/mhn.c +++ b/uip/mhn.c @@ -147,7 +147,6 @@ void store_all_messages (CT *); void cache_all_messages (CT *); /* mhfree.c */ -void free_content (CT); extern CT *cts; void freects_done (int) NORETURN; @@ -622,7 +621,6 @@ static void pipeser (int i) { if (i == SIGQUIT) { - unlink ("core"); fflush (stdout); fprintf (stderr, "\n"); fflush (stderr); diff --git a/uip/mhoutsbr.c b/uip/mhoutsbr.c index 57a5df93..db64c4b8 100644 --- a/uip/mhoutsbr.c +++ b/uip/mhoutsbr.c @@ -62,12 +62,14 @@ output_message (CT ct, char *file) FILE *fp; int status; - if ((fp = fopen (file, "w")) == NULL) { + if (! strcmp (file, "-")) { + fp = stdout; + } else if ((fp = fopen (file, "w")) == NULL) { advise (file, "unable to open for writing"); return NOTOK; } status = output_message_fp(ct, fp, file); - fclose(fp); + if (strcmp (file, "-")) fclose(fp); return status; } @@ -81,6 +83,14 @@ output_content (CT ct, FILE *out) { int result = 0; CI ci = &ct->c_ctinfo; + char *boundary = ci->ci_values[0], **ap, **vp; + + for (ap = ci->ci_attrs, vp = ci->ci_values; *ap; ++ap, ++vp) { + if (! mh_strcasecmp ("boundary", *ap)) { + boundary = *vp; + break; + } + } /* * Output all header fields for this content @@ -108,14 +118,23 @@ output_content (CT ct, FILE *out) putc ('\n', out); m = (struct multipart *) ct->c_ctparams; + + if (m->mp_content_before) { + fprintf (out, "%s", m->mp_content_before); + } + for (part = m->mp_parts; part; part = part->mp_next) { CT p = part->mp_part; - fprintf (out, "\n--%s\n", ci->ci_values[0]); + fprintf (out, "\n--%s\n", boundary); if (output_content (p, out) == NOTOK) return NOTOK; } - fprintf (out, "\n--%s--\n", ci->ci_values[0]); + fprintf (out, "\n--%s--\n", boundary); + + if (m->mp_content_after) { + fprintf (out, "%s", m->mp_content_after); + } } break; @@ -142,7 +161,14 @@ output_content (CT ct, FILE *out) default: switch (ct->c_encoding) { case CE_7BIT: - putc ('\n', out); + /* Special case: if this is a non-MIME message with no + body, don't emit the newline that would appear between + the headers and body. In that case, the call to + write8Bit() shouldn't be needed, but is harmless. */ + if (ct->c_ctinfo.ci_attrs[0] != NULL || + ct->c_begin != ct->c_end) { + putc ('\n', out); + } result = write8Bit (ct, out); break; @@ -272,6 +298,7 @@ static int write8Bit (CT ct, FILE *out) { int fd; + size_t inbytes; char c, *file, buffer[BUFSIZ]; CE ce = ct->c_cefile; @@ -280,9 +307,9 @@ write8Bit (CT ct, FILE *out) return NOTOK; c = '\n'; - while (fgets (buffer, sizeof(buffer) - 1, ce->ce_fp)) { - c = buffer[strlen (buffer) - 1]; - fputs (buffer, out); + while ((inbytes = fread (buffer, 1, sizeof buffer, ce->ce_fp)) > 0) { + c = buffer[inbytes - 1]; + fwrite (buffer, 1, inbytes, out); } if (c != '\n') putc ('\n', out); diff --git a/uip/mhparam.c b/uip/mhparam.c index 1fb50a72..c4b0af2e 100644 --- a/uip/mhparam.c +++ b/uip/mhparam.c @@ -46,7 +46,6 @@ static struct proc procs [] = { { "foldprot", &foldprot }, { "formatproc", &formatproc }, { "incproc", &incproc }, - { "installproc", &installproc }, { "lproc", &lproc }, { "mailproc", &mailproc }, { "mhlproc", &mhlproc }, diff --git a/uip/mhparse.c b/uip/mhparse.c index 93f1f26f..69d2f2c8 100644 --- a/uip/mhparse.c +++ b/uip/mhparse.c @@ -36,6 +36,16 @@ int checksw = 0; /* check Content-MD5 field */ */ char *tmp; +/* + * These are for mhfixmsg to: + * 1) Instruct parser not to detect invalid Content-Transfer-Encoding + * in a multipart. + * 2) Suppress the warning about bogus multipart content, and report it. + */ +int skip_mp_cte_check; +int suppress_bogus_mp_content_warning; +int bogus_mp_content; + /* * Structures for TEXT messages */ @@ -88,14 +98,13 @@ int type_ok (CT, int); void content_error (char *, CT, char *, ...); /* mhfree.c */ -void free_content (CT); void free_encoding (CT, int); /* * static prototypes */ static CT get_content (FILE *, char *, int); -static int get_comment (CT, unsigned char **, int); +static int get_comment (CT, char **, int); static int InitGeneric (CT); static int InitText (CT); @@ -118,6 +127,7 @@ static int openFTP (CT, char **); static int InitMail (CT); static int openMail (CT, char **); static int readDigest (CT, char *); +static int get_leftover_mp_content (CT, int); struct str2init str2cts[] = { { "application", CT_APPLICATION, InitApplication }, @@ -262,6 +272,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 +286,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 +300,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 +331,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 @@ -335,8 +345,7 @@ get_content (FILE *in, char *file, int toplevel) /* Get MIME-Version field */ if (!mh_strcasecmp (hp->name, VRSN_FIELD)) { int ucmp; - char c; - unsigned char *cp, *dp; + char c, *cp, *dp; if (ct->c_vrsn) { advise (NULL, "message %s has multiple %s: fields", @@ -348,12 +357,12 @@ get_content (FILE *in, char *file, int toplevel) /* Now, cleanup this field */ cp = ct->c_vrsn; - while (isspace (*cp)) + while (isspace ((unsigned char) *cp)) cp++; for (dp = strchr(cp, '\n'); dp; dp = strchr(dp, '\n')) *dp++ = ' '; for (dp = cp + strlen (cp) - 1; dp >= cp; dp--) - if (!isspace (*dp)) + if (!isspace ((unsigned char) *dp)) break; *++dp = '\0'; if (debugsw) @@ -403,8 +412,7 @@ get_content (FILE *in, char *file, int toplevel) } else if (!mh_strcasecmp (hp->name, ENCODING_FIELD)) { /* Get Content-Transfer-Encoding field */ - char c; - unsigned char *cp, *dp; + char c, *cp, *dp; struct str2init *s2i; /* @@ -420,7 +428,7 @@ get_content (FILE *in, char *file, int toplevel) /* get copy of this field */ ct->c_celine = cp = add (hp->value, NULL); - while (isspace (*cp)) + while (isspace ((unsigned char) *cp)) cp++; for (dp = cp; istoken (*dp); dp++) continue; @@ -445,8 +453,7 @@ get_content (FILE *in, char *file, int toplevel) } else if (!mh_strcasecmp (hp->name, MD5_FIELD)) { /* Get Content-MD5 field */ - unsigned char *cp, *dp; - char *ep; + char *cp, *dp, *ep; if (!checksw) goto next_header; @@ -459,12 +466,12 @@ get_content (FILE *in, char *file, int toplevel) ep = cp = add (hp->value, NULL); /* get a copy */ - while (isspace (*cp)) + while (isspace ((unsigned char) *cp)) cp++; for (dp = strchr(cp, '\n'); dp; dp = strchr(dp, '\n')) *dp++ = ' '; for (dp = cp + strlen (cp) - 1; dp >= cp; dp--) - if (!isspace (*dp)) + if (!isspace ((unsigned char) *dp)) break; *++dp = '\0'; if (debugsw) @@ -475,7 +482,7 @@ get_content (FILE *in, char *file, int toplevel) goto out; } - for (dp = cp; *dp && !isspace (*dp); dp++) + for (dp = cp; *dp && !isspace ((unsigned char) *dp); dp++) continue; *dp = '\0'; @@ -578,7 +585,7 @@ add_header (CT ct, char *name, char *value) filename="foo". If it doesn't and value does, use value from that. */ static char * -incl_name_value (unsigned char *buf, char *name, char *value) { +incl_name_value (char *buf, char *name, char *value) { char *newbuf = buf; /* Assume that name is non-null. */ @@ -587,12 +594,11 @@ incl_name_value (unsigned char *buf, char *name, char *value) { if (! strstr (buf, name_plus_equal)) { char *insertion; - unsigned char *cp; - char *prefix, *suffix; + char *cp, *prefix, *suffix; /* Trim trailing space, esp. newline. */ for (cp = &buf[strlen (buf) - 1]; - cp >= buf && isspace (*cp); + cp >= buf && isspace ((unsigned char) *cp); --cp) { *cp = '\0'; } @@ -658,11 +664,10 @@ extract_name_value (char *name_suffix, char *value) { * directives. Fills in the information of the CTinfo structure. */ int -get_ctinfo (unsigned char *cp, CT ct, int magic) +get_ctinfo (char *cp, CT ct, int magic) { int i; - unsigned char *dp; - char **ap, **ep; + char *dp, **ap, **ep; char c; CI ci; @@ -672,7 +677,7 @@ get_ctinfo (unsigned char *cp, CT ct, int magic) /* store copy of Content-Type line */ cp = ct->c_ctline = add (cp, NULL); - while (isspace (*cp)) /* trim leading spaces */ + while (isspace ((unsigned char) *cp)) /* trim leading spaces */ cp++; /* change newlines to spaces */ @@ -681,7 +686,7 @@ get_ctinfo (unsigned char *cp, CT ct, int magic) /* trim trailing spaces */ for (dp = cp + strlen (cp) - 1; dp >= cp; dp--) - if (!isspace (*dp)) + if (!isspace ((unsigned char) *dp)) break; *++dp = '\0'; @@ -705,10 +710,10 @@ get_ctinfo (unsigned char *cp, CT ct, int magic) /* down case the content type string */ for (dp = ci->ci_type; *dp; dp++) - if (isalpha(*dp) && isupper (*dp)) - *dp = tolower (*dp); + if (isalpha((unsigned char) *dp) && isupper ((unsigned char) *dp)) + *dp = tolower ((unsigned char) *dp); - while (isspace (*cp)) + while (isspace ((unsigned char) *cp)) cp++; if (*cp == '(' && get_comment (ct, &cp, 1) == NOTOK) @@ -721,7 +726,7 @@ get_ctinfo (unsigned char *cp, CT ct, int magic) } cp++; - while (isspace (*cp)) + while (isspace ((unsigned char) *cp)) cp++; if (*cp == '(' && get_comment (ct, &cp, 1) == NOTOK) @@ -742,11 +747,11 @@ get_ctinfo (unsigned char *cp, CT ct, int magic) /* down case the content subtype string */ for (dp = ci->ci_subtype; *dp; dp++) - if (isalpha(*dp) && isupper (*dp)) - *dp = tolower (*dp); + if (isalpha((unsigned char) *dp) && isupper ((unsigned char) *dp)) + *dp = tolower ((unsigned char) *dp); magic_skip: - while (isspace (*cp)) + while (isspace ((unsigned char) *cp)) cp++; if (*cp == '(' && get_comment (ct, &cp, 1) == NOTOK) @@ -757,8 +762,7 @@ magic_skip: */ ep = (ap = ci->ci_attrs) + NPARMS; while (*cp == ';') { - char *vp; - unsigned char *up; + char *vp, *up; if (ap >= ep) { advise (NULL, @@ -768,7 +772,7 @@ magic_skip: } cp++; - while (isspace (*cp)) + while (isspace ((unsigned char) *cp)) cp++; if (*cp == '(' && get_comment (ct, &cp, 1) == NOTOK) @@ -782,11 +786,11 @@ magic_skip: } /* down case the attribute name */ - for (dp = cp; istoken (*dp); dp++) - if (isalpha(*dp) && isupper (*dp)) - *dp = tolower (*dp); + for (dp = cp; istoken ((unsigned char) *dp); dp++) + if (isalpha((unsigned char) *dp) && isupper ((unsigned char) *dp)) + *dp = tolower ((unsigned char) *dp); - for (up = dp; isspace (*dp);) + for (up = dp; isspace ((unsigned char) *dp);) dp++; if (dp == cp || *dp != '=') { advise (NULL, @@ -797,7 +801,7 @@ magic_skip: vp = (*ap = add (cp, NULL)) + (up - cp); *vp = '\0'; - for (dp++; isspace (*dp);) + for (dp++; isspace ((unsigned char) *dp);) dp++; /* now add the attribute value */ @@ -842,7 +846,7 @@ bad_quote: } ap++; - while (isspace (*cp)) + while (isspace ((unsigned char) *cp)) cp++; if (*cp == '(' && get_comment (ct, &cp, 1) == NOTOK) @@ -870,7 +874,7 @@ bad_quote: *dp++ = c; cp = dp; - while (isspace (*cp)) + while (isspace ((unsigned char) *cp)) cp++; } @@ -897,7 +901,7 @@ bad_quote: *dp++ = c; cp = dp; - while (isspace (*cp)) + while (isspace ((unsigned char) *cp)) cp++; } @@ -924,7 +928,7 @@ bad_quote: *dp++ = c; cp = dp; - while (isspace (*cp)) + while (isspace ((unsigned char) *cp)) cp++; } @@ -959,11 +963,10 @@ bad_quote: static int -get_comment (CT ct, unsigned char **ap, int istype) +get_comment (CT ct, char **ap, int istype) { int i; - char *bp; - unsigned char *cp; + char *bp, *cp; char c, buffer[BUFSIZ], *dp; CI ci; @@ -1013,7 +1016,7 @@ invalid: } } - while (isspace (*cp)) + while (isspace ((unsigned char) *cp)) cp++; *ap = cp; @@ -1105,8 +1108,7 @@ InitMultiPart (CT ct) { int inout; long last, pos; - unsigned char *cp, *dp; - char **ap, **ep; + char *cp, *dp, **ap, **ep; char *bp, buffer[BUFSIZ]; struct multipart *m; struct k2v *kv; @@ -1119,15 +1121,15 @@ InitMultiPart (CT ct) * The encoding for multipart messages must be either * 7bit, 8bit, or binary (per RFC2045). */ - if (ct->c_encoding != CE_7BIT && ct->c_encoding != CE_8BIT - && ct->c_encoding != CE_BINARY) { + if (! skip_mp_cte_check && ct->c_encoding != CE_7BIT && + ct->c_encoding != CE_8BIT && ct->c_encoding != CE_BINARY) { /* Copy the Content-Transfer-Encoding header field body so we can remove any trailing whitespace and leading blanks from it. */ char *cte = add (ct->c_celine ? ct->c_celine : "(null)", NULL); bp = cte + strlen (cte) - 1; - while (bp >= cte && isspace (*bp)) *bp-- = '\0'; - for (bp = cte; *bp && isblank (*bp); ++bp) continue; + while (bp >= cte && isspace ((unsigned char) *bp)) *bp-- = '\0'; + for (bp = cte; *bp && isblank ((unsigned char) *bp); ++bp) continue; admonish (NULL, "\"%s/%s\" type in message %s must be encoded in\n" @@ -1172,7 +1174,7 @@ InitMultiPart (CT ct) ct->c_ctparams = (void *) m; /* check if boundary parameter contains only whitespace characters */ - for (cp = bp; isspace (*cp); cp++) + for (cp = bp; isspace ((unsigned char) *cp); cp++) continue; if (!*cp) { advise (NULL, "invalid \"boundary\" parameter for \"%s/%s\" type in message %s's %s: field", @@ -1182,7 +1184,7 @@ InitMultiPart (CT ct) /* remove trailing whitespace from boundary parameter */ for (cp = bp, dp = cp + strlen (cp) - 1; dp > cp; dp--) - if (!isspace (*dp)) + if (!isspace ((unsigned char) *dp)) break; *++dp = '\0'; @@ -1245,7 +1247,11 @@ end_part: } } - advise (NULL, "bogus multipart content in message %s", ct->c_file); + if (! suppress_bogus_mp_content_warning) { + advise (NULL, "bogus multipart content in message %s", ct->c_file); + } + bogus_mp_content = 1; + if (!inout && part) { p = part->mp_part; p->c_end = ct->c_end; @@ -1297,6 +1303,9 @@ last_part: } } + get_leftover_mp_content (ct, 1); + get_leftover_mp_content (ct, 0); + fclose (ct->c_fp); ct->c_fp = NULL; return OK; @@ -1731,8 +1740,7 @@ openBase64 (CT ct, char **file) int fd, len, skip, own_ct_fp = 0; uint32_t bits; unsigned char value, b; - unsigned char *cp, *ep; - char buffer[BUFSIZ]; + char *cp, *ep, buffer[BUFSIZ]; /* sbeck -- handle suffixes */ CI ci; CE ce; @@ -1828,13 +1836,13 @@ openBase64 (CT ct, char **file) for (ep = (cp = buffer) + cc; cp < ep; cp++) { switch (*cp) { default: - if (isspace (*cp)) + if (isspace ((unsigned char) *cp)) break; - if (skip || (*cp & 0x80) - || (value = b642nib[*cp & 0x7f]) > 0x3f) { + if (skip || (((unsigned char) *cp) & 0x80) + || (value = b642nib[((unsigned char) *cp) & 0x7f]) > 0x3f) { if (debugsw) { fprintf (stderr, "*cp=0x%x pos=%ld skip=%d\n", - *cp, + (unsigned char) *cp, (long) (lseek (fd, (off_t) 0, SEEK_CUR) - (ep - cp)), skip); } @@ -1965,7 +1973,7 @@ static int openQuoted (CT ct, char **file) { int cc, digested, len, quoted, own_ct_fp = 0; - unsigned char *cp, *ep; + char *cp, *ep; char buffer[BUFSIZ]; unsigned char mask; CE ce; @@ -2057,7 +2065,7 @@ openQuoted (CT ct, char **file) len -= cc; for (ep = (cp = buffer) + cc - 1; cp <= ep; ep--) - if (!isspace (*ep)) + if (!isspace ((unsigned char) *ep)) break; *++ep = '\n', ep++; @@ -2066,13 +2074,13 @@ openQuoted (CT ct, char **file) /* in an escape sequence */ if (quoted == 1) { /* at byte 1 of an escape sequence */ - mask = hex2nib[*cp & 0x7f]; + mask = hex2nib[((unsigned char) *cp) & 0x7f]; /* next is byte 2 */ quoted = 2; } else { /* at byte 2 of an escape sequence */ mask <<= 4; - mask |= hex2nib[*cp & 0x7f]; + mask |= hex2nib[((unsigned char) *cp) & 0x7f]; putc (mask, ce->ce_fp); if (digested) MD5Update (&mdContext, &mask, 1); @@ -2099,7 +2107,8 @@ openQuoted (CT ct, char **file) if (cp + 1 >= ep || cp + 2 >= ep) { /* We don't have 2 bytes left, so this is an invalid * escape sequence; just show the raw bytes (below). */ - } else if (isxdigit (cp[1]) && isxdigit (cp[2])) { + } else if (isxdigit ((unsigned char) cp[1]) && + isxdigit ((unsigned char) cp[2])) { /* Next 2 bytes are hex digits, making this a valid escape * sequence; let's decode it (above). */ quoted = 1; @@ -2628,7 +2637,7 @@ openFTP (CT ct, char **file) fflush (stdout); - for (i = 0; (child_id = vfork()) == NOTOK && i < 5; i++) + for (i = 0; (child_id = fork()) == NOTOK && i < 5; i++) sleep (5); switch (child_id) { case NOTOK: @@ -2770,7 +2779,7 @@ openMail (CT ct, char **file) vec[vecp++] = e->eb_body; vec[vecp] = NULL; - for (i = 0; (child_id = vfork()) == NOTOK && i < 5; i++) + for (i = 0; (child_id = fork()) == NOTOK && i < 5; i++) sleep (5); switch (child_id) { case NOTOK: @@ -2889,3 +2898,109 @@ invalid_digest: return OK; } + + +/* Multipart parts might have content before the first subpart and/or + after the last subpart that hasn't been stored anywhere else, so do + that. */ +int +get_leftover_mp_content (CT ct, int before /* or after */) { + struct multipart *m = (struct multipart *) ct->c_ctparams; + char *boundary; + int found_boundary = 0; + char buffer[BUFSIZ]; + int max = BUFSIZ; + int read = 0; + char *content = NULL; + + if (! m) return NOTOK; + + if (before) { + if (! m->mp_parts || ! m->mp_parts->mp_part) return NOTOK; + + /* Isolate the beginning of this part to the beginning of the + first subpart and save any content between them. */ + fseeko (ct->c_fp, ct->c_begin, SEEK_SET); + max = m->mp_parts->mp_part->c_begin - ct->c_begin; + boundary = concat ("--", m->mp_start, NULL); + } else { + struct part *last_subpart = NULL; + struct part *subpart; + + /* Go to the last subpart to get its end position. */ + for (subpart = m->mp_parts; subpart; subpart = subpart->mp_next) { + last_subpart = subpart; + } + + if (last_subpart == NULL) return NOTOK; + + /* Isolate the end of the last subpart to the end of this part + and save any content between them. */ + fseeko (ct->c_fp, last_subpart->mp_part->c_end, SEEK_SET); + max = ct->c_end - last_subpart->mp_part->c_end; + boundary = concat ("--", m->mp_stop, NULL); + } + + /* Back up by 1 to pick up the newline. */ + while (fgets (buffer, sizeof(buffer) - 1, ct->c_fp)) { + read += strlen (buffer); + /* Don't look beyond beginning of first subpart (before) or + next part (after). */ + if (read > max) buffer[read-max] = '\0'; + + if (before) { + if (! strcmp (buffer, boundary)) { + found_boundary = 1; + } + } else { + if (! found_boundary && ! strcmp (buffer, boundary)) { + found_boundary = 1; + continue; + } + } + + if ((before && ! found_boundary) || (! before && found_boundary)) { + if (content) { + char *old_content = content; + content = concat (content, buffer, NULL); + free (old_content); + } else { + content = before + ? concat ("\n", buffer, NULL) + : concat (buffer, NULL); + } + } + + if (before) { + if (found_boundary || read > max) break; + } else { + if (read > max) break; + } + } + + /* Skip the newline if that's all there is. */ + if (content) { + char *cp; + + /* Remove trailing newline, except at EOF. */ + if ((before || ! feof (ct->c_fp)) && + (cp = content + strlen (content)) > content && + *--cp == '\n') { + *cp = '\0'; + } + + if (strlen (content) > 1) { + if (before) { + m->mp_content_before = content; + } else { + m->mp_content_after = content; + } + } else { + free (content); + } + } + + free (boundary); + + return OK; +} diff --git a/uip/mhshow.c b/uip/mhshow.c index 8e1a9003..f5666b07 100644 --- a/uip/mhshow.c +++ b/uip/mhshow.c @@ -99,7 +99,6 @@ void flush_errors (void); void show_all_messages (CT *); /* mhfree.c */ -void free_content (CT); extern CT *cts; void freects_done (int) NORETURN; @@ -430,7 +429,6 @@ static void pipeser (int i) { if (i == SIGQUIT) { - unlink ("core"); fflush (stdout); fprintf (stderr, "\n"); fflush (stderr); diff --git a/uip/mhshowsbr.c b/uip/mhshowsbr.c index 3b91eebf..db804cb7 100644 --- a/uip/mhshowsbr.c +++ b/uip/mhshowsbr.c @@ -168,30 +168,30 @@ 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; fflush (stdout); - for (i = 0; (child_id = vfork()) == NOTOK && i < 5; i++) + for (i = 0; (child_id = fork()) == NOTOK && i < 5; i++) sleep (5); switch (child_id) { @@ -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); } @@ -558,7 +560,7 @@ show_content_aux2 (CT ct, int serial, int alternate, char *cracked, char *buffer fflush (stdout); - for (i = 0; (child_id = vfork()) == NOTOK && i < 5; i++) + for (i = 0; (child_id = fork()) == NOTOK && i < 5; i++) sleep (5); switch (child_id) { case NOTOK: diff --git a/uip/mhstore.c b/uip/mhstore.c index 61a54e63..1865f14c 100644 --- a/uip/mhstore.c +++ b/uip/mhstore.c @@ -86,7 +86,6 @@ void flush_errors (void); void store_all_messages (CT *); /* mhfree.c */ -void free_content (CT); extern CT *cts; void freects_done (int) NORETURN; @@ -384,7 +383,6 @@ static void pipeser (int i) { if (i == SIGQUIT) { - unlink ("core"); fflush (stdout); fprintf (stderr, "\n"); fflush (stderr); diff --git a/uip/mhtest.c b/uip/mhtest.c index 44cc3b23..cf7f8642 100644 --- a/uip/mhtest.c +++ b/uip/mhtest.c @@ -83,7 +83,6 @@ int type_ok (CT, int); void flush_errors (void); /* mhfree.c */ -void free_content (CT); extern CT *cts; void freects_done (int) NORETURN; diff --git a/uip/msh.c b/uip/msh.c index 6069cac4..4ab73286 100644 --- a/uip/msh.c +++ b/uip/msh.c @@ -155,6 +155,8 @@ void seq_setcur (struct msgs *, int); void padios (char *, char *, ...); void padvise (char *, char *, ...); +extern m_getfld_state_t gstate; /* use the gstate in scansbr.c */ + /* * static prototypes @@ -341,6 +343,7 @@ main (int argc, char **argv) display_info (id > 0 ? scansw : 0); msh (id > 0 ? scansw : 0); + scan_finished (); m_reset (); @@ -682,7 +685,7 @@ setup (char *file) mp->msgattrs[0] = getcpy ("unseen"); mp->msgattrs[1] = NULL; - m_unknown (fp); /* the MAGIC invocation */ + scan_detect_mbox_style (fp); /* the MAGIC invocation */ if (fmsh) { free (fmsh); fmsh = NULL; @@ -805,7 +808,8 @@ msh_ready (int msgnum, int full) return yp; } - m_eomsbr ((int (*)()) 0); /* XXX */ + scan_reset_m_getfld_state (); + scan_eom_action ((int (*)()) 0); /* XXX */ fseek (fp, Msgs[msgnum].m_start, SEEK_SET); return fp; } @@ -974,15 +978,16 @@ readid (int msgnum) return Msgs[msgnum].m_bboard_id; zp = msh_ready (msgnum, 0); - for (state = FLD;;) - switch (state = m_getfld (state, name, buf, sizeof(buf), zp)) { + for (;;) { + int bufsz = sizeof buf; + switch (state = m_getfld (&gstate, name, buf, &bufsz, zp)) { case FLD: - case FLDEOF: case FLDPLUS: if (!mh_strcasecmp (name, BBoard_ID)) { bp = getcpy (buf); while (state == FLDPLUS) { - state = m_getfld (state, name, buf, sizeof(buf), zp); + bufsz = sizeof buf; + state = m_getfld (&gstate, name, buf, &bufsz, zp); bp = add (buf, bp); } i = atoi (bp); @@ -992,14 +997,16 @@ readid (int msgnum) else continue; } - while (state == FLDPLUS) - state = m_getfld (state, name, buf, sizeof(buf), zp); - if (state != FLDEOF) - continue; + while (state == FLDPLUS) { + bufsz = sizeof buf; + state = m_getfld (&gstate, name, buf, &bufsz, zp); + } + continue; default: return 0; } + } } @@ -1267,8 +1274,7 @@ static int parse (char *buffer, struct Cmd *cmdp) { int argp = 0; - unsigned char c, *cp; - char *pp; + char c, *cp, *pp; cmdp->line[0] = 0; pp = cmdp->args[argp++] = cmdp->line; @@ -1277,7 +1283,7 @@ parse (char *buffer, struct Cmd *cmdp) cmdp->stream = NULL; for (cp = buffer; (c = *cp); cp++) { - if (!isspace (c)) + if (!isspace ((unsigned char) c)) break; } if (c == '\0') { @@ -1287,8 +1293,8 @@ parse (char *buffer, struct Cmd *cmdp) } while ((c = *cp++)) { - if (isspace (c)) { - while (isspace (c)) + if (isspace ((unsigned char) c)) { + while (isspace ((unsigned char) c)) c = *cp++; if (c == 0) break; @@ -1343,7 +1349,7 @@ parse (char *buffer, struct Cmd *cmdp) } cmdp->redirect = pp + 1;/* sigh */ for (; (c = *cp); cp++) - if (!isspace (c)) + if (!isspace ((unsigned char) c)) break; if (c == 0) { padvise (NULL, cmdp->direction != PIPIO @@ -1354,7 +1360,7 @@ parse (char *buffer, struct Cmd *cmdp) strcpy (cmdp->redirect, cp); if (cmdp->direction != PIPIO) { for (; *cp; cp++) - if (isspace (*cp)) { + if (isspace ((unsigned char) *cp)) { padvise (NULL, "bad name for redirect"); return NOTOK; } @@ -1586,7 +1592,7 @@ static int pINI (void) { int i, vrsn; - unsigned char *bp; + char *bp; struct record rcs, *rc; rc = &rcs; @@ -1595,7 +1601,7 @@ pINI (void) switch (peer2rc (rc)) { case RC_INI: bp = rc->rc_data; - while (isspace (*bp)) + while (isspace ((unsigned char) *bp)) bp++; if (sscanf (bp, "%d", &vrsn) != 1) { bad_init: ; @@ -1607,9 +1613,9 @@ pINI (void) done (1); } - while (*bp && !isspace (*bp)) + while (*bp && !isspace ((unsigned char) *bp)) bp++; - while (isspace (*bp)) + while (isspace ((unsigned char) *bp)) bp++; if (sscanf (bp, "%d", &numwins) != 1 || numwins <= 0) goto bad_init; @@ -1617,9 +1623,9 @@ pINI (void) numwins = NWIN; for (i = 1; i <= numwins; i++) { - while (*bp && !isspace (*bp)) + while (*bp && !isspace ((unsigned char) *bp)) bp++; - while (isspace (*bp)) + while (isspace ((unsigned char) *bp)) bp++; if (sscanf (bp, "%d", &windows[i]) != 1 || windows[i] <= 0) goto bad_init; diff --git a/uip/mshcmds.c b/uip/mshcmds.c index 8212375a..41017430 100644 --- a/uip/mshcmds.c +++ b/uip/mshcmds.c @@ -51,6 +51,8 @@ static int process (int, char *, int, char **); static void copy_message (int, FILE *); static void copy_digest (int, FILE *); +extern m_getfld_state_t gstate; /* use the gstate in scansbr.c */ + void forkcmd (char **args, char *pgm) { @@ -950,7 +952,7 @@ forw (char *proc, char *filter, int vecp, char **vec) args[i++] = getcpy (m_name (msgnum)); args[i] = NULL; mhlsbr (i, args, mhl_action); - m_eomsbr ((int (*) ()) 0); + scan_eom_action ((int (*) ()) 0); fclose (stdout); _exit (0); @@ -2211,7 +2213,7 @@ finish: ; if (mp->numsel == 1 && headersw) show (mp->lowsel); mhlsbr (vecp, vec, mhl_action); - m_eomsbr ((int (*)()) 0); + scan_eom_action ((int (*)()) 0); while (msgp < vecp) free (vec[msgp++]); } else { @@ -2283,7 +2285,7 @@ mhl_action (char *name) mhlfp = msh_ready (msgnum, 1); if (!fmsh) - m_eomsbr (eom_action); + scan_eom_action (eom_action); return mhlfp; } @@ -2330,8 +2332,7 @@ static int is_nontext (int msgnum) { int result, state; - unsigned char *bp, *dp; - char *cp; + char *bp, *dp, *cp; char buf[BUFSIZ], name[NAMESZ]; FILE *fp; @@ -2341,11 +2342,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,14 +2356,15 @@ 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; passno = 1; again: - for (; isspace (*bp); bp++) + for (; isspace ((unsigned char) *bp); bp++) continue; if (*bp == '(') { int i; @@ -2407,24 +2409,24 @@ invalid: if ((result = (mh_strcasecmp (bp, "plain") != 0))) goto out; *dp = c; - for (dp++; isspace (*dp); dp++) + for (dp++; isspace ((unsigned char) *dp); dp++) continue; if (*dp) { if ((result = !uprf (dp, "charset"))) goto out; dp += sizeof "charset" - 1; - while (isspace (*dp)) + while (isspace ((unsigned char) *dp)) dp++; if (*dp++ != '=') goto invalid; - while (isspace (*dp)) + while (isspace ((unsigned char) *dp)) dp++; if (*dp == '"') { if ((bp = strchr(++dp, '"'))) *bp = '\0'; } else { for (bp = dp; *bp; bp++) - if (isspace (*bp)) { + if (isspace ((unsigned char) *bp)) { *bp = '\0'; break; } @@ -2458,10 +2460,11 @@ 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++) + for (bp = cp; isspace ((unsigned char) *bp); bp++) continue; for (dp = bp; istoken (*dp); dp++) continue; @@ -2482,8 +2485,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 +2498,7 @@ out: default: return 0; } + } } @@ -2645,15 +2651,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 +2678,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 +2688,14 @@ get_fields (char *datesw, char *subjsw, int msgnum, struct Msg *msgp) else subjsw = (char *)0;/* subject done, need date */ } else { - while (state == FLDPLUS) /* flush this one */ - state = m_getfld (state, name, buf, sizeof buf, zp); + while (state == FLDPLUS) { /* flush this one */ + bufsz = sizeof buf; + state = m_getfld (&gstate, name, buf, &bufsz, zp); + } } continue; case BODY: - case BODYEOF: case FILEEOF: break; diff --git a/uip/new.c b/uip/new.c index e88a0dd7..e391ba20 100644 --- a/uip/new.c +++ b/uip/new.c @@ -99,6 +99,7 @@ get_msgnums(char *folder, char *sequences[]) char name[NAMESZ], field[BUFSIZ]; char *cp; char *msgnums = NULL, *this_msgnums, *old_msgnums; + m_getfld_state_t gstate = 0; /* no sequences file -> no messages */ if (fp == NULL) { @@ -106,16 +107,16 @@ get_msgnums(char *folder, char *sequences[]) } /* copied from seq_read.c:seq_public */ - for (state = FLD;;) { - switch (state = m_getfld (state, name, field, sizeof(field), fp)) { + for (;;) { + int fieldsz = sizeof field; + switch (state = m_getfld (&gstate, name, field, &fieldsz, fp)) { case FLD: case FLDPLUS: - case FLDEOF: if (state == FLDPLUS) { cp = getcpy (field); while (state == FLDPLUS) { - state = m_getfld (state, name, field, - sizeof(field), fp); + fieldsz = sizeof field; + state = m_getfld (&gstate, name, field, &fieldsz, fp); cp = add (field, cp); } @@ -150,12 +151,9 @@ get_msgnums(char *folder, char *sequences[]) } } - if (state == FLDEOF) - break; continue; case BODY: - case BODYEOF: adios (NULL, "no blank lines are permitted in %s", seqfile); /* fall */ @@ -167,6 +165,7 @@ get_msgnums(char *folder, char *sequences[]) } break; /* break from for loop */ } + m_getfld_state_destroy (&gstate); fclose(fp); diff --git a/uip/picksbr.c b/uip/picksbr.c index 7b64f819..ec7400a3 100644 --- a/uip/picksbr.c +++ b/uip/picksbr.c @@ -562,8 +562,8 @@ gcompile (struct nexus *n, char *astr) int cclcnt; register unsigned char *ep, *dp, *sp, *lastep = 0; - dp = (ep = n->n_expbuf) + sizeof n->n_expbuf; - sp = astr; + dp = (ep = (unsigned char *) n->n_expbuf) + sizeof n->n_expbuf; + sp = (unsigned char *) astr; if (*sp == '^') { n->n_circf = 1; sp++; @@ -802,7 +802,7 @@ advance (char *alp, char *aep) star: do { lp--; - if (advance (lp, ep)) + if (advance ((char *) lp, (char *) ep)) return (1); } while (lp > curlp); return 0; @@ -934,28 +934,28 @@ plist register char *bp; char buf[BUFSIZ], name[NAMESZ]; register struct tws *tw; + m_getfld_state_t gstate = 0; NMH_UNUSED (stop); fseek (fp, start, SEEK_SET); - for (state = FLD, bp = NULL;;) { - switch (state = m_getfld (state, name, buf, sizeof buf, fp)) { + for (bp = NULL;;) { + int bufsz = sizeof buf; + switch (state = m_getfld (&gstate, name, buf, &bufsz, fp)) { case FLD: - case FLDEOF: case FLDPLUS: if (bp != NULL) free (bp), bp = NULL; bp = add (buf, NULL); while (state == FLDPLUS) { - state = m_getfld (state, name, buf, sizeof buf, fp); + bufsz = sizeof buf; + state = m_getfld (&gstate, name, buf, &bufsz, fp); bp = add (buf, bp); } if (!mh_strcasecmp (name, n->n_datef)) break; - if (state != FLDEOF) - continue; + continue; case BODY: - case BODYEOF: case FILEEOF: case LENERR: case FMTERR: @@ -970,6 +970,7 @@ plist } break; } + m_getfld_state_destroy (&gstate); if ((tw = dparsetime (bp)) == NULL) advise (NULL, "unable to parse %s field in message %d, matching...", diff --git a/uip/post.c b/uip/post.c index f6f7924c..9b8bcbef 100644 --- a/uip/post.c +++ b/uip/post.c @@ -185,8 +185,6 @@ static short fccind = 0; /* index into fccfold[] */ static short outputlinelen = OUTPUTLINELEN; static int pfd = NOTOK; /* fd to write annotation list to */ -static uid_t myuid= -1; /* my user id */ -static gid_t mygid= -1; /* my group id */ static int recipients = 0; /* how many people will get a copy */ static int unkadr = 0; /* how many of those were unknown */ static int badadr = 0; /* number of bad addrs */ @@ -263,7 +261,7 @@ static int insert (struct mailname *); static void pl (void); static void anno (void); static int annoaux (struct mailname *); -static void insert_fcc (struct headers *, unsigned char *); +static void insert_fcc (struct headers *, char *); static void make_bcc_file (int); static void verify_all_addresses (int, char *); static void chkadr (void); @@ -286,6 +284,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 +521,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 +541,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 +582,7 @@ main (int argc, char **argv) } break; } + m_getfld_state_destroy (&gstate); if (pfd != NOTOK) anno (); @@ -923,12 +921,9 @@ putfmt (char *name, char *str, FILE *out) static void start_headers (void) { - unsigned char *cp; - char sigbuf[BUFSIZ]; + char *cp, sigbuf[BUFSIZ]; struct mailname *mp; - myuid = getuid (); - mygid = getgid (); time (&tclock); /* @@ -1257,13 +1252,13 @@ annoaux (struct mailname *mp) static void -insert_fcc (struct headers *hdr, unsigned char *pp) +insert_fcc (struct headers *hdr, char *pp) { - unsigned char *cp; + char *cp; - for (cp = pp; isspace (*cp); cp++) + for (cp = pp; isspace ((unsigned char) *cp); cp++) continue; - for (pp += strlen (pp) - 1; pp > cp && isspace (*pp); pp--) + for (pp += strlen (pp) - 1; pp > cp && isspace ((unsigned char) *pp); pp--) continue; if (pp >= cp) *++pp = 0; @@ -1284,9 +1279,9 @@ make_bcc_file (int dashstuff) { int fd, i; pid_t child_id; - char *vec[6]; + char **vec; FILE *out; - char *tfile = NULL; + char *tfile = NULL, *program; tfile = m_mktemp2(NULL, "bccs", NULL, &out); if (tfile == NULL) adios("bcc", "unable to create temporary file"); @@ -1338,8 +1333,6 @@ make_bcc_file (int dashstuff) * of MIME encapsulation. */ if (filter != NULL) { - vec[0] = r1bindex (mhlproc, '/'); - for (i = 0; (child_id = fork()) == NOTOK && i < 5; i++) sleep (5); switch (child_id) { @@ -1349,7 +1342,7 @@ make_bcc_file (int dashstuff) case OK: dup2 (fileno (out), 1); - i = 1; + vec = argsplit(mhlproc, &program, &i); vec[i++] = "-forward"; vec[i++] = "-form"; vec[i++] = filter; @@ -1362,7 +1355,7 @@ make_bcc_file (int dashstuff) vec[i++] = "-nodashstuffing"; vec[i] = NULL; - execvp (mhlproc, vec); + execvp (program, vec); fprintf (stderr, "unable to exec "); perror (mhlproc); _exit (-1); @@ -1405,7 +1398,7 @@ static int find_prefix (void) { int result = OK; - unsigned char buffer[BUFSIZ]; + char buffer[BUFSIZ]; FILE *in; if ((in = fopen (tmpfil, "r")) == NULL) @@ -1413,10 +1406,10 @@ find_prefix (void) while (fgets (buffer, sizeof(buffer) - 1, in)) if (buffer[0] == '-' && buffer[1] == '-') { - unsigned char *cp; + char *cp; for (cp = buffer + strlen (buffer) - 1; cp >= buffer; cp--) - if (!isspace (*cp)) + if (!isspace ((unsigned char) *cp)) break; *++cp = '\0'; if (strcmp (buffer + 2, prefix) == 0) { @@ -1513,7 +1506,8 @@ post (char *file, int bccque, int talk, char *envelope) sigon (); if (sm_mts == MTS_SENDMAIL_PIPE) { - char *sargv[16], **argp; + char **argp, *program; + int argc; for (i = 0; (child_id = fork()) == NOTOK && i < 5; i++) sleep (5); @@ -1526,17 +1520,16 @@ post (char *file, int bccque, int talk, char *envelope) adios (file, "can't reopen for sendmail"); } - argp = sargv; - *argp++ = "sendmail"; - *argp++ = "-t"; /* read msg for recipients */ - *argp++ = "-i"; /* don't stop on "." */ + argp = argsplit(sendmail, &program, &argc); + argp[argc++] = "-t"; /* read msg for recipients */ + argp[argc++] = "-i"; /* don't stop on "." */ if (whomsw) - *argp++ = "-bv"; + argp[argc++] = "-bv"; if (snoop) - *argp++ = "-v"; - *argp = NULL; + argp[argc++] = "-v"; + argp[argc] = NULL; - execv (sendmail, sargv); + execv (program, argp); adios (sendmail, "can't exec"); default: @@ -1787,8 +1780,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 +1805,14 @@ fcc (char *file, char *folder) *folder == '+' || *folder == '@' ? "" : "+", folder); /* now exec the fileproc */ - execlp (fileproc, r1bindex (fileproc, '/'), - "-link", "-file", file, fold, NULL); + + arglist = argsplit(fileproc, &program, &argp); + arglist[argp++] = "-link"; + arglist[argp++] = "-file"; + arglist[argp++] = file; + arglist[argp++] = fold; + arglist[argp] = NULL; + execvp (program, arglist); _exit (-1); default: diff --git a/uip/prompter.c b/uip/prompter.c index d950163d..563da058 100644 --- a/uip/prompter.c +++ b/uip/prompter.c @@ -78,6 +78,7 @@ main (int argc, char **argv) char **arguments, **argp; FILE *in, *out; char *tfile = NULL; + m_getfld_state_t gstate = 0; #ifdef LOCALE setlocale(LC_ALL, ""); @@ -202,10 +203,10 @@ main (int argc, char **argv) /* * Loop through the lines of the draft skeleton. */ - for (state = FLD;;) { - switch (state = m_getfld (state, name, field, sizeof(field), in)) { + for (;;) { + int fieldsz = sizeof field; + switch (state = m_getfld (&gstate, name, field, &fieldsz, in)) { case FLD: - case FLDEOF: case FLDPLUS: /* * Check if the value of field contains anything @@ -220,8 +221,8 @@ main (int argc, char **argv) printf ("%s:%s", name, field); fprintf (out, "%s:%s", name, field); while (state == FLDPLUS) { - state = - m_getfld (state, name, field, sizeof(field), in); + fieldsz = sizeof field; + state = m_getfld (&gstate, name, field, &fieldsz, in); printf ("%s", field); fprintf (out, "%s", field); } @@ -251,17 +252,9 @@ abort: } } - if (state == FLDEOF) { /* moby hack */ - fprintf (out, "--------\n"); - printf ("--------\n"); - if (!body) - break; - goto no_body; - } continue; case BODY: - case BODYEOF: case FILEEOF: if (!body) break; @@ -287,13 +280,14 @@ abort: if (!rapid && !sigint) printf ("%s", field); } while (state == BODY && - (state = m_getfld (state, name, field, sizeof(field), in))); + (fieldsz = sizeof field, + state = m_getfld (&gstate, name, field, &fieldsz, in))); if (prepend || !body) break; else printf ("\n--------Enter additional text\n\n"); } -no_body: + fflush (stdout); for (;;) { getln (field, sizeof(field)); @@ -310,6 +304,7 @@ no_body: } break; } + m_getfld_state_destroy (&gstate); if (body) printf ("--------\n"); diff --git a/uip/rcvdist.c b/uip/rcvdist.c index 2db1b050..6cc8e277 100644 --- a/uip/rcvdist.c +++ b/uip/rcvdist.c @@ -42,9 +42,9 @@ int main (int argc, char **argv) { pid_t child_id; - int i, vecp = 1; - char *addrs = NULL, *cp, *form = NULL, buf[BUFSIZ]; - char **argp, **arguments, *vec[MAXARGS]; + int i, vecp; + char *addrs = NULL, *cp, *form = NULL, buf[BUFSIZ], *program; + char **argp, **arguments, **vec; FILE *fp; char *tfile = NULL; @@ -58,6 +58,13 @@ main (int argc, char **argv) /* read user profile/context */ context_read(); + /* + * Configure this now, since any unknown switches to rcvdist get + * sent to postproc + */ + + vec = argsplit(postproc, &program, &vecp); + mts_init (invo_name); arguments = getarguments (invo_name, argc, argv, 1); argp = arguments; @@ -114,7 +121,6 @@ main (int argc, char **argv) if (distout (drft, tmpfil, backup) == NOTOK) done (1); - vec[0] = r1bindex (postproc, '/'); vec[vecp++] = "-dist"; vec[vecp++] = drft; if ((cp = context_find ("mhlproc"))) { @@ -129,7 +135,7 @@ main (int argc, char **argv) case NOTOK: admonish (NULL, "unable to fork");/* fall */ case OK: - execvp (postproc, vec); + execvp (program, vec); fprintf (stderr, "unable to exec "); perror (postproc); _exit (1); @@ -176,6 +182,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 +202,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 +235,7 @@ rcvdistout (FILE *inb, char *form, char *addrs) } } finished: ; + m_getfld_state_destroy (&gstate); i = format_len + char_read + 256; scanl = mh_xmalloc ((size_t) i + 2); diff --git a/uip/rcvtty.c b/uip/rcvtty.c index 9cd77dd6..5443748c 100644 --- a/uip/rcvtty.c +++ b/uip/rcvtty.c @@ -192,7 +192,7 @@ message_fd (char **vec) fd = mkstemp (strncpy (tmpfil, "/tmp/rcvttyXXXXX", sizeof(tmpfil))); unlink (tmpfil); - if ((child_id = vfork()) == NOTOK) { + if ((child_id = fork()) == NOTOK) { /* fork error */ close (fd); return header_fd (); @@ -257,6 +257,7 @@ header_fd (void) /* get new format string */ nfs = new_fs (form, format, SCANFMT); scan (stdin, 0, 0, nfs, width, 0, 0, NULL, 0L, 0); + scan_finished (); if (newline) write (fd, "\n\r", 2); write (fd, scanl, strlen (scanl)); diff --git a/uip/refile.c b/uip/refile.c index ae71de23..54b6e5f8 100644 --- a/uip/refile.c +++ b/uip/refile.c @@ -321,17 +321,19 @@ clsfolds (struct st_fold *folders, int nfolders) static void remove_files (int filep, char **files) { - int i; - char **vec; + int i, vecp; + char **vec, *program; /* If rmmproc is defined, we use that */ if (rmmproc) { - vec = files++; /* vec[0] = filevec[0] */ - files[filep] = NULL; /* NULL terminate list */ + vec = argsplit(rmmproc, &program, &vecp); + files++; /* Yes, we need to do this */ + for (i = 0; i < filep; i++) + vec[vecp++] = files[i]; + vec[vecp] = NULL; /* NULL terminate list */ fflush (stdout); - vec[0] = r1bindex (rmmproc, '/'); - execvp (rmmproc, vec); + execvp (program, vec); adios (rmmproc, "unable to exec"); } diff --git a/uip/replsbr.c b/uip/replsbr.c index 21170376..a7a214bf 100644 --- a/uip/replsbr.c +++ b/uip/replsbr.c @@ -71,9 +71,9 @@ replout (FILE *inb, char *msg, char *drft, struct msgs *mp, int outputlinelen, struct format *fmt; register char **ap; int char_read = 0, format_len, mask; - char name[NAMESZ], *scanl; - unsigned char *cp; + char name[NAMESZ], *scanl, *cp; static int dat[5]; /* aux. data for format routine */ + m_getfld_state_t gstate = 0; struct fmt_callbacks cb; FILE *out; @@ -134,8 +134,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: @@ -150,15 +151,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: @@ -176,6 +179,7 @@ replout (FILE *inb, char *msg, char *drft, struct msgs *mp, int outputlinelen, * format and output the header lines. */ finished: + m_getfld_state_destroy (&gstate); /* * if there's a "Subject" component, strip any "Re:"s off it @@ -185,7 +189,7 @@ finished: register char *sp = cp; for (;;) { - while (isspace(*cp)) + while (isspace((unsigned char) *cp)) cp++; if(uprf(cp, "re:")) cp += 3; @@ -413,7 +417,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; @@ -421,12 +426,10 @@ 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); - switch (pid = vfork()) { + switch (pid = fork()) { case NOTOK: adios ("fork", "unable to"); @@ -435,26 +438,29 @@ replfilter (FILE *in, FILE *out, char *filter, int fmtproc) dup2 (fileno (out), fileno (stdout)); closefds (3); - arglist[0] = mhl; - arglist[1] = "-form"; - arglist[2] = filter; - arglist[3] = "-noclear"; + /* + * We're not allocating the memory for the extra arguments, + * because we never call arglist_free(). But if we ever change + * that be sure to use getcpy() for the extra arguments. + */ + arglist = argsplit(mhlproc, &mhl, &argnum); + arglist[argnum++] = "-form"; + arglist[argnum++] = filter; + arglist[argnum++] = "-noclear"; switch (fmtproc) { case 1: - arglist[4] = "-fmtproc"; - arglist[5] = formatproc; - arglist[6] = NULL; + arglist[argnum++] = "-fmtproc"; + arglist[argnum++] = formatproc; break; case 0: - arglist[4] = "-nofmtproc"; - arglist[5] = NULL; + arglist[argnum++] = "-nofmtproc"; break; - default: - arglist[4] = NULL; } - execvp (mhlproc, arglist); + arglist[argnum++] = NULL; + + execvp (mhl, arglist); errstr = strerror(errno); write(2, "unable to exec ", 15); write(2, mhlproc, strlen(mhlproc)); diff --git a/uip/scan.c b/uip/scan.c index e1b9a165..459fcb07 100644 --- a/uip/scan.c +++ b/uip/scan.c @@ -175,13 +175,14 @@ main (int argc, char **argv) printf ("FOLDER %s\t%s\n", file, dtimenow (1)); } - m_unknown (in); + scan_detect_mbox_style (in); for (msgnum = 1; ; ++msgnum) { state = scan (in, msgnum, -1, nfs, width, 0, 0, hdrflag ? file : NULL, 0L, 1); if (state != SCNMSG && state != SCNENC) break; } + scan_finished (); fclose (in); done (0); } @@ -276,6 +277,7 @@ main (int argc, char **argv) advise (NULL, "message %d: empty", msgnum); break; } + scan_finished (); hdrflag = 0; fclose (in); if (ontty) diff --git a/uip/scansbr.c b/uip/scansbr.c index ddfdd841..c038622e 100644 --- a/uip/scansbr.c +++ b/uip/scansbr.c @@ -36,6 +36,7 @@ static struct comp **used_buf = 0; /* stack for comp that use buffers */ static int dat[5]; /* aux. data for format routine */ char *scanl = 0; /* text of most recent scanline */ +m_getfld_state_t gstate; /* for access by msh */ #define DIEWRERR() adios (scnmsg, "write error on") @@ -60,14 +61,14 @@ scan (FILE *inb, int innum, int outnum, char *nfs, int width, int curflg, int unseen, char *folder, long size, int noisy) { int i, compnum, encrypted, state; - unsigned char *cp, *tmpbuf, *startbody; - char **nxtbuf; + char *cp, *tmpbuf, *startbody, **nxtbuf; char *saved_c_text = NULL; struct comp *cptr; struct comp **savecomp; char *scnmsg = NULL; FILE *scnout = NULL; char name[NAMESZ]; + int bufsz; static int rlwidth, slwidth; static size_t scanl_size; @@ -162,7 +163,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 +187,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: @@ -205,7 +209,7 @@ scan (FILE *inb, int innum, int outnum, char *nfs, int width, int curflg, cptr->c_text = tmpbuf; for (cp = tmpbuf + strlen (tmpbuf) - 1; cp >= tmpbuf; cp--) - if (isspace (*cp)) + if (isspace ((unsigned char) *cp)) *cp = 0; else break; @@ -215,7 +219,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 +234,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 +269,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 +378,23 @@ mh_fputs(char *s, FILE *stream) return (0); } +/* The following three functions allow access to the global gstate above. */ +void +scan_finished () { + m_getfld_state_destroy (&gstate); +} + +void +scan_detect_mbox_style (FILE *f) { + m_unknown (&gstate, f); +} + +void +scan_eom_action (int (*action)()) { + m_eomsbr (gstate, action); +} + +void +scan_reset_m_getfld_state () { + m_getfld_state_reset (&gstate); +} diff --git a/uip/send.c b/uip/send.c index 1bfd0608..510047a0 100644 --- a/uip/send.c +++ b/uip/send.c @@ -56,10 +56,6 @@ X("help", 0, HELPSW) \ X("dashstuffing", -12, BITSTUFFSW) \ X("nodashstuffing", -14, NBITSTUFFSW) \ - X("mail", -4, MAILSW) \ - X("saml", -4, SAMLSW) \ - X("send", -4, SENDSW) \ - X("soml", -4, SOMLSW) \ X("client host", -6, CLIESW) \ X("server host", 6, SERVSW) \ X("snoop", 5, SNOOPSW) \ @@ -114,12 +110,12 @@ extern char *distfile; int main (int argc, char **argv) { - int msgp = 0, distsw = 0, vecp = 1; + int msgp = 0, distsw = 0, vecp; int isdf = 0, mime = 0; int msgnum, status; char *cp, *dfolder = NULL, *maildir = NULL; - char buf[BUFSIZ], **ap, **argp, **arguments; - char *msgs[MAXARGS], *vec[MAXARGS]; + char buf[BUFSIZ], **ap, **argp, **arguments, *program; + char *msgs[MAXARGS], **vec; struct msgs *mp; struct stat st; char *attach = NMH_ATTACH_HEADER; /* header field name for attachments */ @@ -136,6 +132,8 @@ main (int argc, char **argv) arguments = getarguments (invo_name, argc, argv, 1); argp = arguments; + vec = argsplit(postproc, &program, &vecp); + vec[vecp++] = "-library"; vec[vecp++] = getcpy (m_maildir ("")); @@ -243,10 +241,6 @@ main (int argc, char **argv) case NMSGDSW: case WATCSW: case NWATCSW: - case MAILSW: - case SAMLSW: - case SENDSW: - case SOMLSW: case SNOOPSW: case SASLSW: case NOSASLSW: @@ -443,11 +437,10 @@ go_to_it: push (); status = 0; - vec[0] = r1bindex (postproc, '/'); closefds (3); for (msgnum = 0; msgnum < msgp; msgnum++) { - switch (sendsbr (vec, vecp, msgs[msgnum], &st, 1, attach, + switch (sendsbr (vec, vecp, program, msgs[msgnum], &st, 1, attach, attachformat)) { case DONE: done (++status); diff --git a/uip/sendsbr.c b/uip/sendsbr.c index dfd974f4..e3a8195f 100644 --- a/uip/sendsbr.c +++ b/uip/sendsbr.c @@ -46,7 +46,7 @@ static FILE *composition_file; /* composition file pointer */ /* * external prototypes */ -int sendsbr (char **, int, char *, struct stat *, int, char *, int); +int sendsbr (char **, int, char *, char *, struct stat *, int, char *, int); char *getusername (void); /* @@ -57,8 +57,8 @@ static void alert (char *, int); static int tmp_fd (void); static void anno (int, struct stat *); static void annoaux (int); -static int splitmsg (char **, int, char *, struct stat *, int); -static int sendaux (char **, int, char *, struct stat *); +static int splitmsg (char **, int, char *, char *, struct stat *, int); +static int sendaux (char **, int, char *, char *, struct stat *); static int attach(char *, char *, int); static void clean_up_temporary_files(void); @@ -71,7 +71,8 @@ static void make_mime_composition_file_entry(char *, int, char *); */ int -sendsbr (char **vec, int vecp, char *drft, struct stat *st, int rename_drft, char *attachment_header_field_name, int attachformat) +sendsbr (char **vec, int vecp, char *program, char *drft, struct stat *st, + int rename_drft, char *attachment_header_field_name, int attachformat) { int status; char buffer[BUFSIZ], file[BUFSIZ]; @@ -132,9 +133,9 @@ sendsbr (char **vec, int vecp, char *drft, struct stat *st, int rename_drft, cha */ if (splitsw >= 0 && !distfile && stat (drft, &sts) != NOTOK && sts.st_size >= CPERMSG) { - status = splitmsg (vec, vecp, drft, st, splitsw) ? NOTOK : OK; + status = splitmsg (vec, vecp, program, drft, st, splitsw) ? NOTOK : OK; } else { - status = sendaux (vec, vecp, drft, st) ? NOTOK : OK; + status = sendaux (vec, vecp, program, drft, st) ? NOTOK : OK; } /* rename the original draft */ @@ -582,7 +583,8 @@ make_mime_composition_file_entry(char *file_name, int attachformat, */ static int -splitmsg (char **vec, int vecp, char *drft, struct stat *st, int delay) +splitmsg (char **vec, int vecp, char *program, char *drft, + struct stat *st, int delay) { int compnum, nparts, partno, state, status; long pos, start; @@ -591,6 +593,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 +605,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 +644,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 +655,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 +678,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"); @@ -695,7 +700,7 @@ splitmsg (char **vec, int vecp, char *drft, struct stat *st, int delay) free (dp); fclose (in); - return sendaux (vec, vecp, drft, st); + return sendaux (vec, vecp, program, drft, st); } if (!pushsw) { @@ -785,7 +790,7 @@ splitmsg (char **vec, int vecp, char *drft, struct stat *st, int delay) } snprintf (partnum, sizeof(partnum), "%d", partno); - status = sendaux (vec, vecp, tmpdrf, st); + status = sendaux (vec, vecp, program, tmpdrf, st); unlink (tmpdrf); if (status != OK) break; @@ -808,11 +813,11 @@ splitmsg (char **vec, int vecp, char *drft, struct stat *st, int delay) /* * Annotate original message, and - * call `postproc' to send message. + * call `postproc' (which is passed down in "program") to send message. */ static int -sendaux (char **vec, int vecp, char *drft, struct stat *st) +sendaux (char **vec, int vecp, char *program, char *drft, struct stat *st) { pid_t child_id; int i, status, fd, fd2; @@ -835,7 +840,7 @@ sendaux (char **vec, int vecp, char *drft, struct stat *st) done (1); vec[vecp] = NULL; - for (i = 0; (child_id = vfork()) == NOTOK && i < 5; i++) + for (i = 0; (child_id = fork()) == NOTOK && i < 5; i++) sleep (5); switch (child_id) { @@ -856,7 +861,7 @@ sendaux (char **vec, int vecp, char *drft, struct stat *st) dup2 (fd, fileno (stderr)); close (fd); } - execvp (postproc, vec); + execvp (program, vec); fprintf (stderr, "unable to exec "); perror (postproc); _exit (-1); @@ -905,8 +910,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 +953,14 @@ alert (char *file, int out) snprintf (buf, sizeof(buf), "send failed on %s", forwsw ? "enclosed draft" : file); - execlp (mailproc, r1bindex (mailproc, '/'), getusername (), - "-subject", buf, NULL); + arglist = argsplit(mailproc, &program, &argp); + + arglist[argp++] = getusername(); + arglist[argp++] = "-subject"; + arglist[argp++] = buf; + arglist[argp] = NULL; + + execvp (program, arglist); fprintf (stderr, "unable to exec "); perror (mailproc); _exit (-1); diff --git a/uip/show.c b/uip/show.c index 229e6edd..dc426130 100644 --- a/uip/show.c +++ b/uip/show.c @@ -55,7 +55,7 @@ main (int argc, char **argv) int draftsw = 0, headersw = 1; int nshow = 0, checkmime = 1, mime; int isdf = 0, mode = SHOW, msgnum; - char *cp, *maildir, *file = NULL, *folder = NULL, *proc; + char *cp, *maildir, *file = NULL, *folder = NULL, *proc, *program; char buf[BUFSIZ], **argp, **arguments; struct msgs *mp = NULL; struct msgs_array msgs = { 0, 0, NULL }; @@ -66,8 +66,6 @@ main (int argc, char **argv) #endif invo_name = r1bindex (argv[0], '/'); - app_msgarg(&vec, NULL); /* placeholder, filled later with proc name */ - /* read user profile/context */ context_read(); @@ -256,8 +254,8 @@ usage: context_replace (pfolder, folder); /* update current folder */ context_save (); /* save the context file */ - if (headersw && vec.size == 2) - printf ("(Message %s:%s)\n", folder, vec.msgs[1]); + if (headersw && vec.size == 1) + printf ("(Message %s:%s)\n", folder, vec.msgs[0]); go_to_it: ; fflush (stdout); @@ -311,15 +309,15 @@ go_to_it: ; } } else if (strcmp (r1bindex (proc, '/'), "mhl") == 0) { /* If "mhl", then run it internally */ - vec.msgs[0] = "mhl"; + argsplit_insert(&vec, "mhl", &program); app_msgarg(&vec, NULL); mhl (vec.size, vec.msgs); done (0); } - vec.msgs[0] = r1bindex (proc, '/'); + argsplit_insert(&vec, proc, &program); app_msgarg(&vec, NULL); - execvp (proc, vec.msgs); + execvp (program, vec.msgs); adios (proc, "unable to exec"); return 0; /* dead code to satisfy the compiler */ } @@ -332,19 +330,19 @@ static int is_nontext (char *msgnam) { int result, state; - unsigned char *bp, *dp; - char *cp; + char *bp, *dp, *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,14 +352,15 @@ 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; passno = 1; again: - for (; isspace (*bp); bp++) + for (; isspace ((unsigned char) *bp); bp++) continue; if (*bp == '(') { int i; @@ -406,17 +405,17 @@ invalid: if ((result = (mh_strcasecmp (bp, "plain") != 0))) goto out; *dp = c; - for (dp++; isspace (*dp); dp++) + for (dp++; isspace ((unsigned char) *dp); dp++) continue; if (*dp) { if ((result = !uprf (dp, "charset"))) goto out; dp += sizeof("charset") - 1; - while (isspace (*dp)) + while (isspace ((unsigned char) *dp)) dp++; if (*dp++ != '=') goto invalid; - while (isspace (*dp)) + while (isspace ((unsigned char) *dp)) dp++; if (*dp == '"') { if ((bp = strchr(++dp, '"'))) @@ -446,6 +445,7 @@ out: free (cp); if (result) { fclose (fp); + m_getfld_state_destroy (&gstate); return result; } break; @@ -457,12 +457,13 @@ 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++) + for (bp = cp; isspace ((unsigned char) *bp); bp++) continue; - for (dp = bp; istoken (*dp); dp++) + for (dp = bp; istoken ((unsigned char) *dp); dp++) continue; *dp = '\0'; result = (mh_strcasecmp (bp, "7bit") @@ -472,6 +473,7 @@ out: free (cp); if (result) { fclose (fp); + m_getfld_state_destroy (&gstate); return result; } break; @@ -481,8 +483,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; /* @@ -491,6 +495,7 @@ out: */ default: fclose (fp); + m_getfld_state_destroy (&gstate); return 0; } } diff --git a/uip/slocal.c b/uip/slocal.c index 1c30dfc5..f570aaaf 100644 --- a/uip/slocal.c +++ b/uip/slocal.c @@ -645,7 +645,7 @@ static int split (char *cp, char **vec) { int i; - unsigned char *s; + char *s; s = cp; @@ -654,7 +654,7 @@ split (char *cp, char **vec) vec[i] = NULL; /* zap any whitespace and comma's */ - while (isspace (*s) || *s == ',') + while (isspace ((unsigned char) *s) || *s == ',') *s++ = 0; /* end of buffer, time to leave */ @@ -684,7 +684,7 @@ split (char *cp, char **vec) vec[i++] = s++; /* move forward to next field delimiter */ - while (*s && !isspace (*s) && *s != ',') + while (*s && !isspace ((unsigned char) *s) && *s != ',') s++; } vec[i] = NULL; @@ -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"))) { @@ -1153,8 +1153,8 @@ static void get_sender (char *envelope, char **sender) { int i; - unsigned char *cp; - unsigned char buffer[BUFSIZ]; + char *cp; + char buffer[BUFSIZ]; if (envelope == NULL) { *sender = getcpy (""); @@ -1174,7 +1174,7 @@ get_sender (char *envelope, char **sender) *cp = 0; for (cp = buffer + strlen (buffer) - 1; cp >= buffer; cp--) - if (isspace (*cp)) + if (isspace ((unsigned char) *cp)) *cp = 0; else break; @@ -1296,7 +1296,7 @@ static char * trim (char *cp) { char buffer[BUFSIZ*4]; - unsigned char *bp, *sp; + char *bp, *sp; if (cp == NULL) return NULL; @@ -1306,12 +1306,12 @@ trim (char *cp) bp = buffer; /* skip over leading whitespace */ - while (isspace(*bp)) + while (isspace((unsigned char) *bp)) bp++; /* start at the end and zap trailing whitespace */ for (sp = bp + strlen(bp) - 1; sp >= bp; sp--) { - if (isspace(*sp)) + if (isspace((unsigned char) *sp)) *sp = 0; else break; @@ -1319,7 +1319,7 @@ trim (char *cp) /* replace remaining whitespace with spaces */ for (sp = bp; *sp; sp++) - if (isspace(*sp)) + if (isspace((unsigned char) *sp)) *sp = ' '; /* now return a copy */ @@ -1405,6 +1405,7 @@ suppress_duplicates (int fd, char *file) datum key, value; DBM *db; FILE *in; + m_getfld_state_t gstate = 0; if ((fd1 = dup (fd)) == -1) return -1; @@ -1414,22 +1415,25 @@ suppress_duplicates (int fd, char *file) } rewind (in); - for (state = FLD;;) { - state = m_getfld (state, name, buf, sizeof(buf), in); + for (;;) { + int bufsz = sizeof buf; + state = m_getfld (&gstate, name, buf, &bufsz, in); switch (state) { case FLD: case FLDPLUS: - case FLDEOF: /* Search for the message ID */ if (mh_strcasecmp (name, "Message-ID")) { - while (state == FLDPLUS) - state = m_getfld (state, name, buf, sizeof(buf), in); + while (state == FLDPLUS) { + bufsz = sizeof buf; + state = m_getfld (&gstate, name, buf, &bufsz, in); + } continue; } cp = add (buf, NULL); while (state == FLDPLUS) { - state = m_getfld (state, name, buf, sizeof(buf), in); + bufsz = sizeof buf; + state = m_getfld (&gstate, name, buf, &bufsz, in); cp = add (buf, cp); } key.dptr = trimcpy (cp); @@ -1477,7 +1481,6 @@ suppress_duplicates (int fd, char *file) break; case BODY: - case BODYEOF: case FILEEOF: break; @@ -1489,6 +1492,7 @@ suppress_duplicates (int fd, char *file) break; } + m_getfld_state_destroy (&gstate); fclose (in); return 0; diff --git a/uip/sortm.c b/uip/sortm.c index 429f75f9..6e7a7491 100644 --- a/uip/sortm.c +++ b/uip/sortm.c @@ -70,8 +70,7 @@ int main (int argc, char **argv) { int i, msgnum; - unsigned char *cp; - char *maildir, *datesw = NULL; + char *cp, *maildir, *datesw = NULL; char *folder = NULL, buf[BUFSIZ], **argp; char **arguments; struct msgs_array msgs = { 0, 0, NULL }; @@ -141,7 +140,7 @@ main (int argc, char **argv) submajor++; /* sort subject-major */ continue; } - if (!isdigit(*cp) || !(datelimit = atoi(cp))) + if (!isdigit((unsigned char) *cp) || !(datelimit = atoi(cp))) adios (NULL, "impossible limit %s", cp); datelimit *= 60*60*24; continue; @@ -357,21 +356,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 +380,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 +418,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 +427,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; @@ -438,14 +445,13 @@ get_fields (char *datesw, int msg, struct smsg *smsg) * leading "re:", everything but letters & smash * letters to lower case. */ - register char *cp, *cp2; - register unsigned char c; + register char *cp, *cp2, c; cp = subjcomp; cp2 = subjcomp; if (strcmp (subjsort, "subject") == 0) { while ((c = *cp)) { - if (! isspace(c)) { + if (! isspace((unsigned char) c)) { if(uprf(cp, "re:")) cp += 2; else @@ -456,8 +462,9 @@ get_fields (char *datesw, int msg, struct smsg *smsg) } while ((c = *cp++)) { - if (isalnum(c)) - *cp2++ = isupper(c) ? tolower(c) : c; + if (isascii((unsigned char) c) && isalnum((unsigned char) c)) + *cp2++ = isupper((unsigned char) c) ? + tolower((unsigned char) c) : c; } *cp2 = '\0'; diff --git a/uip/viamail.c b/uip/viamail.c index 82c7db58..37514d5a 100644 --- a/uip/viamail.c +++ b/uip/viamail.c @@ -183,9 +183,9 @@ static int via_mail (char *mailsw, char *subjsw, char *parmsw, char *descsw, char *cmntsw, int delay, char *fromsw) { - int status, vecp = 1; - char tmpfil[BUFSIZ]; - char *vec[MAXARGS]; + int status, vecp; + char tmpfil[BUFSIZ], *program; + char **vec; struct stat st; FILE *fp; char *tfile = NULL; @@ -240,11 +240,12 @@ via_mail (char *mailsw, char *subjsw, char *parmsw, char *descsw, splitsw = delay; status = 0; - vec[0] = r1bindex (postproc, '/'); + + vec = argsplit(postproc, &program, &vecp); if (verbsw) vec[vecp++] = "-verbose"; - switch (sendsbr (vec, vecp, tmpfil, &st, 0, (char *)0, 0)) { + switch (sendsbr (vec, vecp, program, tmpfil, &st, 0, (char *)0, 0)) { case DONE: case NOTOK: status++; diff --git a/uip/vmhsbr.c b/uip/vmhsbr.c index eb6e0378..ca78c03f 100644 --- a/uip/vmhsbr.c +++ b/uip/vmhsbr.c @@ -155,11 +155,13 @@ str2peer (char code, char *str) int fmt2peer (char code, char *fmt, ...) { + int return_value; va_list ap; va_start(ap, fmt); - return verr2peer (code, NULL, fmt, ap); + return_value = verr2peer (code, NULL, fmt, ap); va_end(ap); + return return_value; } diff --git a/uip/whatnowsbr.c b/uip/whatnowsbr.c index 9a9fec1b..0beba2b1 100644 --- a/uip/whatnowsbr.c +++ b/uip/whatnowsbr.c @@ -644,7 +644,7 @@ editfile (char **ed, char **arg, char *file, int use, struct msgs *mp, { int pid, status, vecp; char altpath[BUFSIZ], linkpath[BUFSIZ]; - char *cp, *vec[MAXARGS]; + char *cp, *prog, **vec; struct stat st; #ifdef HAVE_LSTAT @@ -697,7 +697,7 @@ editfile (char **ed, char **arg, char *file, int use, struct msgs *mp, context_save (); /* save the context file */ fflush (stdout); - switch (pid = vfork()) { + switch (pid = fork()) { case NOTOK: advise ("fork", "unable to"); status = NOTOK; @@ -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); @@ -816,7 +816,7 @@ sendfile (char **arg, char *file, int pushsw) { pid_t child_id; int i, vecp; - char *cp, *sp, *vec[MAXARGS]; + char *cp, *sp, **vec, *program; /* Translate MIME composition file, if necessary */ if ((cp = context_find ("automimeproc")) @@ -845,14 +845,13 @@ sendfile (char **arg, char *file, int pushsw) context_save (); /* save the context file */ fflush (stdout); - for (i = 0; (child_id = vfork()) == NOTOK && i < 5; i++) + for (i = 0; (child_id = fork()) == NOTOK && i < 5; i++) sleep (5); switch (child_id) { case NOTOK: advise (NULL, "unable to fork, so sending directly..."); case OK: - vecp = 0; - vec[vecp++] = invo_name; + vec = argsplit(sendproc, &program, &vecp); if (pushsw) vec[vecp++] = "-push"; if (arg) @@ -861,7 +860,7 @@ sendfile (char **arg, char *file, int pushsw) vec[vecp++] = file; vec[vecp] = NULL; - execvp (sendproc, vec); + execvp (program, vec); fprintf (stderr, "unable to exec "); perror (sendproc); _exit (-1); @@ -924,14 +923,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 @@ -939,10 +939,13 @@ check_draft (char *msgnam) */ if (uprf (name, XXX_FIELD_PRF)) { fclose (fp); + m_getfld_state_destroy (&gstate); 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: @@ -952,17 +955,21 @@ check_draft (char *msgnam) for (bp = buf; *bp; bp++) if (*bp != ' ' && *bp != '\t' && *bp != '\n') { fclose (fp); + m_getfld_state_destroy (&gstate); 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... */ default: fclose (fp); + m_getfld_state_destroy (&gstate); return 0; } + } } @@ -1005,10 +1012,6 @@ check_draft (char *msgnam) X("help", 0, SHELPSW) \ X("dashstuffing", -12, BITSTUFFSW) \ X("nodashstuffing", -14, NBITSTUFFSW) \ - X("mail", -4, MAILSW) \ - X("saml", -4, SAMLSW) \ - X("send", -4, SSNDSW) \ - X("soml", -4, SOMLSW) \ X("client host", -6, CLIESW) \ X("server host", 6, SERVSW) \ X("snoop", -5, SNOOPSW) \ @@ -1055,8 +1058,8 @@ static void sendit (char *sp, char **arg, char *file, int pushed) { int vecp, n = 1; - char *cp, buf[BUFSIZ], **argp; - char **arguments, *vec[MAXARGS]; + char *cp, buf[BUFSIZ], **argp, *program; + char **arguments, *savearg[MAXARGS], **vec; struct stat st; char *attach = NMH_ATTACH_HEADER;/* attachment header field name */ int attachformat = 1; /* mhbuild format specifier for @@ -1068,17 +1071,17 @@ sendit (char *sp, char **arg, char *file, int pushed) /* * Make sure these are defined. In particular, we need - * vec[1] to be NULL, in case "arg" is NULL below. It - * doesn't matter what is the value of vec[0], but we + * savearg[1] to be NULL, in case "arg" is NULL below. It + * doesn't matter what is the value of savearg[0], but we * set it to NULL, to help catch "off-by-one" errors. */ - vec[0] = NULL; - vec[1] = NULL; + savearg[0] = NULL; + savearg[1] = NULL; /* - * Temporarily copy arg to vec, since the brkstring() call in + * Temporarily copy arg to savearg, since the brkstring() call in * getarguments() will wipe it out before it is merged in. - * Also, we skip the first element of vec, since getarguments() + * Also, we skip the first element of savearg, since getarguments() * skips it. Then we count the number of arguments * copied. The value of "n" will be one greater than * this in order to simulate the standard argc/argv. @@ -1086,17 +1089,17 @@ sendit (char *sp, char **arg, char *file, int pushed) if (arg) { char **bp; - copyip (arg, vec+1, MAXARGS-1); - bp = vec+1; + copyip (arg, savearg+1, MAXARGS-1); + bp = savearg+1; while (*bp++) n++; } /* - * Merge any arguments from command line (now in vec) + * Merge any arguments from command line (now in savearg) * and arguments from profile. */ - arguments = getarguments (sp, n, vec, 1); + arguments = getarguments (sp, n, savearg, 1); argp = arguments; debugsw = 0; @@ -1108,7 +1111,12 @@ sendit (char *sp, char **arg, char *file, int pushed) annotext = NULL; distfile = NULL; - vecp = 1; /* we'll get the zero'th element later */ + /* + * Get our initial arguments for postproc now + */ + + vec = argsplit(postproc, &program, &vecp); + vec[vecp++] = "-library"; vec[vecp++] = getcpy (m_maildir ("")); @@ -1189,10 +1197,6 @@ sendit (char *sp, char **arg, char *file, int pushed) case NMSGDSW: case WATCSW: case NWATCSW: - case MAILSW: - case SAMLSW: - case SSNDSW: - case SOMLSW: case SNOOPSW: case SASLSW: case NOSASLSW: @@ -1304,10 +1308,9 @@ sendit (char *sp, char **arg, char *file, int pushed) if ((pushsw = pushed)) push (); - vec[0] = r1bindex (postproc, '/'); closefds (3); - if (sendsbr (vec, vecp, file, &st, 1, attach, attachformat) == OK) + if (sendsbr (vec, vecp, program, file, &st, 1, attach, attachformat) == OK) done (0); } @@ -1320,26 +1323,25 @@ whomfile (char **arg, char *file) { pid_t pid; int vecp; - char *vec[MAXARGS]; + char **vec, *program; context_save (); /* save the context file */ fflush (stdout); - switch (pid = vfork()) { + switch (pid = fork()) { case NOTOK: advise ("fork", "unable to"); return 1; case OK: - vecp = 0; - vec[vecp++] = r1bindex (whomproc, '/'); + vec = argsplit(whomproc, &program, &vecp); vec[vecp++] = file; if (arg) while (*arg) vec[vecp++] = *arg++; vec[vecp] = NULL; - execvp (whomproc, vec); + execvp (program, vec); fprintf (stderr, "unable to exec "); perror (whomproc); _exit (-1); /* NOTREACHED */