]> diplodocus.org Git - nmh/commitdiff
Merge remote-tracking branch 'origin' into convertargs
authorDavid Levine <levinedl@acm.org>
Thu, 8 Jan 2015 02:32:20 +0000 (20:32 -0600)
committerDavid Levine <levinedl@acm.org>
Thu, 8 Jan 2015 02:32:20 +0000 (20:32 -0600)
23 files changed:
Makefile.am
configure.ac
docs/pending-release-notes
h/mhparse.h
h/prototypes.h
man/mh-profile.man
man/mhfixmsg.man
sbr/fmt_scan.c
sbr/getansreadline.c
sbr/mime_type.c
sbr/uprf.c
test/common.sh.in
test/format/test-fmtdump
test/format/test-functions
test/mhfixmsg/test-mhfixmsg
test/mhparam/test-mhparam
test/whatnow/test-cd
uip/mhfixmsg.c
uip/mhlsbr.c
uip/mhparse.c
uip/mhshowsbr.c
uip/prompter.c
uip/whatnowsbr.c

index 5552527..90dee63 100644 (file)
@@ -39,6 +39,7 @@ TESTS_ENVIRONMENT = MH_OBJ_DIR="@abs_builddir@" \
                    MH_TEST_DIR="@abs_builddir@/test/testdir" \
                    nmhlibexecdir="$(nmhlibexecdir)" bindir="$(bindir)" \
                    mandir="$(mandir)" nmhetcdir="$(nmhetcdir)" \
+                   nmhetcdirinst="@nmhetcdirinst@$(nmhetcdir)" \
                    supported_locks="$(supported_locks)" \
                    default_locking="${default_locking}" \
                    MULTIBYTE_ENABLED=$(MULTIBYTE_ENABLED) \
@@ -104,7 +105,13 @@ TESTS = test/ali/test-ali test/anno/test-anno \
 check_SCRIPTS = test/common.sh
 check_PROGRAMS = test/getfullname test/getcanon test/fakepop test/fakesmtp \
                 test/getcwidth
-DISTCHECK_CONFIGURE_FLAGS = DISABLE_SETGID_MAIL=1
+
+## The location of installed nmhetcdir is, for all purposes except
+## distcheck, $nmhetcdir.  For distcheck, prepend $MH_INST_DIR (from
+## test/common.sh.in), which is based on $MH_TEST_DIR (from
+## $TESTS_ENVIRONMENT).
+DISTCHECK_CONFIGURE_FLAGS = DISABLE_SETGID_MAIL=1 \
+                           NMHETCDIRINST='$${abs_builddir}/test/testdir/inst'
 
 ##
 ## Stuff that should be cleaned via "make clean"
@@ -608,7 +615,7 @@ sbr_libmh_a_SOURCES = sbr/addrsbr.c sbr/ambigsw.c sbr/atooi.c sbr/arglist.c \
 
 config/sbr_libmh_a-config.$(OBJEXT) sbr/sbr_libmh_a-mts.$(OBJEXT): Makefile
 
-sbr_libmh_a_CPPFLAGS = -I./sbr -DNMHETCDIR='"$(nmhetcdir)"' \
+sbr_libmh_a_CPPFLAGS = -I./sbr -DNMHETCDIR='"@nmhetcdirinst@$(nmhetcdir)"' \
                -DMAILSPOOL='"$(mailspool)"' \
                -DSENDMAILPATH='"$(sendmailpath)"' -DNMHBINDIR='"$(bindir)"' \
                -DNMHLIBEXECDIR='"$(nmhlibexecdir)"'
index 4e195b6..754ccb6 100644 (file)
@@ -516,6 +516,13 @@ AS_IF([test "$LEX" = flex],
 '; sed "s/\(   \)int i;/\1yy_size_t i;/" $@ >$@.tmp && mv -f $@.tmp $@'])
        AC_SUBST([LFLAGS])])
 
+dnl ------------------
+dnl FOR INTERNAL USE by the NMH test suite
+dnl ------------------
+AC_ARG_VAR([NMHETCDIRINST], [for internal use by nmh test suite])
+AS_IF([test -n "$NMHETCDIRINST"], [nmhetcdirinst=$NMHETCDIRINST]
+      AC_SUBST([nmhetcdirinst]))
+
 dnl ----------------
 dnl CHECK STRUCTURES
 dnl ----------------
index 991b169..4ae6707 100644 (file)
@@ -25,7 +25,8 @@ NEW FEATURES
 - When building from source, configure will derive ${prefix} from an existing
   nmh installation if it finds one in your $PATH.
 - Added getmymbox and getmyaddr mh-format(5) function escapes.
-- The -changecur and -nochangecur switches have been added to mhfixmsg(1).
+- New -changecur, -nochangecur, and -fixtype switches have been added
+  to mhfixmsg(1).
 - mhfixmsg now removes an extraneous trailing semicolon from header
   parameter lists.
 - Added -convertargs switch to repl(1), to pass arguments to programs
