Commit 463bbba9 463bbba90fad80906a347fcd0a13e84d3142f994 by Sergey Poznyakoff

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.
1 parent 602902e1
......@@ -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;
......
......@@ -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;
}
......
......@@ -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 *
......