From: Ken Hornstein Date: Sun, 2 Mar 2014 04:24:47 +0000 (-0500) Subject: Add a new get_param_value(); redo iconv() parameter conversion code. X-Git-Url: https://diplodocus.org/git/nmh/commitdiff_plain/8a7e08bb681a99e07d38f667389769c02d3a2464?ds=inline Add a new get_param_value(); redo iconv() parameter conversion code. Start having code use get_param() and get_param_value() rather than walking the whole parameter linked list. --- diff --git a/h/mhparse.h b/h/mhparse.h index d6afe095..16083816 100644 --- a/h/mhparse.h +++ b/h/mhparse.h @@ -418,4 +418,21 @@ PM add_param(PM *first, PM *last, const char *name, const char *value); char *get_param(PM first, const char *name, char replace, int fetchonly); +/* + * Fetch a parameter value from a parameter structure, converting it to + * the local character set. + * + * Arguments are: + * + * pm - Pointer to parameter structure + * replace - If characters in the parameter list cannot be converted to + * the local character set, replace with this character. + * + * Returns a pointer to the parameter value. Memory is stored in an + * internal buffer, so the returned value is only valid until the next + * call to get_param_value() or get_param() (get_param() uses get_param_value() + * internally). + */ +char *get_param_value(PM pm, char replace); + extern int checksw; /* Add Content-MD5 field */ diff --git a/uip/mhlistsbr.c b/uip/mhlistsbr.c index a3ac0c24..5105a6a9 100644 --- a/uip/mhlistsbr.c +++ b/uip/mhlistsbr.c @@ -202,8 +202,10 @@ list_content (CT ct, int toplevel, int realsize, int verbose, int debug) CI ci = &ct->c_ctinfo; PM pm; - for (pm = ci->ci_first_pm; pm; pm = pm->pm_next) - printf ("\t %s=\"%s\"\n", pm->pm_name, pm->pm_value); + for (pm = ci->ci_first_pm; pm; pm = pm->pm_next) { + printf ("\t %s=\"%s\"\n", pm->pm_name, + get_param_value(pm, '?')); + } /* * If verbose, print any RFC-822 comments in the diff --git a/uip/mhparse.c b/uip/mhparse.c index 1781ee6b..b659ce8d 100644 --- a/uip/mhparse.c +++ b/uip/mhparse.c @@ -3868,95 +3868,121 @@ get_param(PM first, const char *name, char replace, int fetchonly) if (strcasecmp(name, first->pm_name) == 0) { if (fetchonly) return first->pm_value; - else { - char convbuf[BUFSIZ]; - size_t inbytes, outbytes = sizeof(convbuf); + else + return getcpy(get_param_value(first, replace)); + } + first = first->pm_next; + } + + return NULL; +} + +/* + * Return a parameter value, converting to the local character set if + * necessary + */ + +char *get_param_value(PM pm, char replace) +{ + static char buffer[4096]; /* I hope no parameters are larger */ + size_t bufsize = sizeof(buffer); #ifdef HAVE_ICONV - int utf8; - iconv_t cd; - ICONV_CONST char *p; - char *q; + size_t inbytes; + int utf8; + iconv_t cd; + ICONV_CONST char *p; #endif /* HAVE_ICONV */ - if (!first->pm_charset || - check_charset(first->pm_charset, - strlen(first->pm_charset))) { - /* - * No conversion necessary - */ - return getcpy(first->pm_value); - } -#ifdef HAVE_ICONV - utf8 = strcasecmp(first->pm_charset, "UTF-8") == 0; + char *q; - cd = iconv_open(get_charset(), first->pm_charset); - if (cd == (iconv_t) -1) { - goto noconvert; - } + /* + * If we don't have a character set indicated, it's assumed to be + * US-ASCII. If it matches our character set, we don't need to convert + * anything. + */ - inbytes = strlen(first->pm_value); - outbytes = sizeof(convbuf); - p = first->pm_value; - q = convbuf; + if (!pm->pm_charset || check_charset(pm->pm_charset, + strlen(pm->pm_charset))) { + return pm->pm_value; + } - while (inbytes) { - if (iconv(cd, &p, &inbytes, &q, &outbytes) == (size_t)-1) { - if (errno != EILSEQ) { - iconv_close(cd); - goto noconvert; - } - /* - * Reset shift state, substitute our character, - * try to restart conversion. - */ - iconv(cd, NULL, NULL, &q, &outbytes); - if (outbytes == 0) { - iconv_close(cd); - goto noconvert; - } - *q++ = replace; - outbytes--; - if (outbytes == 0) { - iconv_close(cd); - goto noconvert; - } - if (utf8) { - for (++p, --inbytes; inbytes > 0 && - (((unsigned char) *q) & 0xc0) == 0x80; - ++p, --inbytes) - continue; - } else { - p++; - inbytes--; - } - } - } + /* + * In this case, we need to convert. If we have iconv support, use + * that. Otherwise, go through and simply replace every non-ASCII + * character with the substitution character. + */ - iconv_close(cd); +#ifdef HAVE_ICONV + q = buffer; + bufsize = sizeof(buffer); + utf8 = strcasecmp(pm->pm_charset, "UTF-8") == 0; - if (outbytes == 0) - q--; - *q = '\0'; + cd = iconv_open(get_charset(), pm->pm_charset); + if (cd == (iconv_t) -1) { + goto noiconv; + } - return getcpy(convbuf); -#endif /* HAVE_ICONV */ -noconvert: - for (p = first->pm_value, q = convbuf; *p && outbytes > 1; - p++, q++, outbytes--) { - if (isascii((unsigned char) p) && - isprint((unsigned char) p)) - *q = *p; - else - *q = replace; - } + inbytes = strlen(pm->pm_value); + p = pm->pm_value; + + while (inbytes) { + if (iconv(cd, &p, &inbytes, &q, &bufsize) == (size_t)-1) { + if (errno != EILSEQ) { + iconv_close(cd); + goto noiconv; + } + /* + * Reset shift state, substitute our character, + * try to restart conversion. + */ - *q = '\0'; + iconv(cd, NULL, NULL, &q, &bufsize); - return getcpy(convbuf); + if (bufsize == 0) { + iconv_close(cd); + goto noiconv; + } + *q++ = replace; + bufsize--; + if (bufsize == 0) { + iconv_close(cd); + goto noiconv; + } + if (utf8) { + for (++p, --inbytes; + inbytes > 0 && (((unsigned char) *q) & 0xc0) == 0x80; + ++p, --inbytes) + continue; + } else { + p++; + inbytes--; } } + } - first = first->pm_next; + iconv_close(cd); + + if (bufsize == 0) + q--; + *q = '\0'; + + return buffer; +#endif /* HAVE_ICONV */ + +noiconv: + /* + * Take everything non-ASCII and substituite the replacement character + */ + + q = buffer; + bufsize = sizeof(buffer); + for (p = pm->pm_value; *p != '\0' && bufsize > 1; p++, q++, bufsize--) { + if (isascii((unsigned char) *p) && !iscntrl((unsigned char) *p)) + *q = *p; + else + *q = replace; } - return NULL; + *q = '\0'; + + return buffer; } diff --git a/uip/mhstoresbr.c b/uip/mhstoresbr.c index 799bdb42..156411b7 100644 --- a/uip/mhstoresbr.c +++ b/uip/mhstoresbr.c @@ -194,7 +194,6 @@ static int store_application (CT ct) { CI ci = &ct->c_ctinfo; - PM pm; /* Check if the content specifies a filename */ if (autosw) @@ -207,32 +206,23 @@ store_application (CT ct) */ if (!ct->c_storeproc && ct->c_subtype == APPLICATION_OCTETS) { int tarP = 0, zP = 0, gzP = 0; + char *cp; - for (pm = ci->ci_first_pm; pm; pm = pm->pm_next) { - /* check for "type=tar" attribute */ - if (!strcasecmp (pm->pm_name, "type")) { - if (strcasecmp (pm->pm_value, "tar")) - break; - + if ((cp = get_param(ci->ci_first_pm, "type", ' ', 1))) { + if (strcasecmp (cp, "tar") == 0) tarP = 1; - continue; - } + } - /* check for "conversions=compress" attribute */ - if ((!strcasecmp (pm->pm_name, "conversions") || - !strcasecmp (pm->pm_name, "x-conversions")) - && (!strcasecmp (pm->pm_value, "compress") || - !strcasecmp (pm->pm_value, "x-compress"))) { + /* check for "conversions=compress" attribute */ + if ((cp = get_param(ci->ci_first_pm, "conversions", ' ', 1)) || + (cp = get_param(ci->ci_first_pm, "x-conversions", ' ', 1))) { + if (strcasecmp (cp, "compress") == 0 || + strcasecmp (cp, "x-compress") == 0) { zP = 1; - continue; } - /* check for "conversions=gzip" attribute */ - if ((!strcasecmp (pm->pm_name, "conversions") || - !strcasecmp (pm->pm_name, "x-conversions")) - && (!strcasecmp (pm->pm_value, "gzip") || - !strcasecmp (pm->pm_value, "x-gzip"))) { + if (strcasecmp (cp, "gzip") == 0 || + strcasecmp (cp, "x-gzip") == 0) { gzP = 1; - continue; } } @@ -970,7 +960,7 @@ parse_format_string (CT ct, char *cp, char *buffer, int buflen, char *dir) for (pm = ci->ci_first_pm; pm; pm = pm->pm_next) { snprintf (bp, buflen, "%s%s=\"%s\"", s, - pm->pm_name, pm->pm_value); + pm->pm_name, get_param_value(pm, '?')); len = strlen (bp); bp += len; buflen -= len; @@ -1044,7 +1034,6 @@ get_storeproc (CT ct) { char *cp; CI ci; - PM pm; /* * If the storeproc has already been defined, @@ -1059,21 +1048,18 @@ get_storeproc (CT ct) * use that (RFC-2183). */ if (ct->c_dispo) { - int found_filename = 0; - - for (pm = ct->c_dispo_first; pm; pm = pm->pm_next) { - if (! strcasecmp (pm->pm_name, "filename") - && *(cp = pm->pm_value) != '/' - && *cp != '.' - && *cp != '|' - && *cp != '!' - && !strchr (cp, '%')) { + if ((cp = get_param(ct->c_dispo_first, "filename", '_', 0)) + && *cp != '/' + && *cp != '.' + && *cp != '|' + && *cp != '!' + && !strchr (cp, '%')) { ct->c_storeproc = add (cp, NULL); - found_filename = 1; - } + free(cp); + return; } - - if (found_filename) return; + if (cp) + free(cp); } /* @@ -1082,17 +1068,17 @@ get_storeproc (CT ct) * the storeproc. */ ci = &ct->c_ctinfo; - for (pm = ci->ci_first_pm; pm; pm = pm->pm_next) { - if (! strcasecmp (pm->pm_name, "name") - && *(cp = pm->pm_value) != '/' - && *cp != '.' - && *cp != '|' - && *cp != '!' - && !strchr (cp, '%')) { + if ((cp = get_param(ci->ci_first_pm, "name", '_', 0)) + && *cp != '/' + && *cp != '.' + && *cp != '|' + && *cp != '!' + && !strchr (cp, '%')) { ct->c_storeproc = add (cp, NULL); - return; - } + } + if (cp) + free(cp); }