From: David Levine Date: Sun, 16 Feb 2014 19:12:39 +0000 (-0600) Subject: Added support for %{charset} display string escape to mhshow(1). X-Git-Url: https://diplodocus.org/git/nmh/commitdiff_plain/bcf252dfcdd7db22634ee483b457167eebf81951?ds=inline Added support for %{charset} display string escape to mhshow(1). --- diff --git a/docs/pending-release-notes b/docs/pending-release-notes index 419569bc..7187a491 100644 --- a/docs/pending-release-notes +++ b/docs/pending-release-notes @@ -77,6 +77,7 @@ NEW FEATURES - If nmh was configured with iconv(3) support, mhshow will convert, if necessary, the charset of text/plain content to match the user's locale setting. +- Added support for %{charset} display string escape to mhshow(1). ----------------- OBSOLETE FEATURES diff --git a/man/mhshow.man b/man/mhshow.man index 7cb76cf1..2237bdd2 100644 --- a/man/mhshow.man +++ b/man/mhshow.man @@ -1,4 +1,4 @@ -.TH MHSHOW %manext1% "February 9, 2014" "%nmhversion%" +.TH MHSHOW %manext1% "February 16, 2014" "%nmhversion%" .\" .\" %nmhwarning% .\" @@ -224,16 +224,17 @@ The display string may contain the following escapes: .PP .RS 5 .nf -.ta \w'%F 'u -%a Insert parameters from Content-Type field -%e exclusive execution -%f Insert filename containing content -%F %e, %f, and stdin is terminal not content -%l display listing prior to displaying content -%p %l, and ask for confirmation -%s Insert content subtype -%d Insert content description -%% Insert the character % +.ta \w'%F 'u +%a Insert parameters from Content-Type field +%{charset} Insert the charset value from the Content-Type field +%e exclusive execution +%f Insert filename containing content +%F %e, %f, and stdin is terminal not content +%l display listing prior to displaying content +%p %l, and ask for confirmation +%s Insert content subtype +%d Insert content description +%% Insert the character % .fi .RE .PP diff --git a/test/mhshow/test-textcharset b/test/mhshow/test-textcharset index c55f95b9..4768808a 100755 --- a/test/mhshow/test-textcharset +++ b/test/mhshow/test-textcharset @@ -25,6 +25,7 @@ LC_ALL=en_US.UTF-8; export LC_ALL expected="$MH_TEST_DIR"/$$.expected actual="$MH_TEST_DIR"/$$.actual +# check charset conversion msgfile=`mhpath new` cat >"$msgfile" <"$actual" 2>&1 check "$expected" "$actual" +cat >>"$MH" <<'EOF' +mhshow-show-text/plain: echo %{charset} +EOF + +# check expansion of %{charset} by itself +msgfile=`mhpath new` +cat >"$msgfile" <"$expected" <"$actual" 2>&1 +check "$expected" "$actual" + +# check expansion of empty %{charset} by itself +msgfile=`mhpath new` +cat >"$msgfile" <"$expected" <"$actual" 2>&1 +check "$expected" "$actual" + +grep -v 'mhshow-show-text/plain:' "$MH" >"$MH.new" +mv -f "$MH.new" "$MH" +cat >>"$MH" <<'EOF' +mhshow-show-text/plain: echo `ap -format '%(void(lit %{charset}))%<(nonnull)-I %(putstr)%>' 0` +EOF + +# check expansion of embedded %{charset} with no text following +cat >"$expected" <"$actual" 2>&1 +check "$expected" "$actual" + +# check expansion of empty embedded %{charset} with no text following +cat >"$expected" <"$actual" 2>&1 +check "$expected" "$actual" + +sed -e 's%\(mhshow-show-text/plain:.*\)%\1 file%' "$MH" >"$MH.new" +mv -f "$MH.new" "$MH" + +# check expansion of embedded %{charset} with text following +cat >"$expected" <"$actual" 2>&1 +check "$expected" "$actual" + +# check expansion of empty embedded %{charset} with text following +cat >"$expected" <"$actual" 2>&1 +check "$expected" "$actual" + +sed -e 's/%{charset}/%{unknown}/' "$MH" >"$MH.new" +mv -f "$MH.new" "$MH" + +# check expansion of unknown parameter +msgfile=`mhpath new` +cat >"$msgfile" <"$expected" <"$actual" 2>&1 +check "$expected" "$actual" + + exit $failed diff --git a/uip/mhshowsbr.c b/uip/mhshowsbr.c index 0a970179..13090561 100644 --- a/uip/mhshowsbr.c +++ b/uip/mhshowsbr.c @@ -73,6 +73,7 @@ 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); @@ -833,40 +834,40 @@ 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 = " "; + } + /* 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; case 'p': /* %l, and pause prior to displaying content */ @@ -887,6 +888,52 @@ parse_display_string (CT ct, char *cp, int *xstdin, int *xlist, int *xpause, /* insert character % */ 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; + + if (*cp == '\0') { + break; + } 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; + } + } + } else { + /* cp points to an unrecognized parameter. Output + it as-is, starting here with the "%{". */ + *bp++ = '%'; + *bp++ = '{'; + *bp = '\0'; + buflen -= 2; + break; + } + + /* No parameter was found, so fall thru to default to + output the rest of the text as-is. */ + } + default: *bp++ = *--cp; *bp = '\0'; @@ -1132,6 +1179,37 @@ convert_content_charset (CT ct, char **file) { } +/* + * 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) {