index 371e671..c3b0b9f 100644 (file)
@@ -338,6 +338,8 @@ void close_encoding (CT);
 void free_content (CT);
 char *ct_type_str (int);
 char *ct_subtype_str (int, int);
+int ct_str_type (const char *);
+int ct_str_subtype (int, const char *);
 const struct str2init *get_ct_init (int);
 const char *ce_str (int);
 const struct str2init *get_ce_method (const char *);
index a338fd5..3399384 100644 (file)
@@ -384,7 +384,7 @@ int unputenv (char *);
  *
  */
 void unquote_string(const char *input, char *output);
-int uprf (char *, char *);
+int uprf (const char *, const char *);
 int vfgets (FILE *, char **);
 
 /*
index 81e2ccb..cdd7812 100644 (file)
@@ -1,4 +1,4 @@
-.TH MH-PROFILE %manext5% "April 18, 2014" "%nmhversion%"
+.TH MH-PROFILE %manext5% "December 21, 2014" "%nmhversion%"
 .\"
 .\" %nmhwarning%
 .\"
@@ -44,6 +44,15 @@ context, and indicates what the default value is.  Note that a profile
 component can only appear once.  Multiple appearances with trigger a
 warning that all appearances after the first are ignored.
 .PP
+Some MH programs, including
+.BR mhbuild ,
+.BR mhshow ,
+and
+.BR mhstore ,
+have specific profile components that are described in their respective
+man pages.  Each component name begins with the name of the program and
+is followed by a dash.
+.PP
 .BR Path :
 Mail
 .RS 5
@@ -1045,6 +1054,9 @@ if annotations are to occur.
 .SH "SEE ALSO"
 .IR environ (5),
 .IR mh-sequence (5),
+.IR mhbuild (1),
+.IR mhshow (1),
+.IR mhstore (1),
 .IR nmh (7)
 .SH HISTORY
 The
index 3bb8e84..3afb4ba 100644 (file)
@@ -1,4 +1,4 @@
-.TH MHFIXMSG %manext1% "November 30, 2014" "%nmhversion%"
+.TH MHFIXMSG %manext1% "December 25, 2014" "%nmhversion%"
 .\"
 .\" %nmhwarning%
 .\"
@@ -23,6 +23,8 @@ mhfixmsg \- rewrite MIME messages with various transformations
 .RB [ \-replacetextplain " | " \-noreplacetextplain ]
 .RB [ \-fixboundary " | " \-nofixboundary ]
 .RB [ \-fixcte " | " \-nofixcte ]
+.RB [ \-fixtype
+.IR mimetype ]
 .RB [ \-outfile
 .IR outfile ]
 .RB [ \-rmmproc
@@ -149,6 +151,14 @@ and other
 .B nmh
 programs that parse MIME messages.
 .PP
+The
+.B \-fixtype
+switch ensures that each part of the message has the correct MIME type
+shown in its Content-Type header.  It may be repeated.  It is
+typically used to replace \*(lqapplication/octet-stream\*(rq with a
+more descriptive MIME type.  It may not be used for multipart and
+message types.
+.PP
 .B mhfixmsg
 applies one transformation unconditionally:  it removes an extraneous
 trailing semicolon from the parameter lists of MIME header fields.
@@ -240,6 +250,7 @@ content type and/or encoding as follows:
 \-reformat     text parts that are not text/plain
 \-fixboundary  outermost multipart part
 \-fixcte       multipart part
+\-fixtype      all except multipart and message parts
 .fi
 .RE
 .PP
index 5732af9..97a4a05 100644 (file)
@@ -93,13 +93,18 @@ cpnumber(charstring_t dest, int num, unsigned int wid, char fill, size_t max) {
            charstring_push_back (rev, '?');
        } else if (num < 0  &&  wid > 0) {
            /* Shouldn't need the wid > 0 check, that's why the condition
-               at the top checks wid < max-1 when num < 0. */
-           charstring_push_back (rev, '-');
+              at the top checks wid < max-1 when num < 0. */
            --wid;
+           if (fill == ' ') {
+               charstring_push_back (rev, '-');
+           }
        }
        while (wid-- > 0  &&  fill != 0) {
            charstring_push_back (rev, fill);
        }
