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