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 &lt;%s&gt;\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