+       if (num < 0  &&  fill == '0') {
+           charstring_push_back (rev, '-');
+       }
 
        {
            /* Output the string in reverse. */
index 3282e49..e68cba8 100644 (file)
@@ -9,7 +9,6 @@
 
 #include <h/mh.h>
 #include <h/signals.h>
-#include <setjmp.h>
 
 #ifdef READLINE_SUPPORT
 #include <readline/readline.h>
index 06a6156..23ccf03 100644 (file)
@@ -37,14 +37,15 @@ mime_type(const char *file_name) {
             if ((mimeencoding = get_file_info(MIMEENCODINGPROC, file_name))) {
                 content_type = concat(mimetype, "; charset=", mimeencoding,
                                       NULL);
+                free (mimetype);
             } else {
-                content_type = strdup(mimetype);
+                content_type = mimetype;
             }
         } else {
-            content_type = strdup(mimetype);
+            content_type = mimetype;
         }
 #else  /* MIMEENCODINGPROC */
-        content_type = strdup(mimetype);
+        content_type = mimetype;
 #endif /* MIMEENCODINGPROC */
     }
 #endif /* MIMETYPEPROC */
index 500b036..dddacaf 100644 (file)
@@ -11,7 +11,7 @@
 
 
 int
-uprf (char *c1, char *c2)
+uprf (const char *c1, const char *c2)
 {
     int c, mask;
 
index 99d64a5..e84d8e6 100644 (file)
@@ -1,27 +1,26 @@
-# Common helper routines for test shell scripts -- intended to be sourced by them
+# Common helper routines for test shell scripts -- to be sourced by them
 # @configure_input@
 
 
-#### The following exported variables are set by "make check".  Ensure
+#### The following variables are set by "make check".  Ensure
 #### that they are set here so that individual tests can be run
 #### outside of make.  Requires that MH_OBJ_DIR be set on entry.
 test -z "$MH_TEST_DIR"  &&  MH_TEST_DIR="$MH_OBJ_DIR/test/testdir"
+test -z "$MH_INST_DIR"  &&  MH_INST_DIR="${MH_TEST_DIR}/inst"
 test -z "$prefix"  &&  prefix=@prefix@
 test -z "$datarootdir"  &&  datarootdir=@datarootdir@
 test -z "$exec_prefix"  &&  exec_prefix=@exec_prefix@
-test -z "$nmhexecdir"  &&  nmhexecdir="@libexecdir@/nmh"
 test -z "$bindir"  &&  bindir="@bindir@"
 test -z "$mandir"  &&  mandir="@mandir@"
 test -z "$nmhetcdir"  &&  nmhetcdir="@sysconfdir@/nmh"
+#### The following doesn't support running the distcheck version of
+#### test-mhparam standalone, but only via make distcheck.
+test -z "$nmhetcdirinst"  &&  nmhetcdirinst="@nmhetcdirinst@$nmhetcdir"
+test -z "$nmhlibexecdir"  &&  nmhlibexecdir="@libexecdir@/nmh"
 test -z "$supported_locks"  &&  supported_locks="@supported_locks@"
 test -z "$default_locking"  &&  default_locking="@default_locking@"
 test -z "$MULTIBYTE_ENABLED"  &&  MULTIBYTE_ENABLED="@MULTIBYTE_ENABLED@"
 test -z "$ICONV_ENABLED"  &&  ICONV_ENABLED="@ICONV_ENABLED@"
-export MH_TEST_DIR nmhexecdir bindir mandir nmhetcdir
-export MULTIBYTE_ENABLED ICONV_ENABLED
-
-test -z "$MH_INST_DIR"  &&  MH_INST_DIR="${MH_TEST_DIR}/inst"
-export MH_INST_DIR
 
 unset MAILDROP MHBUILD MHCONTEXT MHMTSUSERCONF MHN MHSHOW MHSTORE
 unset MHLDEBUG MHPDEBUG MHWDEBUG PAGER
@@ -247,7 +246,7 @@ setup_test ()
 {
   MH="${MH_TEST_DIR}/Mail/.mh_profile"
   MHMTSCONF="${MH_INST_DIR}${nmhetcdir}/mts.conf"
-  MH_LIBEXEC_DIR="${MH_INST_DIR}${nmhexecdir}"
+  MH_LIBEXEC_DIR="${MH_INST_DIR}${nmhlibexecdir}"
   export MH MHMTSCONF MH_LIBEXEC_DIR
 
   #
@@ -293,16 +292,14 @@ postproc: ${MH_LIBEXEC_DIR}/post
 showproc: ${MH_LIBEXEC_DIR}/mhl
 EOF
 
-  for f in MailAliases components digestcomps distcomps forwcomps \
-           mhical.12hour mhical.24hour mhl.body mhl.digest mhl.format \
-           mhl.forward mhl.headers mhl.reply mhl.replywithoutbody \
-           mhn.defaults rcvdistcomps replcomps replgroupcomps \
-           scan.MMDDYY scan.YYYYMMDD scan.curses scan.default \
-           scan.highlighted scan.mailx scan.nomime scan.size scan.time \
-           scan.timely scan.unseen
-  do
-    cp "${MH_INST_DIR}${nmhetcdir}/${f}" "${MH_TEST_DIR}/Mail" || exit 1
-  done
+  if test -z '@nmhetcdirinst@'; then
+    #### This isn't used with make distcheck, so that we can use it to
+    #### be sure that etc files are not used from an existing nmh
+    #### installation.
+    #### posh doesn't like "${MH_INST_DIR}${nmhetcdir}"/*, so cd to
+    #### the directory and provide an argument without quotes to cp.
+    (cd "${MH_INST_DIR}${nmhetcdir}/"  &&  cp * "${MH_TEST_DIR}/Mail")
+  fi
 
   folder -create +inbox > /dev/null
   # create 10 basic messages
index b10374c..5680a5b 100755 (executable)
@@ -110,7 +110,7 @@ run_prog $fmtdump >$actual 2>&1
 check $expected $actual 'keep first'
 
 # check -form
-run_prog $fmtdump -form "$MH_TEST_DIR/Mail/scan.default" >$actual 2>&1
+run_prog $fmtdump -form "$MH_INST_DIR${nmhetcdir}/scan.default" >$actual 2>&1
 check $expected $actual
 
 # check -format
index 9cfaeee..b757e8e 100755 (executable)
@@ -12,18 +12,29 @@ fi
 . "$MH_OBJ_DIR/test/common.sh"
 
 setup_test
-expected="$MH_TEST_DIR/$$.expected"
-actual="$MH_TEST_DIR/$$.actual"
+expected="$MH_TEST_DIR/test-functions$$.expected"
+actual="$MH_TEST_DIR/test-functions$$.actual"
 
 # check sday when day of week is specified
-echo 1 >"$expected"
+printf '1\n' >"$expected"
 fmttest -raw -format '%(sday{text})' 'Fri Sep 12 20:02 2014' >"$actual"
 check "$expected" "$actual"
 
 # check sday when day of week is not specified
-echo 0 >"$expected"
+printf '0\n' >"$expected"
 fmttest -raw -format '%(sday{text})' 'Sep 12 20:02 2014' >"$actual"
 check "$expected" "$actual"
 
+# check negative number, without padding
+printf '%s\n' ' -42' >"$expected"
+fmttest -raw -format '%4(minus -42)' 0 >"$actual"
+check "$expected" "$actual"
+
+# check negative number, with padding
+# Output was "0-42" with nmh 1.6 and earlier.
+printf '%s\n' -042 >"$expected"
+fmttest -raw -format '%04(minus -42)' 0 >"$actual"
+check "$expected" "$actual"
+
 
 exit $failed
index cc69aea..b8e0b42 100755 (executable)
@@ -12,7 +12,9 @@ if test -z "${MH_OBJ_DIR}"; then
     MH_OBJ_DIR=`cd $srcdir && pwd`; export MH_OBJ_DIR
 fi
 
-. "${srcdir}/test/post/test-post-common.sh"
+. "${MH_OBJ_DIR}/test/common.sh"
+
+setup_test
 
 #### Make sure that html-to-text conversion is what we expect.
 require_locale en_US.utf-8 en_US.utf8
@@ -23,10 +25,12 @@ expected_err="$MH_TEST_DIR/test-mhfixmsg$$.expected_err"
 actual="$MH_TEST_DIR/test-mhfixmsg$$.actual"
 actual_err="$MH_TEST_DIR/test-mhfixmsg$$.actual_err"
 
-if grep mhfixmsg-format-text/html "${MH_TEST_DIR}/Mail/mhn.defaults" \
+mhn_defaults="$MH_INST_DIR${nmhetcdir}/mhn.defaults"
+
+if grep mhfixmsg-format-text/html "${mhn_defaults}" \
   >/dev/null; then
   can_reformat_texthtml=1
-  if grep 'mhfixmsg-format-text/html.*w3m' "${MH_TEST_DIR}/Mail/mhn.defaults" \
+  if grep 'mhfixmsg-format-text/html.*w3m' "${mhn_defaults}" \
     >/dev/null; then
     #### w3m uses $HOME/.w3m/, and creates it if it doesn't exist.  To
     #### support testing with non-writeable $HOME, and to not leave
@@ -42,7 +46,6 @@ fi
 
 
 # check -help
-# Verified behavior consistent with compiled sendmail.
 cat >"$expected" <<EOF
 Usage: mhfixmsg [+folder] [msgs] [switches]
   switches are:
@@ -53,6 +56,7 @@ Usage: mhfixmsg [+folder] [msgs] [switches]
   -[no]replacetextplain
   -[no]fixboundary
   -[no]fixcte
+  -fixtype mimetype
   -file file
   -outfile file
   -rmmproc program
@@ -68,7 +72,6 @@ check "$expected" "$actual"
 
 
 # check -version
-# Verified same behavior as compiled mhfixmsg.
 case `mhfixmsg -version` in
   mhfixmsg\ --*) ;;
   *) printf '%s: mhfixmsg -version generated unexpected output\n' "$0" >&2
