2 * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 2014-2015 Ricardo Mones and the Claws Mail Team
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "claws-features.h"
25 #include <glib/gi18n.h>
27 #include "libravatar.h"
30 #include <gtk/filesel.h>
33 #include "libravatar_prefs.h"
34 #include "prefs_common.h"
35 #include "prefs_gtk.h"
37 #define PREFS_BLOCK_NAME "Libravatar"
38 #define NUM_DEF_BUTTONS 7
39 #define CUSTOM_URL_BUTTON_INDEX 6
40 /* cache interval goes from 1 hour to 30 days */
41 #define INTERVAL_MIN_H 1.0
42 #define INTERVAL_MAX_H 720.0
43 /* timeout interval goes from 0 seconds (= use general timeout value)
44 to (general timeout value - 1) seconds */
45 #define TIMEOUT_MIN_S 0.0
47 LibravatarPrefs libravatarprefs;
48 GHashTable *libravatarmisses;
50 struct LibravatarPrefsPage
54 GtkWidget *cache_interval_spin;
55 GtkWidget *cache_icons_check;
56 GtkWidget *defm_radio[NUM_DEF_BUTTONS];
57 GtkWidget *defm_url_text;
58 GtkWidget *allow_redirects_check;
59 #if (defined USE_GNUTLS && GLIB_CHECK_VERSION(2,22,0))
60 GtkWidget *allow_federated_check;
65 struct LibravatarPrefsPage libravatarprefs_page;
67 static PrefParam param[] = {
68 { "base_url", "http://cdn.libravatar.org/avatar",
69 &libravatarprefs.base_url,
70 P_STRING, NULL, NULL, NULL },
71 { "cache_interval", "24",
72 &libravatarprefs.cache_interval,
73 P_INT, NULL, NULL, NULL },
74 { "cache_icons", "TRUE",
75 &libravatarprefs.cache_icons,
76 P_BOOL, NULL, NULL, NULL },
77 { "default_mode", "0",
78 &libravatarprefs.default_mode,
79 P_INT, NULL, NULL, NULL },
80 { "default_mode_url", "",
81 &libravatarprefs.default_mode_url,
82 P_STRING, NULL, NULL, NULL },
83 { "allow_redirects", "TRUE",
84 &libravatarprefs.allow_redirects,
85 P_BOOL, NULL, NULL, NULL },
86 #if (defined USE_GNUTLS && GLIB_CHECK_VERSION(2,22,0))
87 { "allow_federated", "TRUE",
88 &libravatarprefs.allow_federated,
89 P_BOOL, NULL, NULL, NULL },
92 &libravatarprefs.timeout,
93 P_INT, NULL, NULL, NULL },
94 {NULL, NULL, NULL, P_OTHER, NULL, NULL, NULL}
97 static GtkWidget *create_checkbox(gchar *label, gchar *hint)
99 GtkWidget *cb = gtk_check_button_new_with_mnemonic(label);
100 CLAWS_SET_TIP(cb, hint);
106 static void cache_icons_check_toggled_cb(GtkToggleButton *button, gpointer data)
108 gtk_widget_set_sensitive(libravatarprefs_page.cache_interval_spin,
109 gtk_toggle_button_get_active(button));
112 static GtkWidget *labeled_spinner_box(gchar *label, GtkWidget *spinner, gchar *units, gchar *hint)
114 GtkWidget *lbl, *lbla, *hbox;
116 lbl = gtk_label_new(label);
117 gtk_widget_show(lbl);
118 lbla = gtk_label_new(units);
119 gtk_widget_show(lbla);
120 hbox = gtk_hbox_new(FALSE, 6);
122 CLAWS_SET_TIP(spinner, hint);
124 gtk_box_pack_start(GTK_BOX(hbox), lbl, FALSE, FALSE, 0);
125 gtk_box_pack_start(GTK_BOX(hbox), spinner, FALSE, FALSE, 0);
126 gtk_box_pack_start(GTK_BOX(hbox), lbla, FALSE, FALSE, 0);
131 static GtkWidget *p_create_frame_cache(struct LibravatarPrefsPage *page)
133 GtkWidget *vbox, *checkbox, *spinner, *hbox;
136 vbox = gtk_vbox_new(FALSE, 6);
138 checkbox = create_checkbox(_("_Use cached icons"),
139 _("Keep icons on disk for reusing instead "
140 "of making another network request"));
141 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbox),
142 libravatarprefs.cache_icons);
143 g_signal_connect(checkbox, "toggled",
144 G_CALLBACK(cache_icons_check_toggled_cb), NULL);
145 page->cache_icons_check = checkbox;
147 adj = (GtkAdjustment *) gtk_adjustment_new(
148 libravatarprefs.cache_interval,
149 INTERVAL_MIN_H, INTERVAL_MAX_H, 1.0,
151 spinner = gtk_spin_button_new(adj, 1.0, 0);
152 gtk_widget_show(spinner);
153 gtk_widget_set_sensitive(spinner, libravatarprefs.cache_icons);
154 hbox = labeled_spinner_box(_("Cache refresh interval"), spinner, _("hours"), NULL);
155 page->cache_interval_spin = spinner;
157 gtk_box_pack_start(GTK_BOX(vbox), checkbox, FALSE, FALSE, 0);
158 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
163 static void default_mode_radio_button_cb(GtkToggleButton *button, gpointer data)
168 if (gtk_toggle_button_get_active(button) != TRUE)
171 mode = *((guint *)data);
172 is_url = (mode == DEF_MODE_URL)? TRUE: FALSE;
174 gtk_widget_set_sensitive(libravatarprefs_page.defm_url_text, is_url);
175 if (is_url) /* custom URL requires following redirects */
176 gtk_toggle_button_set_active(
177 GTK_TOGGLE_BUTTON(libravatarprefs_page.allow_redirects_check),
180 if (mode == DEF_MODE_NONE) {
181 prefs_common_get_prefs()->enable_avatars = AVATARS_ENABLE_BOTH;
183 /* don't waste time with headers that won't be displayed */
184 prefs_common_get_prefs()->enable_avatars = AVATARS_DISABLE;
185 /* empty missing cache when switching to generated */
186 g_hash_table_remove_all(libravatarmisses);
190 static const guint radio_value[] = {
200 static GtkWidget *p_create_frame_missing(struct LibravatarPrefsPage *page)
202 GtkWidget *vbox, *radio[NUM_DEF_BUTTONS], *hbox, *entry;
203 gboolean enable = FALSE;
205 gchar *radio_label[] = {
214 gchar *radio_hint[] = {
216 _("The unobtrusive low-contrast greyish silhouette"),
217 _("A generated geometric pattern"),
218 _("A generated full-body monster"),
219 _("A generated almost unique face"),
220 _("A generated 8-bit arcade-style pixelated image"),
221 _("Redirect to a user provided URL")
224 vbox = gtk_vbox_new(FALSE, 6);
226 for (i = 0; i < NUM_DEF_BUTTONS; ++i) {
227 enable = (libravatarprefs.default_mode == radio_value[i])? TRUE: FALSE;
229 radio[i] = gtk_radio_button_new_with_label_from_widget(
230 (i > 0)? GTK_RADIO_BUTTON(radio[i - 1]): NULL, radio_label[i]);
231 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio[i]), enable);
232 if (i == CUSTOM_URL_BUTTON_INDEX) {
233 /* set related entry next to radio button */
234 entry = gtk_entry_new_with_max_length(MAX_URL_LENGTH);
235 CLAWS_SET_TIP(entry, _("Enter the URL you want to be "
236 "redirected when no user icon is available. "
237 "Leave an empty URL to use the default "
238 "libravatar orange icon."));
239 gtk_widget_show(entry);
240 gtk_entry_set_text(GTK_ENTRY(entry),
241 libravatarprefs.default_mode_url);
242 hbox = gtk_hbox_new(FALSE, 6);
243 gtk_box_pack_start(GTK_BOX(hbox), radio[i], FALSE, FALSE, 0);
244 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
245 gtk_widget_set_sensitive(entry,
246 (libravatarprefs.default_mode == DEF_MODE_URL)
248 page->defm_url_text = entry;
249 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
251 gtk_box_pack_start(GTK_BOX(vbox), radio[i], FALSE, FALSE, 0);
253 g_signal_connect(radio[i], "toggled",
254 G_CALLBACK(default_mode_radio_button_cb),
255 (gpointer) &(radio_value[i]));
256 CLAWS_SET_TIP(radio[i], radio_hint[i]);
257 gtk_widget_show(radio[i]);
258 page->defm_radio[i] = radio[i];
260 if (e == 0) { /* unknown value, go default */
261 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio[0]), TRUE);
262 libravatarprefs.default_mode = DEF_MODE_NONE;
264 /* don't waste time with headers that won't be displayed */
265 prefs_common_get_prefs()->enable_avatars =
266 (libravatarprefs.default_mode == DEF_MODE_NONE)
267 ? AVATARS_ENABLE_BOTH: AVATARS_DISABLE;
274 static GtkWidget *p_create_frame_network(struct LibravatarPrefsPage *page)
276 GtkWidget *vbox, *chk_redirects, *spinner, *hbox;
278 #if (defined USE_GNUTLS && GLIB_CHECK_VERSION(2,22,0))
279 GtkWidget *chk_federated;
282 vbox = gtk_vbox_new(FALSE, 6);
284 chk_redirects = create_checkbox(_("_Allow redirects to other sites"),
285 _("Follow redirect responses received from "
286 "libravatar server to other avatar "
287 "services like gravatar.com"));
288 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chk_redirects),
289 libravatarprefs.allow_redirects);
290 page->allow_redirects_check = chk_redirects;
291 gtk_box_pack_start(GTK_BOX(vbox), chk_redirects, FALSE, FALSE, 0);
293 #if (defined USE_GNUTLS && GLIB_CHECK_VERSION(2,22,0))
294 chk_federated = create_checkbox(_("_Enable federated servers"),
295 _("Try to get avatar from sender's domain "
296 "libravatar server"));
297 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chk_federated),
298 libravatarprefs.allow_federated);
299 page->allow_federated_check = chk_federated;
300 gtk_box_pack_start(GTK_BOX(vbox), chk_federated, FALSE, FALSE, 0);
303 adj = (GtkAdjustment *) gtk_adjustment_new(
304 libravatarprefs.timeout,
306 (prefs_common_get_prefs()->io_timeout_secs > 0)
307 ? (prefs_common_get_prefs()->io_timeout_secs - 1)
310 spinner = gtk_spin_button_new(adj, 1.0, 0);
311 gtk_widget_show(spinner);
312 hbox = labeled_spinner_box(_("Request timeout"), spinner, _("seconds"),
313 _("Set to 0 to use global socket I/O timeout. "
314 "Maximum value must be also less than global socket "
316 page->timeout = spinner;
317 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
323 ┌─Icon cache───────────────────────────────────────────┐
324 │ [✔] Use cached icons │
325 │ Cache refresh interval [ 24 |⬘] hours │
326 └──────────────────────────────────────────────────────┘
327 ┌─Default missing icon mode────────────────────────────┐
334 │ ( ) Custom URL [___________________________________] │
335 └──────────────────────────────────────────────────────┘
336 ┌─Network──────────────────────────────────────────────┐
337 │ [✔] Allow redirects │
338 │ [✔] Federated servers │
339 │ Timeout [ 10 |⬘] seconds │
340 └──────────────────────────────────────────────────────┘
342 static void libravatar_prefs_create_widget_func(PrefsPage * _page,
346 struct LibravatarPrefsPage *page = (struct LibravatarPrefsPage *) _page;
347 GtkWidget *vbox, *vbox1, *vbox2, *vbox3, *frame;
349 vbox1 = p_create_frame_cache(page);
350 vbox2 = p_create_frame_missing(page);
351 vbox3 = p_create_frame_network(page);
353 vbox = gtk_vbox_new(FALSE, 6);
354 gtk_container_set_border_width(GTK_CONTAINER(vbox), VBOX_BORDER);
356 PACK_FRAME (vbox, frame, _("Icon cache"));
357 gtk_container_set_border_width(GTK_CONTAINER(vbox1), 6);
358 gtk_container_add(GTK_CONTAINER(frame), vbox1);
360 PACK_FRAME (vbox, frame, _("Default missing icon mode"));
361 gtk_container_set_border_width(GTK_CONTAINER(vbox2), 6);
362 gtk_container_add(GTK_CONTAINER(frame), vbox2);
364 PACK_FRAME (vbox, frame, _("Network"));
365 gtk_container_set_border_width(GTK_CONTAINER(vbox3), 6);
366 gtk_container_add(GTK_CONTAINER(frame), vbox3);
368 gtk_widget_show_all(vbox);
369 page->page.widget = vbox;
372 static void libravatar_prefs_destroy_widget_func(PrefsPage *_page)
377 static void libravatar_save_config(void)
382 debug_print("Saving Libravatar Page\n");
384 rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, COMMON_RC, NULL);
385 pfile = prefs_write_open(rcpath);
387 if (!pfile || (prefs_set_block_label(pfile, PREFS_BLOCK_NAME) < 0))
390 if (prefs_write_param(param, pfile->fp) < 0) {
391 g_warning("failed to write Libravatar configuration to file");
392 prefs_file_close_revert(pfile);
395 if (fprintf(pfile->fp, "\n") < 0) {
396 FILE_OP_ERROR(rcpath, "fprintf");
397 prefs_file_close_revert(pfile);
399 prefs_file_close(pfile);
402 static void libravatar_prefs_save_func(PrefsPage * _page)
404 struct LibravatarPrefsPage *page = (struct LibravatarPrefsPage *) _page;
408 libravatarprefs.cache_icons = gtk_toggle_button_get_active(
409 GTK_TOGGLE_BUTTON(page->cache_icons_check));
411 libravatarprefs.cache_interval = gtk_spin_button_get_value_as_int(
412 GTK_SPIN_BUTTON(page->cache_interval_spin));
414 for (i = 0; i < NUM_DEF_BUTTONS; ++i) {
415 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->defm_radio[i]))) {
416 libravatarprefs.default_mode = radio_value[i];
421 if (libravatarprefs.default_mode_url != NULL) {
422 g_free(libravatarprefs.default_mode_url);
424 libravatarprefs.default_mode_url = gtk_editable_get_chars(
425 GTK_EDITABLE(page->defm_url_text), 0, -1);
427 libravatarprefs.allow_redirects = gtk_toggle_button_get_active(
428 GTK_TOGGLE_BUTTON(page->allow_redirects_check));
430 #if (defined USE_GNUTLS && GLIB_CHECK_VERSION(2,22,0))
431 libravatarprefs.allow_federated = gtk_toggle_button_get_active(
432 GTK_TOGGLE_BUTTON(page->allow_federated_check));
435 libravatarprefs.timeout = gtk_spin_button_get_value_as_int(
436 GTK_SPIN_BUTTON(page->timeout));
438 libravatar_save_config();
441 void libravatar_prefs_init(void)
443 static gchar *path[3];
446 path[0] = _("Plugins");
447 path[1] = _("Libravatar");
450 prefs_set_default(param);
451 rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, COMMON_RC, NULL);
452 prefs_read_config(param, PREFS_BLOCK_NAME, rcpath, NULL);
455 libravatarprefs_page.page.path = path;
456 libravatarprefs_page.page.create_widget = libravatar_prefs_create_widget_func;
457 libravatarprefs_page.page.destroy_widget = libravatar_prefs_destroy_widget_func;
458 libravatarprefs_page.page.save_page = libravatar_prefs_save_func;
459 libravatarprefs_page.page.weight = 40.0;
461 prefs_gtk_register_page((PrefsPage *) &libravatarprefs_page);
464 void libravatar_prefs_done(void)
466 prefs_gtk_unregister_page((PrefsPage *) &libravatarprefs_page);