Fix uip/whom.c for C89 compatibility
[mmh] / uip / mhshowsbr.c
index be03d96..c7923c8 100644 (file)
 /*
- * mhshowsbr.c -- routines to display the contents of MIME messages
- *
- * 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.
- */
+** mhshowsbr.c -- routines to display the contents of MIME messages
+**
+** This code is Copyright (c) 2002, by the authors of nmh.  See the
+** COPYRIGHT file in the root directory of the nmh distribution for
+** complete copyright information.
+*/
 
 #include <h/mh.h>
 #include <fcntl.h>
 #include <h/signals.h>
-#include <h/md5.h>
 #include <errno.h>
-#include <setjmp.h>
 #include <signal.h>
-#include <h/mts.h>
 #include <h/tws.h>
 #include <h/mime.h>
 #include <h/mhparse.h>
 #include <h/utils.h>
-
-#ifdef HAVE_SYS_WAIT_H
-# include <sys/wait.h>
-#endif
-
-/*
- * Just use sigjmp/longjmp on older machines that
- * don't have sigsetjmp/siglongjmp.
- */
-#ifndef HAVE_SIGSETJMP
-# define sigjmp_buf jmp_buf
-# define sigsetjmp(env,mask) setjmp(env)
-# define siglongjmp(env,val) longjmp(env,val)
-#endif
+#include <sys/wait.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sysexits.h>
 
 extern int debugsw;
 
-int pausesw  = 1;
-int serialsw = 0;
 int nolist   = 0;
-
-char *progsw = NULL;
-
-/* flags for moreproc/header display */
-int nomore   = 0;
 char *formsw = NULL;
 
-pid_t xpid = 0;
-
-static sigjmp_buf intrenv;
-
-
-/* termsbr.c */
-int SOprintf (char *, ...);
 
 /* mhparse.c */
-int pidcheck (int);
+int pidcheck(int);
 
 /* mhmisc.c */
-int part_ok (CT, int);
-int type_ok (CT, int);
-void content_error (char *, CT, char *, ...);
-void flush_errors (void);
+int part_ok(CT, int);
+int type_ok(CT, int);
+void content_error(char *, CT, char *, ...);
+void flush_errors(void);
 
 /* mhlistsbr.c */
-int list_switch (CT, int, int, int, int);
-int list_content (CT, int, int, int, int);
+int list_switch(CT, int, int, int);
+int list_content(CT, int, int, int);
 
 /*
- * prototypes
- */
-void show_all_messages (CT *);
-int show_content_aux (CT, int, int, char *, char *);
+** prototypes
+*/
+void show_all_messages(CT *);
+int show_content_aux(CT, int, char *, char *);
 
 /*
- * 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 RETSIGTYPE intrser (int);
+** static prototypes
+*/
+static void show_single_message(CT, char *);
+static void DisplayMsgHeader(CT, char *);
+static int show_switch(CT, int);
+static int show_content(CT, int);
+static int show_content_aux2(CT, int, char *, char *, int, int, int);
+static int show_text(CT, int);
+static int show_multi(CT, int);
+static int show_multi_internal(CT, int);
+static int show_multi_aux(CT, int, char *);
+static int show_message_rfc822(CT, int);
+static int show_partial(CT, int);
+static int show_external(CT, int);
 
 
 /*
- * Top level entry point to show/display a group of messages
- */
+** Top level entry point to show/display a group of messages
+*/
 
 void
-show_all_messages (CT *cts)
+show_all_messages(CT *cts)
 {
        CT ct, *ctp;
 
        /*
-        * If form is not specified, then get default form
-        * for showing headers of MIME messages.
-        */
+       ** If form is not specified, then get default form
+       ** for showing headers of MIME messages.
+       */
        if (!formsw)
-               formsw = getcpy (etcpath ("mhl.headers"));
+               formsw = mh_xstrdup(etcpath("mhl.headers"));
 
        /*
-        * If form is "mhl.null", suppress display of header.
-        */
-       if (!strcmp (formsw, "mhl.null"))
+       ** If form is "mhl.null", suppress display of header.
+       */
+       if (strcmp(formsw, "mhl.null")==0)
                formsw = NULL;
 
        for (ctp = cts; *ctp; ctp++) {
                ct = *ctp;
 
-               /* if top-level type is ok, then display message */
-               if (type_ok (ct, 1))
-                       show_single_message (ct, formsw);
+               if (!type_ok(ct, 1)) {  /* top-level type */
+                       continue;
+               }
+               if (cts[1]) {
+                       if (ctp != cts) {
+                               printf("\n\n");
+                       }
+                       printf(">>> Message %s\n\n", ct->c_file);
+               }
+               show_single_message(ct, formsw);
        }
 }
 
 
 /*
- * Entry point to show/display a single message
- */
+** Entry point to show/display a single message
+*/
 
 static void