@@ -1110,6 +1113,41 @@ if test -f '${MH_TEST_DIR}/Mail/inbox/20.backup'; then
 fi
 
 
+# check -fixtype
+cat >"$expected" <<EOF
+To: recipient@example.com
+From: sender@example.com
+Subject: mhfixmsg with incorrect Content-Type
+MIME-Version: 1.0
+Content-Type: multipart/mixed; boundary="----- =_aaaaaaaaaa0"
+
+------- =_aaaaaaaaaa0
+Content-Type: text/plain; name="plaintext.txt"
+
+this is plain text
+
+------- =_aaaaaaaaaa0--
+EOF
+
+cat >`mhpath new` <<EOF
+To: recipient@example.com
+From: sender@example.com
+Subject: mhfixmsg with incorrect Content-Type
+MIME-Version: 1.0
+Content-Type: multipart/mixed; boundary="----- =_aaaaaaaaaa0"
+
+------- =_aaaaaaaaaa0
+Content-Type: application/octet-stream; name="plaintext.txt"
+
+this is plain text
+
+------- =_aaaaaaaaaa0--
+EOF
+
+mhfixmsg -fixtype application/octet-stream last
+check "$expected" `mhpath last`
+
+
 # make sure there are no tmp files left over
 find "$MH_TEST_DIR/Mail" \( -name 'mhfix*' -o -name ',mhfix*' \) -print \
   >"$actual"
