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) ...@@ -31,6 +31,8 @@ _parse_lc_all (const char *arg, struct mu_lc_all *str, int flags)
31 char *s; 31 char *s;
32 size_t n; 32 size_t n;
33 33
34 str->flags = 0;
35
34 n = strcspn (arg, "_.@"); 36 n = strcspn (arg, "_.@");
35 if (flags & MU_LC_LANG) 37 if (flags & MU_LC_LANG)
36 { 38 {
...@@ -103,17 +105,22 @@ _parse_lc_all (const char *arg, struct mu_lc_all *str, int flags) ...@@ -103,17 +105,22 @@ _parse_lc_all (const char *arg, struct mu_lc_all *str, int flags)
103 void 105 void
104 mu_lc_all_free (struct mu_lc_all *str) 106 mu_lc_all_free (struct mu_lc_all *str)
105 { 107 {
106 free (str->language); 108 if (str->flags & MU_LC_LANG)
107 free (str->territory); 109 free (str->language);
108 free (str->charset); 110 if (str->flags & MU_LC_TERR)
109 free (str->modifier); 111 free (str->territory);
112 if (str->flags & MU_LC_CSET)
113 free (str->charset);
114 if (str->flags & MU_LC_MOD)
115 free (str->modifier);
116 str->flags = 0;
110 } 117 }
111 118
112 int 119 int
113 mu_parse_lc_all (const char *arg, struct mu_lc_all *str, int flags) 120 mu_parse_lc_all (const char *arg, struct mu_lc_all *str, int flags)
114 { 121 {
115 int rc; 122 int rc;
116 123
117 memset (str, 0, sizeof (str[0])); 124 memset (str, 0, sizeof (str[0]));
118 if (!arg) 125 if (!arg)
119 { 126 {
...@@ -125,18 +132,60 @@ mu_parse_lc_all (const char *arg, struct mu_lc_all *str, int flags) ...@@ -125,18 +132,60 @@ mu_parse_lc_all (const char *arg, struct mu_lc_all *str, int flags)
125 } 132 }
126 return 0; 133 return 0;
127 } 134 }
128 135
129 rc = _parse_lc_all (arg, str, flags); 136 /* If charset is requested (MU_LC_CSET), request also language and
130 if (rc == 0 && !str->charset) 137 territory. These will be used if ARG doesn't provide the charset
138 information. In any case, the surplus data will be discarded before
139 returning. */
140 rc = _parse_lc_all (arg, str,
141 (flags & MU_LC_CSET)
142 ? (flags | MU_LC_LANG | MU_LC_TERR)
143 : flags);
144 if (rc == 0 && (flags & MU_LC_CSET))
131 { 145 {
132 const char *charset = mu_charset_lookup (str->language, str->territory); 146 if (!str->charset)
133 if (charset) 147 {
148 /* The caller requested charset, but we're unable to satisfy
149 the request based on the ARG only. Try the charset table
150 lookup. */
151 const char *charset =
152 mu_charset_lookup (str->language, str->territory);
153 if (charset)
154 {
155 /* Found it. Fill in the charset field. */
156 str->charset = strdup (charset);
157 if (!str->charset)
158 {
159 rc = ENOMEM;
160 goto err;
161 }
162 str->flags |= MU_LC_CSET;
163 }
164 }
165
166 /* The STR struct most probably contains data not requested by
167 the caller. First, see what these are. The following leaves
168 in FLAGS only those bits that weren't requested, but were filled
169 in just in case: */
170 flags = ~flags & str->flags;
171
172 /* Free the surplus data and clear the corresponding flag bits. */
173 if (flags & MU_LC_LANG)
134 { 174 {
135 str->charset = strdup (charset); 175 free (str->language);
136 if (!str->charset) 176 str->language = NULL;
137 rc = ENOMEM; 177 str->flags &= ~MU_LC_LANG;
178 }
179
180 if (flags & MU_LC_TERR)
181 {
182 free (str->territory);
183 str->territory = NULL;
184 str->flags &= ~MU_LC_TERR;
138 } 185 }
139 } 186 }
187
188 err:
140 if (rc) 189 if (rc)
141 mu_lc_all_free (str); 190 mu_lc_all_free (str);
142 return rc; 191 return rc;
......
...@@ -235,7 +235,7 @@ mu_charset_lookup (char *lang, char *terr) ...@@ -235,7 +235,7 @@ mu_charset_lookup (char *lang, char *terr)
235 if (mu_c_strcasecmp (p->lang, lang) == 0 235 if (mu_c_strcasecmp (p->lang, lang) == 0
236 && (terr == NULL 236 && (terr == NULL
237 || p->terr == NULL 237 || p->terr == NULL
238 || !mu_c_strcasecmp (p->terr, terr) == 0)) 238 || mu_c_strcasecmp (p->terr, terr) == 0))
239 return p->charset; 239 return p->charset;
240 return NULL; 240 return NULL;
241 } 241 }
......
...@@ -1051,31 +1051,19 @@ util_rfc2047_decode (char **value) ...@@ -1051,31 +1051,19 @@ util_rfc2047_decode (char **value)
1051 char *charset = NULL; 1051 char *charset = NULL;
1052 char *tmp; 1052 char *tmp;
1053 int rc; 1053 int rc;
1054 struct mu_lc_all lc_all = { .flags = 0 };
1054 1055
1055 if (!*value || mailvar_get (&charset, "charset", mailvar_type_string, 0)) 1056 if (!*value || mailvar_get (&charset, "charset", mailvar_type_string, 0))
1056 return; 1057 return;
1057 1058
1058 if (mu_c_strcasecmp (charset, "auto") == 0) 1059 if (mu_c_strcasecmp (charset, "auto") == 0)
1059 { 1060 {
1060 static char *saved_charset; 1061 tmp = getenv ("LC_ALL");
1062 if (!tmp)
1063 tmp = getenv ("LANG");
1061 1064
1062 if (!saved_charset) 1065 if (tmp && mu_parse_lc_all (tmp, &lc_all, MU_LC_CSET) == 0)
1063 { 1066 charset = lc_all.charset;
1064 /* Try to deduce the charset from LC_ALL or LANG variables */
1065
1066 tmp = getenv ("LC_ALL");
1067 if (!tmp)
1068 tmp = getenv ("LANG");
1069
1070 if (tmp)
1071 {
1072 struct mu_lc_all lc_all;
1073
1074 if (mu_parse_lc_all (tmp, &lc_all, MU_LC_CSET) == 0)
1075 saved_charset = lc_all.charset;
1076 }
1077 }
1078 charset = saved_charset; /* NOTE: a minor memory leak */
1079 } 1067 }
1080 1068
1081 if (!charset) 1069 if (!charset)
...@@ -1092,6 +1080,8 @@ util_rfc2047_decode (char **value) ...@@ -1092,6 +1080,8 @@ util_rfc2047_decode (char **value)
1092 free (*value); 1080 free (*value);
1093 *value = tmp; 1081 *value = tmp;
1094 } 1082 }
1083 if (lc_all.flags)
1084 mu_lc_all_free (&lc_all);
1095 } 1085 }
1096 1086
1097 const char * 1087 const char *
......