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