evolution-3.6.4/e-util/e-charset.c

No issues found

  1 /*
  2  * This program is free software; you can redistribute it and/or
  3  * modify it under the terms of the GNU Lesser General Public
  4  * License as published by the Free Software Foundation; either
  5  * version 2 of the License, or (at your option) version 3.
  6  *
  7  * This program is distributed in the hope that it will be useful,
  8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 10  * Lesser General Public License for more details.
 11  *
 12  * You should have received a copy of the GNU Lesser General Public
 13  * License along with the program; if not, see <http://www.gnu.org/licenses/>
 14  *
 15  *
 16  * Authors:
 17  *
 18  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 19  *
 20  */
 21 
 22 #ifdef HAVE_CONFIG_H
 23 #include <config.h>
 24 #endif
 25 
 26 #include "e-charset.h"
 27 
 28 #include <string.h>
 29 #include <iconv.h>
 30 
 31 #include <glib/gi18n-lib.h>
 32 
 33 typedef enum {
 34 	E_CHARSET_UNKNOWN,
 35 	E_CHARSET_ARABIC,
 36 	E_CHARSET_BALTIC,
 37 	E_CHARSET_CENTRAL_EUROPEAN,
 38 	E_CHARSET_CHINESE,
 39 	E_CHARSET_CYRILLIC,
 40 	E_CHARSET_GREEK,
 41 	E_CHARSET_HEBREW,
 42 	E_CHARSET_JAPANESE,
 43 	E_CHARSET_KOREAN,
 44 	E_CHARSET_THAI,
 45 	E_CHARSET_TURKISH,
 46 	E_CHARSET_UNICODE,
 47 	E_CHARSET_WESTERN_EUROPEAN,
 48 	E_CHARSET_WESTERN_EUROPEAN_NEW
 49 } ECharsetClass;
 50 
 51 static const gchar *classnames[] = {
 52 	N_("Unknown"),
 53 	N_("Arabic"),
 54 	N_("Baltic"),
 55 	N_("Central European"),
 56 	N_("Chinese"),
 57 	N_("Cyrillic"),
 58 	N_("Greek"),
 59 	N_("Hebrew"),
 60 	N_("Japanese"),
 61 	N_("Korean"),
 62 	N_("Thai"),
 63 	N_("Turkish"),
 64 	N_("Unicode"),
 65 	N_("Western European"),
 66 	N_("Western European, New"),
 67 };
 68 
 69 typedef struct {
 70 	const gchar *name;
 71 	ECharsetClass class;
 72 	const gchar *subclass;
 73 } ECharset;
 74 
 75 /* This list is based on what other mailers/browsers support. There's
 76  * not a lot of point in using, say, ISO-8859-3, if anything that can
 77  * read that can read UTF8 too.
 78  */
 79 static ECharset charsets[] = {
 80 	{ "ISO-8859-6", E_CHARSET_ARABIC, NULL },
 81 	{ "ISO-8859-13", E_CHARSET_BALTIC, NULL },
 82 	{ "ISO-8859-4", E_CHARSET_BALTIC, NULL },
 83 	{ "ISO-8859-2", E_CHARSET_CENTRAL_EUROPEAN, NULL },
 84 	/* Translators: Character set "Chinese, Traditional" */
 85 	{ "Big5", E_CHARSET_CHINESE, N_("Traditional") },
 86 	/* Translators: Character set "Chinese, Traditional" */
 87 	{ "BIG5HKSCS", E_CHARSET_CHINESE, N_("Traditional") },
 88 	/* Translators: Character set "Chinese, Traditional" */
 89 	{ "EUC-TW", E_CHARSET_CHINESE, N_("Traditional") },
 90 	/* Translators: Character set "Chinese, Simplified" */
 91 	{ "GB18030", E_CHARSET_CHINESE, N_("Simplified") },
 92 	/* Translators: Character set "Chinese, Simplified" */
 93 	{ "GB2312", E_CHARSET_CHINESE, N_("Simplified") },
 94 	/* Translators: Character set "Chinese, Simplified" */
 95 	{ "HZ", E_CHARSET_CHINESE, N_("Simplified") },
 96 	/* Translators: Character set "Chinese, Simplified" */
 97 	{ "ISO-2022-CN", E_CHARSET_CHINESE, N_("Simplified") },
 98 	{ "KOI8-R", E_CHARSET_CYRILLIC, NULL },
 99 	{ "Windows-1251", E_CHARSET_CYRILLIC, NULL },
100 	/* Translators: Character set "Cyrillic, Ukrainian" */
101 	{ "KOI8-U", E_CHARSET_CYRILLIC, N_("Ukrainian") },
102 	{ "ISO-8859-5", E_CHARSET_CYRILLIC, NULL },
103 	{ "ISO-8859-7", E_CHARSET_GREEK, NULL },
104 	/* Translators: Character set "Hebrew, Visual" */
105 	{ "ISO-8859-8", E_CHARSET_HEBREW, N_("Visual") },
106 	{ "ISO-2022-JP", E_CHARSET_JAPANESE, NULL },
107 	{ "EUC-JP", E_CHARSET_JAPANESE, NULL },
108 	{ "Shift_JIS", E_CHARSET_JAPANESE, NULL },
109 	{ "EUC-KR", E_CHARSET_KOREAN, NULL },
110 	{ "TIS-620", E_CHARSET_THAI, NULL },
111 	{ "ISO-8859-9", E_CHARSET_TURKISH, NULL },
112 	{ "UTF-8", E_CHARSET_UNICODE, NULL },
113 	{ "UTF-7", E_CHARSET_UNICODE, NULL },
114 	{ "ISO-8859-1", E_CHARSET_WESTERN_EUROPEAN, NULL },
115 	{ "ISO-8859-15", E_CHARSET_WESTERN_EUROPEAN_NEW, NULL },
116 };
117 
118 /**
119  * e_charset_add_radio_actions:
120  * @action_group: a #GtkActionGroup
121  * @action_prefix: a prefix for action names, or %NULL
122  * @default_charset: the default character set, or %NULL to use the
123  *                   locale character set
124  * @callback: a callback function for actions in the group, or %NULL
125  * @user_data: user data to be passed to @callback, or %NULL
126  *
127  * Adds a set of #GtkRadioActions for available character sets to
128  * @action_group.  The @default_charset (or locale character set if
129  * @default_charset is %NULL) will be added first, and selected by
130  * default (except that ISO-8859-1 will always be used instead of
131  * US-ASCII).  Any other character sets of the same language class as
132  * the default will be added next, followed by the remaining character
133  * sets.
134  *
135  * Returns: the radio action group
136  **/
137 GSList *
138 e_charset_add_radio_actions (GtkActionGroup *action_group,
139                              const gchar *action_prefix,
140                              const gchar *default_charset,
141                              GCallback callback,
142                              gpointer user_data)
143 {
144 	GtkRadioAction *action = NULL;
145 	GSList *group = NULL;
146 	const gchar *locale_charset;
147 	gint def, ii;
148 
149 	g_return_val_if_fail (GTK_IS_ACTION_GROUP (action_group), NULL);
150 
151 	if (action_prefix == NULL)
152 		action_prefix = "";
153 
154 	g_get_charset (&locale_charset);
155 	if (!g_ascii_strcasecmp (locale_charset, "US-ASCII"))
156 		locale_charset = "ISO-8859-1";
157 
158 	if (default_charset == NULL)
159 		default_charset = locale_charset;
160 	for (def = 0; def < G_N_ELEMENTS (charsets); def++)
161 		if (!g_ascii_strcasecmp (charsets[def].name, default_charset))
162 			break;
163 
164 	for (ii = 0; ii < G_N_ELEMENTS (charsets); ii++) {
165 		const gchar *charset_name;
166 		gchar *action_name;
167 		gchar *escaped_name;
168 		gchar *charset_label;
169 		gchar **str_array;
170 
171 		charset_name = charsets[ii].name;
172 		action_name = g_strconcat (action_prefix, charset_name, NULL);
173 
174 		/* Escape underlines in the character set name so
175 		 * they're not treated as GtkLabel mnemonics. */
176 		str_array = g_strsplit (charset_name, "_", -1);
177 		escaped_name = g_strjoinv ("__", str_array);
178 		g_strfreev (str_array);
179 
180 		if (charsets[ii].subclass != NULL)
181 			charset_label = g_strdup_printf (
182 				"%s, %s (%s)",
183 				gettext (classnames[charsets[ii].class]),
184 				gettext (charsets[ii].subclass),
185 				escaped_name);
186 		else if (charsets[ii].class != E_CHARSET_UNKNOWN)
187 			charset_label = g_strdup_printf (
188 				"%s (%s)",
189 				gettext (classnames[charsets[ii].class]),
190 				escaped_name);
191 		else
192 			charset_label = g_strdup (escaped_name);
193 
194 		/* XXX Add a tooltip! */
195 		action = gtk_radio_action_new (
196 			action_name, charset_label, NULL, NULL, ii);
197 
198 		/* Character set name is static so no need to free it. */
199 		g_object_set_data (
200 			G_OBJECT (action), "charset",
201 			(gpointer) charset_name);
202 
203 		gtk_radio_action_set_group (action, group);
204 		group = gtk_radio_action_get_group (action);
205 
206 		if (callback != NULL)
207 			g_signal_connect (
208 				action, "changed", callback, user_data);
209 
210 		gtk_action_group_add_action (
211 			action_group, GTK_ACTION (action));
212 
213 		g_object_unref (action);
214 
215 		g_free (action_name);
216 		g_free (escaped_name);
217 		g_free (charset_label);
218 	}
219 
220 	if (def == G_N_ELEMENTS (charsets)) {
221 		const gchar *charset_name;
222 		gchar *action_name;
223 		gchar *charset_label;
224 		gchar **str_array;
225 
226 		charset_name = default_charset;
227 		action_name = g_strconcat (action_prefix, charset_name, NULL);
228 
229 		/* Escape underlines in the character set name so
230 		 * they're not treated as GtkLabel mnemonics. */
231 		str_array = g_strsplit (charset_name, "_", -1);
232 		charset_label = g_strjoinv ("__", str_array);
233 		g_strfreev (str_array);
234 
235 		/* XXX Add a tooltip! */
236 		action = gtk_radio_action_new (
237 			action_name, charset_label, NULL, NULL, def);
238 
239 		/* Character set name may NOT be static,
240 		 * so we do need to duplicate the string. */
241 		g_object_set_data_full (
242 			G_OBJECT (action), "charset",
243 			g_strdup (charset_name),
244 			(GDestroyNotify) g_free);
245 
246 		gtk_radio_action_set_group (action, group);
247 		group = gtk_radio_action_get_group (action);
248 
249 		if (callback != NULL)
250 			g_signal_connect (
251 				action, "changed", callback, user_data);
252 
253 		gtk_action_group_add_action (
254 			action_group, GTK_ACTION (action));
255 
256 		g_object_unref (action);
257 
258 		g_free (action_name);
259 		g_free (charset_label);
260 	}
261 
262 	/* Any of the actions in the action group will do. */
263 	if (action != NULL)
264 		gtk_radio_action_set_current_value (action, def);
265 
266 	return group;
267 }