index c315778..8a48b8d 100755 (executable)
@@ -85,18 +85,18 @@ $MH_INST_DIR$bindir/refile
 $bindir/inc
 more
 $bindir/mhmail
-$MH_INST_DIR$nmhexecdir/mhl
+$MH_INST_DIR$nmhlibexecdir/mhl
 cat
 600
 $bindir/packf
-$MH_INST_DIR$nmhexecdir/post
+$MH_INST_DIR$nmhlibexecdir/post
 $bindir/send
 $bindir/mhshow
-$MH_INST_DIR$nmhexecdir/mhl
+$MH_INST_DIR$nmhlibexecdir/mhl
 nmh-`cat ${srcdir}/VERSION`
 $bindir/whatnow
 $bindir/whom
-$nmhetcdir
+$nmhetcdirinst
 $MH_LIBEXEC_DIR
 fcntl
 ${default_locking}
index 8b01ab6..e5111bd 100755 (executable)
@@ -37,13 +37,17 @@ actual=$MH_TEST_DIR/$$.actual
 set +e
 whatnowtest=`echo cd | whatnow -prompt ''`
 set -e
-
 case ${whatnowtest} in
     cd) cat > "$expected" <<EOF
 cd ${MH_TEST_DIR}/foo\'s\ bar
 pwd
 $SPDIR
 EOF
+    # If path to $SPDIR is too long, readline will wrap and disturb
+    # the actual output.  It obeys COLUMNS, so set that to a value
+    # that should be longer that $SPDIR plus a bit more.
+    COLUMNS=`getconf PATH_MAX . 2>/dev/null`  ||  COLUMNS=8192
+    export COLUMNS
     ;;
     "") cat > "$expected" <<EOF
 $SPDIR
index f80ff9b..af6cd88 100644 (file)
@@ -26,6 +26,7 @@
     X("nofixboundary", 0, NFIXBOUNDARYSW) \
     X("fixcte", 0, FIXCTESW) \
     X("nofixcte", 0, NFIXCTESW) \
+    X("fixtype mimetype", 0, FIXTYPESW) \
     X("file file", 0, FILESW) \
     X("outfile file", 0, OUTFILESW) \
     X("rmmproc program", 0, RPROCSW) \
