1 /* settingsdlg.c - The GNU Privacy Assistant
2 Copyright (C) 2002, Miguel Coca
3 Copyright (C) 2008 g10 Code GmbH.
4
5 This file is part of GPA.
6
7 GPA is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 GPA is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, see <http://www.gnu.org/licenses/>. */
19
20
21 /* Violation of GNOME standards: Cancel does not revert a previous
22 apply. Except for the UI mode, we do not auto-apply or syntax
23 check after focus change. The rationale for this is that:
24
25 * gpgconf operations are expensive.
26
27 * Some fields depend on each other and without a proper framework
28 for doing plausibility checks it is hard to get it right.
29
30 */
31
32
33 #ifdef HAVE_CONFIG_H
34 # include <config.h>
35 #endif
36
37 /* Required for the IP address check. */
38 #ifdef HAVE_W32_SYSTEM
39 # include <windows.h>
40 #else /*!HAVE_W32_SYSTEM*/
41 # include <sys/socket.h>
42 # include <netinet/in.h>
43 # include <arpa/inet.h>
44 #endif /*!HAVE_W32_SYSTEM*/
45
46
47 #include "gpa.h"
48 #include "gpakeyselector.h"
49 #include "keyserver.h"
50 #include "gtktools.h"
51 #include "confdialog.h"
52 #include "gpg-stuff.h"
53
54 #include "settingsdlg.h"
55
56 /* Object and class definition. */
57 struct _SettingsDlg
58 {
59 GtkDialog parent;
60
61 gboolean modified; /* True is there are unsaved changes. */
62 gboolean gnupg21; /* True if gnupg 2.1.0 or later is in use. */
63
64 /* Data for the user interface frame. */
65 struct {
66 GtkWidget *frame;
67 GtkToggleButton *advanced_mode;
68 GtkToggleButton *show_advanced_options;
69 } ui;
70
71 /* Data for the default key frame. */
72 struct {
73 GtkWidget *frame;
74 GpaKeySelector *list;
75
76 gpgme_key_t key; /* The selected key or NULL if none selected. */
77 } default_key;
78
79 /* Data for the keyserver frame. */
80 struct {
81 GtkWidget *frame;
82 GtkComboBox *combo;
83 char *url; /* Malloced URL or NULL if none selected. */
84 } keyserver;
85
86 /* Data for the auto-key-locate frame. */
87 struct {
88 int enabled; /* True if the AKL feature is enabled. */
89
90 GtkWidget *frame;
91 GtkComboBox *methods;
92 GtkWidget *addr_hbox;
93 GtkEntry *addr_entry;
94
95 int require_addr; /* A valid addr is required. */
96
97 int method_idx; /* Selected method's index into the akl_table. */
98 char *ip_addr; /* Malloced server address or NULL. */
99 } akl;
100
101 };
102
103 struct _SettingsDlgClass
104 {
105 GtkDialogClass parent_class;
106
107 };
108
109 static GObjectClass *parent_class;
110
111 /* We only want one instance of the settings dialog at a time. Thus
112 we use this variable to keep track of a created instance. */
113 static SettingsDlg *the_settings_dialog;
114
115
116
117 /* Identifiers for our properties. */
118 enum
119 {
120 PROP_0
121 };
122
123
124
125 /* A table with common and useful --auto-key-locate combinations. The
126 first entry "local" is a made-up which indicates that no
127 --auto-key-locate is active. "Custom" ist used for all settings
128 which can't be mapped to this table and is also the last entry in
129 the table indicating the end of the table. */
130 static struct {
131 const char *list;
132 const char *text;
133 } akl_table[] = {
134 { "l", N_("Local")},
135 #ifdef ENABLE_KEYSERVER_SUPPORT
136 { "lk", N_("Local, Keyserver")},
137 #endif
138 { "lp", N_("Local, PKA")},
139 #ifdef ENABLE_KEYSERVER_SUPPORT
140 { "lpk", N_("Local, PKA, Keyserver")},
141 { "lkp", N_("Local, Keyserver, PKA")},
142 #endif
143 { "lD", N_("Local, kDNS")},
144 #ifdef ENABLE_KEYSERVER_SUPPORT
145 { "lDk", N_("Local, kDNS, Keyserver")},
146 #endif
147 { "np", N_("PKA")},
148 { "nD", N_("kDNS")},
149 { NULL, N_("Custom")},
150 };
151
152
153
154 static void update_modified (SettingsDlg *dialog, int is_modified);
155
156
157
158
159 /*
160 User interface section.
161 */
162
163 /* Update what parts of the dialog are shown. */
164 void
update_show_advanced_options(SettingsDlg * dialog)165 update_show_advanced_options (SettingsDlg *dialog)
166 {
167 GpaOptions *options = gpa_options_get_instance ();
168
169 g_return_if_fail (IS_SETTINGS_DLG (dialog));
170
171 if (gpa_options_get_show_advanced_options (options))
172 {
173 #ifdef ENABLE_KEYSERVER_SUPPORT
174 if (!dialog->gnupg21)
175 gtk_widget_show_all (dialog->keyserver.frame);
176 #endif /*ENABLE_KEYSERVER_SUPPORT*/
177 if (dialog->akl.enabled)
178 gtk_widget_show_all (dialog->akl.frame);
179 }
180 else
181 {
182 #ifdef ENABLE_KEYSERVER_SUPPORT
183 if (!dialog->gnupg21)
184 gtk_widget_hide_all (dialog->keyserver.frame);
185 #endif /*ENABLE_KEYSERVER_SUPPORT*/
186 if (dialog->akl.enabled)
187 gtk_widget_hide_all (dialog->akl.frame);
188 }
189 }
190
191
192 static void
advanced_mode_toggled(GtkToggleButton * button,gpointer user_data)193 advanced_mode_toggled (GtkToggleButton *button, gpointer user_data)
194 {
195 gpa_options_set_simplified_ui (gpa_options_get_instance (),
196 !gtk_toggle_button_get_active (button));
197 }
198
199 static void
show_advanced_options_toggled(GtkToggleButton * button,gpointer user_data)200 show_advanced_options_toggled (GtkToggleButton *button, gpointer user_data)
201 {
202 SettingsDlg *dialog = user_data;
203
204 gpa_options_set_show_advanced_options
205 (gpa_options_get_instance (), gtk_toggle_button_get_active (button));
206 update_show_advanced_options (dialog);
207 }
208
209
210 static GtkWidget *
user_interface_mode_frame(SettingsDlg * dialog)211 user_interface_mode_frame (SettingsDlg *dialog)
212 {
213 GtkWidget *frame;
214 GtkWidget *label;
215 GtkWidget *frame_vbox;
216 GtkWidget *button;
217
218 /* Build UI. */
219 frame = gtk_frame_new (NULL);
220 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);
221 label = gtk_label_new (_("<b>User interface</b>"));
222 gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
223 gtk_frame_set_label_widget (GTK_FRAME (frame), label);
224
225 frame_vbox = gtk_vbox_new (FALSE, 0);
226 gtk_container_add (GTK_CONTAINER (frame), frame_vbox);
227
228 button = gtk_check_button_new_with_mnemonic (_("Use _advanced mode"));
229 gtk_container_add (GTK_CONTAINER (frame_vbox), button);
230 dialog->ui.advanced_mode = GTK_TOGGLE_BUTTON (button);
231 g_signal_connect (G_OBJECT (button), "toggled",
232 G_CALLBACK (advanced_mode_toggled), dialog);
233
234 button = gtk_check_button_new_with_mnemonic (_("Show advanced _options"));
235 gtk_container_add (GTK_CONTAINER (frame_vbox), button);
236 dialog->ui.show_advanced_options = GTK_TOGGLE_BUTTON (button);
237 g_signal_connect (G_OBJECT (button), "toggled",
238 G_CALLBACK (show_advanced_options_toggled), dialog);
239
240
241 return frame;
242 }
243
244
245
246
247 /*
248 Default key section.
249 */
250 static void
key_selected_cb(SettingsDlg * dialog)251 key_selected_cb (SettingsDlg *dialog)
252 {
253 GList *selected;
254
255 selected = gpa_key_selector_get_selected_keys (dialog->default_key.list);
256 gpgme_key_unref (dialog->default_key.key);
257 dialog->default_key.key = selected? selected->data : NULL;
258 if (dialog->default_key.key)
259 gpgme_key_ref (dialog->default_key.key);
260
261 g_list_free (selected);
262 update_modified (dialog, 1);
263 }
264
265 /* Returns NULL is the default key is valid. On error the erroneous
266 widget is returned. */
267 static GtkWidget *
check_default_key(SettingsDlg * dialog)268 check_default_key (SettingsDlg *dialog)
269 {
270 /* Make sure we have all required data. */
271 key_selected_cb (dialog);
272
273 /* We require that a default key has been selected. If not, we ask
274 the user whether to continue. */
275 if (!dialog->default_key.key)
276 {
277 GtkWidget *msg;
278 int resp;
279
280 msg = gtk_message_dialog_new (GTK_WINDOW(dialog),
281 GTK_DIALOG_DESTROY_WITH_PARENT,
282 GTK_MESSAGE_QUESTION,
283 GTK_BUTTONS_NONE,
284 "%s",
285 _("No default key has been selected. This may lead to problems "
286 "when signing or encrypting. For example you might later not "
287 "be able to read a mail written by you and encrypted to "
288 "someone else.\n\n"
289 "Please consider creating your own key and select it then."));
290 gtk_dialog_add_buttons (GTK_DIALOG (msg),
291 _("Continue without a default key"),
292 GTK_RESPONSE_YES,
293 _("Let me select a default key"),
294 GTK_RESPONSE_NO,
295 NULL);
296 gtk_dialog_set_default_response (GTK_DIALOG (msg), GTK_RESPONSE_NO);
297 resp = gtk_dialog_run (GTK_DIALOG (msg));
298 gtk_widget_destroy (msg);
299 if (resp != GTK_RESPONSE_YES)
300 return GTK_WIDGET (dialog->default_key.list);
301 }
302
303 return NULL;
304 }
305
306
307 static GtkWidget *
default_key_frame(SettingsDlg * dialog)308 default_key_frame (SettingsDlg *dialog)
309 {
310 GtkWidget *frame;
311 GtkWidget *label;
312 GtkWidget *list;
313 GtkWidget *scroller;
314
315 /* Build UI. */
316 frame = gtk_frame_new (NULL);
317 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);
318 label = gtk_label_new_with_mnemonic (_("<b>Default _key</b>"));
319 gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
320 gtk_frame_set_label_widget (GTK_FRAME (frame), label);
321
322 list = gpa_key_selector_new (TRUE, FALSE);
323 dialog->default_key.list = GPA_KEY_SELECTOR (list);
324 gtk_tree_selection_set_mode (gtk_tree_view_get_selection
325 (GTK_TREE_VIEW (list)), GTK_SELECTION_SINGLE);
326 scroller = gtk_scrolled_window_new (NULL, NULL);
327 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroller),
328 GTK_POLICY_AUTOMATIC,
329 GTK_POLICY_AUTOMATIC);
330 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroller),
331 GTK_SHADOW_IN);
332
333 gtk_widget_set_size_request (scroller, 320, 120);
334 gtk_container_set_border_width (GTK_CONTAINER (scroller), 5);
335 gtk_container_add (GTK_CONTAINER (scroller), list);
336 gtk_container_add (GTK_CONTAINER (frame), scroller);
337
338 /* Connect signals. */
339 g_signal_connect_swapped (G_OBJECT (gtk_tree_view_get_selection
340 (GTK_TREE_VIEW (list))),
341 "changed", G_CALLBACK (key_selected_cb), dialog);
342
343 dialog->default_key.frame = frame;
344
345 return frame;
346 }
347
348
349
350 /*
351 Default keyserver section.
352 */
353 #ifdef ENABLE_KEYSERVER_SUPPORT
354 static void
keyserver_selected_from_list_cb(SettingsDlg * dialog)355 keyserver_selected_from_list_cb (SettingsDlg *dialog)
356 {
357 char *text;
358
359 if (dialog->gnupg21)
360 return;
361
362 text = gtk_combo_box_get_active_text (dialog->keyserver.combo);
363 g_message ("got `%s'", text);
364 xfree (dialog->keyserver.url);
365 dialog->keyserver.url = (text && *text)? text : NULL;
366 update_modified (dialog, 1);
367 }
368 #endif /*ENABLE_KEYSERVER_SUPPORT*/
369
370
371
372 /* Return NULL if the default keyserver is valid. */
373 #ifdef ENABLE_KEYSERVER_SUPPORT
374 static GtkWidget *
check_default_keyserver(SettingsDlg * dialog)375 check_default_keyserver (SettingsDlg *dialog)
376 {
377 keyserver_spec_t kspec;
378
379 if (dialog->gnupg21)
380 return NULL; /* GnuPG manages the keyservers. */
381
382 keyserver_selected_from_list_cb (dialog);
383
384 if (!dialog->keyserver.url)
385 return NULL; /* No keyserver is just fine. */
386
387 kspec = parse_keyserver_uri (dialog->keyserver.url, 0, NULL, 0);
388 if (!kspec)
389 return GTK_WIDGET (dialog->keyserver.combo);
390 if (!kspec->host
391 || (kspec->scheme && !(!strcmp (kspec->scheme, "hkp")
392 || !strcmp (kspec->scheme, "http")
393 || !strcmp (kspec->scheme, "ldap")
394 || !strcmp (kspec->scheme, "finger")
395 || !strcmp (kspec->scheme, "mailto"))))
396 {
397 free_keyserver_spec (kspec);
398 return GTK_WIDGET (dialog->keyserver.combo);
399 }
400
401 free_keyserver_spec (kspec);
402 return NULL;
403 }
404 #endif /*ENABLE_KEYSERVER_SUPPORT*/
405
406
407
408 #ifdef ENABLE_KEYSERVER_SUPPORT
409 static void
append_to_combo(gpointer item,gpointer data)410 append_to_combo (gpointer item, gpointer data)
411 {
412 GtkWidget *combo = data;
413 gchar *text = item;
414
415 gtk_combo_box_append_text (GTK_COMBO_BOX (combo), text);
416 }
417 #endif /*ENABLE_KEYSERVER_SUPPORT*/
418
419
420 #ifdef ENABLE_KEYSERVER_SUPPORT
421 static GtkWidget *
default_keyserver_frame(SettingsDlg * dialog)422 default_keyserver_frame (SettingsDlg *dialog)
423 {
424 GtkWidget *frame;
425 GtkWidget *label;
426 GtkWidget *combo;
427 GList *servers;
428
429 /* Build UI */
430 frame = gtk_frame_new (NULL);
431 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);
432 label = gtk_label_new_with_mnemonic (_("<b>Default key_server</b>"));
433 gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
434 gtk_frame_set_label_widget (GTK_FRAME (frame), label);
435
436 combo = gtk_combo_box_entry_new_text ();
437 gtk_container_set_border_width (GTK_CONTAINER (combo), 5);
438 gtk_container_add (GTK_CONTAINER (frame), combo);
439 /* Set current value. */
440 servers = keyserver_get_as_glist ();
441 g_list_foreach (servers, append_to_combo, combo);
442 g_list_free (servers);
443 dialog->keyserver.combo = GTK_COMBO_BOX (combo);
444
445 g_signal_connect_swapped (G_OBJECT (combo),
446 "changed",
447 G_CALLBACK (keyserver_selected_from_list_cb),
448 dialog);
449
450 dialog->keyserver.frame = frame;
451
452 return frame;
453 }
454 #endif /*ENABLE_KEYSERVER_SUPPORT*/
455
456
457 /*
458 Auto Key Locate section.
459 */
460
461 static void
akl_method_changed_cb(SettingsDlg * dialog)462 akl_method_changed_cb (SettingsDlg *dialog)
463 {
464 int idx;
465
466 dialog->akl.require_addr = 0;
467 idx = gtk_combo_box_get_active (dialog->akl.methods);
468 if (idx < 0 || idx > DIM(akl_table))
469 {
470 dialog->akl.method_idx = -1;
471 return;
472 }
473 dialog->akl.method_idx = idx;
474
475 if (akl_table[idx].list && strchr (akl_table[idx].list, 'D'))
476 dialog->akl.require_addr = 1;
477
478 update_modified (dialog, 1);
479 }
480
481 static void
akl_addr_changed_cb(SettingsDlg * dialog)482 akl_addr_changed_cb (SettingsDlg *dialog)
483 {
484 const char *addr;
485 struct in_addr binaddr;
486
487 xfree (dialog->akl.ip_addr );
488 dialog->akl.ip_addr = NULL;
489
490 if (!GTK_WIDGET_IS_SENSITIVE (dialog->akl.addr_entry))
491 return;
492
493 addr = gtk_entry_get_text (dialog->akl.addr_entry);
494 if (!addr || !*addr || !inet_aton (addr, &binaddr) )
495 {
496 g_message ("IP-address is '%s' is NOT valid", addr? addr:"[none]");
497 return;
498 }
499
500 dialog->akl.ip_addr = xstrdup (addr);
501 g_message ("IP-address is '%s' is valid", addr);
502
503 update_modified (dialog, 1);
504 }
505
506
507 /* Returns NULL is the AKL data is valid. On error the erroneous
508 widget is returned. */
509 static GtkWidget *
check_akl(SettingsDlg * dialog)510 check_akl (SettingsDlg *dialog)
511 {
512 /* Make sure we have all required data. */
513 akl_method_changed_cb (dialog);
514 akl_addr_changed_cb (dialog);
515
516 if (dialog->akl.method_idx < 0)
517 return GTK_WIDGET (dialog->akl.methods);
518 if (dialog->akl.require_addr && !dialog->akl.ip_addr)
519 return GTK_WIDGET (dialog->akl.addr_entry);
520
521 return NULL;
522 }
523
524
525 static void
parse_akl(SettingsDlg * dialog)526 parse_akl (SettingsDlg *dialog)
527 {
528 akl_t akllist, akl;
529 char *akloption;
530 char list[10];
531 int listidx = 0;
532 int idx;
533
534 akloption = gpa_load_gpgconf_string ("gpg", "auto-key-locate");
535 if (!akloption)
536 {
537 dialog->akl.require_addr = 0;
538 dialog->akl.method_idx = 0;
539 /* Select the first entry ("Local"). */
540 gtk_combo_box_set_active (dialog->akl.methods, 0);
541 /* Set kDNS server to empty. */
542 gtk_entry_set_text (dialog->akl.addr_entry, "");
543 return;
544 }
545
546 /* Well, lets parse it. */
547 akllist = gpg_parse_auto_key_locate (akloption);
548 g_free (akloption);
549 for (akl = akllist; akl && listidx < sizeof list - 1; akl = akl->next)
550 {
551 keyserver_spec_t k = akl->spec;
552
553 switch (akl->type )
554 {
555 case AKL_NODEFAULT:
556 list[listidx++] = 'n';
557 break;
558 case AKL_LOCAL:
559 list[listidx++] = 'l';
560 break;
561 case AKL_CERT:
562 list[listidx++] = 'c';
563 break;
564 case AKL_PKA:
565 list[listidx++] = 'p';
566 break;
567 case AKL_LDAP:
568 list[listidx++] = 'L';
569 break;
570 case AKL_KEYSERVER:
571 list[listidx++] = 'k';
572 break;
573 case AKL_SPEC:
574 if ( (k = akl->spec)
575 && k->scheme && !strcmp (k->scheme, "kdns")
576 && !k->auth
577 && k->host
578 && !k->port
579 && k->path && !strcmp (k->path, "/?at=_kdnscert&usevc=1")
580 && !k->opaque
581 && !k->options)
582 {
583 gtk_entry_set_text (dialog->akl.addr_entry, k->host);
584 list[listidx++] = 'D';
585 }
586 else
587 list[listidx++] = '?';
588 break;
589
590 default:
591 list[listidx++] = '?';
592 break;
593 }
594 }
595 list[listidx] = 0;
596 gpg_release_akl (akllist);
597 g_debug ("akl list: %s", list);
598
599 for (idx=0; akl_table[idx].list; idx++)
600 if (!strcmp (akl_table[idx].list, list))
601 break;
602 /* (The last entry of the table is the one used for no-match.) */
603 gtk_combo_box_set_active (dialog->akl.methods, idx);
604 dialog->akl.method_idx = idx;
605 /* Enable the kdns Server entry if one is defined. For ease of
606 implementation we have already put the server address into the
607 entry field even if there might be no match. */
608 if (akl_table[idx].list && strchr (akl_table[idx].list, 'D'))
609 dialog->akl.require_addr = 1;
610 }
611
612
613
614 static GtkWidget *
auto_key_locate_frame(SettingsDlg * dialog)615 auto_key_locate_frame (SettingsDlg *dialog)
616 {
617 const char *tooltip;
618 GtkWidget *frame;
619 GtkWidget *label;
620 GtkWidget *frame_vbox;
621 GtkWidget *combo;
622 GtkWidget *entry;
623 GtkWidget *hbox;
624 int xpad, ypad;
625 int idx;
626
627 /* Build UI. */
628 frame = gtk_frame_new (NULL);
629 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);
630 label = gtk_label_new_with_mnemonic (_("<b>Auto key _locate</b>"));
631 gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
632 gtk_frame_set_label_widget (GTK_FRAME (frame), label);
633
634 frame_vbox = gtk_vbox_new (FALSE, 0);
635 gtk_container_add (GTK_CONTAINER (frame), frame_vbox);
636
637 /* The method selection. */
638 hbox = gtk_hbox_new (FALSE, 0);
639 gtk_container_add (GTK_CONTAINER (frame_vbox), hbox);
640 tooltip = _("The list of methods to locate keys via an email address.\n"
641 "All given methods are used in turn until a matching "
642 "key is found. The supported methods are:\n"
643 " Local\n"
644 " - Use the local keyring.\n"
645 #ifdef ENABLE_KEYSERVER_SUPPORT
646 " Keyserver\n"
647 " - Use the default keyserver.\n"
648 #endif /*ENABLE_KEYSERVER_SUPPORT*/
649 " PKA\n"
650 " - Use the Public Key Association.\n"
651 " kDNS\n"
652 " - Use kDNS with the nameserver below.\n"
653 " Custom\n"
654 " - Configured in the backend dialog.\n");
655 gpa_add_tooltip (hbox, tooltip);
656
657 label = gtk_label_new (_("Method:"));
658 gtk_misc_get_padding (GTK_MISC (label), &xpad, &ypad);
659 xpad += 5;
660 gtk_misc_set_padding (GTK_MISC (label), xpad, ypad);
661 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
662
663 combo = gtk_combo_box_new_text ();
664 gtk_box_pack_start (GTK_BOX (hbox), combo, FALSE, FALSE, 0);
665
666 idx=0;
667 do
668 gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _(akl_table[idx].text));
669 while (akl_table[idx++].list);
670
671 /* The kDNS server. */
672 hbox = gtk_hbox_new (FALSE, 0);
673 gtk_container_add (GTK_CONTAINER (frame_vbox), hbox);
674 tooltip = _("The IP address of the nameserver used for the kDNS method.");
675 gpa_add_tooltip (hbox, tooltip);
676 label = gtk_label_new (_("kDNS Server:"));
677 gtk_misc_get_padding (GTK_MISC (label), &xpad, &ypad);
678 xpad += 5;
679 gtk_misc_set_padding (GTK_MISC (label), xpad, ypad);
680 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
681
682 entry = gtk_entry_new ();
683 gtk_entry_set_max_length (GTK_ENTRY(entry), 3+1+3+1+3+1+3);
684 gtk_entry_set_width_chars (GTK_ENTRY(entry), 3+1+3+1+3+1+3);
685 gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, FALSE, 0);
686
687 dialog->akl.addr_hbox = hbox;
688 dialog->akl.addr_entry = GTK_ENTRY (entry);
689 dialog->akl.methods = GTK_COMBO_BOX (combo);
690
691 g_signal_connect_swapped (G_OBJECT (combo),
692 "changed",
693 G_CALLBACK (akl_method_changed_cb), dialog);
694 g_signal_connect_swapped (G_OBJECT (entry),
695 "changed",
696 G_CALLBACK (akl_addr_changed_cb), dialog);
697
698 dialog->akl.frame = frame;
699
700 return frame;
701 }
702
703 /* Update the state of the action buttons. */
704 static void
update_modified(SettingsDlg * dialog,int is_modified)705 update_modified (SettingsDlg *dialog, int is_modified)
706 {
707 int newstate = !!is_modified;
708
709 dialog->modified = newstate;
710
711 gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog),
712 GTK_RESPONSE_APPLY, newstate);
713
714 if (dialog->akl.enabled)
715 gtk_widget_set_sensitive (dialog->akl.addr_hbox, dialog->akl.require_addr);
716 }
717
718
719 static void
load_settings(SettingsDlg * dialog)720 load_settings (SettingsDlg *dialog)
721 {
722 GpaOptions *options = gpa_options_get_instance ();
723
724 g_return_if_fail (IS_SETTINGS_DLG (dialog));
725
726 /* UI section. */
727 gtk_toggle_button_set_active
728 (dialog->ui.advanced_mode, !gpa_options_get_simplified_ui (options));
729 gtk_toggle_button_set_active
730 (dialog->ui.show_advanced_options,
731 !!gpa_options_get_show_advanced_options (options));
732
733 /* Default key section. */
734 /*gpa_options_get_default_key (options);*/
735 /* FIXME: Need to select the one from the list. */
736
737
738 /* Default keyserver section. */
739 #ifdef ENABLE_KEYSERVER_SUPPORT
740 if (!dialog->gnupg21)
741 {
742 gtk_entry_set_text (GTK_ENTRY
743 (gtk_bin_get_child
744 (GTK_BIN (dialog->keyserver.combo))),
745 gpa_options_get_default_keyserver (options));
746 }
747 #endif /*ENABLE_KEYSERVER_SUPPORT*/
748
749 /* AKL section. */
750 if (dialog->akl.enabled)
751 parse_akl (dialog);
752
753
754 update_modified (dialog, 0);
755 }
756
757
758 /* Save all settings, return 0 on success. */
759 static int
save_settings(SettingsDlg * dialog)760 save_settings (SettingsDlg *dialog)
761 {
762 GtkWidget *errwdg;
763
764 if (!dialog->modified)
765 return 0; /* No need to save anything. */
766
767 if ((errwdg = check_default_key (dialog)))
768 {
769 gtk_widget_grab_focus (errwdg);
770 return -1;
771 }
772
773 #ifdef ENABLE_KEYSERVER_SUPPORT
774 if (!dialog->gnupg21)
775 {
776 if ((errwdg = check_default_keyserver (dialog)))
777 {
778 gpa_window_error
779 (_("The URL given for the keyserver is not valid."),
780 GTK_WIDGET (dialog));
781 gtk_widget_grab_focus (errwdg);
782 return -1;
783 }
784 }
785 #endif /*ENABLE_KEYSERVER_SUPPORT*/
786
787 if ( dialog->akl.enabled && (errwdg = check_akl (dialog)))
788 {
789 gpa_window_error
790 (_("The data given for \"Auto key locate\" is not valid."),
791 GTK_WIDGET (dialog));
792 gtk_widget_grab_focus (errwdg);
793 return -1;
794 }
795
796 gpa_options_set_default_key (gpa_options_get_instance (),
797 dialog->default_key.key);
798
799
800 #ifdef ENABLE_KEYSERVER_SUPPORT
801 if (!dialog->gnupg21)
802 gpa_options_set_default_keyserver (gpa_options_get_instance (),
803 dialog->keyserver.url);
804 #endif /*ENABLE_KEYSERVER_SUPPORT*/
805
806 if (!dialog->akl.enabled)
807 ;
808 else if (dialog->akl.method_idx == -1)
809 ; /* oops: none selected. */
810 else if (!akl_table[dialog->akl.method_idx].list)
811 {
812 /* Custom setting: Do nothing. */
813 }
814 else
815 {
816 const char *methods = akl_table[dialog->akl.method_idx].list;
817 GString *newakl;
818
819 newakl = g_string_new ("");
820 for (; *methods; methods++)
821 {
822 if (newakl->len)
823 g_string_append_c (newakl, ',');
824 switch (*methods)
825 {
826 case 'n':
827 g_string_append (newakl, "nodefault");
828 break;
829 case 'l':
830 g_string_append (newakl, "local");
831 break;
832 case 'c':
833 g_string_append (newakl, "cert");
834 break;
835 case 'L':
836 g_string_append (newakl, "ldap");
837 break;
838 case 'k':
839 g_string_append (newakl, "keyserver");
840 break;
841 case 'D':
842 g_string_append_printf (newakl,
843 "kdns://%s/?at=_kdnscert&usevc=1",
844 dialog->akl.ip_addr ?
845 dialog->akl.ip_addr : "");
846 break;
847 default:
848 if (newakl->len)
849 g_string_truncate (newakl, newakl->len - 1);
850 break;
851 }
852 }
853 gpa_store_gpgconf_string ("gpg", "auto-key-locate", newakl->str);
854 g_string_free (newakl, TRUE);
855 }
856 return 0;
857 }
858
859
860 /* Handle the response signal. */
861 static void
dialog_response(GtkDialog * dialog,gint response)862 dialog_response (GtkDialog *dialog, gint response)
863 {
864 switch (response)
865 {
866 case GTK_RESPONSE_OK:
867 if (save_settings (SETTINGS_DLG (dialog)))
868 return;
869 break;
870
871 case GTK_RESPONSE_APPLY:
872 if (save_settings (SETTINGS_DLG (dialog)))
873 return;
874 load_settings (SETTINGS_DLG (dialog));
875 return; /* Do not close. */
876
877 default:
878 break;
879 }
880
881 gtk_widget_destroy (GTK_WIDGET(dialog));
882 }
883
884
885 /************************************************************
886 ****************** Object Management ********************
887 ************************************************************/
888
889
890 static void
settings_dlg_finalize(GObject * object)891 settings_dlg_finalize (GObject *object)
892 {
893 SettingsDlg *dialog = SETTINGS_DLG (object);
894
895 gpgme_key_unref (dialog->default_key.key);
896 dialog->default_key.key = NULL;
897
898 xfree (dialog->keyserver.url);
899 dialog->keyserver.url = NULL;
900
901 xfree (dialog->akl.ip_addr);
902 dialog->akl.ip_addr = NULL;
903
904
905 G_OBJECT_CLASS (parent_class)->finalize (object);
906 }
907
908
909 static void
settings_dlg_init(SettingsDlg * dialog)910 settings_dlg_init (SettingsDlg *dialog)
911 {
912 dialog->akl.method_idx = -1;
913 dialog->gnupg21 = is_gpg_version_at_least ("2.1.0");
914 }
915
916
917 static GObject*
settings_dlg_constructor(GType type,guint n_construct_properties,GObjectConstructParam * construct_properties)918 settings_dlg_constructor (GType type, guint n_construct_properties,
919 GObjectConstructParam *construct_properties)
920 {
921 GObject *object;
922 SettingsDlg *dialog;
923 GtkWidget *frame;
924
925 object = parent_class->constructor (type,
926 n_construct_properties,
927 construct_properties);
928 dialog = SETTINGS_DLG (object);
929 gpa_window_set_title (GTK_WINDOW (dialog), _("Settings"));
930 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
931 GTK_STOCK_APPLY, GTK_RESPONSE_APPLY,
932 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
933 GTK_STOCK_OK, GTK_RESPONSE_OK,
934 NULL);
935 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
936 gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
937 GTK_RESPONSE_OK,
938 GTK_RESPONSE_CANCEL,
939 GTK_RESPONSE_APPLY,
940 -1);
941
942 /* The UI mode section. */
943 frame = user_interface_mode_frame (dialog);
944 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), frame,
945 FALSE, FALSE, 0);
946
947 /* The default key section. */
948 frame = default_key_frame (dialog);
949 gtk_box_pack_start_defaults (GTK_BOX (GTK_DIALOG (dialog)->vbox), frame);
950
951 /* The default keyserver section. Note that there is no keyserver
952 entry if we are using gnupg 2.1. There we do not have the
953 keyserver helpers anymore and thus the keyservers are to be
954 enabled in the backend preferences. */
955 #ifdef ENABLE_KEYSERVER_SUPPORT
956 if (!dialog->gnupg21)
957 {
958 frame = default_keyserver_frame (dialog);
959 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), frame,
960 FALSE, FALSE, 0);
961 }
962 #endif /*ENABLE_KEYSERVER_SUPPORT*/
963
964 /* The auto key locate section. */
965 dialog->akl.enabled = dialog->gnupg21;
966 if (dialog->akl.enabled)
967 {
968 frame = auto_key_locate_frame (dialog);
969 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), frame,
970 FALSE, FALSE, 0);
971 }
972
973 /* Connect the response signal. */
974 g_signal_connect (GTK_OBJECT (dialog), "response",
975 G_CALLBACK (dialog_response), NULL);
976
977
978 /* Load values. */
979 load_settings (dialog);
980
981 /* Show all windows and hide those we don't want. */
982 gtk_widget_show_all (GTK_WIDGET(dialog));
983 update_show_advanced_options (dialog);
984
985 return object;
986 }
987
988
989 static void
settings_dlg_class_init(SettingsDlgClass * klass)990 settings_dlg_class_init (SettingsDlgClass *klass)
991 {
992 GObjectClass *object_class = G_OBJECT_CLASS (klass);
993
994 parent_class = g_type_class_peek_parent (klass);
995
996 object_class->constructor = settings_dlg_constructor;
997 object_class->finalize = settings_dlg_finalize;
998
999 }
1000
1001
1002 GType
settings_dlg_get_type(void)1003 settings_dlg_get_type (void)
1004 {
1005 static GType this_type;
1006
1007 if (!this_type)
1008 {
1009 static const GTypeInfo this_info =
1010 {
1011 sizeof (SettingsDlgClass),
1012 (GBaseInitFunc) NULL,
1013 (GBaseFinalizeFunc) NULL,
1014 (GClassInitFunc) settings_dlg_class_init,
1015 NULL, /* class_finalize */
1016 NULL, /* class_data */
1017
1018 sizeof (SettingsDlg),
1019 0, /* n_preallocs */
1020 (GInstanceInitFunc) settings_dlg_init,
1021 };
1022
1023 this_type = g_type_register_static (GTK_TYPE_DIALOG,
1024 "SettingsDlg",
1025 &this_info, 0);
1026 }
1027
1028 return this_type;
1029 }
1030
1031
1032
1033 /************************************************************
1034 ********************** Public API ************************
1035 ************************************************************/
1036
1037 /* Show the preference dialog and it create it if not yet done. */
1038 void
settings_dlg_new(GtkWidget * parent)1039 settings_dlg_new (GtkWidget *parent)
1040 {
1041 if (parent)
1042 g_return_if_fail (GTK_IS_WINDOW (parent));
1043
1044 if (!the_settings_dialog)
1045 {
1046 the_settings_dialog = g_object_new (SETTINGS_DLG_TYPE, NULL);
1047 g_signal_connect (the_settings_dialog,
1048 "destroy",
1049 G_CALLBACK (gtk_widget_destroyed),
1050 &the_settings_dialog);
1051
1052 }
1053
1054 if (parent
1055 && (GTK_WINDOW (parent)
1056 != gtk_window_get_transient_for (GTK_WINDOW (the_settings_dialog))))
1057 gtk_window_set_transient_for (GTK_WINDOW (the_settings_dialog),
1058 GTK_WINDOW (parent));
1059
1060 gtk_window_present (GTK_WINDOW (the_settings_dialog));
1061 }
1062
1063 /* Tell whether the settings dialog is open. */
1064 gboolean
settings_is_open(void)1065 settings_is_open (void)
1066 {
1067 return !!the_settings_dialog;
1068 }
1069