]> diplodocus.org Git - nmh/blobdiff - uip/mhshowsbr.c
lkopen_dot() would block forever if another process held a lock
[nmh] / uip / mhshowsbr.c
index bd44c85975d5e247a6774cff22a95a18645f655e..c53f22f362b554a072869851bb4ef969672f1085 100644 (file)
@@ -23,8 +23,6 @@
 
 extern int debugsw;
 
-int pausesw  = 1;
-int serialsw = 0;
 int nolist   = 0;
 
 char *progsw = NULL;
@@ -33,10 +31,6 @@ char *progsw = NULL;
 int nomore   = 0;
 char *formsw = NULL;
 
-pid_t xpid = 0;
-
-static sigjmp_buf intrenv;
-
 
 /* mhmisc.c */
 int part_ok (CT, int);
@@ -44,37 +38,31 @@ 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);
-
 /*
  * prototypes
  */
 void show_all_messages (CT *);
-int show_content_aux (CT, int, int, char *, char *);
+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 int parse_display_string (CT, char *, int *, int *, int *, int *, char *,
-                                 char *, size_t, int multipart);
+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);
+static int parse_display_string (CT, char *, int *, int *, char *, char *,
+                                size_t, int multipart);
 static int convert_content_charset (CT, char **);
-static int parameter_value (CI, const char *, const char *, const char **);
-static void intrser (int);
+static int pidcheck(int);
 
 
 /*
@@ -130,11 +118,9 @@ show_single_message (CT ct, char *form)
      */
     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);
@@ -159,7 +145,6 @@ show_single_message (CT ct, char *form)
     /* reset the signal mask */
     sigprocmask (SIG_SETMASK, &oset, &set);
 
-    xpid = 0;
     flush_errors ();
 }
 
@@ -212,7 +197,7 @@ DisplayMsgHeader (CT ct, char *form)
        /* NOTREACHED */
 
     default:
-       xpid = -child_id;
+       pidcheck(pidwait(child_id, NOTOK));
        break;
     }
 
@@ -226,33 +211,33 @@ DisplayMsgHeader (CT ct, char *form)
  */
 
 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);
+           return show_multi (ct, alternate);
 
        case CT_MESSAGE:
            switch (ct->c_subtype) {
                case MESSAGE_PARTIAL:
-                   return show_partial (ct, serial, alternate);
+                   return show_partial (ct, alternate);
 
                case MESSAGE_EXTERNAL:
-                   return show_external (ct, serial, alternate);
+                   return show_external (ct, alternate);
 
                case MESSAGE_RFC822:
                default:
-                   return show_message_rfc822 (ct, serial, alternate);
+                   return show_message_rfc822 (ct, alternate);
            }
 
        case CT_TEXT:
-           return show_text (ct, serial, alternate);
+           return show_text (ct, alternate);
 
        case CT_AUDIO:
        case CT_IMAGE:
        case CT_VIDEO:
        case CT_APPLICATION:
-           return show_content (ct, serial, alternate);
+           return show_content (ct, alternate);
 
        default:
            adios (NULL, "unknown content type %d", ct->c_type);
@@ -267,7 +252,7 @@ show_switch (CT ct, int serial, int alternate)
  */
 
 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;
@@ -276,15 +261,15 @@ show_content (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')
-       return show_content_aux (ct, serial, alternate, cp, NULL);
+       return show_content_aux (ct, alternate, cp, NULL);
 
     /* 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);
 
     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)
@@ -299,10 +284,10 @@ show_content (CT ct, int serial, int alternate)
  */
 
 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;
-    int xstdin = 0, xlist = 0, xpause = 0, xtty = 0;
+    int xstdin = 0, xlist = 0;
     char *file, buffer[BUFSIZ];
 
     if (!ct->c_ceopenfnx) {
@@ -337,15 +322,15 @@ show_content_aux (CT ct, int serial, int alternate, char *cp, char *cracked)
        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:
-    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);
 }
 
 
@@ -354,8 +339,8 @@ got_command:
  */
 
 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, vecp;
