212e51bfec599b8a5a7484084f7ef9ae213a820d
[claws.git] / src / plugins / pgpcore / prefs_gpg.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 2004 Hiroyuki Yamamoto & the Sylpheed-Claws 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 2 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, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19
20 #include <gtk/gtk.h>
21 #include <glib.h>
22 #include <glib/gi18n.h>
23
24 #include "defs.h"
25 #include "utils.h"
26 #include "prefs.h"
27 #include "prefs_gtk.h"
28 #include "prefs_gpg.h"
29
30 struct GPGConfig prefs_gpg;
31
32 static PrefParam param[] = {
33         /* Privacy */
34         {"auto_check_signatures", "FALSE",
35          &prefs_gpg.auto_check_signatures, P_BOOL,
36          NULL, NULL, NULL},
37         {"store_passphrase", "FALSE", &prefs_gpg.store_passphrase, P_BOOL,
38          NULL, NULL, NULL},
39         {"store_passphrase_timeout", "0",
40          &prefs_gpg.store_passphrase_timeout, P_INT,
41          NULL, NULL, NULL},
42         {"passphrase_grab", "FALSE", &prefs_gpg.passphrase_grab, P_BOOL,
43          NULL, NULL, NULL},
44         {"gpg_warning", "TRUE", &prefs_gpg.gpg_warning, P_BOOL,
45          NULL, NULL, NULL},
46
47         {NULL, NULL, NULL, P_OTHER, NULL, NULL, NULL}
48 };
49
50 struct GPGPage
51 {
52         PrefsPage page;
53
54         GtkWidget *checkbtn_auto_check_signatures;
55         GtkWidget *checkbtn_store_passphrase;  
56         GtkWidget *spinbtn_store_passphrase;  
57         GtkWidget *checkbtn_passphrase_grab;  
58         GtkWidget *checkbtn_gpg_warning;
59 };
60
61 static void store_passphrase_toggled(GtkWidget *widget, gpointer data)
62 {
63         struct GPGPage *page = (struct GPGPage *)data;
64         gtk_widget_set_sensitive(page->spinbtn_store_passphrase,
65                 gtk_toggle_button_get_active(
66                         GTK_TOGGLE_BUTTON(page->checkbtn_store_passphrase)));
67 }
68
69 static void prefs_gpg_create_widget_func(PrefsPage *_page,
70                                          GtkWindow *window,
71                                          gpointer data)
72 {
73         struct GPGPage *page = (struct GPGPage *) _page;
74         struct GPGConfig *config;
75
76         /*
77          * BEGIN GLADE CODE 
78          * DO NOT EDIT 
79          */
80         GtkWidget *table;
81         GtkWidget *checkbtn_passphrase_grab;
82         GtkWidget *checkbtn_store_passphrase;
83         GtkWidget *checkbtn_auto_check_signatures;
84         GtkWidget *checkbtn_gpg_warning;
85         GtkWidget *hbox1;
86         GtkWidget *label11;
87         GtkObject *spinbtn_store_passphrase_adj;
88         GtkWidget *spinbtn_store_passphrase;
89         GtkWidget *label12;
90         GtkTooltips *tooltips;
91         gchar *tmp;
92
93         tooltips = gtk_tooltips_new();
94
95         table = gtk_table_new(5, 2, FALSE);
96         gtk_widget_show(table);
97         gtk_container_set_border_width(GTK_CONTAINER(table), 8);
98         gtk_table_set_row_spacings(GTK_TABLE(table), 4);
99         gtk_table_set_col_spacings(GTK_TABLE(table), 8);
100
101         checkbtn_passphrase_grab = gtk_check_button_new_with_label(_("Grab input while entering a passphrase"));
102         gtk_widget_show(checkbtn_passphrase_grab);
103         gtk_table_attach(GTK_TABLE(table), checkbtn_passphrase_grab, 0, 1,
104                          3, 4, (GtkAttachOptions) (GTK_SHRINK | GTK_FILL),
105                          (GtkAttachOptions) (GTK_SHRINK), 0, 0);
106
107         checkbtn_store_passphrase = gtk_check_button_new_with_label(_("Store passphrase in memory"));
108         gtk_widget_show(checkbtn_store_passphrase);
109         gtk_table_attach(GTK_TABLE(table), checkbtn_store_passphrase, 0, 1,
110                          1, 2, (GtkAttachOptions) (GTK_SHRINK | GTK_FILL),
111                          (GtkAttachOptions) (GTK_SHRINK), 0, 0);
112
113         checkbtn_auto_check_signatures =
114             gtk_check_button_new_with_label(_("Automatically check signatures"));
115         gtk_widget_show(checkbtn_auto_check_signatures);
116         gtk_table_attach(GTK_TABLE(table), checkbtn_auto_check_signatures,
117                          0, 1, 0, 1,
118                          (GtkAttachOptions) (GTK_SHRINK | GTK_FILL),
119                          (GtkAttachOptions) (GTK_SHRINK), 0, 0);
120
121         checkbtn_gpg_warning = gtk_check_button_new_with_label(_
122                           ("Display warning on startup if GnuPG doesn't work"));
123         gtk_widget_show(checkbtn_gpg_warning);
124         gtk_table_attach(GTK_TABLE(table), checkbtn_gpg_warning, 0, 1, 4,
125                          5, (GtkAttachOptions) (GTK_SHRINK | GTK_FILL),
126                          (GtkAttachOptions) (GTK_SHRINK), 0, 0);
127
128         hbox1 = gtk_hbox_new(FALSE, 8);
129         gtk_widget_show(hbox1);
130         gtk_table_attach(GTK_TABLE(table), hbox1, 0, 1, 2, 3,
131                          (GtkAttachOptions) (GTK_SHRINK | GTK_FILL),
132                          (GtkAttachOptions) (GTK_SHRINK), 0, 0);
133
134         tmp = g_strdup_printf("        %s", _("Expire after"));
135         label11 = gtk_label_new(tmp);
136         g_free(tmp);
137         gtk_widget_show(label11);
138         gtk_box_pack_start(GTK_BOX(hbox1), label11, FALSE, FALSE, 0);
139
140         spinbtn_store_passphrase_adj =
141             gtk_adjustment_new(1, 0, 1440, 1, 10, 10);
142         spinbtn_store_passphrase =
143             gtk_spin_button_new(GTK_ADJUSTMENT
144                                 (spinbtn_store_passphrase_adj), 1, 0);
145         gtk_widget_show(spinbtn_store_passphrase);
146         gtk_box_pack_start(GTK_BOX(hbox1), spinbtn_store_passphrase, FALSE,
147                            FALSE, 0);
148         gtk_widget_set_size_request(spinbtn_store_passphrase, 64, -1);
149         gtk_tooltips_set_tip(tooltips, spinbtn_store_passphrase,
150                              _
151                              ("Setting to '0' will store the passphrase for the whole session"),
152                              NULL);
153         gtk_spin_button_set_numeric(GTK_SPIN_BUTTON
154                                     (spinbtn_store_passphrase), TRUE);
155
156         label12 = gtk_label_new(_("minute(s)"));
157         gtk_widget_show(label12);
158         gtk_box_pack_start(GTK_BOX(hbox1), label12, TRUE, TRUE, 0);
159         gtk_misc_set_alignment(GTK_MISC(label12), 0.0, 0.5);
160         /* 
161          * END GLADE CODE
162          */
163
164         config = prefs_gpg_get_config();
165
166         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbtn_auto_check_signatures), config->auto_check_signatures);
167         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbtn_store_passphrase), config->store_passphrase);
168         gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinbtn_store_passphrase), (float) config->store_passphrase_timeout);
169         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbtn_passphrase_grab), config->passphrase_grab);
170         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbtn_gpg_warning), config->gpg_warning);
171
172         gtk_widget_set_sensitive(spinbtn_store_passphrase,
173                 gtk_toggle_button_get_active(
174                         GTK_TOGGLE_BUTTON(checkbtn_store_passphrase)));
175         g_signal_connect(G_OBJECT(checkbtn_store_passphrase), "toggled", 
176                          G_CALLBACK(store_passphrase_toggled), page);
177
178         page->checkbtn_auto_check_signatures = checkbtn_auto_check_signatures;
179         page->checkbtn_store_passphrase = checkbtn_store_passphrase;
180         page->spinbtn_store_passphrase = spinbtn_store_passphrase;
181         page->checkbtn_passphrase_grab = checkbtn_passphrase_grab;
182         page->checkbtn_gpg_warning = checkbtn_gpg_warning;
183
184         page->page.widget = table;
185 }
186
187 static void prefs_gpg_destroy_widget_func(PrefsPage *_page)
188 {
189 }
190
191 static void prefs_gpg_save_func(PrefsPage *_page)
192 {
193         struct GPGPage *page = (struct GPGPage *) _page;
194         GPGConfig *config = prefs_gpg_get_config();
195
196         config->auto_check_signatures =
197                 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->checkbtn_auto_check_signatures));
198         config->store_passphrase = 
199                 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->checkbtn_store_passphrase));
200         config->store_passphrase_timeout = 
201                 gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(page->spinbtn_store_passphrase));
202         config->passphrase_grab = 
203                 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->checkbtn_passphrase_grab));
204         config->gpg_warning = 
205                 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->checkbtn_gpg_warning));
206
207         prefs_gpg_save_config();
208 }
209
210 struct GPGAccountPage
211 {
212         PrefsPage page;
213
214         GtkWidget *key_default;
215         GtkWidget *key_by_from;
216         GtkWidget *key_custom;
217         GtkWidget *keyid;
218
219         PrefsAccount *account;
220 };
221
222 void key_custom_toggled(GtkToggleButton *togglebutton, gpointer user_data)
223 {
224         struct GPGAccountPage *page = (struct GPGAccountPage *) user_data;
225         gboolean active;
226
227         active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->key_custom));
228         gtk_widget_set_sensitive(GTK_WIDGET(page->keyid), active);
229         if (!active)
230                 gtk_editable_delete_text(GTK_EDITABLE(page->keyid), 0, -1);
231 }
232
233 static void prefs_gpg_account_create_widget_func(PrefsPage *_page,
234                                                  GtkWindow *window,
235                                                  gpointer data)
236 {
237         struct GPGAccountPage *page = (struct GPGAccountPage *) _page;
238         PrefsAccount *account = (PrefsAccount *) data;
239         GPGAccountConfig *config;
240
241         /*** BEGIN GLADE CODE ***/
242         GtkWidget *vbox;
243         GtkWidget *frame1;
244         GtkWidget *table1;
245         GSList *key_group = NULL;
246         GtkWidget *key_default;
247         GtkWidget *key_by_from;
248         GtkWidget *key_custom;
249         GtkWidget *label13;
250         GtkWidget *label14;
251         GtkWidget *label15;
252         GtkWidget *label16;
253         GtkWidget *keyid;
254
255         vbox = gtk_vbox_new(FALSE, 0);
256         gtk_widget_show(vbox);
257
258         frame1 = gtk_frame_new(_("Sign key"));
259         gtk_widget_show(frame1);
260         gtk_box_pack_start(GTK_BOX(vbox), frame1, FALSE, FALSE, 0);
261         gtk_frame_set_label_align(GTK_FRAME(frame1), 0.0, 0.5);
262
263         table1 = gtk_table_new(4, 3, FALSE);
264         gtk_widget_show(table1);
265         gtk_container_add(GTK_CONTAINER(frame1), table1);
266         gtk_container_set_border_width(GTK_CONTAINER(table1), 8);
267         gtk_table_set_row_spacings(GTK_TABLE(table1), 4);
268         gtk_table_set_col_spacings(GTK_TABLE(table1), 4);
269
270         key_default = gtk_radio_button_new_with_label(key_group, "");
271         key_group = gtk_radio_button_group(GTK_RADIO_BUTTON(key_default));
272         gtk_widget_show(key_default);
273         gtk_table_attach(GTK_TABLE(table1), key_default, 0, 1, 0, 1,
274                          (GtkAttachOptions) (GTK_FILL),
275                          (GtkAttachOptions) (0), 0, 0);
276
277         key_by_from = gtk_radio_button_new_with_label(key_group, "");
278         key_group = gtk_radio_button_group(GTK_RADIO_BUTTON(key_by_from));
279         gtk_widget_show(key_by_from);
280         gtk_table_attach(GTK_TABLE(table1), key_by_from, 0, 1, 1, 2,
281                          (GtkAttachOptions) (GTK_FILL),
282                          (GtkAttachOptions) (0), 0, 0);
283
284         key_custom = gtk_radio_button_new_with_label(key_group, "");
285         key_group = gtk_radio_button_group(GTK_RADIO_BUTTON(key_custom));
286         gtk_widget_show(key_custom);
287         gtk_table_attach(GTK_TABLE(table1), key_custom, 0, 1, 2, 3,
288                          (GtkAttachOptions) (GTK_FILL),
289                          (GtkAttachOptions) (0), 0, 0);
290
291         label13 = gtk_label_new(_("Use default GnuPG key"));
292         gtk_widget_show(label13);
293         gtk_table_attach(GTK_TABLE(table1), label13, 1, 3, 0, 1,
294                          (GtkAttachOptions) (GTK_FILL),
295                          (GtkAttachOptions) (0), 0, 0);
296         gtk_misc_set_alignment(GTK_MISC(label13), 0, 0.5);
297
298         label14 = gtk_label_new(_("Select key by your email address"));
299         gtk_widget_show(label14);
300         gtk_table_attach(GTK_TABLE(table1), label14, 1, 3, 1, 2,
301                          (GtkAttachOptions) (GTK_FILL),
302                          (GtkAttachOptions) (0), 0, 0);
303         gtk_misc_set_alignment(GTK_MISC(label14), 0, 0.5);
304
305         label15 = gtk_label_new(_("Specify key manually"));
306         gtk_widget_show(label15);
307         gtk_table_attach(GTK_TABLE(table1), label15, 1, 3, 2, 3,
308                          (GtkAttachOptions) (GTK_FILL),
309                          (GtkAttachOptions) (0), 0, 0);
310         gtk_misc_set_alignment(GTK_MISC(label15), 0, 0.5);
311
312         label16 = gtk_label_new(_("User or key ID:"));
313         gtk_widget_show(label16);
314         gtk_table_attach(GTK_TABLE(table1), label16, 1, 2, 3, 4,
315                          (GtkAttachOptions) (GTK_FILL),
316                          (GtkAttachOptions) (0), 0, 0);
317         gtk_label_set_justify(GTK_LABEL(label16), GTK_JUSTIFY_LEFT);
318
319         keyid = gtk_entry_new();
320         gtk_widget_show(keyid);
321         gtk_table_attach(GTK_TABLE(table1), keyid, 2, 3, 3, 4,
322                          (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
323                          (GtkAttachOptions) (0), 0, 0);
324         /*** END GLADE CODE ***/
325
326         config = prefs_gpg_account_get_config(account);
327         switch (config->sign_key) {
328         case SIGN_KEY_DEFAULT:
329                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(key_default), TRUE);
330                 gtk_widget_set_sensitive(GTK_WIDGET(keyid), FALSE);
331                 break;
332         case SIGN_KEY_BY_FROM:
333                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(key_by_from), TRUE);
334                 gtk_widget_set_sensitive(GTK_WIDGET(keyid), FALSE);
335                 break;
336         case SIGN_KEY_CUSTOM:
337                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(key_custom), TRUE);
338                 gtk_widget_set_sensitive(GTK_WIDGET(keyid), TRUE);
339                 break;
340         }
341
342         if (config->sign_key_id != NULL)
343                 gtk_entry_set_text(GTK_ENTRY(keyid), config->sign_key_id);
344
345         g_signal_connect(G_OBJECT(key_custom), "toggled", G_CALLBACK(key_custom_toggled), page);
346
347         page->key_default = key_default;
348         page->key_by_from = key_by_from;
349         page->key_custom = key_custom;
350         page->keyid = keyid;
351
352         page->page.widget = vbox;
353         page->account = account;
354 }
355
356 static void prefs_gpg_account_destroy_widget_func(PrefsPage *_page)
357 {
358         /* nothing to do here */
359 }
360
361 static void prefs_gpg_account_save_func(PrefsPage *_page)
362 {
363         struct GPGAccountPage *page = (struct GPGAccountPage *) _page;
364         GPGAccountConfig *config;
365
366         config = prefs_gpg_account_get_config(page->account);
367
368         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->key_default)))
369                 config->sign_key = SIGN_KEY_DEFAULT;
370         else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->key_by_from)))
371                 config->sign_key = SIGN_KEY_BY_FROM;
372         else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->key_custom))) {
373                 config->sign_key = SIGN_KEY_CUSTOM;
374                 g_free(config->sign_key_id);
375                 config->sign_key_id = gtk_editable_get_chars(GTK_EDITABLE(page->keyid), 0, -1);
376         }
377
378         prefs_gpg_account_set_config(page->account, config);
379         prefs_gpg_account_free_config(config);
380 }
381
382 GPGConfig *prefs_gpg_get_config(void)
383 {
384         return &prefs_gpg;
385 }
386
387 void prefs_gpg_save_config(void)
388 {
389         PrefFile *pfile;
390         gchar *rcpath;
391
392         debug_print("Saving GPG config\n");
393
394         rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, COMMON_RC, NULL);
395         pfile = prefs_write_open(rcpath);
396         g_free(rcpath);
397         if (!pfile || (prefs_set_block_label(pfile, "GPG") < 0))
398                 return;
399
400         if (prefs_write_param(param, pfile->fp) < 0) {
401                 g_warning("failed to write GPG configuration to file\n");
402                 prefs_file_close_revert(pfile);
403                 return;
404         }
405         fprintf(pfile->fp, "\n");
406
407         prefs_file_close(pfile);
408 }
409
410 struct GPGAccountConfig *prefs_gpg_account_get_config(PrefsAccount *account)
411 {
412         GPGAccountConfig *config;
413         const gchar *confstr;
414         gchar **strv;
415
416         config = g_new0(GPGAccountConfig, 1);
417         config->sign_key = SIGN_KEY_DEFAULT;
418         config->sign_key_id = NULL;
419
420         confstr = prefs_account_get_privacy_prefs(account, "gpg");
421         if (confstr == NULL)
422                 return config;
423
424         strv = g_strsplit(confstr, ";", 0);
425         if (strv[0] != NULL) {
426                 if (!strcmp(strv[0], "DEFAULT"))
427                         config->sign_key = SIGN_KEY_DEFAULT;
428                 if (!strcmp(strv[0], "BY_FROM"))
429                         config->sign_key = SIGN_KEY_BY_FROM;
430                 if (!strcmp(strv[0], "CUSTOM")) {
431                         if (strv[1] != NULL) {
432                                 config->sign_key = SIGN_KEY_CUSTOM;
433                                 config->sign_key_id = g_strdup(strv[1]);
434                         } else
435                                 config->sign_key = SIGN_KEY_DEFAULT;
436                 }
437         }
438         g_strfreev(strv);
439
440         return config;
441 }
442
443 void prefs_gpg_account_set_config(PrefsAccount *account, GPGAccountConfig *config)
444 {
445         gchar *confstr = NULL;
446
447         switch (config->sign_key) {
448         case SIGN_KEY_DEFAULT:
449                 confstr = g_strdup("DEFAULT");
450                 break;
451         case SIGN_KEY_BY_FROM:
452                 confstr = g_strdup("BY_FROM");
453                 break;
454         case SIGN_KEY_CUSTOM:
455                 confstr = g_strdup_printf("CUSTOM;%s", config->sign_key_id);
456                 break;
457         default:
458                 confstr = g_strdup("");
459                 g_warning("prefs_gpg_account_set_config: bad sign_key val\n");
460         }
461
462         prefs_account_set_privacy_prefs(account, "gpg", confstr);
463
464         g_free(confstr);
465 }
466
467 void prefs_gpg_account_free_config(GPGAccountConfig *config)
468 {
469         g_free(config->sign_key_id);
470         g_free(config);
471 }
472
473 static struct GPGPage gpg_page;
474 static struct GPGAccountPage gpg_account_page;
475
476 void prefs_gpg_init()
477 {
478         static gchar *path[3];
479         gchar *rcpath;
480
481         prefs_set_default(param);
482         rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, COMMON_RC, NULL);
483         prefs_read_config(param, "GPG", rcpath, NULL);
484         g_free(rcpath);
485
486         path[0] = _("Plugins");
487         path[1] = _("GPG");
488         path[2] = NULL;
489
490         gpg_page.page.path = path;
491         gpg_page.page.create_widget = prefs_gpg_create_widget_func;
492         gpg_page.page.destroy_widget = prefs_gpg_destroy_widget_func;
493         gpg_page.page.save_page = prefs_gpg_save_func;
494         gpg_page.page.weight = 30.0;
495
496         prefs_gtk_register_page((PrefsPage *) &gpg_page);
497
498         gpg_account_page.page.path = path;
499         gpg_account_page.page.create_widget = prefs_gpg_account_create_widget_func;
500         gpg_account_page.page.destroy_widget = prefs_gpg_account_destroy_widget_func;
501         gpg_account_page.page.save_page = prefs_gpg_account_save_func;
502         gpg_account_page.page.weight = 30.0;
503
504         prefs_account_register_page((PrefsPage *) &gpg_account_page);
505 }
506
507 void prefs_gpg_done()
508 {
509         prefs_gtk_unregister_page((PrefsPage *) &gpg_page);
510         prefs_account_unregister_page((PrefsPage *) &gpg_account_page);
511 }