-show_single_message (CT ct, char *form)
+show_single_message(CT ct, char *form)
 {
-       sigset_t set, oset;
-
-#ifdef HAVE_UNION_WAIT
-       union wait status;
-#else
-       int status;
-#endif
-
-       /* Allow user executable bit so that temporary directories created by
-        * the viewer (e.g., lynx) are going to be accessible */
-       umask (ct->c_umask & ~(0100));
+       /*
+       ** Allow user executable bit so that temporary directories created by
+       ** the viewer (e.g., lynx) are going to be accessible
+       */
+       umask(ct->c_umask & ~(0100));
 
        /*
-        * If you have a format file, then display
-        * the message headers.
-        */
+       ** If you have a format file, then display
+       ** the message headers.
+       */
        if (form)
                DisplayMsgHeader(ct, form);
-       else
-               xpid = 0;
 
        /* Show the body of the message */
-       show_switch (ct, 1, 0);
+       show_switch(ct, 0);
 
        if (ct->c_fp) {
-               fclose (ct->c_fp);
+               fclose(ct->c_fp);
                ct->c_fp = NULL;
        }
        if (ct->c_ceclosefnx)
                (*ct->c_ceclosefnx) (ct);
 
-       /* block a few signals */
-       sigemptyset (&set);
-       sigaddset (&set, SIGHUP);
-       sigaddset (&set, SIGINT);
-       sigaddset (&set, SIGQUIT);
-       sigaddset (&set, SIGTERM);
-       SIGPROCMASK (SIG_BLOCK, &set, &oset);
-
-       while (wait (&status) != NOTOK) {
-#ifdef HAVE_UNION_WAIT
-               pidcheck (status.w_status);
-#else
-               pidcheck (status);
-#endif
-               continue;
-       }
-
-       /* reset the signal mask */
-       SIGPROCMASK (SIG_SETMASK, &oset, &set);
-
-       xpid = 0;
-       flush_errors ();
+       flush_errors();
 }
 
 
 /*
- * Use the mhlproc to show the header fields
- */
-
+** Use mhl to show the header fields
+*/
 static void
