]> diplodocus.org Git - nmh/blobdiff - uip/mhshowsbr.c
Added probe to configure.ac to output flex version (for fed18arm7 build).
[nmh] / uip / mhshowsbr.c
index 0a970179a25b54325c4e5f49a4f85b2963920995..13c449b36484f098460ed3660a3fb243afffad96 100644 (file)
@@ -44,10 +44,6 @@ 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
  */
@@ -357,8 +353,8 @@ show_content_aux2 (CT ct, int serial, int alternate, char *cracked, char *buffer
                    int fd, int xlist, int xpause, int xstdin, int xtty)
 {
     pid_t child_id;
-    int i;
-    char *vec[4], exec[BUFSIZ + sizeof "exec "];
+    int i, vecp;
+    char **vec, *file;
 
     if (debugsw || cracked) {
        fflush (stdout);
@@ -384,9 +380,9 @@ show_content_aux2 (CT ct, int serial, int alternate, char *cracked, char *buffer
        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);
+           list_switch (ct, -1, 1, 0, 0, 0);
 
        if (xpause && isatty (fileno (stdout))) {
            int intr;
@@ -410,12 +406,8 @@ show_content_aux2 (CT ct, int serial, int alternate, char *cracked, char *buffer
        }
     }
 
-    snprintf (exec, sizeof(exec), "exec %s", buffer);
-
-    vec[0] = "/bin/sh";
-    vec[1] = "-c";
-    vec[2] = exec;
-    vec[3] = NULL;
+    vec = argsplit(buffer, &file, &vecp);
+    vec[vecp++] = NULL;
 
     fflush (stdout);
 
@@ -433,13 +425,15 @@ show_content_aux2 (CT ct, int serial, int alternate, char *cracked, char *buffer
            if (!xstdin)
                dup2 (fd, 0);
            close (fd);
-           execvp ("/bin/sh", vec);
+           execvp (file, vec);
            fprintf (stderr, "unable to exec ");
            perror ("/bin/sh");
            _exit (-1);
            /* NOTREACHED */
 
        default:
+           arglist_free(file, vec);
+
            if (!serial) {
                ct->c_pid = child_id;
                if (xtty)
@@ -481,7 +475,7 @@ show_text (CT ct, int serial, int alternate)
      * 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), "%%p%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);
@@ -686,7 +680,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"))
@@ -732,7 +725,7 @@ show_message_rfc822 (CT ct, int serial, int alternate)
 
     /* default method for message/rfc822 */
     if (ct->c_subtype == MESSAGE_RFC822) {
-       cp = (ct->c_showproc = add ("%pshow -file '%F'", NULL));
+       cp = (ct->c_showproc = add ("%pecho -file %F", NULL));
        return show_content_aux (ct, serial, alternate, cp, NULL);
     }
 
@@ -797,11 +790,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;
@@ -833,40 +827,54 @@ parse_display_string (CT ct, char *cp, int *xstdin, int *xlist, int *xpause,
                /* and fall... */
 
            case 'f':
-                if (multipart) {
-                    /* insert filename(s) containing content */
-                    struct multipart *m = (struct multipart *) ct->c_ctparams;
-                    struct part *part;
-                    char *s = "";
-                    CT p;
-
-                    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);
-                        bp += len;
-                        buflen -= len;
-                        s = " ";
-                    }
-                    /* set our starting pointer back to bp, to avoid
-                     * requoting the filenames we just added
-                     */
-                    pp = bp;
-                } else {
-                    /* 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..)
-                     */
-                    len = strlen(bp);
-                    buflen -= len;
-                    bp += len;
-                    pp = bp;
-                }
-                break;
+               if (multipart) {
+                   /* insert filename(s) containing content */
+                   struct multipart *m = (struct multipart *) ct->c_ctparams;
+                   struct part *part;
+                   char *s = "";
+                   CT p;
+
+                   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);
+                       bp += len;
+                       buflen -= len;
+                       s = " ";
+                   }
+               } else {
+                   /* insert filename containing content */
+                   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
+                    * broken with the quoting logic, but..)
+                    */
+                   /*
+                    * Here's the email that submitted the patch with
+                    * the comment above:
+                    *   https://www.mail-archive.com/nmh-workers@mhost.com/
+                    *     msg00288.html
+                    * I can't tell from that exactly what was broken,
+                    * beyond misquoting of the filename.  The profile
+                    * had appearances of %F both with and without quotes.
+                    * The unquoted ones should have been quoted by the
+                    * code below.
+                    * The fix was to always quote the filename.  But
+                    * that broke '%F' because it expanded to ''filename''.
+                    */
+                   /*
+                    * Old comments above are left here for posterity.
+                    * The quoting below should work properly now.
+                    */
+               }
+               break;
 
            case 'p':
                /* %l, and pause prior to displaying content */
@@ -887,6 +895,42 @@ parse_display_string (CT ct, char *cp, int *xstdin, int *xlist, int *xpause,
                /* insert character % */
                goto raw;
 
+           case '{' : {
+               const char *closing_brace = strchr(cp, '}');
+
+               if (closing_brace) {
+                   const size_t param_len = closing_brace - cp - 1;
+                   char *param = mh_xmalloc(param_len + 1);
+                   char *value;
+
+                   (void) strncpy(param, cp + 1, param_len);
+                   param[param_len] = '\0';
+                   value = get_param(ci->ci_first_pm, param, '?', 0);
+                   free(param);
+
+                   cp += param_len + 1; /* Skip both braces, too. */
+
+                   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 {
+                       /* %{param} not found, so skip it completely.  cp
+                          was advanced above. */
+                       continue;
+                   }
+               } else {
+                   /* 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);
+               }
+               break;
+           }
+
            default:
                *bp++ = *--cp;
                *bp = '\0';
@@ -896,45 +940,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 ||
@@ -1068,13 +1152,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;
@@ -1083,10 +1175,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;
@@ -1126,6 +1215,9 @@ convert_content_charset (CT ct, char **file) {
             return NOTOK;
         }
     }
+#else  /* ! HAVE_ICONV */
+    NMH_UNUSED (ct);
+    NMH_UNUSED (file);
 #endif /* ! HAVE_ICONV */
 
     return OK;