Libravatar: fix copyright headers
[claws.git] / src / plugins / libravatar / libravatar_prefs.c
1 /*
2  * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 2014-2015 Ricardo Mones and the Claws Mail Team
4  *
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.
9  *
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.
14  *
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/>.
17  */
18
19 #ifdef HAVE_CONFIG_H
20 #  include "config.h"
21 #include "claws-features.h"
22 #endif
23
24 #include <glib.h>
25 #include <glib/gi18n.h>
26
27 #include "libravatar.h"
28
29 #include <gtk/gtk.h>
30 #include <gtk/filesel.h>
31
32 #include "defs.h"
33 #include "libravatar_prefs.h"
34 #include "prefs_common.h"
35 #include "prefs_gtk.h"
36
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
46
47 LibravatarPrefs libravatarprefs;
48 GHashTable *libravatarmisses;
49
50 struct LibravatarPrefsPage
51 {
52         PrefsPage page;
53
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;
61 #endif
62         GtkWidget *timeout;
63 };
64
65 struct LibravatarPrefsPage libravatarprefs_page;
66
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 },
90 #endif
91         { "timeout", "0",
92           &libravatarprefs.timeout,
93           P_INT, NULL, NULL, NULL },
94         {NULL, NULL, NULL, P_OTHER, NULL, NULL, NULL}
95 };
96
97 static GtkWidget *create_checkbox(gchar *label, gchar *hint)
98 {
99         GtkWidget *cb = gtk_check_button_new_with_mnemonic(label);
100         CLAWS_SET_TIP(cb, hint);
101         gtk_widget_show(cb);
102
103         return cb;
104 }
105
106 static void cache_icons_check_toggled_cb(GtkToggleButton *button, gpointer data)
107 {
108         gtk_widget_set_sensitive(libravatarprefs_page.cache_interval_spin,
109                                  gtk_toggle_button_get_active(button));
110 }
111
112 static GtkWidget *labeled_spinner_box(gchar *label, GtkWidget *spinner, gchar *units, gchar *hint)
113 {
114         GtkWidget *lbl, *lbla, *hbox;
115
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);
121         if (hint != NULL) {
122                 CLAWS_SET_TIP(spinner, hint);
123         }
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);
127
128         return hbox;
129 }
130
131 static GtkWidget *p_create_frame_cache(struct LibravatarPrefsPage *page)
132 {
133         GtkWidget *vbox, *checkbox, *spinner, *hbox;
134         GtkAdjustment *adj;
135
136         vbox =  gtk_vbox_new(FALSE, 6);
137
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;
146
147         adj = (GtkAdjustment *) gtk_adjustment_new(
148                                         libravatarprefs.cache_interval,
149                                         INTERVAL_MIN_H, INTERVAL_MAX_H, 1.0,
150                                         0.0, 0.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;
156
157         gtk_box_pack_start(GTK_BOX(vbox), checkbox, FALSE, FALSE, 0);
158         gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
159
160         return vbox;
161 }
162
163 static void default_mode_radio_button_cb(GtkToggleButton *button, gpointer data)
164 {
165         guint mode;
166         gboolean is_url;
167
168         if (gtk_toggle_button_get_active(button) != TRUE)
169                 return;
170
171         mode = *((guint *)data);
172         is_url = (mode == DEF_MODE_URL)? TRUE: FALSE;
173
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),
178                         TRUE);
179
180         if (mode == DEF_MODE_NONE) {
181                 prefs_common_get_prefs()->enable_avatars = AVATARS_ENABLE_BOTH;
182         } else {
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);
187         }
188 }
189
190 static const guint radio_value[] = {
191         DEF_MODE_NONE,
192         DEF_MODE_MM,
193         DEF_MODE_IDENTICON,
194         DEF_MODE_MONSTERID,
195         DEF_MODE_WAVATAR,
196         DEF_MODE_RETRO,
197         DEF_MODE_URL
198 };
199
200 static GtkWidget *p_create_frame_missing(struct LibravatarPrefsPage *page)
201 {
202         GtkWidget *vbox, *radio[NUM_DEF_BUTTONS], *hbox, *entry;
203         gboolean enable = FALSE;
204         int i, e = 0;
205         gchar *radio_label[] = {
206                 _("None"),
207                 _("Mystery man"),
208                 _("Identicon"),
209                 _("MonsterID"),
210                 _("Wavatar"),
211                 _("Retro"),
212                 _("Custom URL")
213         };
214         gchar *radio_hint[] = {
215                 _("A blank image"),
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")
222         };
223
224         vbox =  gtk_vbox_new(FALSE, 6);
225
226         for (i = 0; i < NUM_DEF_BUTTONS; ++i) {
227                 enable = (libravatarprefs.default_mode == radio_value[i])? TRUE: FALSE;
228                 e += enable? 1: 0;
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)
247                                 ? TRUE: FALSE);
248                         page->defm_url_text = entry;
249                         gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
250                 } else {
251                         gtk_box_pack_start(GTK_BOX(vbox), radio[i], FALSE, FALSE, 0);
252                 }
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];
259         }
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;
263         }
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;
268
269
270
271         return vbox;
272 }
273
274 static GtkWidget *p_create_frame_network(struct LibravatarPrefsPage *page)
275 {
276         GtkWidget *vbox, *chk_redirects, *spinner, *hbox;
277         GtkAdjustment *adj;
278 #if (defined USE_GNUTLS && GLIB_CHECK_VERSION(2,22,0))
279         GtkWidget *chk_federated;
280 #endif
281
282         vbox =  gtk_vbox_new(FALSE, 6);
283
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);
292
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);
301 #endif
302
303         adj = (GtkAdjustment *) gtk_adjustment_new(
304                                         libravatarprefs.timeout,
305                                         TIMEOUT_MIN_S,
306                                         (prefs_common_get_prefs()->io_timeout_secs > 0)
307                                         ? (prefs_common_get_prefs()->io_timeout_secs - 1)
308                                         : 0,
309                                         1.0, 0.0, 0.0);
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 "
315                   "I/O timeout."));
316         page->timeout = spinner;
317         gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
318
319         return vbox;
320 }
321
322 /*
323   ┌─Icon cache───────────────────────────────────────────┐
324   │ [✔] Use cached icons                                 │
325   │ Cache refresh interval [ 24 |⬘] hours                │
326   └──────────────────────────────────────────────────────┘
327   ┌─Default missing icon mode────────────────────────────┐
328   │ (•) None                                             │
329   │ ( ) Mystery man                                      │
330   │ ( ) Identicon                                        │
331   │ ( ) MonsterID                                        │
332   │ ( ) Wavatar                                          │
333   │ ( ) Retro                                            │
334   │ ( ) Custom URL [___________________________________] │
335   └──────────────────────────────────────────────────────┘
336   ┌─Network──────────────────────────────────────────────┐
337   │ [✔] Allow redirects                                  │
338   │ [✔] Federated servers                                │
339   │ Timeout [ 10 |⬘] seconds                             │
340   └──────────────────────────────────────────────────────┘
341  */
342 static void libravatar_prefs_create_widget_func(PrefsPage * _page,
343                                                 GtkWindow * window,
344                                                 gpointer data)
345 {
346         struct LibravatarPrefsPage *page = (struct LibravatarPrefsPage *) _page;
347         GtkWidget *vbox, *vbox1, *vbox2, *vbox3, *frame;
348
349         vbox1 = p_create_frame_cache(page);
350         vbox2 = p_create_frame_missing(page);
351         vbox3 = p_create_frame_network(page);
352
353         vbox = gtk_vbox_new(FALSE, 6);
354         gtk_container_set_border_width(GTK_CONTAINER(vbox), VBOX_BORDER);
355
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);
359
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);
363
364         PACK_FRAME (vbox, frame, _("Network"));
365         gtk_container_set_border_width(GTK_CONTAINER(vbox3), 6);
366         gtk_container_add(GTK_CONTAINER(frame), vbox3);
367
368         gtk_widget_show_all(vbox);
369         page->page.widget = vbox;
370 }
371
372 static void libravatar_prefs_destroy_widget_func(PrefsPage *_page)
373 {
374         /* nothing */
375 }
376
377 static void libravatar_save_config(void)
378 {
379         PrefFile *pfile;
380         gchar *rcpath;
381
382         debug_print("Saving Libravatar Page\n");
383
384         rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, COMMON_RC, NULL);
385         pfile = prefs_write_open(rcpath);
386         g_free(rcpath);
387         if (!pfile || (prefs_set_block_label(pfile, PREFS_BLOCK_NAME) < 0))
388                 return;
389
390         if (prefs_write_param(param, pfile->fp) < 0) {
391                 g_warning("Failed to write Libravatar configuration to file\n");
392                 prefs_file_close_revert(pfile);
393                 return;
394         }
395         if (fprintf(pfile->fp, "\n") < 0) {
396                 FILE_OP_ERROR(rcpath, "fprintf");
397                 prefs_file_close_revert(pfile);
398         } else
399                 prefs_file_close(pfile);
400 }
401
402 static void libravatar_prefs_save_func(PrefsPage * _page)
403 {
404         struct LibravatarPrefsPage *page = (struct LibravatarPrefsPage *) _page;
405         int i;
406
407         /* cache */
408         libravatarprefs.cache_icons = gtk_toggle_button_get_active(
409                 GTK_TOGGLE_BUTTON(page->cache_icons_check));
410         /* cache interval */
411         libravatarprefs.cache_interval = gtk_spin_button_get_value_as_int(
412                 GTK_SPIN_BUTTON(page->cache_interval_spin));
413         /* default mode */
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];
417                         break;
418                 }
419         }
420         /* custom url */
421         if (libravatarprefs.default_mode_url != NULL) {
422                 g_free(libravatarprefs.default_mode_url);
423         }
424         libravatarprefs.default_mode_url = gtk_editable_get_chars(
425                 GTK_EDITABLE(page->defm_url_text), 0, -1);
426         /* redirects */
427         libravatarprefs.allow_redirects = gtk_toggle_button_get_active(
428                 GTK_TOGGLE_BUTTON(page->allow_redirects_check));
429         /* federation */
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));
433 #endif
434         /* timeout */
435         libravatarprefs.timeout = gtk_spin_button_get_value_as_int(
436                 GTK_SPIN_BUTTON(page->timeout));
437
438         libravatar_save_config();
439 }
440
441 void libravatar_prefs_init(void)
442 {
443         static gchar *path[3];
444         gchar *rcpath;
445
446         path[0] = _("Plugins");
447         path[1] = _("Libravatar");
448         path[2] = NULL;
449
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);
453         g_free(rcpath);
454
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;
460
461         prefs_gtk_register_page((PrefsPage *) &libravatarprefs_page);
462 }
463
464 void libravatar_prefs_done(void)
465 {
466         prefs_gtk_unregister_page((PrefsPage *) &libravatarprefs_page);
467 }
468