X-Git-Url: https://diplodocus.org/git/nmh/blobdiff_plain/f2e710b193928f3e70f48580276498a2debe809b..2d688dc85e80ff9c832d9ea252ed393f0b5105e2:/uip/mhshowsbr.c diff --git a/uip/mhshowsbr.c b/uip/mhshowsbr.c index 6f7f1ee6..13c449b3 100644 --- a/uip/mhshowsbr.c +++ b/uip/mhshowsbr.c @@ -19,7 +19,7 @@ #include #ifdef HAVE_ICONV # include -#endif +#endif /* ! HAVE_ICONV */ extern int debugsw; @@ -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 */ @@ -61,7 +57,8 @@ 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_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); @@ -69,6 +66,9 @@ 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 convert_content_charset (CT, char **); static void intrser (int); @@ -267,13 +267,13 @@ show_content (CT ct, int serial, int alternate) char *cp, buffer[BUFSIZ]; CI ci = &ct->c_ctinfo; - /* Check for mhn-show-type/subtype */ + /* Check for invo_name-show-type/subtype */ snprintf (buffer, sizeof(buffer), "%s-show-%s/%s", invo_name, ci->ci_type, ci->ci_subtype); if ((cp = context_find (buffer)) && *cp != '\0') return show_content_aux (ct, serial, alternate, cp, NULL); - /* Check for mhn-show-type */ + /* 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); @@ -296,10 +296,9 @@ show_content (CT ct, int serial, int alternate) int show_content_aux (CT ct, int serial, int alternate, char *cp, char *cracked) { - int fd, len, buflen, quoted; - int xstdin, xlist, xpause, xtty; - char *bp, *pp, *file, buffer[BUFSIZ]; - CI ci = &ct->c_ctinfo; + int fd; + int xstdin = 0, xlist = 0, xpause = 0, xtty = 0; + char *file, buffer[BUFSIZ]; if (!ct->c_ceopenfnx) { if (!alternate) @@ -313,168 +312,32 @@ show_content_aux (CT ct, int serial, int alternate, char *cp, char *cracked) return NOTOK; if (ct->c_showproc && !strcmp (ct->c_showproc, "true")) return (alternate ? DONE : OK); - - xlist = 0; - xpause = 0; - xstdin = 0; - xtty = 0; + + if (! strcmp(invo_name, "mhshow") && + ct->c_type == CT_TEXT && ct->c_subtype == TEXT_PLAIN) { + /* This has to be done after calling c_ceopenfnx, so + unfortunately the type checks are necessary without + some code rearrangement. And to make this really ugly, + only do it in mhshow, not mhfixmsg, mhn, or mhstore. */ + if (convert_content_charset (ct, &file) != OK) { + admonish (NULL, "unable to convert character set%s to %s", + ct->c_partno ? "of part " : "", + ct->c_partno ? ct->c_partno : "", + content_charset (ct)); + } + } if (cracked) { strncpy (buffer, cp, sizeof(buffer)); goto got_command; } - /* get buffer ready to go */ - bp = buffer; - buflen = sizeof(buffer) - 1; - bp[0] = bp[buflen] = '\0'; - quoted = 0; - - /* Now parse display string */ - for ( ; *cp && buflen > 0; cp++) { - if (*cp == '%') { - pp = bp; - - 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); - bp += len; - buflen -= len; - s = " "; - } - } - break; - - case 'd': - /* insert content description */ - if (ct->c_descr) { - char *s; - - s = trimcpy (ct->c_descr); - strncpy (bp, s, buflen); - free (s); - } - break; - - case 'e': - /* exclusive execution */ - xtty = 1; - break; - - case 'F': - /* %e, %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..) - */ - 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 */ - xlist = !nolist; - break; - - case 's': - /* insert subtype of content */ - strncpy (bp, ci->ci_subtype, buflen); - break; - - case '%': - /* insert character % */ - goto raw; - - default: - *bp++ = *--cp; - *bp = '\0'; - buflen--; - continue; - } - len = strlen (bp); - bp += len; - buflen -= len; - - /* 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); - *pp++ = '\''; - buflen--; - bp++; - } - /* 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 pp is still set, that means we ran out of space. */ - if (pp) - buflen = 0; - if (!quoted && buflen) { - *bp++ = '\''; - *bp = '\0'; - buflen--; - } - } - } else { -raw: - *bp++ = *cp; - *bp = '\0'; - buflen--; - - if (*cp == '\'') - quoted = !quoted; - } - } - - if (buflen <= 0 || - (ct->c_termproc && (size_t) 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"); + if (parse_display_string (ct, cp, &xstdin, &xlist, &xpause, &xtty, file, + buffer, sizeof(buffer) - 1, 0)) { + admonish (NULL, "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); @@ -490,9 +353,9 @@ 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); @@ -517,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; @@ -543,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); @@ -566,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) @@ -598,13 +459,13 @@ show_text (CT ct, int serial, int alternate) char *cp, buffer[BUFSIZ]; CI ci = &ct->c_ctinfo; - /* Check for mhn-show-type/subtype */ + /* Check for invo_name-show-type/subtype */ snprintf (buffer, sizeof(buffer), "%s-show-%s/%s", invo_name, ci->ci_type, ci->ci_subtype); if ((cp = context_find (buffer)) && *cp != '\0') return show_content_aux (ct, serial, alternate, cp, NULL); - /* Check for mhn-show-type */ + /* 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); @@ -614,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); @@ -634,13 +495,13 @@ show_multi (CT ct, int serial, int alternate) char *cp, buffer[BUFSIZ]; CI ci = &ct->c_ctinfo; - /* Check for mhn-show-type/subtype */ + /* Check for invo_name-show-type/subtype */ snprintf (buffer, sizeof(buffer), "%s-show-%s/%s", invo_name, ci->ci_type, ci->ci_subtype); if ((cp = context_find (buffer)) && *cp != '\0') return show_multi_aux (ct, serial, alternate, cp); - /* Check for mhn-show-type */ + /* 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); @@ -701,7 +562,7 @@ show_multi_internal (CT ct, int serial, int alternate) /* * alternate -> we are a part inside an multipart/alternative - * alternating -> we are a multipart/alternative + * alternating -> we are a multipart/alternative */ result = alternate ? NOTOK : OK; @@ -797,12 +658,12 @@ out: static int show_multi_aux (CT ct, int serial, int alternate, char *cp) { - int len, buflen, quoted; - int xlist, xpause, xtty; - char *bp, *pp, *file, buffer[BUFSIZ]; + /* 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; + char *file, buffer[BUFSIZ]; struct multipart *m = (struct multipart *) ct->c_ctparams; struct part *part; - CI ci = &ct->c_ctinfo; CT p; for (part = m->mp_parts; part; part = part->mp_next) { @@ -819,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")) @@ -828,29 +688,114 @@ show_multi_aux (CT ct, int serial, int alternate, char *cp) } } - xlist = 0; - xpause = 0; - xtty = 0; + if (parse_display_string (ct, cp, &xstdin, &xlist, &xpause, &xtty, 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); +} + + +/* + * show content of type "message/rfc822" + */ + +static int +show_message_rfc822 (CT ct, int serial, int alternate) +{ + char *cp, buffer[BUFSIZ]; + CI ci = &ct->c_ctinfo; + + /* Check for invo_name-show-type/subtype */ + snprintf (buffer, sizeof(buffer), "%s-show-%s/%s", + invo_name, ci->ci_type, ci->ci_subtype); + if ((cp = context_find (buffer)) && *cp != '\0') + return show_content_aux (ct, serial, alternate, cp, NULL); + + /* 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); + + if ((cp = ct->c_showproc)) + return show_content_aux (ct, serial, alternate, cp, NULL); + + /* default method for message/rfc822 */ + if (ct->c_subtype == MESSAGE_RFC822) { + cp = (ct->c_showproc = add ("%pecho -file %F", NULL)); + return show_content_aux (ct, serial, alternate, cp, NULL); + } + + /* 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 NOTOK; +} + + +/* + * Show content of type "message/partial". + */ + +static int +show_partial (CT ct, int serial, int alternate) +{ + NMH_UNUSED (serial); + NMH_UNUSED (alternate); + + content_error (NULL, ct, + "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. + */ + +static int +show_external (CT ct, int serial, 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); +} + + +static int +parse_display_string (CT ct, char *cp, int *xstdin, int *xlist, int *xpause, + int *xtty, char *file, char *buffer, size_t buflen, + int multipart) { + int len, quoted = 0; + char *bp = buffer, *pp; + CI ci = &ct->c_ctinfo; - /* get buffer ready to go */ - bp = buffer; - buflen = sizeof(buffer) - 1; bp[0] = bp[buflen] = '\0'; - quoted = 0; - /* Now parse display string */ for ( ; *cp && buflen > 0; cp++) { if (*cp == '%') { pp = bp; + switch (*++cp) { 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; @@ -872,43 +817,73 @@ show_multi_aux (CT ct, int serial, int alternate, char *cp) case 'e': /* exclusive execution */ - xtty = 1; + *xtty = 1; break; case 'F': - /* %e and %f */ - xtty = 1; + /* %e, %f, and stdin is terminal not content */ + *xstdin = 1; + *xtty = 1; /* and fall... */ case 'f': - /* insert filename(s) containing content */ - { - char *s = ""; - - 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 = " "; + 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. + */ } - /* set our starting pointer back to bp, to avoid - * requoting the filenames we just added - */ - pp = bp; - } - break; + break; case 'p': /* %l, and pause prior to displaying content */ - xpause = pausesw; + *xpause = pausesw; /* and fall... */ case 'l': /* display listing prior to displaying content */ - xlist = !nolist; + *xlist = !nolist; break; case 's': @@ -920,6 +895,42 @@ show_multi_aux (CT ct, int serial, int alternate, char *cp) /* 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'; @@ -929,54 +940,93 @@ show_multi_aux (CT ct, int serial, int alternate, char *cp) 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 || - (ct->c_termproc && buflen <= (ssize_t) strlen(ct->c_termproc))) { + (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; } @@ -985,84 +1035,10 @@ raw: char term[BUFSIZ]; strncpy (term, buffer, sizeof(term)); - snprintf (buffer, sizeof(buffer), ct->c_termproc, term); + snprintf (buffer, buflen, ct->c_termproc, term); } - return show_content_aux2 (ct, serial, alternate, NULL, buffer, - NOTOK, xlist, xpause, 0, xtty); -} - - -/* - * show content of type "message/rfc822" - */ - -static int -show_message_rfc822 (CT ct, int serial, int alternate) -{ - char *cp, buffer[BUFSIZ]; - CI ci = &ct->c_ctinfo; - - /* Check for mhn-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); - - /* Check for mhn-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); - - if ((cp = ct->c_showproc)) - return show_content_aux (ct, serial, 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); - } - - /* 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 NOTOK; -} - - -/* - * Show content of type "message/partial". - */ - -static int -show_partial (CT ct, int serial, int alternate) -{ - NMH_UNUSED (serial); - NMH_UNUSED (alternate); - - content_error (NULL, ct, - "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. - */ - -static int -show_external (CT ct, int serial, 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); + return OK; } @@ -1176,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; @@ -1191,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; @@ -1217,6 +1198,32 @@ convert_charset (CT ct, char *dest_charset, int *message_mods) { } +static int +convert_content_charset (CT ct, char **file) { +#ifdef HAVE_ICONV + /* Using current locale, see if the content needs to be converted. */ + + /* content_charset() cannot return NULL. */ + char *charset = content_charset (ct); + + if (! check_charset (charset, strlen (charset))) { + int unused = 0; + + if (convert_charset (ct, get_charset (), &unused) == 0) { + *file = ct->c_cefile.ce_file; + } else { + return NOTOK; + } + } +#else /* ! HAVE_ICONV */ + NMH_UNUSED (ct); + NMH_UNUSED (file); +#endif /* ! HAVE_ICONV */ + + return OK; +} + + static void intrser (int i) {