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 }