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