]> diplodocus.org Git - nmh/blobdiff - uip/mhshowsbr.c
eliminate use of fgets() in mhparse.c
[nmh] / uip / mhshowsbr.c
index 295f43e8b7661a65b83761090e79f4f393080d31..042ca7cb6ddbe7be11c60f853ba14e89774cf943 100644 (file)
@@ -16,6 +16,7 @@
 #include <h/tws.h>
 #include <h/mime.h>
 #include <h/mhparse.h>
 #include <h/tws.h>
 #include <h/mime.h>
 #include <h/mhparse.h>
+#include <h/fmt_scan.h>
 #include <h/utils.h>
 #ifdef HAVE_ICONV
 #   include <iconv.h>
 #include <h/utils.h>
 #ifdef HAVE_ICONV
 #   include <iconv.h>
@@ -23,8 +24,6 @@
 
 extern int debugsw;
 
 
 extern int debugsw;
 
-int pausesw  = 1;
-int serialsw = 0;
 int nolist   = 0;
 
 char *progsw = NULL;
 int nolist   = 0;
 
 char *progsw = NULL;
@@ -33,10 +32,6 @@ char *progsw = NULL;
 int nomore   = 0;
 char *formsw = NULL;
 
 int nomore   = 0;
 char *formsw = NULL;
 
-pid_t xpid = 0;
-
-static sigjmp_buf intrenv;
-
 
 /* mhmisc.c */
 int part_ok (CT, int);
 
 /* mhmisc.c */
 int part_ok (CT, int);
@@ -47,29 +42,49 @@ void flush_errors (void);
 /*
  * prototypes
  */
 /*
  * prototypes
  */
-void show_all_messages (CT *);
-int show_content_aux (CT, int, int, char *, char *);
+int show_content_aux (CT, int, char *, char *, struct format *fmt);
 
 /*
  * static prototypes
  */
 
 /*
  * static prototypes
  */
-static void show_single_message (CT, char *);
-static void DisplayMsgHeader (CT, char *);
-static int show_switch (CT, int, int);
-static int show_content (CT, int, int);
-static int show_content_aux2 (CT, int, int, char *, char *, int, int, int, int,
-                              int);
-static int show_text (CT, int, int);
-static int show_multi (CT, int, int);
-static int show_multi_internal (CT, int, int);
-static int show_multi_aux (CT, int, int, char *);
-static int show_message_rfc822 (CT, int, int);
-static int show_partial (CT, int, int);
-static int show_external (CT, int, int);
-static int parse_display_string (CT, char *, int *, int *, int *, int *, char *,
-                                 char *, size_t, int multipart);
+static void show_single_message (CT, char *, int, int, int, struct format *);
+static void DisplayMsgHeader (CT, char *, int);
+static int show_switch (CT, int, int, int, int, struct format *);
+static int show_content (CT, int, int, int, struct format *);
+static int show_content_aux2 (CT, int, char *, char *, int, int, int, struct format *);
+static int show_text (CT, int, int, struct format *);
+static int show_multi (CT, int, int, int, int, struct format *);
+static int show_multi_internal (CT, int, int, int, int, struct format *);
+static int show_multi_aux (CT, int, char *, struct format *);
+static int show_message_rfc822 (CT, int, struct format *);
+static int show_partial (CT, int);
+static int show_external (CT, int, int, int, int, struct format *);
+static int parse_display_string (CT, char *, int *, int *, char *, char *,
+                                size_t, int multipart);
 static int convert_content_charset (CT, char **);
 static int convert_content_charset (CT, char **);
-static void intrser (int);
+static struct format *compile_marker(char *);
+static void output_marker (CT, struct format *, int);
+static void free_markercomps (void);
+static int pidcheck(int);
+
+/*
+ * Components (and list of parameters/components) we care about for the
+ * content marker display.
+ */
+
+static struct comp *part_comp = NULL;
+static struct comp *ctype_comp = NULL;
+static struct comp *description_comp = NULL;
+static struct comp *dispo_comp = NULL;
+
+struct param_comp_list {
+    char *param;
+    struct comp *comp;
+    struct param_comp_list *next;
+};
+
+static struct param_comp_list *ctype_pc_list = NULL;
+static struct param_comp_list *dispo_pc_list = NULL;
 
 
 /*
 
 
 /*
@@ -77,9 +92,11 @@ static void intrser (int);
  */
 
 void
  */
 
 void
-show_all_messages (CT *cts)
+show_all_messages (CT *cts, int concatsw, int textonly, int inlineonly,
+                  char *markerform)
 {
     CT ct, *ctp;
 {
     CT ct, *ctp;
+    struct format *fmt;
 
     /*
      * If form is not specified, then get default form
 
     /*
      * If form is not specified, then get default form
@@ -88,6 +105,11 @@ show_all_messages (CT *cts)
     if (!formsw)
        formsw = getcpy (etcpath ("mhl.headers"));
 
     if (!formsw)
        formsw = getcpy (etcpath ("mhl.headers"));
 
+    /*
+     * Compile the content marker format line
+     */
+    fmt = compile_marker(markerform);
+
     /*
      * If form is "mhl.null", suppress display of header.
      */
     /*
      * If form is "mhl.null", suppress display of header.
      */
@@ -99,8 +121,12 @@ show_all_messages (CT *cts)
 
        /* if top-level type is ok, then display message */
        if (type_ok (ct, 1))
 
        /* if top-level type is ok, then display message */
        if (type_ok (ct, 1))
-           show_single_message (ct, formsw);
+           show_single_message (ct, formsw, concatsw, textonly, inlineonly,
+                                fmt);
     }
     }
+
+    free_markercomps();
+    fmt_free(fmt, 1);
 }
 
 
 }
 
 
@@ -109,7 +135,8 @@ show_all_messages (CT *cts)
  */
 
 static void
  */
 
 static void
