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.
Showing
3 changed files
with
71 additions
and
32 deletions
... | @@ -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 * | ... | ... |
-
Please register or sign in to post a comment