X-Git-Url: https://diplodocus.org/git/nmh/blobdiff_plain/bcf252dfcdd7db22634ee483b457167eebf81951..2d688dc85e80ff9c832d9ea252ed393f0b5105e2:/uip/mhshowsbr.c diff --git a/uip/mhshowsbr.c b/uip/mhshowsbr.c index 13090561..13c449b3 100644 --- a/uip/mhshowsbr.c +++ b/uip/mhshowsbr.c @@ -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 */ @@ -73,7 +69,6 @@ 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 convert_content_charset (CT, char **); -static int parameter_value (CI, const char *, const char *, const char **); static void intrser (int); @@ -358,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); @@ -385,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; @@ -411,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); @@ -434,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) @@ -482,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); @@ -687,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")) @@ -733,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); } @@ -798,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; @@ -844,28 +837,42 @@ 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; - 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; 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); + 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..) */ - len = strlen(bp); - buflen -= len; - bp += len; - pp = bp; + /* + * 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; @@ -889,49 +896,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; - - /* cp points to the param and it's set in the - Content-Type header. */ - strncpy (bp, value, buflen); - 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; + const char *closing_brace = strchr(cp, '}'); - if (*cp == '\0') { - break; + 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 { - 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; - break; + /* 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: @@ -943,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 || @@ -1115,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; @@ -1130,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; @@ -1173,43 +1215,15 @@ convert_content_charset (CT ct, char **file) { return NOTOK; } } +#else /* ! HAVE_ICONV */ + NMH_UNUSED (ct); + NMH_UNUSED (file); #endif /* ! HAVE_ICONV */ 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 - */ -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) {