support image/x-eps format via pdf_viewer
[claws.git] / src / plugins / libravatar / libravatar_prefs.c
blobb4dbac9ad42c2ba1b046df18538024de54aaf0ec
1 /*
2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client
3 * Copyright (C) 2014-2022 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/>.
19 #ifdef HAVE_CONFIG_H
20 # include "config.h"
21 #include "claws-features.h"
22 #endif
24 #include <glib.h>
25 #include <glib/gi18n.h>
27 #include "libravatar.h"
29 #include <gtk/gtk.h>
30 #include <gtk/filesel.h>
32 #include "defs.h"
33 #include "libravatar_prefs.h"
34 #include "libravatar_cache.h"
35 #include "prefs_common.h"
36 #include "prefs_gtk.h"
37 #include "alertpanel.h"
39 #define PREFS_BLOCK_NAME "Libravatar"
40 #define NUM_DEF_BUTTONS 9
41 #define CUSTOM_URL_BUTTON_INDEX 8
42 /* cache interval goes from 1 hour to 30 days */
43 #define INTERVAL_MIN_H 1.0
44 #define INTERVAL_MAX_H 720.0
45 /* timeout interval goes from 0 seconds (= use general timeout value)
46 to (general timeout value - 1) seconds */
47 #define TIMEOUT_MIN_S 0.0
49 LibravatarPrefs libravatarprefs;
50 GHashTable *libravatarmisses;
52 struct LibravatarPrefsPage
54 PrefsPage page;
56 GtkWidget *cache_interval_spin;
57 GtkWidget *cache_icons_check;
58 GtkWidget *defm_radio[NUM_DEF_BUTTONS];
59 GtkWidget *defm_url_text;
60 GtkWidget *allow_redirects_check;
61 #if defined USE_GNUTLS
62 GtkWidget *allow_federated_check;
63 #endif
64 GtkWidget *timeout;
67 struct LibravatarPrefsPage libravatarprefs_page;
69 static PrefParam param[] = {
70 { "base_url", "https://seccdn.libravatar.org/avatar",
71 &libravatarprefs.base_url,
72 P_STRING, NULL, NULL, NULL },
73 { "cache_interval", "24",
74 &libravatarprefs.cache_interval,
75 P_INT, NULL, NULL, NULL },
76 { "cache_icons", "TRUE",
77 &libravatarprefs.cache_icons,
78 P_BOOL, NULL, NULL, NULL },
79 { "default_mode", "0",
80 &libravatarprefs.default_mode,
81 P_INT, NULL, NULL, NULL },
82 { "default_mode_url", "",
83 &libravatarprefs.default_mode_url,
84 P_STRING, NULL, NULL, NULL },
85 { "allow_redirects", "TRUE",
86 &libravatarprefs.allow_redirects,
87 P_BOOL, NULL, NULL, NULL },
88 #if defined USE_GNUTLS
89 { "allow_federated", "TRUE",
90 &libravatarprefs.allow_federated,
91 P_BOOL, NULL, NULL, NULL },
92 #endif
93 { "timeout", "0",
94 &libravatarprefs.timeout,
95 P_INT, NULL, NULL, NULL },
96 { "max_redirects_url", "7",
97 &libravatarprefs.max_redirects_url,
98 P_INT, NULL, NULL, NULL },
99 { "max_redirects_mm", "5",
100 &libravatarprefs.max_redirects_mm,
101 P_INT, NULL, NULL, NULL },
102 { "max_redirects", "3",
103 &libravatarprefs.max_redirects,
104 P_INT, NULL, NULL, NULL },
105 {NULL, NULL, NULL, P_OTHER, NULL, NULL, NULL}
108 static GtkWidget *create_checkbox(gchar *label, gchar *hint)
110 GtkWidget *cb = gtk_check_button_new_with_mnemonic(label);
111 CLAWS_SET_TIP(cb, hint);
112 gtk_widget_show(cb);
114 return cb;
117 static void cache_icons_check_toggled_cb(GtkToggleButton *button, gpointer data)
119 gtk_widget_set_sensitive(libravatarprefs_page.cache_interval_spin,
120 gtk_toggle_button_get_active(button));
123 static GtkWidget *labeled_spinner_box(gchar *label, GtkWidget *spinner, gchar *units, gchar *hint)
125 GtkWidget *lbl, *lbla, *hbox;
127 lbl = gtk_label_new(label);
128 gtk_widget_show(lbl);
129 lbla = gtk_label_new(units);
130 gtk_widget_show(lbla);
131 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
132 if (hint != NULL) {
133 CLAWS_SET_TIP(spinner, hint);
135 gtk_box_pack_start(GTK_BOX(hbox), lbl, FALSE, FALSE, 0);
136 gtk_box_pack_start(GTK_BOX(hbox), spinner, FALSE, FALSE, 0);
137 gtk_box_pack_start(GTK_BOX(hbox), lbla, FALSE, FALSE, 0);
139 return hbox;
142 static gchar *avatar_stats_label_markup(AvatarCacheStats *stats)
144 if (stats == NULL)
145 return g_markup_printf_escaped("<span color=\"red\">%s</span>",
146 _("Error reading cache stats"));
148 if (stats->errors > 0) {
149 gchar *label_text = g_strdup_printf(_("Using %s in %d files, %d "
150 "directories, %d others and %d errors"),
151 to_human_readable((goffset) stats->bytes),
152 stats->files,
153 stats->dirs,
154 stats->others,
155 stats->errors);
156 gchar *label = g_markup_printf_escaped("<span color=\"red\">%s</span>",
157 label_text);
158 g_free(label_text);
159 return label;
162 return g_strdup_printf(
163 _("Using %s in %d files, %d directories and %d others"),
164 to_human_readable((goffset) stats->bytes),
165 stats->files,
166 stats->dirs,
167 stats->others);
170 static void cache_clean_button_clicked_cb(GtkButton *button, gpointer data)
172 GtkLabel *label = (GtkLabel *) data;
173 gint val = 0;
174 AvatarCleanupResult *acr;
175 guint misses;
177 val = alertpanel_full(_("Clear icon cache"),
178 _("Are you sure you want to remove all cached avatar icons?"),
179 NULL, _("_No"), NULL, _("_Yes"), NULL, NULL,
180 ALERTFOCUS_FIRST, FALSE, NULL, ALERT_WARNING);
181 if (val != G_ALERTALTERNATE)
182 return;
184 debug_print("cleaning missing cache\n");
185 misses = g_hash_table_size(libravatarmisses);
186 g_hash_table_remove_all(libravatarmisses);
188 debug_print("cleaning disk cache\n");
189 acr = libravatar_cache_clean();
190 if (acr == NULL) {
191 alertpanel_error(_("Not enough memory for operation"));
192 return;
195 if (acr->e_stat == 0 && acr->e_unlink == 0) {
196 alertpanel_notice(_("Icon cache successfully cleared:\n"
197 "• %u missing entries removed.\n"
198 "• %u files removed."),
199 misses, acr->removed);
200 gtk_label_set_markup(label, g_strconcat("<span color=\"#006400\">",
201 _("Icon cache successfully cleared!"), "</span>", NULL));
203 else {
204 alertpanel_warning(_("Errors clearing icon cache:\n"
205 "• %u missing entries removed.\n"
206 "• %u files removed.\n"
207 "• %u files failed to be read.\n"
208 "• %u files couldn't be removed."),
209 misses, acr->removed, acr->e_stat, acr->e_unlink);
210 gtk_label_set_markup(label, g_strconcat("<span color=\"red\">",
211 _("Error clearing icon cache."), "</span>", NULL));
213 gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
214 g_free(acr);
217 static GtkWidget *p_create_frame_cache(struct LibravatarPrefsPage *page)
219 GtkWidget *vbox, *checkbox, *spinner, *hbox, *label, *button;
220 GtkAdjustment *adj;
221 AvatarCacheStats *stats;
222 gchar *markup;
224 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6);
226 checkbox = create_checkbox(_("_Use cached icons"),
227 _("Keep icons on disk for reusing instead "
228 "of making another network request"));
229 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbox),
230 libravatarprefs.cache_icons);
231 g_signal_connect(checkbox, "toggled",
232 G_CALLBACK(cache_icons_check_toggled_cb), NULL);
233 page->cache_icons_check = checkbox;
235 adj = (GtkAdjustment *) gtk_adjustment_new(
236 libravatarprefs.cache_interval,
237 INTERVAL_MIN_H, INTERVAL_MAX_H, 1.0,
238 0.0, 0.0);
239 spinner = gtk_spin_button_new(adj, 1.0, 0);
240 gtk_widget_show(spinner);
241 gtk_widget_set_sensitive(spinner, libravatarprefs.cache_icons);
242 hbox = labeled_spinner_box(_("Cache refresh interval"), spinner, _("hours"), NULL);
243 page->cache_interval_spin = spinner;
245 gtk_box_pack_start(GTK_BOX(vbox), checkbox, FALSE, FALSE, 0);
246 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
248 label = gtk_label_new(NULL);
249 gtk_widget_show(label);
250 stats = libravatar_cache_stats();
251 markup = avatar_stats_label_markup(stats);
252 gtk_label_set_markup(GTK_LABEL(label), markup);
253 g_free(markup);
254 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
256 button = gtkut_stock_button("edit-clear", _("C_lear"));
257 gtk_widget_show(button);
258 g_signal_connect(button, "clicked",
259 G_CALLBACK(cache_clean_button_clicked_cb), label);
260 gtk_widget_set_sensitive(button, (stats != NULL && stats->bytes > 0));
262 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
263 gtk_widget_show(hbox);
264 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
265 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
266 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
268 if (stats != NULL)
269 g_free(stats);
271 return vbox;
274 static void default_mode_radio_button_cb(GtkToggleButton *button, gpointer data)
276 guint mode;
277 gboolean is_url;
279 if (gtk_toggle_button_get_active(button) != TRUE)
280 return;
282 mode = *((guint *)data);
283 is_url = (mode == DEF_MODE_URL)? TRUE: FALSE;
285 gtk_widget_set_sensitive(libravatarprefs_page.defm_url_text, is_url);
286 if (is_url) /* custom URL requires following redirects */
287 gtk_toggle_button_set_active(
288 GTK_TOGGLE_BUTTON(libravatarprefs_page.allow_redirects_check),
289 TRUE);
291 if (mode == DEF_MODE_NONE) {
292 prefs_common_get_prefs()->enable_avatars = AVATARS_ENABLE_BOTH;
293 } else {
294 /* don't waste time with headers that won't be displayed */
295 prefs_common_get_prefs()->enable_avatars = AVATARS_DISABLE;
296 /* empty missing cache when switching to generated */
297 g_hash_table_remove_all(libravatarmisses);
301 static const guint radio_value[] = {
302 DEF_MODE_NONE,
303 DEF_MODE_MM,
304 DEF_MODE_IDENTICON,
305 DEF_MODE_MONSTERID,
306 DEF_MODE_WAVATAR,
307 DEF_MODE_RETRO,
308 DEF_MODE_ROBOHASH,
309 DEF_MODE_PAGAN,
310 DEF_MODE_URL
313 static GtkWidget *p_create_frame_missing(struct LibravatarPrefsPage *page)
315 GtkWidget *vbox, *radio[NUM_DEF_BUTTONS], *hbox, *entry;
316 gboolean enable = FALSE;
317 int i, e = 0;
318 gchar *radio_label[] = {
319 _("None"),
320 _("Mystery man"),
321 _("Identicon"),
322 _("MonsterID"),
323 _("Wavatar"),
324 _("Retro"),
325 _("Robohash"),
326 _("Pagan"),
327 _("Custom URL")
329 gchar *radio_hint[] = {
330 _("A blank image"),
331 _("The unobtrusive low-contrast greyish silhouette"),
332 _("A generated geometric pattern"),
333 _("A generated full-body monster"),
334 _("A generated almost unique face"),
335 _("A generated 8-bit arcade-style pixelated image"),
336 _("A generated robotic character"),
337 _("A generated retro adventure game character"),
338 _("Redirect to a user provided URL")
341 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6);
343 for (i = 0; i < NUM_DEF_BUTTONS; ++i) {
344 enable = (libravatarprefs.default_mode == radio_value[i])? TRUE: FALSE;
345 e += enable? 1: 0;
346 radio[i] = gtk_radio_button_new_with_label_from_widget(
347 (i > 0)? GTK_RADIO_BUTTON(radio[i - 1]): NULL, radio_label[i]);
348 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio[i]), enable);
349 if (i == CUSTOM_URL_BUTTON_INDEX) {
350 /* set related entry next to radio button */
351 entry = gtk_entry_new();
352 CLAWS_SET_TIP(entry, _("Enter the URL you want to be "
353 "redirected when no user icon is available. "
354 "Leave an empty URL to use the default "
355 "libravatar orange icon."));
356 gtk_entry_set_text(GTK_ENTRY(entry),
357 libravatarprefs.default_mode_url);
358 gtk_entry_set_max_length(GTK_ENTRY(entry), MAX_URL_LENGTH);
359 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
360 gtk_box_pack_start(GTK_BOX(hbox), radio[i], FALSE, FALSE, 0);
361 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
362 gtk_widget_set_sensitive(entry,
363 (libravatarprefs.default_mode == DEF_MODE_URL)
364 ? TRUE: FALSE);
365 gtk_widget_show(entry);
366 page->defm_url_text = entry;
367 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
368 } else {
369 gtk_box_pack_start(GTK_BOX(vbox), radio[i], FALSE, FALSE, 0);
371 g_signal_connect(radio[i], "toggled",
372 G_CALLBACK(default_mode_radio_button_cb),
373 (gpointer) &(radio_value[i]));
374 CLAWS_SET_TIP(radio[i], radio_hint[i]);
375 gtk_widget_show(radio[i]);
376 page->defm_radio[i] = radio[i];
378 if (e == 0) { /* unknown value, go default */
379 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio[0]), TRUE);
380 libravatarprefs.default_mode = DEF_MODE_NONE;
382 /* don't waste time with headers that won't be displayed */
383 prefs_common_get_prefs()->enable_avatars =
384 (libravatarprefs.default_mode == DEF_MODE_NONE)
385 ? AVATARS_ENABLE_BOTH: AVATARS_DISABLE;
389 return vbox;
392 static GtkWidget *p_create_frame_network(struct LibravatarPrefsPage *page)
394 GtkWidget *vbox, *chk_redirects, *spinner, *hbox;
395 GtkAdjustment *adj;
396 #if defined USE_GNUTLS
397 GtkWidget *chk_federated;
398 #endif
400 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6);
402 chk_redirects = create_checkbox(_("_Allow redirects to other sites"),
403 _("Follow redirect responses received from "
404 "libravatar server to other avatar "
405 "services like gravatar.com"));
406 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chk_redirects),
407 libravatarprefs.allow_redirects);
408 page->allow_redirects_check = chk_redirects;
409 gtk_box_pack_start(GTK_BOX(vbox), chk_redirects, FALSE, FALSE, 0);
411 #if defined USE_GNUTLS
412 chk_federated = create_checkbox(_("_Enable federated servers"),
413 _("Try to get avatar from sender's domain "
414 "libravatar server"));
415 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chk_federated),
416 libravatarprefs.allow_federated);
417 page->allow_federated_check = chk_federated;
418 gtk_box_pack_start(GTK_BOX(vbox), chk_federated, FALSE, FALSE, 0);
419 #endif
421 adj = (GtkAdjustment *) gtk_adjustment_new(
422 libravatarprefs.timeout,
423 TIMEOUT_MIN_S,
424 (prefs_common_get_prefs()->io_timeout_secs > 0)
425 ? (prefs_common_get_prefs()->io_timeout_secs - 1)
426 : 0,
427 1.0, 0.0, 0.0);
428 spinner = gtk_spin_button_new(adj, 1.0, 0);
429 gtk_widget_show(spinner);
430 hbox = labeled_spinner_box(_("Request timeout"), spinner, _("second(s)"),
431 _("Set to 0 to use global socket I/O timeout. "
432 "Maximum value must be also less than global socket "
433 "I/O timeout."));
434 page->timeout = spinner;
435 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
437 return vbox;
441 ┌─Icon cache───────────────────────────────────────────┐
442 │ [✔] Use cached icons │
443 │ Cache refresh interval [ 24 |⬘] hours │
444 │ Using X KB in Y files and Z directories [Clear] │
445 └──────────────────────────────────────────────────────┘
446 ┌─Default missing icon mode────────────────────────────┐
447 │ (•) None │
448 │ ( ) Mystery man │
449 │ ( ) Identicon │
450 │ ( ) MonsterID │
451 │ ( ) Wavatar │
452 │ ( ) Retro │
453 │ ( ) Robohash │
454 │ ( ) Pagan │
455 │ ( ) Custom URL [___________________________________] │
456 └──────────────────────────────────────────────────────┘
457 ┌─Network──────────────────────────────────────────────┐
458 │ [✔] Allow redirects │
459 │ [✔] Federated servers │
460 │ Timeout [ 10 |⬘] seconds │
461 └──────────────────────────────────────────────────────┘
463 static void libravatar_prefs_create_widget_func(PrefsPage * _page,
464 GtkWindow * window,
465 gpointer data)
467 struct LibravatarPrefsPage *page = (struct LibravatarPrefsPage *) _page;
468 GtkWidget *vbox, *vbox1, *vbox2, *vbox3, *frame;
470 vbox1 = p_create_frame_cache(page);
471 vbox2 = p_create_frame_missing(page);
472 vbox3 = p_create_frame_network(page);
474 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6);
475 gtk_container_set_border_width(GTK_CONTAINER(vbox), VBOX_BORDER);
477 PACK_FRAME (vbox, frame, _("Icon cache"));
478 gtk_container_set_border_width(GTK_CONTAINER(vbox1), 6);
479 gtk_container_add(GTK_CONTAINER(frame), vbox1);
481 PACK_FRAME (vbox, frame, _("Default missing icon mode"));
482 gtk_container_set_border_width(GTK_CONTAINER(vbox2), 6);
483 gtk_container_add(GTK_CONTAINER(frame), vbox2);
485 PACK_FRAME (vbox, frame, _("Network"));
486 gtk_container_set_border_width(GTK_CONTAINER(vbox3), 6);
487 gtk_container_add(GTK_CONTAINER(frame), vbox3);
489 gtk_widget_show_all(vbox);
490 page->page.widget = vbox;
493 static void libravatar_prefs_destroy_widget_func(PrefsPage *_page)
495 /* nothing */
498 static void libravatar_save_config(void)
500 PrefFile *pfile;
501 gchar *rcpath;
503 debug_print("Saving Libravatar Page\n");
505 rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, COMMON_RC, NULL);
506 pfile = prefs_write_open(rcpath);
507 g_free(rcpath);
508 if (!pfile || (prefs_set_block_label(pfile, PREFS_BLOCK_NAME) < 0))
509 return;
511 if (prefs_write_param(param, pfile->fp) < 0) {
512 g_warning("failed to write Libravatar configuration to file");
513 prefs_file_close_revert(pfile);
514 return;
516 if (fprintf(pfile->fp, "\n") < 0) {
517 FILE_OP_ERROR(rcpath, "fprintf");
518 prefs_file_close_revert(pfile);
519 } else
520 prefs_file_close(pfile);
523 static void libravatar_prefs_save_func(PrefsPage * _page)
525 struct LibravatarPrefsPage *page = (struct LibravatarPrefsPage *) _page;
526 int i;
528 /* cache */
529 libravatarprefs.cache_icons = gtk_toggle_button_get_active(
530 GTK_TOGGLE_BUTTON(page->cache_icons_check));
531 /* cache interval */
532 libravatarprefs.cache_interval = gtk_spin_button_get_value_as_int(
533 GTK_SPIN_BUTTON(page->cache_interval_spin));
534 /* default mode */
535 for (i = 0; i < NUM_DEF_BUTTONS; ++i) {
536 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->defm_radio[i]))) {
537 libravatarprefs.default_mode = radio_value[i];
538 break;
541 /* custom url */
542 if (libravatarprefs.default_mode_url != NULL) {
543 g_free(libravatarprefs.default_mode_url);
545 libravatarprefs.default_mode_url = gtk_editable_get_chars(
546 GTK_EDITABLE(page->defm_url_text), 0, -1);
547 /* redirects */
548 libravatarprefs.allow_redirects = gtk_toggle_button_get_active(
549 GTK_TOGGLE_BUTTON(page->allow_redirects_check));
550 /* federation */
551 #if defined USE_GNUTLS
552 libravatarprefs.allow_federated = gtk_toggle_button_get_active(
553 GTK_TOGGLE_BUTTON(page->allow_federated_check));
554 #endif
555 /* timeout */
556 libravatarprefs.timeout = gtk_spin_button_get_value_as_int(
557 GTK_SPIN_BUTTON(page->timeout));
559 libravatar_save_config();
562 void libravatar_prefs_init(void)
564 static gchar *path[3];
565 gchar *rcpath;
567 path[0] = _("Plugins");
568 path[1] = _("Libravatar");
569 path[2] = NULL;
571 prefs_set_default(param);
572 rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, COMMON_RC, NULL);
573 prefs_read_config(param, PREFS_BLOCK_NAME, rcpath, NULL);
574 g_free(rcpath);
576 libravatarprefs_page.page.path = path;
577 libravatarprefs_page.page.create_widget = libravatar_prefs_create_widget_func;
578 libravatarprefs_page.page.destroy_widget = libravatar_prefs_destroy_widget_func;
579 libravatarprefs_page.page.save_page = libravatar_prefs_save_func;
580 libravatarprefs_page.page.weight = 40.0;
582 prefs_gtk_register_page((PrefsPage *) &libravatarprefs_page);
585 void libravatar_prefs_done(void)
587 prefs_gtk_unregister_page((PrefsPage *) &libravatarprefs_page);