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