-DisplayMsgHeader (CT ct, char *form)
+DisplayMsgHeader(CT ct, char *form)
 {
        pid_t child_id;
-       int i, vecp;
+       int vecp;
        char *vec[8];
 
        vecp = 0;
-       vec[vecp++] = r1bindex (mhlproc, '/');
+       vec[vecp++] = "mhl";
        vec[vecp++] = "-form";
        vec[vecp++] = form;
        vec[vecp++] = "-nobody";
        vec[vecp++] = ct->c_file;
-
-       /*
-        * If we've specified -(no)moreproc,
-        * then just pass that along.
-        */
-       if (nomore) {
-               vec[vecp++] = "-nomoreproc";
-       } else if (progsw) {
-               vec[vecp++] = "-moreproc";
-               vec[vecp++] = progsw;
-       }
        vec[vecp] = NULL;
 
-       fflush (stdout);
+       fflush(stdout);
 
-       for (i = 0; (child_id = vfork()) == NOTOK && i < 5; i++)
-               sleep (5);
-
-       switch (child_id) {
+       switch (child_id = fork()) {
        case NOTOK:
-               adios ("fork", "unable to");
+               adios(EX_OSERR, "fork", "unable to");
                /* NOTREACHED */
 
        case OK:
-               execvp (mhlproc, vec);
-               fprintf (stderr, "unable to exec ");
-               perror (mhlproc);
-               _exit (-1);
+               execvp("mhl", vec);
+               fprintf(stderr, "unable to exec ");
+               perror("mhl");
+               _exit(EX_OSERR);
                /* NOTREACHED */
 
        default:
-               xpid = -child_id;
+               pidcheck(pidwait(child_id, NOTOK));
                break;
        }
 }
 
 
 /*
- * Switching routine.  Call the correct routine
- * based on content type.
- */
+** Switching routine.  Call the correct routine
+** based on content type.
+*/
 
 static int
-show_switch (CT ct, int serial, int alternate)
+show_switch(CT ct, int alternate)
 {
        switch (ct->c_type) {
-               case CT_MULTIPART:
-                       return show_multi (ct, serial, alternate);
-                       break;
+       case CT_MULTIPART:
+               return show_multi(ct, alternate);
+               break;
 
-               case CT_MESSAGE:
-                       switch (ct->c_subtype) {
-                               case MESSAGE_PARTIAL:
-                                       return show_partial (ct, serial, alternate);
-                                       break;
+       case CT_MESSAGE:
+               switch (ct->c_subtype) {
+                       case MESSAGE_PARTIAL:
+                               return show_partial(ct, alternate);
+                               break;
 
-                               case MESSAGE_EXTERNAL:
-                                       return show_external (ct, serial, alternate);
-                                       break;
+                       case MESSAGE_EXTERNAL:
+                               return show_external(ct, alternate);
+                               break;
 
-                               case MESSAGE_RFC822:
-                               default:
-                                       return show_message_rfc822 (ct, serial, alternate);
-                                       break;
-                       }
-                       break;
+                       case MESSAGE_RFC822:
+                       default:
+                               return show_message_rfc822(ct, alternate);
+                               break;
+               }
+               break;
 
-               case CT_TEXT:
-                       return show_text (ct, serial, alternate);
-                       break;
+       case CT_TEXT:
+               return show_text(ct, alternate);
+               break;
 
-               case CT_AUDIO:
-               case CT_IMAGE:
-               case CT_VIDEO:
-               case CT_APPLICATION:
-                       return show_content (ct, serial, alternate);
-                       break;
+       case CT_AUDIO:
+       case CT_IMAGE:
+       case CT_VIDEO:
+       case CT_APPLICATION:
+               return show_content(ct, alternate);
+               break;
 
-               default:
-                       adios (NULL, "unknown content type %d", ct->c_type);
-                       break;
+       default:
+               adios(EX_DATAERR, NULL, "unknown content type %d", ct->c_type);
+               break;
        }
 
        return 0;  /* NOT REACHED */
@@ -290,52 +225,52 @@ show_switch (CT ct, int serial, int alternate)
 
 
 /*
- * Generic method for displaying content
- */
+** Generic method for displaying content
+*/
 
 static int
-show_content (CT ct, int serial, int alternate)
+show_content(CT ct, int alternate)
 {
        char *cp, buffer[BUFSIZ];
        CI ci = &ct->c_ctinfo;
 
        /* Check for mhshow-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);
+       snprintf(buffer, sizeof(buffer), "mhshow-show-%s/%s",
+                               ci->ci_type, ci->ci_subtype);
+       if ((cp = context_find(buffer)) && *cp != '\0')
+               return show_content_aux(ct, alternate, cp, NULL);
 
        /* Check for mhshow-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);
+       snprintf(buffer, sizeof(buffer), "mhshow-show-%s", ci->ci_type);
+       if ((cp = context_find(buffer)) && *cp != '\0')
+               return show_content_aux(ct, alternate, cp, NULL);
 
        if ((cp = ct->c_showproc))
-               return show_content_aux (ct, serial, alternate, cp, NULL);
+               return show_content_aux(ct, alternate, cp, NULL);
 
        /* complain if we are not a part of a multipart/alternative */
        if (!alternate)
-               content_error (NULL, ct, "don't know how to display content");
+               return show_content_aux(ct, alternate, "%l", NULL);
 
        return NOTOK;
 }
 
 
 /*
- * Parse the display string for displaying generic content
- */
-
+** Parse the display string for displaying generic content
+*/
 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)
 {
        int fd, len, buflen, quoted;
-       int xstdin, xlist, xpause, xtty;
+       int xstdin, xlist;
        char *bp, *pp, *file, buffer[BUFSIZ];
        CI ci = &ct->c_ctinfo;
 
        if (!ct->c_ceopenfnx) {
                if (!alternate)
-                       content_error (NULL, ct, "don't know how to decode content");
+                       content_error(NULL, ct,
+                                       "don't know how to decode content");
 
                return NOTOK;
        }
@@ -343,16 +278,14 @@ show_content_aux (CT ct, int serial, int alternate, char *cp, char *cracked)
        file = NULL;
        if ((fd = (*ct->c_ceopenfnx) (ct, &file)) == NOTOK)
                return NOTOK;
-       if (ct->c_showproc && !strcmp (ct->c_showproc, "true"))
+       if (ct->c_showproc && strcmp(ct->c_showproc, "true")==0)
                return (alternate ? DONE : OK);
 
        xlist  = 0;
-       xpause = 0;
        xstdin = 0;
-       xtty   = 0;
 
        if (cracked) {
-               strncpy (buffer, cp, sizeof(buffer));
+               strncpy(buffer, cp, sizeof(buffer));
                goto got_command;
        }
 
@@ -370,69 +303,70 @@ show_content_aux (CT ct, int serial, int alternate, char *cp, char *cracked)
                        switch (*++cp) {
                        case 'a':
                                /* insert parameters from Content-Type field */
-                       {
+                               {
                                char **ap, **ep;
                                char *s = "";
 
-                               for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++) {
-                                       snprintf (bp, buflen, "%s%s=\"%s\"", s, *ap, *ep);
-                                       len = strlen (bp);
+                               for (ap = ci->ci_attrs, ep = ci->ci_values;
+                                               *ap; ap++, ep++) {
+                                       snprintf(bp, buflen, "%s%s=\"%s\"",
+                                                       s, *ap, *ep);
+                                       len = strlen(bp);
                                        bp += len;
                                        buflen -= len;
                                        s = " ";
                                }
-                       }
-                       break;
+                               }
+                               break;
+
+                       case 'c':
+                               /* insert charset */
+                               strncpy(bp, ct->c_charset ? ct->c_charset :
+                                               "US-ASCII", buflen);
+                               break;
 
                        case 'd':
                                /* insert content description */
                                if (ct->c_descr) {
                                        char *s;
 
-                                       s = trimcpy (ct->c_descr);
-                                       strncpy (bp, s, buflen);
-                                       free (s);
+                                       s = trimcpy(ct->c_descr);
+                                       strncpy(bp, s, buflen);
+                                       mh_free0(&s);
                                }
                                break;
 
-                       case 'e':
-                               /* exclusive execution */
-                               xtty = 1;
-                               break;
-
                        case 'F':
-                               /* %e, %f, and stdin is terminal not content */
+                               /* %f, and stdin is terminal not content */
                                xstdin = 1;
-                               xtty = 1;
                                /* and fall... */
 
                        case 'f':
                                /* insert filename containing content */
-                               snprintf (bp, buflen, "'%s'", file);
-                               /* since we've quoted the file argument, set things up
-                                * to look past it, to avoid problems with the quoting
-                                * logic below.  (I know, I should figure out what's
-                                * broken with the quoting logic, but..)
-                                */
+                               snprintf(bp, buflen, "'%s'", file);
+                               /*
+                               ** since we've quoted the file argument,
+                               ** set things up to look past it, to avoid
+                               ** problems with the quoting logic below.
+                               ** (I know, I should figure out what's
+                               ** broken with the quoting logic, but..)
+                               */
                                len = strlen(bp);
                                buflen -= len;
                                bp += len;
                                pp = bp;
                                break;
 
-                       case 'p':
-                               /* %l, and pause prior to displaying content */
-                               xpause = pausesw;
-                               /* and fall... */
-
                        case 'l':
-                               /* display listing prior to displaying content */
+                               /*
+                               ** display listing prior to displaying content
+                               */
                                xlist = !nolist;
                                break;
 
                        case 's':
                                /* insert subtype of content */
-                               strncpy (bp, ci->ci_subtype, buflen);
+                               strncpy(bp, ci->ci_subtype, buflen);
                                break;
 
                        case '%':
@@ -445,31 +379,37 @@ show_content_aux (CT ct, int serial, int alternate, char *cp, char *cracked)
                                buflen--;
                                continue;
                        }
-                       len = strlen (bp);
+                       len = strlen(bp);
                        bp += len;
                        buflen -= len;
 
                        /* Did we actually insert something? */
                        if (bp != pp) {
-                               /* Insert single quote if not inside quotes already */
+                               /*
+                               ** Insert single quote if not inside quotes
+                               ** already
+                               */
                                if (!quoted && buflen) {
-                                       len = strlen (pp);
-                                       memmove (pp + 1, pp, len);
+                                       len = strlen(pp);
+                                       memmove(pp + 1, pp, len);
                                        *pp++ = '\'';
                                        buflen--;
                                        bp++;
                                }
                                /* Escape existing quotes */
-                               while ((pp = strchr (pp, '\'')) && buflen > 3) {
-                                       len = strlen (pp++);
-                                       memmove (pp + 3, pp, len);
+                               while ((pp = strchr(pp, '\'')) && buflen > 3) {
+                                       len = strlen(pp++);
+                                       memmove(pp + 3, pp, len);
                                        *pp++ = '\\';
                                        *pp++ = '\'';
                                        *pp++ = '\'';
                                        buflen -= 3;
                                        bp += 3;
                                }
-                               /* If pp is still set, that means we ran out of space. */
+                               /*
+                               ** If pp is still set, that means we ran
+                               ** out of space.
+                               */
                                if (pp)
                                        buflen = 0;
                                if (!quoted && buflen) {
@@ -489,166 +429,106 @@ raw:
                }
        }
 
-       if (buflen <= 0 || (ct->c_termproc && buflen <= strlen(ct->c_termproc))) {
-               /* content_error would provide a more useful error message
-                * here, except that if we got overrun, it probably would
-                * too.
-                */
-               fprintf(stderr, "Buffer overflow constructing show command!\n");
-               return NOTOK;
-       }
-
-       /* use charset string to modify display method */
-       if (ct->c_termproc) {
-               char term[BUFSIZ];
-
-               strncpy (term, buffer, sizeof(term));
-               snprintf (buffer, sizeof(buffer), ct->c_termproc, term);
-       }
-
 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);
 }
 
 
 /*
- * Routine to actually display the content
- */
-
+** Routine to actually display the content
+*/
 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)
 {
        pid_t child_id;
-       int i;
-       char *vec[4], exec[BUFSIZ + sizeof "exec "];
 
        if (debugsw || cracked) {
-               fflush (stdout);
+               fflush(stdout);
 
-               fprintf (stderr, "%s msg %s", cracked ? "storing" : "show",
+               fprintf(stderr, "%s msg %s", cracked ? "storing" : "show",
                                 ct->c_file);
                if (ct->c_partno)
-                       fprintf (stderr, " part %s", ct->c_partno);
+                       fprintf(stderr, " part %s", ct->c_partno);
                if (cracked)
-                       fprintf (stderr, " using command (cd %s; %s)\n", cracked, buffer);
+                       fprintf(stderr, " using command (cd %s; %s)\n",
+                                       cracked, buffer);
                else
-                       fprintf (stderr, " using command %s\n", buffer);
-       }
-
-       if (xpid < 0 || (xtty && xpid)) {
-               if (xpid < 0)
-                       xpid = -xpid;
-               pidcheck(pidwait (xpid, NOTOK));
-               xpid = 0;
+                       fprintf(stderr, " using command %s\n", buffer);
        }
 
        if (xlist) {
-               char prompt[BUFSIZ];
-
                if (ct->c_type == CT_MULTIPART)
-                       list_content (ct, -1, 1, 0, 0);
+                       list_content(ct, -1, 0, 0);
                else
-                       list_switch (ct, -1, 1, 0, 0);
-
-               if (xpause && SOprintf ("Press <return> to show content..."))
-                       printf ("Press <return> to show content...");
-
-               if (xpause) {
-                       int intr;
-                       SIGNAL_HANDLER istat;
-
-                       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);
-               }
+                       list_switch(ct, -1, 0, 0);
        }
 
-       snprintf (exec, sizeof(exec), "exec %s", buffer);
-
-       vec[0] = "/bin/sh";
-       vec[1] = "-c";
-       vec[2] = exec;
-       vec[3] = NULL;
+       fflush(stdout);
 
-       fflush (stdout);
+       switch (child_id = fork()) {
+       case NOTOK:
+               advise("fork", "unable to");
+               (*ct->c_ceclosefnx) (ct);
+               return NOTOK;
 
-       for (i = 0; (child_id = vfork ()) == NOTOK && i < 5; i++)
-               sleep (5);
-       switch (child_id) {
-               case NOTOK:
-                       advise ("fork", "unable to");
-                       (*ct->c_ceclosefnx) (ct);
-                       return NOTOK;
+       case OK:
+               if (cracked)
+                       chdir(cracked);
+               if (!xstdin)
+                       dup2(fd, 0);
+               close(fd);
+               execlp("/bin/sh", "/bin/sh", "-c", buffer, NULL);
+               fprintf(stderr, "unable to exec ");
+               perror("/bin/sh");
+               _exit(EX_OSERR);
+               /* NOTREACHED */
 
-               case OK:
-                       if (cracked)
-                               chdir (cracked);
-                       if (!xstdin)
-                               dup2 (fd, 0);
-                       close (fd);
-                       execvp ("/bin/sh", vec);
-                       fprintf (stderr, "unable to exec ");
-                       perror ("/bin/sh");
-                       _exit (-1);
-                       /* NOTREACHED */
-
-               default:
-                       if (!serial) {
-                               ct->c_pid = child_id;
-                               if (xtty)
-                                       xpid = child_id;
-                       } else {
-                               pidcheck (pidXwait (child_id, NULL));
-                       }
+       default:
+               pidcheck(pidXwait(child_id, NULL));
 
-                       if (fd != NOTOK)
-                               (*ct->c_ceclosefnx) (ct);
-                       return (alternate ? DONE : OK);
+               if (fd != NOTOK)
+                       (*ct->c_ceclosefnx) (ct);
+               return (alternate ? DONE : OK);
        }
 }
 
 
 /*
- * show content of type "text"
- */
+** show content of type "text"
+*/
 
 static int
-show_text (CT ct, int serial, int alternate)
+show_text(CT ct, int alternate)
 {
        char *cp, buffer[BUFSIZ];
        CI ci = &ct->c_ctinfo;
 
        /* Check for mhshow-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);
+       snprintf(buffer, sizeof(buffer), "mhshow-show-%s/%s",
+                       ci->ci_type, ci->ci_subtype);
+       if ((cp = context_find(buffer)) && *cp != '\0')
+               return show_content_aux(ct, alternate, cp, NULL);
 
        /* Check for mhshow-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);
+       snprintf(buffer, sizeof(buffer), "mhshow-show-%s", ci->ci_type);
+       if ((cp = context_find(buffer)) && *cp != '\0')
+               return show_content_aux(ct, alternate, cp, NULL);
 
        /*
-        * Use default method if content is text/plain, or if
-        * if it is not a text part of a multipart/alternative
-        */
+       ** 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 : "more");
-               cp = (ct->c_showproc = add (buffer, NULL));
-               return show_content_aux (ct, serial, alternate, cp, NULL);
+               if (ct->c_charset && !is_native_charset(ct->c_charset)) {
+                       snprintf(buffer, sizeof(buffer), "%%liconv -f '%s'",
+                                       ct->c_charset);
+               } else {
+                       snprintf(buffer, sizeof(buffer), "%%lcat");
+               }
+               ct->c_showproc = mh_xstrdup(buffer);
+               return show_content_aux(ct, alternate, ct->c_showproc, NULL);
        }
 
        return NOTOK;
