diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2017-03-21 21:58:10 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2017-03-21 21:58:10 +0200 |
commit | 463bbba90fad80906a347fcd0a13e84d3142f994 (patch) | |
tree | ddfe70996308d1e4e87bd2b5df3eca4806b6ce18 | |
parent | 602902e1c3495bc0b689905ab4c19f9ecde9f801 (diff) | |
download | mailutils-463bbba90fad80906a347fcd0a13e84d3142f994.tar.gz mailutils-463bbba90fad80906a347fcd0a13e84d3142f994.tar.bz2 |
Bugfixes in NLS code.
* libmailutils/base/lcall.c (mu_lc_all_free): Use str->flags to
determine what fields need to be freed.
(mu_parse_lc_all): Force retrieving language and territory if charset
is requested. Use this to provide a default value, in case charset cannot
be determined. Deallocate the surplus data afterwards.
* libmailutils/base/locale.c (mu_charset_lookup): Bugfix.
* mail/util.c (util_rfc2047_decode): Avoid memory leak.
-rw-r--r-- | libmailutils/base/lcall.c | 75 | ||||
-rw-r--r-- | libmailutils/base/locale.c | 2 | ||||
-rw-r--r-- | mail/util.c | 26 |
3 files changed, 71 insertions, 32 deletions
diff --git a/libmailutils/base/lcall.c b/libmailutils/base/lcall.c index 109cc520f..71c7a9cda 100644 --- a/libmailutils/base/lcall.c +++ b/libmailutils/base/lcall.c @@ -31,6 +31,8 @@ _parse_lc_all (const char *arg, struct mu_lc_all *str, int flags) char *s; size_t n; + str->flags = 0; + n = strcspn (arg, "_.@"); if (flags & MU_LC_LANG) { @@ -103,17 +105,22 @@ _parse_lc_all (const char *arg, struct mu_lc_all *str, int flags) void mu_lc_all_free (struct mu_lc_all *str) { - free (str->language); - free (str->territory); - free (str->charset); - free (str->modifier); + if (str->flags & MU_LC_LANG) + free (str->language); + if (str->flags & MU_LC_TERR) + free (str->territory); + if (str->flags & MU_LC_CSET) + free (str->charset); + if (str->flags & MU_LC_MOD) + free (str->modifier); + str->flags = 0; } int mu_parse_lc_all (const char *arg, struct mu_lc_all *str, int flags) { int rc; - + memset (str, 0, sizeof (str[0])); if (!arg) { @@ -125,18 +132,60 @@ mu_parse_lc_all (const char *arg, struct mu_lc_all *str, int flags) } return 0; } - - rc = _parse_lc_all (arg, str, flags); - if (rc == 0 && !str->charset) + + /* If charset is requested (MU_LC_CSET), request also language and + territory. These will be used if ARG doesn't provide the charset + information. In any case, the surplus data will be discarded before + returning. */ + rc = _parse_lc_all (arg, str, + (flags & MU_LC_CSET) + ? (flags | MU_LC_LANG | MU_LC_TERR) + : flags); + if (rc == 0 && (flags & MU_LC_CSET)) { - const char *charset = mu_charset_lookup (str->language, str->territory); - if (charset) + if (!str->charset) + { + /* The caller requested charset, but we're unable to satisfy + the request based on the ARG only. Try the charset table + lookup. */ + const char *charset = + mu_charset_lookup (str->language, str->territory); + if (charset) + { + /* Found it. Fill in the charset field. */ + str->charset = strdup (charset); + if (!str->charset) + { + rc = ENOMEM; + goto err; + } + str->flags |= MU_LC_CSET; + } + } + + /* The STR struct most probably contains data not requested by + the caller. First, see what these are. The following leaves + in FLAGS only those bits that weren't requested, but were filled + in just in case: */ + flags = ~flags & str->flags; + + /* Free the surplus data and clear the corresponding flag bits. */ + if (flags & MU_LC_LANG) { - str->charset = strdup (charset); - if (!str->charset) - rc = ENOMEM; + free (str->language); + str->language = NULL; + str->flags &= ~MU_LC_LANG; + } + + if (flags & MU_LC_TERR) + { + free (str->territory); + str->territory = NULL; + str->flags &= ~MU_LC_TERR; } } + + err: if (rc) mu_lc_all_free (str); return rc; diff --git a/libmailutils/base/locale.c b/libmailutils/base/locale.c index 664600257..3167f29fa 100644 --- a/libmailutils/base/locale.c +++ b/libmailutils/base/locale.c @@ -235,7 +235,7 @@ mu_charset_lookup (char *lang, char *terr) if (mu_c_strcasecmp (p->lang, lang) == 0 && (terr == NULL || p->terr == NULL - || !mu_c_strcasecmp (p->terr, terr) == 0)) + || mu_c_strcasecmp (p->terr, terr) == 0)) return p->charset; return NULL; } diff --git a/mail/util.c b/mail/util.c index afe345719..3344d064f 100644 --- a/mail/util.c +++ b/mail/util.c @@ -1051,31 +1051,19 @@ util_rfc2047_decode (char **value) char *charset = NULL; char *tmp; int rc; + struct mu_lc_all lc_all = { .flags = 0 }; if (!*value || mailvar_get (&charset, "charset", mailvar_type_string, 0)) return; if (mu_c_strcasecmp (charset, "auto") == 0) { - static char *saved_charset; + tmp = getenv ("LC_ALL"); + if (!tmp) + tmp = getenv ("LANG"); - if (!saved_charset) - { - /* Try to deduce the charset from LC_ALL or LANG variables */ - - tmp = getenv ("LC_ALL"); - if (!tmp) - tmp = getenv ("LANG"); - - if (tmp) - { - struct mu_lc_all lc_all; - - if (mu_parse_lc_all (tmp, &lc_all, MU_LC_CSET) == 0) - saved_charset = lc_all.charset; - } - } - charset = saved_charset; /* NOTE: a minor memory leak */ + if (tmp && mu_parse_lc_all (tmp, &lc_all, MU_LC_CSET) == 0) + charset = lc_all.charset; } if (!charset) @@ -1092,6 +1080,8 @@ util_rfc2047_decode (char **value) free (*value); *value = tmp; } + if (lc_all.flags) + mu_lc_all_free (&lc_all); } const char * |