@@ -374,41 +359,11 @@ show_content_aux2 (CT ct, int serial, int alternate, char *cracked, char *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) {
-       char prompt[BUFSIZ];
-
        if (ct->c_type == CT_MULTIPART)
-           list_content (ct, -1, 1, 0, 0);
+           list_content (ct, -1, 1, 0, 0, 0);
        else
-           list_switch (ct, -1, 1, 0, 0);
-
-       if (xpause && isatty (fileno (stdout))) {
-           int intr;
-           SIGNAL_HANDLER istat;
-
-           if (SOprintf ("Press <return> to show content..."))
-               printf ("Press <return> to show content...");
-
-           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, 1, 0, 0, 0);
     }
 
     vec = argsplit(buffer, &file, &vecp);
@@ -439,13 +394,7 @@ show_content_aux2 (CT ct, int serial, int alternate, char *cracked, char *buffer
        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);
@@ -459,7 +408,7 @@ show_content_aux2 (CT ct, int serial, int alternate, char *cracked, char *buffer
  */
 
 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;
@@ -468,22 +417,22 @@ 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')
-       return show_content_aux (ct, serial, alternate, cp, NULL);
+       return show_content_aux (ct, alternate, cp, NULL);
 
     /* 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);
 
     /*
      * 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 :
+       snprintf (buffer, sizeof(buffer), "%%l%s %%F", progsw ? progsw :
                moreproc && *moreproc ? moreproc : DEFAULT_PAGER);
        cp = (ct->c_showproc = add (buffer, NULL));
-       return show_content_aux (ct, serial, alternate, cp, NULL);
+       return show_content_aux (ct, alternate, cp, NULL);
     }
 
     return NOTOK;
@@ -495,7 +444,7 @@ show_text (CT ct, int serial, int alternate)
  */
 
 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;
@@ -504,22 +453,22 @@ 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')
-       return show_multi_aux (ct, serial, alternate, cp);
+       return show_multi_aux (ct, alternate, cp);
 
     /* 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);
 
     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.  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);
 }
 
 
@@ -529,40 +478,19 @@ show_multi (CT ct, int serial, int alternate)
  */
 
 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);
     }
 
 /*
@@ -578,7 +506,7 @@ show_multi_internal (CT ct, int serial, int alternate)
        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) {
@@ -611,46 +539,7 @@ show_multi_internal (CT ct, int serial, int alternate)
        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:
-    if (!nowserial) {
-       /* reset the signal mask */
-       sigprocmask (SIG_SETMASK, &oset, &set);
-    }
-
     return result;
 }
 
@@ -661,11 +550,11 @@ out:
  */
 
 static int
-show_multi_aux (CT ct, int serial, int alternate, char *cp)
+show_multi_aux (CT ct, int alternate, char *cp)
 {
     /* 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;
@@ -685,7 +574,6 @@ show_multi_aux (CT ct, int serial, int alternate, char *cp)
            if ((*p->c_ceopenfnx) (p, &file) == NOTOK)
                return NOTOK;
 
-           /* I'm not sure if this is necessary? */
            p->c_storage = add (file, NULL);
 
            if (p->c_showproc && !strcmp (p->c_showproc, "true"))
@@ -694,14 +582,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;
     }
 
-    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);
 }
 
 
@@ -710,7 +597,7 @@ show_multi_aux (CT ct, int serial, int alternate, char *cp)
  */
 
 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;
@@ -719,20 +606,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')
-       return show_content_aux (ct, serial, alternate, cp, NULL);
+       return show_content_aux (ct, alternate, cp, NULL);
 
     /* 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);
 
     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 = add ("%pecho -file %F", NULL));
+       return show_content_aux (ct, alternate, cp, NULL);
     }
 
     /* complain if we are not a part of a multipart/alternative */
@@ -748,9 +635,8 @@ show_message_rfc822 (CT ct, int serial, int alternate)
  */
 
 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,
@@ -766,7 +652,7 @@ show_partial (CT ct, int serial, int alternate)
  */
 
 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;
@@ -774,13 +660,13 @@ show_external (CT ct, int serial, int alternate)
     if (!type_ok (p, 0))
        return OK;
 