@@ -656,117 +536,104 @@ show_text (CT ct, int serial, int alternate)
 
 
 /*
- * show message body of type "multipart"
- */
+** show message body of type "multipart"
+*/
 
 static int
-show_multi (CT ct, int serial, int alternate)
+show_multi(CT ct, int alternate)
 {
        char *cp, buffer[BUFSIZ];
        CI ci = &ct->c_ctinfo;
 
        /* Check for mhshow-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_multi_aux (ct, serial, alternate, cp);
+       snprintf(buffer, sizeof(buffer), "mhshow-show-%s/%s",
+                       ci->ci_type, ci->ci_subtype);
+       if ((cp = context_find(buffer)) && *cp != '\0')
+               return show_multi_aux(ct, alternate, cp);
 
        /* Check for mhshow-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);
+       snprintf(buffer, sizeof(buffer), "mhshow-show-%s", ci->ci_type);
+       if ((cp = context_find(buffer)) && *cp != '\0')
+               return show_multi_aux(ct, alternate, cp);
 
        if ((cp = ct->c_showproc))
-               return show_multi_aux (ct, serial, alternate, cp);
+               return show_multi_aux(ct, alternate, cp);
 
        /*
-        * Use default method to display this multipart content
-        * if it is not a (nested) part of a multipart/alternative,
-        * or if it is one of the known subtypes of multipart.
-        */
+       ** Use default method to display this multipart content
+       ** if it is not a (nested) part of a multipart/alternative,
+       ** or if it is one of the known subtypes of multipart.
+       */
        if (!alternate || ct->c_subtype != MULTI_UNKNOWN)
-               return show_multi_internal (ct, serial, alternate);
+               return show_multi_internal(ct, alternate);
 
        return NOTOK;
 }
 
 
 /*
- * show message body of subtypes of multipart that
- * we understand directly (mixed, alternate, etc...)
- */
+** show message body of subtypes of multipart that
+** we understand directly (mixed, alternate, etc...)
+*/
 
 static int
