summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2017-03-21 21:58:10 +0200
committerSergey Poznyakoff <gray@gnu.org.ua>2017-03-21 21:58:10 +0200
commit463bbba90fad80906a347fcd0a13e84d3142f994 (patch)
treeddfe70996308d1e4e87bd2b5df3eca4806b6ce18
parent602902e1c3495bc0b689905ab4c19f9ecde9f801 (diff)
downloadmailutils-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.c75
-rw-r--r--libmailutils/base/locale.c2
-rw-r--r--mail/util.c26
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 *

Return to:

Send suggestions and report system problems to the System administrator.