-    return show_switch (p, serial, alternate);
+    return show_switch (p, alternate);
 }
 
 
 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;
@@ -796,11 +682,12 @@ parse_display_string (CT ct, char *cp, int *xstdin, int *xlist, int *xpause,
            case 'a':
                /* insert parameters from Content-Type field */
            {
-               char **ap, **ep;
+               PM pm;
                char *s = "";
 
-               for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++) {
-                   snprintf (bp, buflen, "%s%s=\"%s\"", s, *ap, *ep);
+               for (pm = ci->ci_first_pm; pm; pm = pm->pm_next) {
+                   snprintf (bp, buflen, "%s%s=\"%s\"", s, pm->pm_name,
+                             get_param_value(pm, '?'));
                    len = strlen (bp);
                    bp += len;
                    buflen -= len;
@@ -821,14 +708,12 @@ parse_display_string (CT ct, char *cp, int *xstdin, int *xlist, int *xpause,
                break;
 
            case 'e':
-               /* exclusive execution */
-               *xtty = 1;
+               /* no longer implemented */
                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':
@@ -842,25 +727,7 @@ parse_display_string (CT ct, char *cp, int *xstdin, int *xlist, int *xpause,
                    for (part = m->mp_parts; part; part = part->mp_next) {
                        p = part->mp_part;
 
-                       /* Don't quote filename if it's already quoted. */
-                       if (p->c_storage  &&  *(p->c_storage-1) == '\'') {
-                           /* If there isn't a matching close quote, bail
-                              out. */
-                           if (*(cp+1) != '\'') {
-                               adios(NULL, "%%f/%%F not properly escaped: "
-                                     "%s%s\n",
-                                     buffer, cp);
-                           }
-                           snprintf (bp, buflen, "%s%s", s, p->c_storage);
-                       } else {
-                           if (*(cp+1) != '\0'  &&  *(cp+1) == '\'') {
-                               adios(NULL, "%%f/%%F not properly escaped: "
-                                     "%s%s\n",
-                                     buffer, cp);
-                           }
-                           snprintf (bp, buflen, "%s'%s'", s, p->c_storage);
-                       }
-
+                       snprintf (bp, buflen, "%s%s", s, p->c_storage);
                        len = strlen (bp);
                        bp += len;
                        buflen -= len;
@@ -868,23 +735,12 @@ parse_display_string (CT ct, char *cp, int *xstdin, int *xlist, int *xpause,
                    }
                } else {
                    /* insert filename containing content */
-                   if (bp > buffer  &&  *(bp-1) == '\'') {
-                       /* Don't quote filename if it's already quoted. */
-                       /* If there isn't a matching close quote, bail
-                          out. */
-                       if (*(cp+1) != '\'') {
-                           adios(NULL, "%%f/%%F not properly escaped: %s%s\n",
-                                 buffer, cp);
-                       }
-                       snprintf (bp, buflen, "%s", file);
-                   } else {
-                       if (*(cp+1) != '\0'  &&  *(cp+1) == '\'') {
-                           adios(NULL, "%%f/%%F not properly escaped: %s%s\n",
-                                 buffer, cp);
-                       }
-                       snprintf (bp, buflen, "'%s'", file);
-                   }
+                   snprintf (bp, buflen, "%s", file);
 
+                   /*
+                    * Old comments below are left here for posterity.
+                    * This was/is tricky.
+                    */
                    /* 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
@@ -902,26 +758,16 @@ parse_display_string (CT ct, char *cp, int *xstdin, int *xlist, int *xpause,
                     * code below.
                     * The fix was to always quote the filename.  But
                     * that broke '%F' because it expanded to ''filename''.
-                    * That's why I added the condition above to not
-                    * quote if the escape was wrapped with single
-                    * quotes.  It would be (much) better to rely on
-                    * the quoting code below, but until I understand
-                    * what is wrong with it, I won't do that.
                     */
-                   len = strlen(bp);
-                   bp += len;
-                   buflen -= len;
+                   /*
+                    * Old comments above are left here for posterity.
+                    * The quoting below should work properly now.
+                    */
                }
-
-               /* 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;
+               /* No longer supported */
                /* and fall... */
 
            case 'l':
@@ -939,60 +785,39 @@ parse_display_string (CT ct, char *cp, int *xstdin, int *xlist, int *xpause,
                goto raw;
 
            case '{' : {
-               static const char param[] = "charset";
-               const char *value;
-               const int found = parameter_value (ci, param, cp, &value);
-
-               if (found == OK) {
-                   /* Because it'll get incremented in the next iteration,
-                      just increment by 1 for the '{'. */
-                   cp += strlen(param) + 1;
+               const char *closing_brace = strchr(cp, '}');
 
-                   /* cp pointed to the param and it's set in the
-                      Content-Type header. */
-                   strncpy (bp, value, buflen);
+               if (closing_brace) {
+                   const size_t param_len = closing_brace - cp - 1;
+                   char *param = mh_xmalloc(param_len + 1);
+                   char *value;
 
-                   /* 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);
-                   bp += len;
-                   buflen -= len;
-                   pp = bp;
+                   (void) strncpy(param, cp + 1, param_len);
+                   param[param_len] = '\0';
+                   value = get_param(ci->ci_first_pm, param, '?', 0);
+                   free(param);
 
-                   break;
-               } else if (found == 1) {
-                   /* cp points to the param and it's not set in the
-                      Content-Type header, so skip it. */
-                   cp += strlen(param) + 1;
+                   cp += param_len + 1; /* Skip both braces, too. */
 
-                   if (*cp == '\0') {
-                       break;
+                   if (value) {
+                       /* %{param} is set in the Content-Type header.
+                          After the break below, quote it if necessary. */
+                       (void) strncpy(bp, value, buflen);
+                       free(value);
                    } else {
-                       if (*(cp + 1) == '\0') {
-                           break;
-                       } else {
-                           ++cp;
-                           /* Increment cp again so that the last
-                              character of the %{} token isn't output
-                              after falling thru below. */
-                           ++cp;
-                       }
+                       /* %{param} not found, so skip it completely.  cp
+                          was advanced above. */
+                       continue;
                    }
                } else {
-                   /* cp points to an unrecognized parameter.  Output
-                      it as-is, starting here with the "%{". */
-                   *bp++ = '%';
-                   *bp++ = '{';
-                   *bp = '\0';
-                   buflen -= 2;
-                   continue;
+                   /* This will get confused if there are multiple %{}'s,
+                      but its real purpose is to avoid doing bad things
+                      above if a closing brace wasn't found. */
+                   admonish(NULL,
+                            "no closing brace for display string escape %s",
+                            cp);
                }
-
-               /* No parameter was found, so fall thru to default to
-                  output the rest of the text as-is. */
+               break;
            }
 
            default:
@@ -1004,45 +829,85 @@ parse_display_string (CT ct, char *cp, int *xstdin, int *xlist, int *xpause,
            len = strlen (bp);
            bp += len;
            buflen -= len;
+           *bp = '\0';
 
            /* Did we actually insert something? */
            if (bp != pp) {
                /* Insert single quote if not inside quotes already */
                if (!quoted && buflen) {
                    len = strlen (pp);
-                   memmove (pp + 1, pp, len);
+                   memmove (pp + 1, pp, len+1);
                    *pp++ = '\'';
                    buflen--;
                    bp++;
+                   quoted = 1;
                }
                /* Escape existing quotes */
                while ((pp = strchr (pp, '\'')) && buflen > 3) {
                    len = strlen (pp++);
-                   memmove (pp + 3, pp, len);
-                   *pp++ = '\\';
-                   *pp++ = '\'';
-                   *pp++ = '\'';
-                   buflen -= 3;
-                   bp += 3;
+                   if (quoted) {
+                       /* Quoted.  Let this quote close that quoting.
+                          Insert an escaped quote to replace it and
+                          another quote to reopen quoting, which will be
+                          closed below. */
+                       memmove (pp + 2, pp, len);
+                       *pp++ = '\\';
+                       *pp++ = '\'';
+                       buflen -= 2;
+                       bp += 2;
+                       quoted = 0;
+                   } else {
+                       /* Not quoted.  This should not be reached with
+                          the current code, but handle the condition
+                          in case the code changes.  Just escape the
+                          quote. */
+                       memmove (pp, pp-1, len+1);
+                       *(pp++-1) = '\\';
+                       buflen -= 1;
+                       bp += 1;
+                   }
                }
                /* If pp is still set, that means we ran out of space. */
                if (pp)
                    buflen = 0;
-               if (!quoted && buflen) {
-                   *bp++ = '\'';
-                   *bp = '\0';
-                   buflen--;
+               /* Close quoting. */
+               if (quoted && buflen) {
+                   /* See if we need to close the quote by looking
+                      for an odd number of unescaped close quotes in
+                      the remainder of the display string. */
+                   int found_quote = 0, escaped = 0;
+                   char *c;
+
+                   for (c = cp+1; *c; ++c) {
+                       if (*c == '\\') {
+                           escaped = ! escaped;
+                       } else {
+                           if (escaped) {
+                               escaped = 0;
+                           } else {
+                               if (*c == '\'') {
+                                   found_quote = ! found_quote;
+                               }
+                           }
+                       }
+                   }
+                   if (! found_quote) {
+                       *bp++ = '\'';
+                       buflen--;
+                       quoted = 0;
+                   }
                }
            }
        } else {
 raw:
            *bp++ = *cp;
-           *bp = '\0';
            buflen--;
 
            if (*cp == '\'')
                quoted = !quoted;
        }
+
+       *bp = '\0';
     }
 
     if (buflen <= 0 ||
@@ -1176,13 +1041,21 @@ convert_charset (CT ct, char *dest_charset, int *message_mods) {
 
             ++*message_mods;
 
-            /* Update ci_attrs. */
-            src_charset = dest_charset;
-
             /* Update ct->c_ctline. */
             if (ct->c_ctline) {
-                char *ctline =
-                    update_attr (ct->c_ctline, "charset=", dest_charset);
+                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);
+               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);
+               }
 
                 free (ct->c_ctline);
                 ct->c_ctline = ctline;
@@ -1191,10 +1064,7 @@ convert_charset (CT ct, char *dest_charset, int *message_mods) {
             /* Update Content-Type header field. */
             for (hf = ct->c_first_hf; hf; hf = hf->next) {
                 if (! strcasecmp (TYPE_FIELD, hf->name)) {
-                    char *ctline_less_newline =
-                        update_attr (hf->value, "charset=", dest_charset);
-                    char *ctline = concat (ctline_less_newline, "\n", NULL);
-                    free (ctline_less_newline);
+                    char *ctline = concat (ct->c_ctline, "\n", NULL);
 
                     free (hf->value);
                     hf->value = ctline;
@@ -1242,43 +1112,19 @@ convert_content_charset (CT ct, char **file) {
     return OK;
 }
 
-
 /*
- * Return values:
- *   NOTOK if cp doesn't point to {param}
- *   OK    if cp points to {param} and that attribute exists, and returns
- *         its value
- *   1     if cp points to {param} and that attribute doesn't exist
+ * Exit if the display process returned with a nonzero exit code, or terminated
+ * with a SIGQUIT signal.
  */
-int
-parameter_value (CI ci, const char *param, const char *cp, const char **value) {
-    int found = NOTOK;
-    char *braced_param = concat ("{", param, "}", NULL);
-
-    if (! strncasecmp(cp, braced_param, strlen (braced_param))) {
-        char **ap, **ep;
 
-        found = 1;
-
-        for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ++ap, ++ep) {
-            if (!strcasecmp (*ap, param)) {
-                found = OK;
-                *value = *ep;
-                break;
-            }
-        }
-    }
-
-    free (braced_param);
-    return found;
-}
-
-
-static void
-intrser (int i)
+static int
+pidcheck (int status)
 {
-    NMH_UNUSED (i);
+    if ((status & 0xff00) == 0xff00 || (status & 0x007f) != SIGQUIT)
+       return status;
 
-    putchar ('\n');
-    siglongjmp (intrenv, DONE);
+    fflush (stdout);
+    fflush (stderr);
+    done (1);
+    return 1;
 }