-show_single_message (CT ct, char *form)
+show_single_message (CT ct, char *form, int concatsw, int textonly,
+                    int inlineonly, struct format *fmt)
 {
     sigset_t set, oset;
 
 {
     sigset_t set, oset;
 
@@ -124,12 +151,10 @@ show_single_message (CT ct, char *form)
      * the message headers.
      */
     if (form)
      * the message headers.
      */
     if (form)
-       DisplayMsgHeader(ct, form);
-    else
-       xpid = 0;
+       DisplayMsgHeader(ct, form, concatsw);
 
     /* Show the body of the message */
 
     /* Show the body of the message */
-    show_switch (ct, 1, 0);
+    show_switch (ct, 0, concatsw, textonly, inlineonly, fmt);
 
     if (ct->c_fp) {
        fclose (ct->c_fp);
 
     if (ct->c_fp) {
        fclose (ct->c_fp);
@@ -146,7 +171,7 @@ show_single_message (CT ct, char *form)
     sigaddset (&set, SIGTERM);
     sigprocmask (SIG_BLOCK, &set, &oset);
 
     sigaddset (&set, SIGTERM);
     sigprocmask (SIG_BLOCK, &set, &oset);
 
-    while (wait (&status) != NOTOK) {
+    while (!concatsw && wait (&status) != NOTOK) {
        pidcheck (status);
        continue;
     }
        pidcheck (status);
        continue;
     }
@@ -154,7 +179,6 @@ show_single_message (CT ct, char *form)
     /* reset the signal mask */
     sigprocmask (SIG_SETMASK, &oset, &set);
 
     /* reset the signal mask */
     sigprocmask (SIG_SETMASK, &oset, &set);
 
-    xpid = 0;
     flush_errors ();
 }
 
     flush_errors ();
 }
 
@@ -164,7 +188,7 @@ show_single_message (CT ct, char *form)
  */
 
 static void
  */
 
 static void
-DisplayMsgHeader (CT ct, char *form)
+DisplayMsgHeader (CT ct, char *form, int concatsw)
 {
     pid_t child_id;
     int i, vecp;
 {
     pid_t child_id;
     int i, vecp;
@@ -181,7 +205,7 @@ DisplayMsgHeader (CT ct, char *form)
      * If we've specified -(no)moreproc,
      * then just pass that along.
      */
      * If we've specified -(no)moreproc,
      * then just pass that along.
      */
-    if (nomore) {
+    if (nomore || concatsw) {
        vec[vecp++] = getcpy("-nomoreproc");
     } else if (progsw) {
        vec[vecp++] = getcpy("-moreproc");
        vec[vecp++] = getcpy("-nomoreproc");
     } else if (progsw) {
        vec[vecp++] = getcpy("-moreproc");
@@ -207,7 +231,7 @@ DisplayMsgHeader (CT ct, char *form)
        /* NOTREACHED */
 
     default:
        /* NOTREACHED */
 
     default:
-       xpid = -child_id;
+       pidcheck(pidwait(child_id, NOTOK));
        break;
     }
 
        break;
     }
 
@@ -221,36 +245,37 @@ DisplayMsgHeader (CT ct, char *form)
  */
 
 static int
  */
 
 static int
-show_switch (CT ct, int serial, int alternate)
+show_switch (CT ct, int alternate, int concatsw, int textonly, int inlineonly,
+            struct format *fmt)
 {
     switch (ct->c_type) {
        case CT_MULTIPART:
 {
     switch (ct->c_type) {
        case CT_MULTIPART:
-           return show_multi (ct, serial, alternate);
+           return show_multi (ct, alternate, concatsw, textonly,
+                              inlineonly, fmt);
 
        case CT_MESSAGE:
            switch (ct->c_subtype) {
                case MESSAGE_PARTIAL:
 
        case CT_MESSAGE:
            switch (ct->c_subtype) {
                case MESSAGE_PARTIAL:
-                   return show_partial (ct, serial, alternate);
+                   return show_partial (ct, alternate);
 
                case MESSAGE_EXTERNAL:
 
                case MESSAGE_EXTERNAL:
-                   return show_external (ct, serial, alternate);
+                   return show_external (ct, alternate, concatsw, textonly,
+                                         inlineonly, fmt);
 
                case MESSAGE_RFC822:
                default:
 
                case MESSAGE_RFC822:
                default:
-                   return show_message_rfc822 (ct, serial, alternate);
+                   return show_message_rfc822 (ct, alternate, fmt);
            }
 
        case CT_TEXT:
            }
 
        case CT_TEXT:
-           return show_text (ct, serial, alternate);
+           return show_text (ct, alternate, concatsw, fmt);
 
        case CT_AUDIO:
        case CT_IMAGE:
        case CT_VIDEO:
        case CT_APPLICATION:
 
        case CT_AUDIO:
        case CT_IMAGE:
        case CT_VIDEO:
        case CT_APPLICATION:
-           return show_content (ct, serial, alternate);
-
        default:
        default:
-           adios (NULL, "unknown content type %d", ct->c_type);
+           return show_content (ct, alternate, textonly, inlineonly, fmt);
     }
 
     return 0;  /* NOT REACHED */
     }
 
     return 0;  /* NOT REACHED */
@@ -262,24 +287,35 @@ show_switch (CT ct, int serial, int alternate)
  */
 
 static int
  */
 
 static int
-show_content (CT ct, int serial, int alternate)
+show_content (CT ct, int alternate, int textonly, int inlineonly,
+             struct format *fmt)
 {
     char *cp, buffer[BUFSIZ];
     CI ci = &ct->c_ctinfo;
 
 {
     char *cp, buffer[BUFSIZ];
     CI ci = &ct->c_ctinfo;
 
+    /*
+     * If we're here, we are not a text type.  So we don't need to check
+     * the content-type.
+     */
+
+    if (textonly || (inlineonly && !is_inline(ct))) {
+       output_marker(ct, fmt, 1);
+       return OK;
+    }
+
     /* Check for invo_name-show-type/subtype */
     snprintf (buffer, sizeof(buffer), "%s-show-%s/%s",
                invo_name, ci->ci_type, ci->ci_subtype);
     if ((cp = context_find (buffer)) && *cp != '\0')
     /* Check for invo_name-show-type/subtype */
     snprintf (buffer, sizeof(buffer), "%s-show-%s/%s",
                invo_name, ci->ci_type, ci->ci_subtype);
     if ((cp = context_find (buffer)) && *cp != '\0')
-       return show_content_aux (ct, serial, alternate, cp, NULL);
+       return show_content_aux (ct, alternate, cp, NULL, fmt);
 
     /* Check for invo_name-show-type */
     snprintf (buffer, sizeof(buffer), "%s-show-%s", invo_name, ci->ci_type);
     if ((cp = context_find (buffer)) && *cp != '\0')
 
     /* Check for invo_name-show-type */
     snprintf (buffer, sizeof(buffer), "%s-show-%s", invo_name, ci->ci_type);
     if ((cp = context_find (buffer)) && *cp != '\0')
-       return show_content_aux (ct, serial, alternate, cp, NULL);
+       return show_content_aux (ct, alternate, cp, NULL, fmt);
 
     if ((cp = ct->c_showproc))
 
     if ((cp = ct->c_showproc))
-       return show_content_aux (ct, serial, alternate, cp, NULL);
+       return show_content_aux (ct, alternate, cp, NULL, fmt);
 
     /* complain if we are not a part of a multipart/alternative */
     if (!alternate)
 
     /* complain if we are not a part of a multipart/alternative */
     if (!alternate)
@@ -294,10 +330,10 @@ show_content (CT ct, int serial, int alternate)
  */
 
 int
  */
 
 int
-show_content_aux (CT ct, int serial, int alternate, char *cp, char *cracked)
+show_content_aux (CT ct, int alternate, char *cp, char *cracked, struct format *fmt)
 {
     int fd;
 {
     int fd;
-    int xstdin = 0, xlist = 0, xpause = 0, xtty = 0;
+    int xstdin = 0, xlist = 0;
     char *file, buffer[BUFSIZ];
 
     if (!ct->c_ceopenfnx) {
     char *file, buffer[BUFSIZ];
 
     if (!ct->c_ceopenfnx) {
@@ -319,9 +355,13 @@ show_content_aux (CT ct, int serial, int alternate, char *cp, char *cracked)
            unfortunately the type checks are necessary without
            some code rearrangement.  And to make this really ugly,
            only do it in mhshow, not mhfixmsg, mhn, or mhstore. */
            unfortunately the type checks are necessary without
            some code rearrangement.  And to make this really ugly,
            only do it in mhshow, not mhfixmsg, mhn, or mhstore. */
-        if (convert_content_charset (ct, &file) != OK) {
-            admonish (NULL, "unable to convert character set%s to %s",
-                      ct->c_partno  ?  "of part "  :  "",
+        if (convert_content_charset (ct, &file) == OK) {
+            (*ct->c_ceclosefnx) (ct);
+            if ((fd = (*ct->c_ceopenfnx) (ct, &file)) == NOTOK)
+                return NOTOK;
+        } else {
+            admonish (NULL, "unable to convert character set%s%s to %s",
+                      ct->c_partno  ?  " of part "  :  "",
                       ct->c_partno  ?  ct->c_partno  :  "",
                       content_charset (ct));
         }
                       ct->c_partno  ?  ct->c_partno  :  "",
                       content_charset (ct));
         }
@@ -332,15 +372,15 @@ show_content_aux (CT ct, int serial, int alternate, char *cp, char *cracked)
        goto got_command;
     }
 
        goto got_command;
     }
 
-    if (parse_display_string (ct, cp, &xstdin, &xlist, &xpause, &xtty, file,
-                             buffer, sizeof(buffer) - 1, 0)) {
+    if (parse_display_string (ct, cp, &xstdin, &xlist, file, buffer,
+                             sizeof(buffer) - 1, 0)) {
        admonish (NULL, "Buffer overflow constructing show command!\n");
        return NOTOK;
     }
 
 got_command:
        admonish (NULL, "Buffer overflow constructing show command!\n");
        return NOTOK;
     }
 
 got_command:
-    return show_content_aux2 (ct, serial, alternate, cracked, buffer,
-                             fd, xlist, xpause, xstdin, xtty);
+    return show_content_aux2 (ct, alternate, cracked, buffer,
+                             fd, xlist, xstdin, fmt);
 }
 
 
 }
 
 
@@ -349,8 +389,8 @@ got_command:
  */
 
 static int
  */
 
 static int
-show_content_aux2 (CT ct, int serial, int alternate, char *cracked, char *buffer,
-                   int fd, int xlist, int xpause, int xstdin, int xtty)
+show_content_aux2 (CT ct, int alternate, char *cracked, char *buffer,
+                   int fd, int xlist, int xstdin, struct format *fmt)
 {
     pid_t child_id;
     int i, vecp;
 {
     pid_t child_id;
     int i, vecp;
@@ -369,41 +409,35 @@ show_content_aux2 (CT ct, int serial, int alternate, char *cracked, char *buffer
            fprintf (stderr, " using command %s\n", buffer);
     }
 
            fprintf (stderr, " using command %s\n", buffer);
     }
 
-    if (xpid < 0 || (xtty && xpid)) {
-       if (xpid < 0)
-           xpid = -xpid;
-       pidcheck(pidwait (xpid, NOTOK));
-       xpid = 0;
+    if (xlist) {
+       output_marker(ct, fmt, 0);
     }
 
     }
 
-    if (xlist) {
-       char prompt[BUFSIZ];
+    /*
+     * If the command is a zero-length string, just write the output on
+     * stdout.
+     */
 
 
-       if (ct->c_type == CT_MULTIPART)
-           list_content (ct, -1, 1, 0, 0, 0);
-       else
-           list_switch (ct, -1, 1, 0, 0, 0);
+    if (buffer[0] == '\0') {
+       char readbuf[BUFSIZ];
+       ssize_t cc;
 
 
-       if (xpause && isatty (fileno (stdout))) {
-           int intr;
-           SIGNAL_HANDLER istat;
+       if (fd == NOTOK) {
+           advise(NULL, "Cannot use NULL command to display content-type "
+                  "%s/%s", ct->c_ctinfo.ci_type, ct->c_ctinfo.ci_subtype);
+           return NOTOK;
+       }
 
 
-           if (SOprintf ("Press <return> to show content..."))
-               printf ("Press <return> to show content...");
+       while ((cc = read(fd, readbuf, sizeof(readbuf))) > 0) {
+           fwrite(readbuf, sizeof(char), cc, stdout);
+       }
 
 
-           istat = SIGNAL (SIGINT, intrser);
-           if ((intr = sigsetjmp (intrenv, 1)) == OK) {
-               fflush (stdout);
-               prompt[0] = 0;
-               read (fileno (stdout), prompt, sizeof(prompt));
-           }
-           SIGNAL (SIGINT, istat);
-           if (intr != OK || prompt[0] == 'n') {
-               (*ct->c_ceclosefnx) (ct);
-               return (alternate ? DONE : NOTOK);
-           }
-           if (prompt[0] == 'q') done(OK);
+       if (cc < 0) {
+           advise("read", "while reading text content");
+           return NOTOK;
        }
        }
+
+       return OK;
     }
 
     vec = argsplit(buffer, &file, &vecp);
     }
 
     vec = argsplit(buffer, &file, &vecp);
@@ -427,20 +461,14 @@ show_content_aux2 (CT ct, int serial, int alternate, char *cracked, char *buffer
            close (fd);
            execvp (file, vec);
            fprintf (stderr, "unable to exec ");
            close (fd);
            execvp (file, vec);
            fprintf (stderr, "unable to exec ");
-           perror ("/bin/sh");
+           perror (buffer);
            _exit (-1);
            /* NOTREACHED */
 
        default:
            arglist_free(file, vec);
 
            _exit (-1);
            /* NOTREACHED */
 
        default:
            arglist_free(file, vec);
 
-           if (!serial) {
-               ct->c_pid = child_id;
-               if (xtty)
-                   xpid = child_id;
-           } else {
-               pidcheck (pidXwait (child_id, NULL));
-           }
+           pidcheck (pidXwait (child_id, NULL));
 
            if (fd != NOTOK)
                (*ct->c_ceclosefnx) (ct);
 
            if (fd != NOTOK)
                (*ct->c_ceclosefnx) (ct);
@@ -454,7 +482,7 @@ show_content_aux2 (CT ct, int serial, int alternate, char *cracked, char *buffer
  */
 
 static int
  */
 
 static int
-show_text (CT ct, int serial, int alternate)
+show_text (CT ct, int alternate, int concatsw, struct format *fmt)
 {
     char *cp, buffer[BUFSIZ];
     CI ci = &ct->c_ctinfo;
 {
     char *cp, buffer[BUFSIZ];
     CI ci = &ct->c_ctinfo;
@@ -463,22 +491,28 @@ show_text (CT ct, int serial, int alternate)
     snprintf (buffer, sizeof(buffer), "%s-show-%s/%s",
                invo_name, ci->ci_type, ci->ci_subtype);
     if ((cp = context_find (buffer)) && *cp != '\0')
     snprintf (buffer, sizeof(buffer), "%s-show-%s/%s",
                invo_name, ci->ci_type, ci->ci_subtype);
     if ((cp = context_find (buffer)) && *cp != '\0')
-       return show_content_aux (ct, serial, alternate, cp, NULL);
+       return show_content_aux (ct, alternate, cp, NULL, fmt);
 
     /* Check for invo_name-show-type */
     snprintf (buffer, sizeof(buffer), "%s-show-%s", invo_name, ci->ci_type);
     if ((cp = context_find (buffer)) && *cp != '\0')
 
     /* Check for invo_name-show-type */
     snprintf (buffer, sizeof(buffer), "%s-show-%s", invo_name, ci->ci_type);
     if ((cp = context_find (buffer)) && *cp != '\0')
-       return show_content_aux (ct, serial, alternate, cp, NULL);
+       return show_content_aux (ct, alternate, cp, NULL, fmt);
 
     /*
      * Use default method if content is text/plain, or if
      * if it is not a text part of a multipart/alternative
      */
     if (!alternate || ct->c_subtype == TEXT_PLAIN) {
 
     /*
      * Use default method if content is text/plain, or if
      * if it is not a text part of a multipart/alternative
      */
     if (!alternate || ct->c_subtype == TEXT_PLAIN) {
-       snprintf (buffer, sizeof(buffer), "%%p%s %%F", progsw ? progsw :
-               moreproc && *moreproc ? moreproc : DEFAULT_PAGER);
+       if (concatsw) {
+           if (ct->c_termproc)
+               snprintf(buffer, sizeof(buffer), "%%lcat");
+           else
+               snprintf(buffer, sizeof(buffer), "%%l");
+       } else
+           snprintf (buffer, sizeof(buffer), "%%l%s %%F", progsw ? progsw :
+                     moreproc && *moreproc ? moreproc : DEFAULT_PAGER);
        cp = (ct->c_showproc = add (buffer, NULL));
        cp = (ct->c_showproc = add (buffer, NULL));
-       return show_content_aux (ct, serial, alternate, cp, NULL);
+       return show_content_aux (ct, alternate, cp, NULL, fmt);
     }
 
     return NOTOK;
     }
 
     return NOTOK;
@@ -490,7 +524,8 @@ show_text (CT ct, int serial, int alternate)
  */
 
 static int
  */
 
 static int
-show_multi (CT ct, int serial, int alternate)
+show_multi (CT ct, int alternate, int concatsw, int textonly, int inlineonly,
+           struct format *fmt)
 {
     char *cp, buffer[BUFSIZ];
     CI ci = &ct->c_ctinfo;
 {
     char *cp, buffer[BUFSIZ];
     CI ci = &ct->c_ctinfo;
@@ -499,22 +534,23 @@ show_multi (CT ct, int serial, int alternate)
     snprintf (buffer, sizeof(buffer), "%s-show-%s/%s",
                invo_name, ci->ci_type, ci->ci_subtype);
     if ((cp = context_find (buffer)) && *cp != '\0')
     snprintf (buffer, sizeof(buffer), "%s-show-%s/%s",
                invo_name, ci->ci_type, ci->ci_subtype);
     if ((cp = context_find (buffer)) && *cp != '\0')
-       return show_multi_aux (ct, serial, alternate, cp);
+       return show_multi_aux (ct, alternate, cp, fmt);
 
     /* Check for invo_name-show-type */
     snprintf (buffer, sizeof(buffer), "%s-show-%s", invo_name, ci->ci_type);
     if ((cp = context_find (buffer)) && *cp != '\0')
 
     /* Check for invo_name-show-type */
     snprintf (buffer, sizeof(buffer), "%s-show-%s", invo_name, ci->ci_type);
     if ((cp = context_find (buffer)) && *cp != '\0')
-       return show_multi_aux (ct, serial, alternate, cp);
+       return show_multi_aux (ct, alternate, cp, fmt);
 
     if ((cp = ct->c_showproc))
 
     if ((cp = ct->c_showproc))
-       return show_multi_aux (ct, serial, alternate, cp);
+       return show_multi_aux (ct, alternate, cp, fmt);
 
     /*
      * Use default method to display this multipart content.  Even
      * unknown types are displayable, since they're treated as mixed
      * per RFC 2046.
      */
 
     /*
      * Use default method to display this multipart content.  Even
      * unknown types are displayable, since they're treated as mixed
      * per RFC 2046.
      */
-    return show_multi_internal (ct, serial, alternate);
+    return show_multi_internal (ct, alternate, concatsw, textonly,
+                               inlineonly, fmt);
 }
 
 
 }
 
 
@@ -524,40 +560,21 @@ show_multi (CT ct, int serial, int alternate)
  */
 
 static int
  */
 
 static int
-show_multi_internal (CT ct, int serial, int alternate)
+show_multi_internal (CT ct, int alternate, int concatsw, int textonly,
+                    int inlineonly, struct format *fmt)
 {
 {
-    int        alternating, nowalternate, nowserial, result;
+    int        alternating, nowalternate, result;
     struct multipart *m = (struct multipart *) ct->c_ctparams;
     struct part *part;
     struct multipart *m = (struct multipart *) ct->c_ctparams;
     struct part *part;
+    int any_part_ok;
     CT p;
     CT p;
-    sigset_t set, oset;
 
     alternating = 0;
     nowalternate = alternate;
 
 
     alternating = 0;
     nowalternate = alternate;
 
-    if (ct->c_subtype == MULTI_PARALLEL) {
-       nowserial = serialsw;
-    } else if (ct->c_subtype == MULTI_ALTERNATE) {
+    if (ct->c_subtype == MULTI_ALTERNATE) {
        nowalternate = 1;
        alternating  = 1;
        nowalternate = 1;
        alternating  = 1;
-       nowserial = serial;
-    } else {
-       /*
-        * multipart/mixed
-        * mutlipart/digest
-        * unknown subtypes of multipart (treat as mixed per rfc2046)
-        */
-       nowserial = serial;
-    }
-
-    /* block a few signals */
-    if (!nowserial) {
-       sigemptyset (&set);
-       sigaddset (&set, SIGHUP);
-       sigaddset (&set, SIGINT);
-       sigaddset (&set, SIGQUIT);
-       sigaddset (&set, SIGTERM);
-       sigprocmask (SIG_BLOCK, &set, &oset);
     }
 
 /*
     }
 
 /*
@@ -566,6 +583,7 @@ show_multi_internal (CT ct, int serial, int alternate)
  */
 
     result = alternate ? NOTOK : OK;
  */
 
     result = alternate ? NOTOK : OK;
+    any_part_ok = 0;
 
     for (part = m->mp_parts; part; part = part->mp_next) {
        p = part->mp_part;
 
     for (part = m->mp_parts; part; part = part->mp_next) {
        p = part->mp_part;
@@ -573,7 +591,10 @@ show_multi_internal (CT ct, int serial, int alternate)
        if (part_ok (p, 1) && type_ok (p, 1)) {
            int inneresult;
 
        if (part_ok (p, 1) && type_ok (p, 1)) {
            int inneresult;
 
-           inneresult = show_switch (p, nowserial, nowalternate);
+           any_part_ok = 1;
+
+           inneresult = show_switch (p, nowalternate, concatsw, textonly,
+                                     inlineonly, fmt);
            switch (inneresult) {
                case NOTOK:
                    if (alternate && !alternating) {
            switch (inneresult) {
                case NOTOK:
                    if (alternate && !alternating) {
@@ -599,53 +620,14 @@ show_multi_internal (CT ct, int serial, int alternate)
        }
     }
 
        }
     }
 
-    if (alternating && !part) {
+    if (alternating && !part && any_part_ok) {
        if (!alternate)
            content_error (NULL, ct, "don't know how to display any of the contents");
        result = NOTOK;
        goto out;
     }
 
        if (!alternate)
            content_error (NULL, ct, "don't know how to display any of the contents");
        result = NOTOK;
        goto out;
     }
 
-    if (serial && !nowserial) {
-       pid_t pid;
-       int kids;
-       int status;
-
-       kids = 0;
-       for (part = m->mp_parts; part; part = part->mp_next) {
-           p = part->mp_part;
-
-           if (p->c_pid > OK) {
-               if (kill (p->c_pid, 0) == NOTOK)
-                   p->c_pid = 0;
-               else
-                   kids++;
-           }
-       }
-
-       while (kids > 0 && (pid = wait (&status)) != NOTOK) {
-           pidcheck (status);
-
-           for (part = m->mp_parts; part; part = part->mp_next) {
-               p = part->mp_part;
-
-               if (xpid == pid)
-                   xpid = 0;
-               if (p->c_pid == pid) {
-                   p->c_pid = 0;
-                   kids--;
-                   break;
-               }
-           }
-       }
-    }
-
 out:
 out:
-    if (!nowserial) {
-       /* reset the signal mask */
-       sigprocmask (SIG_SETMASK, &oset, &set);
-    }
-
     return result;
 }
 
     return result;
 }
 
@@ -656,11 +638,11 @@ out:
  */
 
 static int
  */
 
 static int
-show_multi_aux (CT ct, int serial, int alternate, char *cp)
+show_multi_aux (CT ct, int alternate, char *cp, struct format *fmt)
 {
     /* xstdin is only used in the call to parse_display_string():
        its value is ignored in the function. */
 {
     /* xstdin is only used in the call to parse_display_string():
        its value is ignored in the function. */
-    int xstdin = 0, xlist = 0, xpause = 0, xtty = 0;
+    int xstdin = 0, xlist = 0;
     char *file, buffer[BUFSIZ];
     struct multipart *m = (struct multipart *) ct->c_ctparams;
     struct part *part;
     char *file, buffer[BUFSIZ];
     struct multipart *m = (struct multipart *) ct->c_ctparams;
     struct part *part;
@@ -688,14 +670,13 @@ show_multi_aux (CT ct, int serial, int alternate, char *cp)
        }
     }
 
        }
     }
 
-    if (parse_display_string (ct, cp, &xstdin, &xlist, &xpause, &xtty, file,
+    if (parse_display_string (ct, cp, &xstdin, &xlist, file,
                              buffer, sizeof(buffer) - 1, 1)) {
        admonish (NULL, "Buffer overflow constructing show command!\n");
        return NOTOK;
     }
 
                              buffer, sizeof(buffer) - 1, 1)) {
        admonish (NULL, "Buffer overflow constructing show command!\n");
        return NOTOK;
     }
 
-    return show_content_aux2 (ct, serial, alternate, NULL, buffer,
-                             NOTOK, xlist, xpause, 0, xtty);
+    return show_content_aux2 (ct, alternate, NULL, buffer, NOTOK, xlist, 0, fmt);
 }
 
 
 }
 
 
@@ -704,7 +685,7 @@ show_multi_aux (CT ct, int serial, int alternate, char *cp)
  */
 
 static int
  */
 
 static int
-show_message_rfc822 (CT ct, int serial, int alternate)
+show_message_rfc822 (CT ct, int alternate, struct format *fmt)
 {
     char *cp, buffer[BUFSIZ];
     CI ci = &ct->c_ctinfo;
 {
     char *cp, buffer[BUFSIZ];
     CI ci = &ct->c_ctinfo;
@@ -713,20 +694,20 @@ show_message_rfc822 (CT ct, int serial, int alternate)
     snprintf (buffer, sizeof(buffer), "%s-show-%s/%s",
                invo_name, ci->ci_type, ci->ci_subtype);
     if ((cp = context_find (buffer)) && *cp != '\0')
     snprintf (buffer, sizeof(buffer), "%s-show-%s/%s",
                invo_name, ci->ci_type, ci->ci_subtype);
     if ((cp = context_find (buffer)) && *cp != '\0')
-       return show_content_aux (ct, serial, alternate, cp, NULL);
+       return show_content_aux (ct, alternate, cp, NULL, fmt);
 
     /* Check for invo_name-show-type */
     snprintf (buffer, sizeof(buffer), "%s-show-%s", invo_name, ci->ci_type);
     if ((cp = context_find (buffer)) && *cp != '\0')
 
     /* Check for invo_name-show-type */
     snprintf (buffer, sizeof(buffer), "%s-show-%s", invo_name, ci->ci_type);
     if ((cp = context_find (buffer)) && *cp != '\0')
-       return show_content_aux (ct, serial, alternate, cp, NULL);
+       return show_content_aux (ct, alternate, cp, NULL, fmt);
 
     if ((cp = ct->c_showproc))
 
     if ((cp = ct->c_showproc))
-       return show_content_aux (ct, serial, alternate, cp, NULL);
+       return show_content_aux (ct, alternate, cp, NULL, fmt);
 
     /* default method for message/rfc822 */
     if (ct->c_subtype == MESSAGE_RFC822) {
 
     /* default method for message/rfc822 */
     if (ct->c_subtype == MESSAGE_RFC822) {
-       cp = (ct->c_showproc = add ("%pecho -file %F", NULL));
-       return show_content_aux (ct, serial, alternate, cp, NULL);
+       cp = (ct->c_showproc = add ("%pshow -file %F", NULL));
+       return show_content_aux (ct, alternate, cp, NULL, fmt);
     }
 
     /* complain if we are not a part of a multipart/alternative */
     }
 
     /* complain if we are not a part of a multipart/alternative */
@@ -742,9 +723,8 @@ show_message_rfc822 (CT ct, int serial, int alternate)
  */
 
 static int
  */
 
 static int
-show_partial (CT ct, int serial, int alternate)
+show_partial (CT ct, int alternate)
 {
 {
-    NMH_UNUSED (serial);
     NMH_UNUSED (alternate);
 
     content_error (NULL, ct,
     NMH_UNUSED (alternate);
 
     content_error (NULL, ct,
@@ -760,7 +740,8 @@ show_partial (CT ct, int serial, int alternate)
  */
 
 static int
  */
 
 static int
-show_external (CT ct, int serial, int alternate)
+show_external (CT ct, int alternate, int concatsw, int textonly, int inlineonly,
+              struct format *fmt)
 {
     struct exbody *e = (struct exbody *) ct->c_ctparams;
     CT p = e->eb_content;
 {
     struct exbody *e = (struct exbody *) ct->c_ctparams;
     CT p = e->eb_content;
@@ -768,13 +749,13 @@ show_external (CT ct, int serial, int alternate)
     if (!type_ok (p, 0))
        return OK;
 
     if (!type_ok (p, 0))
        return OK;
 
-    return show_switch (p, serial, alternate);
+    return show_switch (p, alternate, concatsw, textonly, inlineonly, fmt);
 }
 
 
 static int
 }
 
 
 static int
-parse_display_string (CT ct, char *cp, int *xstdin, int *xlist, int *xpause,
-                      int *xtty, char *file, char *buffer, size_t buflen,
+parse_display_string (CT ct, char *cp, int *xstdin, int *xlist,
+                      char *file, char *buffer, size_t buflen,
                       int multipart) {
     int len, quoted = 0;
     char *bp = buffer, *pp;
                       int multipart) {
     int len, quoted = 0;
     char *bp = buffer, *pp;
@@ -816,14 +797,12 @@ parse_display_string (CT ct, char *cp, int *xstdin, int *xlist, int *xpause,
                break;
 
            case 'e':
                break;
 
            case 'e':
-               /* exclusive execution */
-               *xtty = 1;
+               /* no longer implemented */
                break;
 
            case 'F':
                break;
 
            case 'F':
-               /* %e, %f, and stdin is terminal not content */
+               /* %f, and stdin is terminal not content */
                *xstdin = 1;
                *xstdin = 1;
-               *xtty = 1;
                /* and fall... */
 
            case 'f':
                /* and fall... */
 
            case 'f':
@@ -877,8 +856,7 @@ parse_display_string (CT ct, char *cp, int *xstdin, int *xlist, int *xpause,
                break;
 
            case 'p':
                break;
 
            case 'p':
-               /* %l, and pause prior to displaying content */
-               *xpause = pausesw;
+               /* No longer supported */
                /* and fall... */
 
            case 'l':
                /* and fall... */
 
            case 'l':
@@ -1047,16 +1025,7 @@ convert_charset (CT ct, char *dest_charset, int *message_mods) {
     char *src_charset = content_charset (ct);
     int status = OK;
 
     char *src_charset = content_charset (ct);
     int status = OK;
 
-    /* norm_charmap() is case sensitive. */
-    char *src_charset_u = upcase (src_charset);
-    char *dest_charset_u = upcase (dest_charset);
-    int different_charsets =
-        strcmp (norm_charmap (src_charset), norm_charmap (dest_charset));
-
-    free (dest_charset_u);
-    free (src_charset_u);
-
-    if (different_charsets) {
+    if (strcasecmp (src_charset, dest_charset)) {
 #ifdef HAVE_ICONV
         iconv_t conv_desc = NULL;
         char *dest;
 #ifdef HAVE_ICONV
         iconv_t conv_desc = NULL;
         char *dest;
@@ -1067,6 +1036,8 @@ convert_charset (CT ct, char *dest_charset, int *message_mods) {
         size_t end;
         int opened_input_file = 0;
         char src_buffer[BUFSIZ];
         size_t end;
         int opened_input_file = 0;
         char src_buffer[BUFSIZ];
+       size_t dest_buffer_size = BUFSIZ;
+       char *dest_buffer = mh_xmalloc(dest_buffer_size);
         HF hf;
         char *tempfile;
 
         HF hf;
         char *tempfile;
 
@@ -1113,16 +1084,30 @@ convert_charset (CT ct, char *dest_charset, int *message_mods) {
             while ((inbytes = fread (src_buffer, 1,
                                      min (bytes_to_read, sizeof src_buffer),
                                      *fp)) > 0) {
             while ((inbytes = fread (src_buffer, 1,
                                      min (bytes_to_read, sizeof src_buffer),
                                      *fp)) > 0) {
-                char dest_buffer[BUFSIZ];
                 ICONV_CONST char *ib = src_buffer;
                 char *ob = dest_buffer;
                 ICONV_CONST char *ib = src_buffer;
                 char *ob = dest_buffer;
-                size_t outbytes = sizeof dest_buffer;
+                size_t outbytes = dest_buffer_size;
                 size_t outbytes_before = outbytes;
 
                 if (end > 0) bytes_to_read -= inbytes;
 
                 size_t outbytes_before = outbytes;
 
                 if (end > 0) bytes_to_read -= inbytes;
 
+iconv_start:
                 if (iconv (conv_desc, &ib, &inbytes, &ob, &outbytes) ==
                     (size_t) -1) {
                 if (iconv (conv_desc, &ib, &inbytes, &ob, &outbytes) ==
                     (size_t) -1) {
+                   if (errno == E2BIG) {
+                       /*
+                        * Bump up the buffer by at least a factor of 2
+                        * over what we need.
+                        */
+                       size_t bumpup = inbytes * 2, ob_off = ob - dest_buffer;
+                       dest_buffer_size += bumpup;
+                       dest_buffer = mh_xrealloc(dest_buffer,
+                                                 dest_buffer_size);
+                       ob = dest_buffer + ob_off;
+                       outbytes += bumpup;
+                       outbytes_before += bumpup;
+                       goto iconv_start;
+                   }
                     status = NOTOK;
                     break;
                 } else {
                     status = NOTOK;
                     break;
                 } else {
@@ -1152,20 +1137,17 @@ convert_charset (CT ct, char *dest_charset, int *message_mods) {
 
             ++*message_mods;
 
 
             ++*message_mods;
 
-            /* Update ci_attrs. */
-            src_charset = dest_charset;
-
             /* Update ct->c_ctline. */
             if (ct->c_ctline) {
                 char *ctline = concat(" ", ct->c_ctinfo.ci_type, "/",
                                      ct->c_ctinfo.ci_subtype, NULL);
             /* Update ct->c_ctline. */
             if (ct->c_ctline) {
                 char *ctline = concat(" ", ct->c_ctinfo.ci_type, "/",
                                      ct->c_ctinfo.ci_subtype, NULL);
+               char *outline;
+
                replace_param(&ct->c_ctinfo.ci_first_pm,
                              &ct->c_ctinfo.ci_last_pm, "charset",
                              dest_charset, 0);
                replace_param(&ct->c_ctinfo.ci_first_pm,
                              &ct->c_ctinfo.ci_last_pm, "charset",
                              dest_charset, 0);
-               char *outline = output_params(strlen(TYPE_FIELD) + 1 +
-                                             strlen(ctline),
-                                             ct->c_ctinfo.ci_first_pm,
-                                             NULL, 0);
+               outline = output_params(strlen(TYPE_FIELD) + 1 + strlen(ctline),
+                                       ct->c_ctinfo.ci_first_pm, NULL, 0);
                if (outline) {
                    ctline = add(outline, ctline);
                    free(outline);
                if (outline) {
                    ctline = add(outline, ctline);
                    free(outline);
@@ -1188,11 +1170,13 @@ convert_charset (CT ct, char *dest_charset, int *message_mods) {
         } else {
             (void) m_unlink (dest);
         }
         } else {
             (void) m_unlink (dest);
         }
+       free(dest_buffer);
 #else  /* ! HAVE_ICONV */
         NMH_UNUSED (message_mods);
 
         advise (NULL, "Can't convert %s to %s without iconv", src_charset,
                 dest_charset);
 #else  /* ! HAVE_ICONV */
         NMH_UNUSED (message_mods);
 
         advise (NULL, "Can't convert %s to %s without iconv", src_charset,
                 dest_charset);
+        errno = ENOSYS;
         status = NOTOK;
 #endif /* ! HAVE_ICONV */
     }
         status = NOTOK;
 #endif /* ! HAVE_ICONV */
     }
@@ -1203,6 +1187,8 @@ convert_charset (CT ct, char *dest_charset, int *message_mods) {
 
 static int
 convert_content_charset (CT ct, char **file) {
 
 static int
 convert_content_charset (CT ct, char **file) {
+    int status = OK;
+
 #ifdef HAVE_ICONV
     /* Using current locale, see if the content needs to be converted. */
 
 #ifdef HAVE_ICONV
     /* Using current locale, see if the content needs to be converted. */
 
@@ -1212,26 +1198,193 @@ convert_content_charset (CT ct, char **file) {
     if (! check_charset (charset, strlen (charset))) {
         int unused = 0;
 
     if (! check_charset (charset, strlen (charset))) {
         int unused = 0;
 
-        if (convert_charset (ct, get_charset (), &unused) == 0) {
+        char *charset = getcpy (get_charset ());
+
+        if (convert_charset (ct, charset, &unused) == 0) {
             *file = ct->c_cefile.ce_file;
         } else {
             *file = ct->c_cefile.ce_file;
         } else {
-            return NOTOK;
+            status = NOTOK;
         }
         }
+
+        free (charset);
     }
 #else  /* ! HAVE_ICONV */
     NMH_UNUSED (ct);
     NMH_UNUSED (file);
 #endif /* ! HAVE_ICONV */
 
     }
 #else  /* ! HAVE_ICONV */
     NMH_UNUSED (ct);
     NMH_UNUSED (file);
 #endif /* ! HAVE_ICONV */
 
-    return OK;
+    return status;
+}
+
+/*
+ * Compile our format string and save any parameters we care about.
+ */
+
+#define DEFAULT_MARKER "[ part %{part} - %{content-type} - " \
+                      "%<{description}%{description}" \
+                        "%?{cdispo-filename}%{cdispo-filename}" \
+                        "%|%{ctype-name}%>  " \
+                      "%(units(size))B %<(unseen)\\(suppressed\\)%> ]"
+
+static struct format *
+compile_marker(char *markerform)
+{
+    struct format *fmt;
+    char *fmtstring;
+    struct comp *comp = NULL;
+    unsigned int bucket;
+    struct param_comp_list *pc_entry;
+
+    fmtstring = new_fs(markerform, NULL, DEFAULT_MARKER);
+
+    (void) fmt_compile(fmtstring, &fmt, 1);
+    free(fmtstring);
+
+    /*
+     * Things we care about:
+     *
+     * part            - Part name (e.g., 1.1)
+     * content-type    - Content-Type
+     * description     - Content-Description
+     * disposition     - Content-Disposition (inline, attachment)
+     * ctype-<param>   - Content-Type parameter
+     * cdispo-<param>  - Content-Disposition parameter
+     */
+
+    while ((comp = fmt_nextcomp(comp, &bucket)) != NULL) {
+       if (strcasecmp(comp->c_name, "part") == 0) {
+           part_comp = comp;
+       } else if (strcasecmp(comp->c_name, "content-type") == 0) {
+           ctype_comp = comp;
+       } else if (strcasecmp(comp->c_name, "description") == 0) {
+           description_comp = comp;
+       } else if (strcasecmp(comp->c_name, "disposition") == 0) {
+           dispo_comp = comp;
+       } else if (strncasecmp(comp->c_name, "ctype-", 6) == 0 &&
+                  strlen(comp->c_name) > 6) {
+           pc_entry = mh_xmalloc(sizeof(*pc_entry));
+           pc_entry->param = getcpy(comp->c_name + 6);
+           pc_entry->comp = comp;
+           pc_entry->next = ctype_pc_list;
+           ctype_pc_list = pc_entry;
+       } else if (strncasecmp(comp->c_name, "cdispo-", 7) == 0 &&
+                  strlen(comp->c_name) > 7) {
+           pc_entry = mh_xmalloc(sizeof(*pc_entry));
+           pc_entry->param = getcpy(comp->c_name + 7);
+           pc_entry->comp = comp;
+           pc_entry->next = dispo_pc_list;
+           dispo_pc_list = pc_entry;
+       }
+    }
+
+    return fmt;
 }
 
 }
 
+/*
+ * Output on stdout an appropriate marker for this content, using mh-format
+ */
 
 static void
 
 static void
-intrser (int i)
+output_marker(CT ct, struct format *fmt, int hidden)
 {
 {
-    NMH_UNUSED (i);
+    char outbuf[BUFSIZ];
+    struct param_comp_list *pcentry;
+    int partsize;
+    int dat[5];
+
+    /*
+     * Grab any items we care about.
+     */
+
+    if (ctype_comp && ct->c_ctinfo.ci_type) {
+       ctype_comp->c_text = concat(ct->c_ctinfo.ci_type, "/",
+                                   ct->c_ctinfo.ci_subtype, NULL);
+    }
+
+    if (part_comp && ct->c_partno) {
+       part_comp->c_text = getcpy(ct->c_partno);
+    }
+
+    if (description_comp && ct->c_descr) {
+       description_comp->c_text = getcpy(ct->c_descr);
+    }
 
 
-    putchar ('\n');
-    siglongjmp (intrenv, DONE);
+    if (dispo_comp && ct->c_dispo_type) {
+       dispo_comp->c_text = getcpy(ct->c_dispo_type);
+    }
+
+    for (pcentry = ctype_pc_list; pcentry != NULL; pcentry = pcentry->next) {
+       pcentry->comp->c_text = get_param(ct->c_ctinfo.ci_first_pm,
+                                         pcentry->param, '?', 0);
+    }
+
+    for (pcentry = dispo_pc_list; pcentry != NULL; pcentry = pcentry->next) {
+       pcentry->comp->c_text = get_param(ct->c_dispo_first,
+                                         pcentry->param, '?', 0);
+    }
+
+    if (ct->c_cesizefnx)
+       partsize = (*ct->c_cesizefnx) (ct);
+    else
+       partsize = ct->c_end - ct->c_begin;
+
+    /* make the part's hidden aspect available by overloading the
+     * %(unseen) function.  make the part's size available via %(size).
+     * see comments in h/fmt_scan.h.
+     */
+    dat[2] = partsize;
+    dat[4] = hidden;
+    dat[0] = dat[1] = dat[3] = 0;
+
+    fmt_scan(fmt, outbuf, sizeof(outbuf), sizeof(outbuf), dat, NULL);
+
+    fputs(outbuf, stdout);
+
+    fmt_freecomptext();
+}
+
+/*
+ * Reset (and free) any of the saved marker text
+ */
+
+static void
+free_markercomps(void)
+{
+    struct param_comp_list *pc_entry, *pc2;
+
+    part_comp = NULL;
+    ctype_comp = NULL;
+    description_comp = NULL;
+    dispo_comp = NULL;
+
+    for (pc_entry = ctype_pc_list; pc_entry != NULL; ) {
+       free(pc_entry->param);
+       pc2 = pc_entry->next;
+       free(pc_entry);
+       pc_entry = pc2;
+    }
+
+    for (pc_entry = dispo_pc_list; pc_entry != NULL; ) {
+       free(pc_entry->param);
+       pc2 = pc_entry->next;
+       free(pc_entry);
+       pc_entry = pc2;
+    }
+}
+
+/*
+ * Exit if the display process returned with a nonzero exit code, or terminated
+ * with a SIGQUIT signal.
+ */
+
+static int
+pidcheck (int status)
+{
+    if ((status & 0xff00) == 0xff00 || (status & 0x007f) != SIGQUIT)
+       return status;
+
+    fflush (stdout);
+    fflush (stderr);
+    done (1);
+    return 1;
 }
 }