@@ -75,6 +76,7 @@ void freects_done (int) NORETURN;
 typedef struct fix_transformations {
     int fixboundary;
     int fixcte;
+    svector_t fixtypes;
     int reformat;
     int replacetextplain;
     int decodetext;
@@ -85,6 +87,8 @@ int mhfixmsgsbr (CT *, const fix_transformations *, char *);
 static int fix_boundary (CT *, int *);
 static int get_multipart_boundary (CT, char **);
 static int replace_boundary (CT, char *, char *);
+static int fix_types (CT, svector_t, int *);
+static char *replace_substring (char **, const char *, const char *);
 static int fix_multipart_cte (CT, int *);
 static int set_ce (CT, int);
 static int ensure_text_plain (CT *, CT, int *, int);
@@ -126,6 +130,7 @@ main (int argc, char **argv) {
     int status = OK;
     fix_transformations fx;
     fx.reformat = fx.fixcte = fx.fixboundary = 1;
+    fx.fixtypes = NULL;
     fx.replacetextplain = 0;
     fx.decodetext = CE_8BIT;
     fx.textcharset = NULL;
@@ -192,6 +197,18 @@ main (int argc, char **argv) {
             case NFIXCTESW:
                 fx.fixcte = 0;
                 continue;
+            case FIXTYPESW:
+                if (! (cp = *argp++) || (*cp == '-' && cp[1]))
+                    adios (NULL, "missing argument to %s", argp[-2]);
+                if (! strncasecmp (cp, "multipart/", 10)  ||
+                    ! strncasecmp (cp, "message/", 8)) {
+                    adios (NULL, "-fixtype %s not allowed", cp);
+                } else if (! strchr (cp, '/')) {
+                    adios (NULL, "-fixtype requires type/subtype");
+                }
+                if (fx.fixtypes == NULL) { fx.fixtypes = svector_create (10); }
+                svector_push_back (fx.fixtypes, cp);
+                continue;
             case REFORMATSW:
                 fx.reformat = 1;
                 continue;
@@ -376,6 +393,7 @@ main (int argc, char **argv) {
         status = 1;
     }
 
+    if (fx.fixtypes != NULL) { svector_free (fx.fixtypes); }
     free (outfile);
     free (file);
 
@@ -414,6 +432,9 @@ mhfixmsgsbr (CT *ctp, const fix_transformations *fx, char *outfile) {
     if (status == OK  &&  fx->fixboundary) {
         status = fix_boundary (ctp, &message_mods);
     }
+    if (status == OK  && fx->fixtypes != NULL) {
+        status = fix_types (*ctp, fx->fixtypes, &message_mods);
+    }
     if (status == OK  &&  fx->fixcte) {
         status = fix_multipart_cte (*ctp, &message_mods);
     }
@@ -727,6 +748,144 @@ replace_boundary (CT ct, char *file, char *boundary) {
 }
 
 
+static int
+fix_types (CT ct, svector_t fixtypes, int *message_mods) {
+    int status = OK;
+
+    switch (ct->c_type) {
+    case CT_MULTIPART: {
+        struct multipart *m = (struct multipart *) ct->c_ctparams;
+        struct part *part;
+
+        for (part = m->mp_parts; status == OK  &&  part; part = part->mp_next) {
+            status = fix_types (part->mp_part, fixtypes, message_mods);
+        }
+        break;
+    }
+
+    case CT_MESSAGE:
+        if (ct->c_subtype == MESSAGE_EXTERNAL) {
+            struct exbody *e = (struct exbody *) ct->c_ctparams;
+
+            status = fix_types (e->eb_content, fixtypes, message_mods);
+        }
+        break;
+
+    default: {
+        char **typep, *type;
+
+        if (ct->c_ctinfo.ci_type  &&  ct->c_ctinfo.ci_subtype) {
+            for (typep = svector_strs (fixtypes);
+                 typep && (type = *typep);
+                 ++typep) {
+                char *type_subtype =
+                    concat (ct->c_ctinfo.ci_type, "/", ct->c_ctinfo.ci_subtype,
+                            NULL);
+
+                if (! strcasecmp (type, type_subtype)  &&
+                    decode_part (ct) == OK  &&
+                    ct->c_cefile.ce_file != NULL) {
+                    char *ct_type_subtype = mime_type (ct->c_cefile.ce_file);
+                    char *cp;
+
+                    if ((cp = strchr (ct_type_subtype, ';'))) {
+                        /* Truncate to remove any parameter list from
+                           mime_type () result. */
+                        *cp = '\0';
+                    }
+
+                    if (strcasecmp (type, ct_type_subtype)) {
+                        char *ct_type, *ct_subtype;
+                        HF hf;
+
+                        /* The Content-Type header does not match the
+                           content, so update these struct Content
+                           fields to match:
+                           * c_type, c_subtype
+                           * c_ctinfo.ci_type, c_ctinfo.ci_subtype
+                           * c_ctline
+                           */
+                        /* Extract type and subtype from type/subtype. */
+                        ct_type = getcpy (ct_type_subtype);
+                        if ((cp = strchr (ct_type, '/'))) {
+                            *cp = '\0';
+                            ct_subtype = getcpy (++cp);
+                        } else {
+                            advise (NULL, "missing / in MIME type of %s %s",
+                                    ct->c_file, ct->c_partno);
+                            free (ct_type);
+                            return NOTOK;
+                        }
+
+                        ct->c_type = ct_str_type (ct_type);
+                        ct->c_subtype = ct_str_subtype (ct->c_type, ct_subtype);
+
+                        free (ct->c_ctinfo.ci_type);
+                        ct->c_ctinfo.ci_type = ct_type;
+                        free (ct->c_ctinfo.ci_subtype);
+                        ct->c_ctinfo.ci_subtype = ct_subtype;
+                        if (! replace_substring (&ct->c_ctline, type,
+                                                 ct_type_subtype)) {
+                            advise (NULL, "did not find %s in %s",
+                                    type, ct->c_ctline);
+                        }
+
+                        /* Update Content-Type header field. */
+                        for (hf = ct->c_first_hf; hf; hf = hf->next) {
+                            if (! strcasecmp (TYPE_FIELD, hf->name)) {
+                                if (replace_substring (&hf->value, type,
+                                                       ct_type_subtype)) {
+                                    ++*message_mods;
+                                    if (verbosw) {
+                                        report (NULL, ct->c_partno, ct->c_file,
+                                                "change Content-Type in header "
+                                                "from %s to %s",
+                                                type, ct_type_subtype);
+                                    }
+                                    break;
+                                } else {
+                                    advise (NULL, "did not find %s in %s",
+                                            type, hf->value);
+                                }
+                            }
+                        }
+                    }
+                    free (ct_type_subtype);
+                }
+                free (type_subtype);
+            }
+        }
+    }}
+
+    return status;
+}
+
+char *
+replace_substring (char **str, const char *old, const char *new) {
+    char *cp;
+
+    if ((cp = strstr (*str, old))) {
+        char *remainder = cp + strlen (old);
+        char *prefix, *new_str;
+
+        if (cp - *str) {
+            prefix = getcpy (*str);
+            *(prefix + (cp - *str)) = '\0';
+            new_str = concat (prefix, new, remainder, NULL);
+            free (prefix);
+        } else {
+            new_str = concat (new, remainder, NULL);
+        }
+
+        free (*str);
+
+        return *str = new_str;
+    } else {
+        return NULL;
+    }
+}
+
+
 static int
 fix_multipart_cte (CT ct, int *message_mods) {
     int status = OK;
@@ -1062,13 +1221,14 @@ build_text_plain_part (CT encoded_part) {
         if ((tempfile = m_mktemp2 (NULL, invo_name, NULL, NULL)) == NULL) {
             advise (NULL, "unable to create temporary file in %s",
                     get_temp_dir());
-        }
-        tmp_plain_file = add (tempfile, NULL);
-        if (reformat_part (tp_part, tmp_plain_file,
-                           tp_part->c_ctinfo.ci_type,
-                           tp_part->c_ctinfo.ci_subtype,
-                           tp_part->c_type) == OK) {
-            return tp_part;
+        } else {
+            tmp_plain_file = add (tempfile, NULL);
+            if (reformat_part (tp_part, tmp_plain_file,
+                               tp_part->c_ctinfo.ci_type,
+                               tp_part->c_ctinfo.ci_subtype,
+                               tp_part->c_type) == OK) {
+                return tp_part;
+            }
         }
     }
 
index 28d4894..3bc0808 100644 (file)
@@ -875,14 +875,18 @@ parse (void)
 static void
 process (char *folder, char *fname, int ofilen, int ofilec)
 {
-    char *cp = NULL;
-    FILE *fp = NULL;
+    /* static to prevent "might be clobbered" warning from gcc 4.9.2: */
+    static char *cp;
+    static FILE *fp;
     struct mcomp *c1;
     struct stat st;
     struct arglist *ap;
     /* volatile to prevent "might be clobbered" warning from gcc: */
     char *volatile fname2 = fname ? fname : "(stdin)";
 
+    cp = NULL;
+    fp = NULL;
+
     switch (setjmp (env)) {
        case OK: 
            if (fname) {
@@ -913,12 +917,12 @@ process (char *folder, char *fname, int ofilen, int ofilec)
            if (arglist_head)
                fmt_free(NULL, 1);
 
-       default: 
+       default:
            if (ontty != PITTY)
                SIGNAL (SIGINT, SIG_IGN);
-           if (mhl_action == NULL && fp != stdin)
+           if (mhl_action == NULL && fp != stdin && fp != NULL)
                fclose (fp);
-           free (cp);
+               free (cp);
            if (holder.c_text) {
                free (holder.c_text);
                holder.c_text = NULL;
index 96af58e..a3a80f9 100644 (file)
@@ -1008,7 +1008,6 @@ InitText (CT ct)
     char *chset = NULL;
     char *cp;
     PM pm;
-    struct k2v *kv;
     struct text *t;
     CI ci = &ct->c_ctinfo;
 
@@ -1017,10 +1016,7 @@ InitText (CT ct)
        ci->ci_subtype = add ("plain", ci->ci_subtype);
 
     /* match subtype */
-    for (kv = SubText; kv->kv_key; kv++)
-       if (!strcasecmp (ci->ci_subtype, kv->kv_key))
-           break;
-    ct->c_subtype = kv->kv_value;
+    ct->c_subtype = ct_str_subtype (CT_TEXT, ci->ci_subtype);
 
     /* allocate text character set structure */
     if ((t = (struct text *) mh_xcalloc (1, sizeof(*t))) == NULL)
@@ -1073,7 +1069,6 @@ InitMultiPart (CT ct)
     size_t buflen;
     ssize_t gotlen;
     struct multipart *m;
-    struct k2v *kv;
     struct part *part, **next;
     CI ci = &ct->c_ctinfo;
     CT p;
@@ -1105,10 +1100,7 @@ InitMultiPart (CT ct)
     }
 
     /* match subtype */
-    for (kv = SubMultiPart; kv->kv_key; kv++)
-       if (!strcasecmp (ci->ci_subtype, kv->kv_key))
-           break;
-    ct->c_subtype = kv->kv_value;
+    ct->c_subtype = ct_str_subtype (CT_MULTIPART, ci->ci_subtype);
 
     /*
      * Check for "boundary" parameter, which is
@@ -1329,7 +1321,6 @@ reverse_alternative_parts (CT ct) {
 static int
 InitMessage (CT ct)
 {
-    struct k2v *kv;
     CI ci = &ct->c_ctinfo;
 
     if ((ct->c_encoding != CE_7BIT) && (ct->c_encoding != CE_8BIT)) {
@@ -1344,10 +1335,7 @@ InitMessage (CT ct)
        ci->ci_subtype = add ("rfc822", ci->ci_subtype);
 
     /* match subtype */
-    for (kv = SubMessage; kv->kv_key; kv++)
-       if (!strcasecmp (ci->ci_subtype, kv->kv_key))
-           break;
-    ct->c_subtype = kv->kv_value;
+    ct->c_subtype = ct_str_subtype (CT_MESSAGE, ci->ci_subtype);
 
     switch (ct->c_subtype) {
        case MESSAGE_RFC822:
@@ -1597,14 +1585,10 @@ params_external (CT ct, int composing)
 static int
 InitApplication (CT ct)
 {
-    struct k2v *kv;
     CI ci = &ct->c_ctinfo;
 
     /* match subtype */
-    for (kv = SubApplication; kv->kv_key; kv++)
-       if (!strcasecmp (ci->ci_subtype, kv->kv_key))
-           break;
-    ct->c_subtype = kv->kv_value;
+    ct->c_subtype = ct_str_subtype (CT_APPLICATION, ci->ci_subtype);
 
     return OK;
 }
@@ -3176,6 +3160,62 @@ ct_subtype_str (int type, int subtype) {
 }
 
 
+int
+ct_str_type (const char *type) {
+    struct str2init *s2i;
+
+    for (s2i = str2cts; s2i->si_key; ++s2i) {
+        if (! strcasecmp (type, s2i->si_key)) {
+            break;
+        }
+    }
+    if (! s2i->si_key  &&  ! uprf (type, "X-")) {
+        ++s2i;
+    }
+
+    return s2i->si_val;
+}
+
+
+int
+ct_str_subtype (int type, const char *subtype) {
+    struct k2v *kv;
+
+    switch (type) {
+    case CT_APPLICATION:
+        for (kv = SubApplication; kv->kv_key; ++kv) {
+            if (! strcasecmp (subtype, kv->kv_key)) {
+                break;
+            }
+        }
+        return kv->kv_value;
+    case CT_MESSAGE:
+        for (kv = SubMessage; kv->kv_key; ++kv) {
+            if (! strcasecmp (subtype, kv->kv_key)) {
+                break;
+            }
+        }
+        return kv->kv_value;
+    case CT_MULTIPART:
+        for (kv = SubMultiPart; kv->kv_key; ++kv) {
+            if (! strcasecmp (subtype, kv->kv_key)) {
+                break;
+            }
+        }
+        return kv->kv_value;
+    case CT_TEXT:
+        for (kv = SubText; kv->kv_key; ++kv) {
+            if (! strcasecmp (subtype, kv->kv_key)) {
+                break;
+            }
+        }
+        return kv->kv_value;
+    default:
+        return 0;
+    }
+}
+
+
 /* Find the content type and InitFunc for the CT. */
 const struct str2init *
 get_ct_init (int type) {
index 986ffb9..a9aa9c0 100644 (file)
@@ -11,7 +11,6 @@
 #include <fcntl.h>
 #include <h/signals.h>
 #include <h/md5.h>
-#include <setjmp.h>
 #include <h/mts.h>
 #include <h/tws.h>
 #include <h/mime.h>
index 304c9a5..58347d4 100644 (file)
@@ -331,8 +331,7 @@ getln (char *buffer, int n)
     char *cp;
     static int quoting = 0;
 
-    cp = buffer;
-    *cp = 0;
+    *buffer = 0;
 
     switch (setjmp (sigenv)) {
        case OK: 
@@ -348,6 +347,9 @@ getln (char *buffer, int n)
            return NOTOK;
     }
 
+    cp = buffer;
+    *cp = 0;
+
     for (;;) {
        switch (c = getchar ()) {
            case EOF: 
index 2c2d204..21fb151 100644 (file)
@@ -446,9 +446,6 @@ WhatNow (int argc, char **argv)
                    annotate(drft, ATTACH_FIELD, file, 1, 0, -2, 1);
                    if (verbose) {
                        ctype = mime_type(file);
-                   }
-
-                   if (verbose) {
                        printf ("Attaching %s as a %s\n", file, ctype);
                        free (ctype);
                    }