1 /* select-keys.c - GTK+ based key selection
2 * Copyright (C) 2001-2016 Werner Koch (dd9jn) and the Claws Mail team
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21
22 #ifdef USE_GPGME
23 #include <stdio.h>
24 #include <stdlib.h>
25
26 #include <glib.h>
27 #include <glib/gi18n.h>
28 #include <gdk/gdkkeysyms.h>
29 #include <gtk/gtk.h>
30 #include "select-keys.h"
31 #include "utils.h"
32 #include "gtkutils.h"
33 #include "inputdialog.h"
34 #include "manage_window.h"
35 #include "alertpanel.h"
36
37 #define DIM(v) (sizeof(v)/sizeof((v)[0]))
38 #define DIMof(type,member) DIM(((type *)0)->member)
39
40
41 enum col_titles {
42 COL_ALGO,
43 COL_KEYID,
44 COL_NAME,
45 COL_ADDRESS,
46 COL_TRUST,
47 COL_PTR,
48
49 N_COL_TITLES
50 };
51
52 #define COL_ALGO_WIDTH 70
53 #define COL_KEYID_WIDTH 120
54 #define COL_NAME_WIDTH 115
55 #define COL_ADDRESS_WIDTH 140
56 #define COL_TRUST_WIDTH 20
57
58 struct select_keys_s {
59 int okay;
60 GtkWidget *window;
61 GtkLabel *toplabel;
62 GtkWidget *view;
63 const char *pattern;
64 unsigned int num_keys;
65 gpgme_key_t *kset;
66 gpgme_ctx_t select_ctx;
67 gpgme_protocol_t proto;
68 GtkSortType sort_type;
69 enum col_titles sort_column;
70 SelectionResult result;
71 };
72
73
74 static void set_row (GtkListStore *store, gpgme_key_t key, gpgme_protocol_t proto);
75 static gpgme_key_t fill_view (struct select_keys_s *sk, const char *pattern,
76 gpgme_protocol_t proto);
77 static void create_dialog (struct select_keys_s *sk);
78 static void open_dialog (struct select_keys_s *sk);
79 static void close_dialog (struct select_keys_s *sk);
80 static gint delete_event_cb (GtkWidget *widget,
81 GdkEventAny *event, gpointer data);
82 static gboolean key_pressed_cb (GtkWidget *widget,
83 GdkEventKey *event, gpointer data);
84 static void select_btn_cb (GtkWidget *widget, gpointer data);
85 static void cancel_btn_cb (GtkWidget *widget, gpointer data);
86 static void dont_encrypt_btn_cb (GtkWidget *widget, gpointer data);
87 static void other_btn_cb (GtkWidget *widget, gpointer data);
88
89 static gboolean use_untrusted (gpgme_key_t, gpgme_user_id_t uid, gpgme_protocol_t proto);
90
91 static void
update_progress(struct select_keys_s * sk,int running,const char * pattern)92 update_progress (struct select_keys_s *sk, int running, const char *pattern)
93 {
94 static int windmill[] = { '-', '\\', '|', '/' };
95 char *buf;
96
97 if (!running)
98 buf = g_strdup_printf (_("No exact match for '%s'; please select the key."),
99 pattern);
100 else
101 buf = g_strdup_printf (_("Collecting info for '%s' ... %c"),
102 pattern,
103 windmill[running%DIM(windmill)]);
104 gtk_label_set_text (sk->toplabel, buf);
105 g_free (buf);
106 }
107
108
109 /**
110 * gpgmegtk_recipient_selection:
111 * @recp_names: A list of email addresses
112 *
113 * Select a list of recipients from a given list of email addresses.
114 * This may pop up a window to present the user a choice, it will also
115 * check that the recipients key are all valid.
116 *
117 * Return value: NULL on error or a list of list of recipients.
118 **/
119 gpgme_key_t *
gpgmegtk_recipient_selection(GSList * recp_names,SelectionResult * result,gpgme_protocol_t proto)120 gpgmegtk_recipient_selection (GSList *recp_names, SelectionResult *result,
121 gpgme_protocol_t proto)
122 {
123 struct select_keys_s sk;
124 gpgme_key_t key = NULL;
125 memset (&sk, 0, sizeof sk);
126
127 open_dialog (&sk);
128
129 do {
130 sk.pattern = recp_names? recp_names->data:NULL;
131 sk.proto = proto;
132 if (sk.view != NULL) {
133 GtkTreeModel *model =
134 gtk_tree_view_get_model(GTK_TREE_VIEW(sk.view));
135 gtk_list_store_clear(GTK_LIST_STORE(model));
136 }
137 key = fill_view (&sk, sk.pattern, proto);
138 update_progress (&sk, 0, sk.pattern ? sk.pattern : "NULL");
139 if (!key) {
140 gtk_widget_show_all (sk.window);
141 gtk_main ();
142 } else {
143 gtk_widget_hide (sk.window);
144 sk.kset = g_realloc(sk.kset,
145 sizeof(gpgme_key_t) * (sk.num_keys + 1));
146 gpgme_key_ref(key);
147 sk.kset[sk.num_keys] = key;
148 sk.num_keys++;
149 sk.okay = 1;
150 sk.result = KEY_SELECTION_OK;
151 gpgme_release (sk.select_ctx);
152 sk.select_ctx = NULL;
153 debug_print("used %s\n", key->uids->email);
154 }
155 key = NULL;
156 if (recp_names)
157 recp_names = recp_names->next;
158 } while (sk.okay && recp_names);
159
160 close_dialog (&sk);
161
162 if (!sk.okay) {
163 g_free(sk.kset);
164 sk.kset = NULL;
165 } else {
166 sk.kset = g_realloc(sk.kset, sizeof(gpgme_key_t) * (sk.num_keys + 1));
167 sk.kset[sk.num_keys] = NULL;
168 }
169 if (result)
170 *result = sk.result;
171 return sk.kset;
172 }
173
174 static void
set_row(GtkListStore * store,gpgme_key_t key,gpgme_protocol_t proto)175 set_row (GtkListStore *store, gpgme_key_t key, gpgme_protocol_t proto)
176 {
177 const gchar *s;
178 gchar *algo_buf, *name, *address;
179 GtkTreeIter iter;
180 gsize by_read = 0, by_written = 0;
181 gchar *ret_str = NULL;
182
183 /* first check whether the key is capable of encryption which is not
184 * the case for revoked, expired or sign-only keys */
185 if (!key->can_encrypt || key->revoked || key->expired || key->disabled)
186 return;
187
188 algo_buf = g_strdup_printf ("%du/%s",
189 key->subkeys->length,
190 gpgme_pubkey_algo_name(key->subkeys->pubkey_algo) );
191
192 s = key->uids->name;
193 if (!s || !*s)
194 s = key->uids->uid;
195 if (proto == GPGME_PROTOCOL_CMS) {
196 if (strstr(s, ",CN="))
197 s = strstr(s, ",CN=")+4;
198 else if (strstr(s, "CN="))
199 s = strstr(s, "CN=")+3;
200 }
201
202 ret_str = NULL;
203 if (!g_utf8_validate(s, -1, NULL))
204 ret_str = g_locale_to_utf8 (s, strlen(s), &by_read, &by_written, NULL);
205 if (ret_str && by_written) {
206 s = ret_str;
207 }
208 name = g_strdup(s);
209
210 if (proto == GPGME_PROTOCOL_CMS && (!key->uids->email || !*key->uids->email)) {
211 gpgme_user_id_t uid = key->uids->next;
212 if (uid)
213 s = uid->email;
214 else
215 s = key->uids->email;
216 } else {
217 s = key->uids->email;
218 }
219
220 ret_str = NULL;
221 if (!g_utf8_validate(s, -1, NULL))
222 ret_str = g_locale_to_utf8 (s, strlen(s), &by_read, &by_written, NULL);
223 if (ret_str && by_written) {
224 s = ret_str;
225 }
226 address = g_strdup(s);
227
228 switch (key->uids->validity)
229 {
230 case GPGME_VALIDITY_UNDEFINED:
231 s = _("Undefined");
232 break;
233 case GPGME_VALIDITY_NEVER:
234 s = _("Never");
235 break;
236 case GPGME_VALIDITY_MARGINAL:
237 s = _("Marginal");
238 break;
239 case GPGME_VALIDITY_FULL:
240 s = _("Full");
241 break;
242 case GPGME_VALIDITY_ULTIMATE:
243 s = _("Ultimate");
244 break;
245 case GPGME_VALIDITY_UNKNOWN:
246 default:
247 s = _("Unknown");
248 break;
249 }
250
251 gtk_list_store_append(store, &iter);
252 gtk_list_store_set(store, &iter,
253 COL_ALGO, algo_buf,
254 COL_KEYID, key->subkeys->keyid,
255 COL_NAME, name,
256 COL_ADDRESS, address,
257 COL_TRUST, s,
258 COL_PTR, key,
259 -1);
260 gpgme_key_ref(key);
261
262 g_free(name);
263 g_free(address);
264 g_free (algo_buf);
265 }
266
267 static gpgme_key_t
fill_view(struct select_keys_s * sk,const char * pattern,gpgme_protocol_t proto)268 fill_view (struct select_keys_s *sk, const char *pattern, gpgme_protocol_t proto)
269 {
270 GtkWidget *view;
271 GtkTreeModel *model;
272 GtkTreeSelection *sel;
273 GtkTreeIter iter;
274 gpgme_ctx_t ctx;
275 gpgme_error_t err;
276 gpgme_key_t key;
277 int running=0;
278 int num_results = 0;
279 gboolean exact_match = FALSE;
280 gpgme_key_t last_key = NULL;
281 gpgme_user_id_t last_uid = NULL;
282
283 cm_return_val_if_fail (sk, NULL);
284
285 view = sk->view;
286 cm_return_val_if_fail (view, NULL);
287 model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
288
289 debug_print ("select_keys:fill_view: pattern '%s' proto %d\n", pattern != NULL ? pattern : "NULL", proto);
290
291 err = gpgme_new (&ctx);
292 g_assert (!err);
293
294 gpgme_set_protocol(ctx, proto);
295 sk->select_ctx = ctx;
296
297 update_progress (sk, ++running, pattern);
298 while (gtk_events_pending ())
299 gtk_main_iteration ();
300
301 err = gpgme_op_keylist_start (ctx, pattern, 0);
302 if (err) {
303 debug_print ("** gpgme_op_keylist_start(%s) failed: %s\n",
304 pattern != NULL ? pattern : "NULL", gpgme_strerror (err));
305 sk->select_ctx = NULL;
306 gpgme_release(ctx);
307 return NULL;
308 }
309 update_progress (sk, ++running, pattern);
310 while ( !(err = gpgme_op_keylist_next ( ctx, &key )) ) {
311 gpgme_user_id_t uid = key->uids;
312 if (!key->can_encrypt || key->revoked || key->expired || key->disabled) {
313 gpgme_key_unref(key);
314 continue;
315 }
316 debug_print ("%% %s:%d: insert\n", __FILE__ ,__LINE__ );
317 set_row (GTK_LIST_STORE(model), key, proto );
318 for (; uid; uid = uid->next) {
319 gchar *raw_mail = NULL;
320
321 if (!uid->email)
322 continue;
323 if (uid->revoked || uid->invalid)
324 continue;
325 raw_mail = g_strdup(uid->email);
326 extract_address(raw_mail);
327 if (pattern != NULL && !strcasecmp(pattern, raw_mail)) {
328 exact_match = TRUE;
329 last_uid = uid;
330 g_free(raw_mail);
331 break;
332 }
333 g_free(raw_mail);
334 }
335
336 /* Select the first row */
337 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
338 if (gtk_tree_model_get_iter_first(model, &iter))
339 gtk_tree_selection_select_iter(sel, &iter);
340
341 num_results++;
342 if (last_key != NULL)
343 gpgme_key_unref(last_key);
344 last_key = key;
345 key = NULL;
346 update_progress (sk, ++running, pattern);
347 while (gtk_events_pending ())
348 gtk_main_iteration ();
349 }
350
351 if (exact_match == TRUE && num_results == 1) {
352 if (last_key->uids->validity < GPGME_VALIDITY_FULL &&
353 !use_untrusted(last_key, last_uid, proto))
354 exact_match = FALSE;
355 }
356
357 debug_print ("%% %s:%d: ready\n", __FILE__ ,__LINE__ );
358 if (gpgme_err_code(err) != GPG_ERR_EOF) {
359 debug_print ("** gpgme_op_keylist_next failed: %s\n",
360 gpgme_strerror (err));
361 gpgme_op_keylist_end(ctx);
362 }
363 if (!exact_match || num_results != 1) {
364 sk->select_ctx = NULL;
365 gpgme_release (ctx);
366 }
367
368 if (exact_match && num_results == 1)
369 return last_key;
370
371 if (last_key != NULL)
372 gpgme_key_unref(last_key);
373
374 return NULL;
375 }
376
377
378 static void
view_row_activated_cb(GtkTreeView * view,GtkTreePath * path,GtkTreeViewColumn * column,gpointer user_data)379 view_row_activated_cb(GtkTreeView *view,
380 GtkTreePath *path,
381 GtkTreeViewColumn *column,
382 gpointer user_data)
383 {
384 select_btn_cb(NULL, user_data);
385 }
386
387
388 static void
create_dialog(struct select_keys_s * sk)389 create_dialog (struct select_keys_s *sk)
390 {
391 GtkWidget *window;
392 GtkWidget *vbox, *vbox2, *hbox;
393 GtkWidget *bbox;
394 GtkWidget *scrolledwin;
395 GtkWidget *view;
396 GtkWidget *label;
397 GtkWidget *select_btn, *cancel_btn, *dont_encrypt_btn, *other_btn;
398 GtkListStore *store;
399 GtkCellRenderer *rdr;
400 GtkTreeViewColumn *col;
401 GtkTreeSelection *sel;
402 gint i = 0;
403
404 g_assert (!sk->window);
405 window = gtkut_window_new (GTK_WINDOW_TOPLEVEL, "select-keys");
406 gtk_widget_set_size_request (window, 560, 280);
407 gtk_container_set_border_width (GTK_CONTAINER (window), 8);
408 gtk_window_set_title (GTK_WINDOW (window), _("Select Keys"));
409 gtk_window_set_modal (GTK_WINDOW (window), TRUE);
410 gtk_window_set_type_hint(GTK_WINDOW(window), GDK_WINDOW_TYPE_HINT_DIALOG);
411 g_signal_connect (G_OBJECT (window), "delete_event",
412 G_CALLBACK (delete_event_cb), sk);
413 g_signal_connect (G_OBJECT (window), "key_press_event",
414 G_CALLBACK (key_pressed_cb), sk);
415 MANAGE_WINDOW_SIGNALS_CONNECT (window);
416
417 vbox = gtk_vbox_new (FALSE, 8);
418 gtk_container_add (GTK_CONTAINER (window), vbox);
419
420 hbox = gtk_hbox_new(FALSE, 4);
421 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
422 label = gtk_label_new ( "" );
423 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
424
425 hbox = gtk_hbox_new (FALSE, 8);
426 gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
427 gtk_container_set_border_width (GTK_CONTAINER (hbox), 2);
428
429 scrolledwin = gtk_scrolled_window_new (NULL, NULL);
430 gtk_box_pack_start (GTK_BOX (hbox), scrolledwin, TRUE, TRUE, 0);
431 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwin),
432 GTK_POLICY_AUTOMATIC,
433 GTK_POLICY_AUTOMATIC);
434
435 store = gtk_list_store_new(N_COL_TITLES,
436 G_TYPE_STRING,
437 G_TYPE_STRING,
438 G_TYPE_STRING,
439 G_TYPE_STRING,
440 G_TYPE_STRING,
441 G_TYPE_POINTER,
442 -1);
443
444 view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
445 g_object_unref(store);
446 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), TRUE);
447 gtk_tree_view_set_reorderable(GTK_TREE_VIEW(view), FALSE);
448 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
449 gtk_tree_selection_set_mode(sel, GTK_SELECTION_BROWSE);
450
451 rdr = gtk_cell_renderer_text_new();
452 col = gtk_tree_view_column_new_with_attributes(_("Size"), rdr,
453 "markup", COL_ALGO, NULL);
454 gtk_tree_view_column_set_min_width(col, COL_ALGO_WIDTH);
455 gtk_tree_view_column_set_sort_column_id(col, i++);
456 gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
457
458 col = gtk_tree_view_column_new_with_attributes(_("Key ID"), rdr,
459 "markup", COL_KEYID, NULL);
460 gtk_tree_view_column_set_min_width(col, COL_KEYID_WIDTH);
461 gtk_tree_view_column_set_sort_column_id(col, i++);
462 gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
463
464 col = gtk_tree_view_column_new_with_attributes(_("Name"), rdr,
465 "markup", COL_NAME, NULL);
466 gtk_tree_view_column_set_min_width(col, COL_NAME_WIDTH);
467 gtk_tree_view_column_set_sort_column_id(col, i++);
468 gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
469
470 col = gtk_tree_view_column_new_with_attributes(_("Address"), rdr,
471 "markup", COL_ADDRESS, NULL);
472 gtk_tree_view_column_set_min_width(col, COL_ADDRESS_WIDTH);
473 gtk_tree_view_column_set_sort_column_id(col, i++);
474 gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
475
476 col = gtk_tree_view_column_new_with_attributes(_("Trust"), rdr,
477 "markup", COL_TRUST, NULL);
478 gtk_tree_view_column_set_min_width(col, COL_TRUST_WIDTH);
479 gtk_tree_view_column_set_sort_column_id(col, i++);
480 gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
481
482 g_signal_connect(G_OBJECT(view), "row-activated",
483 G_CALLBACK(view_row_activated_cb), sk);
484
485 gtk_container_add (GTK_CONTAINER (scrolledwin), view);
486
487 hbox = gtk_hbox_new (FALSE, 8);
488 gtk_box_pack_end (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
489
490 /* TRANSLATORS: check that the accelerators in _Select, _Other and
491 * Do_n't encrypt are different than the one in the stock Cancel
492 * button */
493 gtkut_stock_button_set_create (&bbox,
494 &select_btn, _("_Select"),
495 &other_btn, _("_Other"),
496 &dont_encrypt_btn, _("Do_n't encrypt"));
497
498 cancel_btn = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
499 gtk_widget_set_can_default(cancel_btn, TRUE);
500 gtk_box_pack_start(GTK_BOX(bbox), cancel_btn, TRUE, TRUE, 0);
501 gtk_widget_show(cancel_btn);
502 gtk_box_pack_end (GTK_BOX (hbox), bbox, FALSE, FALSE, 0);
503 gtk_widget_grab_default (select_btn);
504
505 g_signal_connect (G_OBJECT (select_btn), "clicked",
506 G_CALLBACK (select_btn_cb), sk);
507 g_signal_connect (G_OBJECT(cancel_btn), "clicked",
508 G_CALLBACK (cancel_btn_cb), sk);
509 g_signal_connect (G_OBJECT(dont_encrypt_btn), "clicked",
510 G_CALLBACK (dont_encrypt_btn_cb), sk);
511 g_signal_connect (G_OBJECT (other_btn), "clicked",
512 G_CALLBACK (other_btn_cb), sk);
513
514 vbox2 = gtk_vbox_new (FALSE, 4);
515 gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, FALSE, 0);
516
517 sk->window = window;
518 sk->toplabel = GTK_LABEL (label);
519 sk->view = view;
520 }
521
522
523 /* Function called by gtk_tree_model_foreach() upon dialog close,
524 * which unrefs the gpgme_key_t pointer from each model line */
525 static gboolean
close_dialog_foreach_func(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer user_data)526 close_dialog_foreach_func(GtkTreeModel *model,
527 GtkTreePath *path,
528 GtkTreeIter *iter,
529 gpointer user_data)
530 {
531 gpgme_key_t key;
532
533 gtk_tree_model_get(model, iter, COL_PTR, &key, -1);
534 gpgme_key_unref(key);
535 return FALSE;
536 }
537
538
539 static void
open_dialog(struct select_keys_s * sk)540 open_dialog (struct select_keys_s *sk)
541 {
542 if (!sk->window)
543 create_dialog (sk);
544 manage_window_set_transient (GTK_WINDOW (sk->window));
545 sk->okay = 0;
546 sk->sort_column = N_COL_TITLES; /* use an invalid value */
547 sk->sort_type = GTK_SORT_ASCENDING;
548 }
549
550
551 static void
close_dialog(struct select_keys_s * sk)552 close_dialog (struct select_keys_s *sk)
553 {
554 GtkTreeModel *model;
555 cm_return_if_fail (sk);
556
557 debug_print("pgpcore select-keys dialog closing\n");
558 if (sk->view != NULL) {
559 model = gtk_tree_view_get_model(GTK_TREE_VIEW(sk->view));
560 gtk_tree_model_foreach(model, close_dialog_foreach_func, NULL);
561 gtk_list_store_clear(GTK_LIST_STORE(model));
562 }
563
564 gtk_widget_destroy (sk->window);
565 sk->window = NULL;
566 }
567
568
569 static gint
delete_event_cb(GtkWidget * widget,GdkEventAny * event,gpointer data)570 delete_event_cb (GtkWidget *widget, GdkEventAny *event, gpointer data)
571 {
572 struct select_keys_s *sk = data;
573
574 sk->okay = 0;
575 gtk_main_quit ();
576
577 return TRUE;
578 }
579
580
581 static gboolean
key_pressed_cb(GtkWidget * widget,GdkEventKey * event,gpointer data)582 key_pressed_cb (GtkWidget *widget, GdkEventKey *event, gpointer data)
583 {
584 struct select_keys_s *sk = data;
585
586 cm_return_val_if_fail (sk, FALSE);
587 if (event && event->keyval == GDK_KEY_Escape) {
588 sk->okay = 0;
589 gtk_main_quit ();
590 }
591 return FALSE;
592 }
593
594
595 static void
select_btn_cb(GtkWidget * widget,gpointer data)596 select_btn_cb (GtkWidget *widget, gpointer data)
597 {
598 struct select_keys_s *sk = data;
599 gboolean use_key;
600 gpgme_key_t key;
601
602 cm_return_if_fail (sk);
603
604 key = gtkut_tree_view_get_selected_pointer(
605 GTK_TREE_VIEW(sk->view), COL_PTR,
606 NULL, NULL, NULL);
607 if (key) {
608 gpgme_user_id_t uid;
609 for (uid = key->uids; uid; uid = uid->next) {
610 gchar *raw_mail = NULL;
611
612 if (!uid->email)
613 continue;
614 raw_mail = g_strdup(uid->email);
615 extract_address(raw_mail);
616 if (sk->pattern && !strcasecmp(sk->pattern, raw_mail)) {
617 g_free(raw_mail);
618 break;
619 }
620 g_free(raw_mail);
621 }
622 if (!uid)
623 uid = key->uids;
624
625 if ( uid->validity < GPGME_VALIDITY_FULL ) {
626 use_key = use_untrusted(key, uid, sk->proto);
627 if (!use_key) {
628 debug_print ("** Key untrusted, will not encrypt\n");
629 return;
630 }
631 }
632 sk->kset = g_realloc(sk->kset,
633 sizeof(gpgme_key_t) * (sk->num_keys + 1));
634 gpgme_key_ref(key);
635 sk->kset[sk->num_keys] = key;
636 sk->num_keys++;
637 sk->okay = 1;
638 sk->result = KEY_SELECTION_OK;
639 gtk_main_quit ();
640 }
641 }
642
643
644 static void
cancel_btn_cb(GtkWidget * widget,gpointer data)645 cancel_btn_cb (GtkWidget *widget, gpointer data)
646 {
647 struct select_keys_s *sk = data;
648
649 cm_return_if_fail (sk);
650 sk->okay = 0;
651 sk->result = KEY_SELECTION_CANCEL;
652 if (sk->select_ctx)
653 gpgme_cancel (sk->select_ctx);
654 gtk_main_quit ();
655 }
656
657 static void
dont_encrypt_btn_cb(GtkWidget * widget,gpointer data)658 dont_encrypt_btn_cb (GtkWidget *widget, gpointer data)
659 {
660 struct select_keys_s *sk = data;
661
662 cm_return_if_fail (sk);
663 sk->okay = 0;
664 sk->result = KEY_SELECTION_DONT;
665 if (sk->select_ctx)
666 gpgme_cancel (sk->select_ctx);
667 gtk_main_quit ();
668 }
669
670 static void
other_btn_cb(GtkWidget * widget,gpointer data)671 other_btn_cb (GtkWidget *widget, gpointer data)
672 {
673 struct select_keys_s *sk = data;
674 char *uid;
675
676 cm_return_if_fail (sk);
677 uid = input_dialog ( _("Add key"),
678 _("Enter another user or key ID:"),
679 NULL );
680 if (!uid)
681 return;
682 if (fill_view (sk, uid, sk->proto) != NULL) {
683 gpgme_release(sk->select_ctx);
684 sk->select_ctx = NULL;
685 }
686 update_progress (sk, 0, sk->pattern);
687 g_free (uid);
688 }
689
690
691 static gboolean
use_untrusted(gpgme_key_t key,gpgme_user_id_t uid,gpgme_protocol_t proto)692 use_untrusted (gpgme_key_t key, gpgme_user_id_t uid, gpgme_protocol_t proto)
693 {
694 AlertValue aval;
695 gchar *buf = NULL;
696 gchar *title = NULL;
697 if (proto != GPGME_PROTOCOL_OpenPGP)
698 return TRUE;
699
700 title = g_strdup_printf(_("Encrypt to %s <%s>"), uid->name, uid->email);
701 buf = g_strdup_printf(_("This encryption key is not fully trusted.\n"
702 "If you choose to encrypt the message with this key, you don't\n"
703 "know for sure that it will go to the person you mean it to.\n\n"
704 "Key details: ID %s, primary identity %s <%s>\n\n"
705 "Do you trust this key enough to use it anyway?"),
706 key->subkeys->keyid, key->uids->name, key->uids->email);
707 aval = alertpanel(title, buf,
708 GTK_STOCK_NO, GTK_STOCK_YES, NULL, ALERTFOCUS_FIRST);
709 g_free(buf);
710 g_free(title);
711 if (aval == G_ALERTALTERNATE)
712 return TRUE;
713 else
714 return FALSE;
715 }
716
717 #endif /*USE_GPGME*/
718