-show_multi_internal (CT ct, int serial, int alternate)
+show_multi_internal(CT ct, int alternate)
 {
-       int alternating, nowalternate, nowserial, result;
+       int alternating, nowalternate, result;
        struct multipart *m = (struct multipart *) ct->c_ctparams;
        struct part *part;
        CT p;
-       sigset_t set, oset;
 
        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;
-               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);
-       }
+       /*
+       ** Other possible multipart types are:
+       ** - multipart/parallel
+       ** - multipart/mixed
+       ** - multipart/digest
+       ** - unknown subtypes of multipart (treat as mixed per rfc2046)
+       */
 
-/*
- * alternate   -> we are a part inside an multipart/alternative
- * alternating -> we are a multipart/alternative
- */
+       /*
+       ** alternate   -> we are a part inside an multipart/alternative
+       ** alternating -> we are a multipart/alternative
+       */
 
        result = alternate ? NOTOK : OK;
 
        for (part = m->mp_parts; part; part = part->mp_next) {
                p = part->mp_part;
 
-               if (part_ok (p, 0) && type_ok (p, 0)) {
+               if (part_ok(p, 1) && type_ok(p, 1)) {
                        int inneresult;
 
-                       inneresult = show_switch (p, nowserial, nowalternate);
+                       inneresult = show_switch(p, nowalternate);
                        switch (inneresult) {
-                               case NOTOK:
-                                       if (alternate && !alternating) {
-                                               result = NOTOK;
-                                               goto out;
-                                       }
-                                       continue;
-
-                               case OK:
-                               case DONE:
-                                       if (alternating) {
-                                               result = DONE;
-                                               break;
-                                       }
-                                       if (alternate) {
-                                               alternate = nowalternate = 0;
-                                               if (result == NOTOK)
-                                                       result = inneresult;
-                                       }
-                                       continue;
+                       case NOTOK:
+                               if (alternate && !alternating) {
+                                       result = NOTOK;
+                                       goto out;
+                               }
+                               continue;
+
+                       case OK:
+                       case DONE:
+                               if (alternating) {
+                                       result = DONE;
+                                       break;
+                               }
+                               if (alternate) {
+                                       alternate = nowalternate = 0;
+                                       if (result == NOTOK)
+                                               result = inneresult;
+                               }
+                               continue;
                        }
                        break;
                }
@@ -774,73 +641,25 @@ show_multi_internal (CT ct, int serial, int alternate)
 
        if (alternating && !part) {
                if (!alternate)
-                       content_error (NULL, ct, "don't know how to display any of the contents");
+                       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;
-#ifdef HAVE_UNION_WAIT
-               union wait status;
-#else
-               int status;
-#endif
-
-               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) {
-#ifdef HAVE_UNION_WAIT
-                       pidcheck (status.w_status);
-#else
-                       pidcheck (status);
-#endif
-
-                       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:
-       if (!nowserial) {
-               /* reset the signal mask */
-               SIGPROCMASK (SIG_SETMASK, &oset, &set);
-       }
-
        return result;
 }
 
 
 /*
- * Parse display string for multipart content
- * and use external program to display it.
- */
+** Parse display string for multipart content
+** and use external program to display it.
+*/
 
 static int
-show_multi_aux (CT ct, int serial, int alternate, char *cp)
+show_multi_aux(CT ct, int alternate, char *cp)
 {
        int len, buflen, quoted;
-       int xlist, xpause, xtty;
+       int xlist;
        char *bp, *pp, *file, buffer[BUFSIZ];
        struct multipart *m = (struct multipart *) ct->c_ctparams;
        struct part *part;
@@ -852,7 +671,7 @@ show_multi_aux (CT ct, int serial, int alternate, char *cp)
 
                if (!p->c_ceopenfnx) {
                        if (!alternate)
-                               content_error (NULL, p, "don't know how to decode content");
+                               content_error(NULL, p, "don't know how to decode content");
                        return NOTOK;
                }
 
@@ -862,17 +681,15 @@ show_multi_aux (CT ct, int serial, int alternate, char *cp)
                                return NOTOK;
 
                        /* I'm not sure if this is necessary? */
-                       p->c_storage = add (file, NULL);
+                       p->c_storage = mh_xstrdup(file);
 
-                       if (p->c_showproc && !strcmp (p->c_showproc, "true"))
+                       if (p->c_showproc && strcmp(p->c_showproc, "true")==0)
                                return (alternate ? DONE : OK);
                        (*p->c_ceclosefnx) (p);
                }
        }
 
        xlist = 0;
-       xpause = 0;
-       xtty = 0;
 
        /* get buffer ready to go */
        bp = buffer;
@@ -887,75 +704,75 @@ show_multi_aux (CT ct, int serial, int alternate, char *cp)
                        switch (*++cp) {
                        case 'a':
                                /* insert parameters from Content-Type field */
-                       {
+                               {
                                char **ap, **ep;
                                char *s = "";
 
-                               for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++) {
-                                       snprintf (bp, buflen, "%s%s=\"%s\"", s, *ap, *ep);
-                                       len = strlen (bp);
+                               for (ap = ci->ci_attrs, ep = ci->ci_values;
+                                               *ap; ap++, ep++) {
+                                       snprintf(bp, buflen, "%s%s=\"%s\"",
+                                                       s, *ap, *ep);
+                                       len = strlen(bp);
                                        bp += len;
                                        buflen -= len;
                                        s = " ";
                                }
-                       }
-                       break;
+                               }
+                               break;
+
+                       case 'c':
+                               /* insert charset */
+                               strncpy(bp, ct->c_charset ? ct->c_charset :
+                                               "US-ASCII", buflen);
+                               break;
 
                        case 'd':
                                /* insert content description */
                                if (ct->c_descr) {
                                        char *s;
 
-                                       s = trimcpy (ct->c_descr);
-                                       strncpy (bp, s, buflen);
-                                       free (s);
+                                       s = trimcpy(ct->c_descr);
+                                       strncpy(bp, s, buflen);
+                                       mh_free0(&s);
                                }
                                break;
 
-                       case 'e':
-                               /* exclusive execution */
-                               xtty = 1;
-                               break;
-
                        case 'F':
-                               /* %e and %f */
-                               xtty = 1;
-                               /* and fall... */
-
                        case 'f':
                                /* insert filename(s) containing content */
                        {
                                char *s = "";
 
-                               for (part = m->mp_parts; part; part = part->mp_next) {
+                               for (part = m->mp_parts; part;
+                                               part = part->mp_next) {
                                        p = part->mp_part;
 
-                                       snprintf (bp, buflen, "%s'%s'", s, p->c_storage);
-                                       len = strlen (bp);
+                                       snprintf(bp, buflen, "%s'%s'",
+                                                       s, p->c_storage);
+                                       len = strlen(bp);
                                        bp += len;
                                        buflen -= len;
                                        s = " ";
                                }
-                               /* set our starting pointer back to bp, to avoid
-                                * requoting the filenames we just added
-                                */
+                               /*
+                               ** set our starting pointer back to bp,
+                               ** to avoid requoting the filenames we
+                               ** just added
+                               */
                                pp = bp;
                        }
                        break;
 
-                       case 'p':
-                               /* %l, and pause prior to displaying content */
-                               xpause = pausesw;
-                               /* and fall... */
-
                        case 'l':
-                               /* display listing prior to displaying content */
+                               /*
+                               ** display listing prior to displaying content
+                               */
                                xlist = !nolist;
                                break;
 
                        case 's':
                                /* insert subtype of content */
-                               strncpy (bp, ci->ci_subtype, buflen);
+                               strncpy(bp, ci->ci_subtype, buflen);
                                break;
 
                        case '%':
@@ -968,31 +785,37 @@ show_multi_aux (CT ct, int serial, int alternate, char *cp)
                                buflen--;
                                continue;
                        }
-                       len = strlen (bp);
+                       len = strlen(bp);
                        bp += len;
                        buflen -= len;
 
                        /* Did we actually insert something? */
                        if (bp != pp) {
-                               /* Insert single quote if not inside quotes already */
+                               /*
+                               ** Insert single quote if not inside quotes
+                               ** already
+                               */
                                if (!quoted && buflen) {
-                                       len = strlen (pp);
-                                       memmove (pp + 1, pp, len);
+                                       len = strlen(pp);
+                                       memmove(pp + 1, pp, len);
                                        *pp++ = '\'';
                                        buflen--;
                                        bp++;
                                }
                                /* Escape existing quotes */
-                               while ((pp = strchr (pp, '\'')) && buflen > 3) {
-                                       len = strlen (pp++);
-                                       memmove (pp + 3, pp, len);
+                               while ((pp = strchr(pp, '\'')) && buflen > 3) {
+                                       len = strlen(pp++);
+                                       memmove(pp + 3, pp, len);
                                        *pp++ = '\\';
                                        *pp++ = '\'';
                                        *pp++ = '\'';
                                        buflen -= 3;
                                        bp += 3;
                                }
-                               /* If pp is still set, that means we ran out of space. */
+                               /*
+                               ** If pp is still set, that means we ran
+                               ** out of space.
+                               */
                                if (pp)
                                        buflen = 0;
                                if (!quoted && buflen) {
@@ -1012,110 +835,95 @@ raw:
                }
        }
 
-       if (buflen <= 0 || (ct->c_termproc && buflen <= strlen(ct->c_termproc))) {
-               /* content_error would provide a more useful error message
-                * here, except that if we got overrun, it probably would
-                * too.
-                */
-               fprintf(stderr, "Buffer overflow constructing show command!\n");
-               return NOTOK;
-       }
-
-       /* use charset string to modify display method */
-       if (ct->c_termproc) {
-               char term[BUFSIZ];
-
-               strncpy (term, buffer, sizeof(term));
-               snprintf (buffer, sizeof(buffer), ct->c_termproc, term);
-       }
-
-       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);
 }
 
 
 /*
- * show content of type "message/rfc822"
- */
+** show content of type "message/rfc822"
+*/
 
 static int
-show_message_rfc822 (CT ct, int serial, int alternate)
+show_message_rfc822(CT ct, int alternate)
 {
        char *cp, buffer[BUFSIZ];
        CI ci = &ct->c_ctinfo;
 
        /* Check for mhshow-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);
+       snprintf(buffer, sizeof(buffer), "mhshow-show-%s/%s",
+                               ci->ci_type, ci->ci_subtype);
+       if ((cp = context_find(buffer)) && *cp != '\0')
+               return show_content_aux(ct, alternate, cp, NULL);
 
        /* Check for mhshow-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);
+       snprintf(buffer, sizeof(buffer), "mhshow-show-%s", ci->ci_type);
+       if ((cp = context_find(buffer)) && *cp != '\0')
+               return show_content_aux(ct, alternate, cp, NULL);
 
        if ((cp = ct->c_showproc))
-               return show_content_aux (ct, serial, alternate, cp, NULL);
+               return show_content_aux(ct, alternate, cp, NULL);
 
        /* default method for message/rfc822 */
        if (ct->c_subtype == MESSAGE_RFC822) {
-               cp = (ct->c_showproc = add ("%pshow -file '%F'", NULL));
-               return show_content_aux (ct, serial, alternate, cp, NULL);
+               cp = (ct->c_showproc = mh_xstrdup("%lshow -file %F"));
+               return show_content_aux(ct, alternate, cp, NULL);
        }
 
        /* complain if we are not a part of a multipart/alternative */
        if (!alternate)
-               content_error (NULL, ct, "don't know how to display content");
+               return show_content_aux(ct, alternate, "%l", NULL);
 
        return NOTOK;
 }
 
 
 /*
- * Show content of type "message/partial".
- */
+** Show content of type "message/partial".
+*/
 
 static int
-show_partial (CT ct, int serial, int alternate)
+show_partial(CT ct, int alternate)
 {
-       content_error (NULL, ct,
-               "in order to display this message, you must reassemble it");
+       show_content_aux(ct, alternate, "%l", NULL);
+       puts("in order to display this message, you must reassemble it");
        return NOTOK;
 }
 
 
 /*
- * Show content of type "message/external".
- *
- * THE ERROR CHECKING IN THIS ONE IS NOT DONE YET.
- */
-
+** Show how to retrieve content of type "message/external".
+*/
 static int
-show_external (CT ct, int serial, int alternate)
+show_external(CT ct, int alternate)
 {
-       struct exbody *e = (struct exbody *) ct->c_ctparams;
-       CT p = e->eb_content;
-
-       if (!type_ok (p, 0))
-               return OK;
-
-       return show_switch (p, serial, alternate);
-
-#if 0
-       content_error (NULL, p, "don't know how to display content");
-       return NOTOK;
-#endif
-}
-
-
-static RETSIGTYPE
-intrser (int i)
-{
-#ifndef RELIABLE_SIGNALS
-       SIGNAL (SIGINT, intrser);
-#endif
-
-       putchar ('\n');
-       siglongjmp (intrenv, DONE);
+       char **ap, **ep;
+       char *msg;
+       FILE *fp;
+       char buf[BUFSIZ];
+
+       msg = add("You need to fetch the contents yourself:\n", NULL);
+       ap = ct->c_ctinfo.ci_attrs;
+       ep = ct->c_ctinfo.ci_values;
+       for (; *ap; ap++, ep++) {
+               msg = add(concat("\t", *ap, ": ", *ep, NULL), msg);
+       }
+       if (!(fp = fopen(ct->c_file, "r"))) {
+               adios(EX_IOERR, ct->c_file, "unable to open");
+       }
+       fseek(fp, ct->c_begin, SEEK_SET);
+       while (!feof(fp) && ftell(fp) < ct->c_end) {
+               if (!fgets(buf, sizeof buf, fp)) {
+                       adios(EX_IOERR, ct->c_file, "unable to read");
+               }
+               *strchr(buf, '\n') = '\0';
+               if (!*buf) {
+                       continue;  /* skip empty lines */
+               }
+               msg = add(concat("\t", buf, "\n", NULL), msg);
+       }
+       fclose(fp);
+       show_content_aux(ct, alternate, "%l", NULL);
+       fputs(msg, stdout);
+       return OK;
 }