407d7c2c0ee94f9f9103ab43c08bcfdc34f0d909
[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                 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), TRUE);
458                 gtk_tree_view_set_reorderable(GTK_TREE_VIEW(view), FALSE);
459                 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
460                 gtk_tree_selection_set_mode(sel, GTK_SELECTION_BROWSE);
461
462                 rdr = gtk_cell_renderer_text_new();
463                 col = gtk_tree_view_column_new_with_attributes(_("Size"), rdr,
464                                 "markup", COL_ALGO, NULL);
465                 gtk_tree_view_column_set_min_width(col, COL_ALGO_WIDTH);
466                 gtk_tree_view_column_set_sort_column_id(col, i++);
467                 gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
468
469                 col = gtk_tree_view_column_new_with_attributes(_("Key ID"), rdr,
470                                 "markup", COL_KEYID, NULL);
471                 gtk_tree_view_column_set_min_width(col, COL_KEYID_WIDTH);
472                 gtk_tree_view_column_set_sort_column_id(col, i++);
473                 gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
474
475                 col = gtk_tree_view_column_new_with_attributes(_("Name"), rdr,
476                                 "markup", COL_NAME, NULL);
477                 gtk_tree_view_column_set_min_width(col, COL_NAME_WIDTH);
478                 gtk_tree_view_column_set_sort_column_id(col, i++);
479                 gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
480
481                 col = gtk_tree_view_column_new_with_attributes(_("Address"), rdr,
482                                 "markup", COL_ADDRESS, NULL);
483                 gtk_tree_view_column_set_min_width(col, COL_ADDRESS_WIDTH);
484                 gtk_tree_view_column_set_sort_column_id(col, i++);
485                 gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
486
487                 col = gtk_tree_view_column_new_with_attributes(_("Trust"), rdr,
488                                 "markup", COL_TRUST, NULL);
489                 gtk_tree_view_column_set_min_width(col, COL_TRUST_WIDTH);
490                 gtk_tree_view_column_set_sort_column_id(col, i++);
491                 gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
492
493                 g_signal_connect(G_OBJECT(view), "row-activated",
494                                 G_CALLBACK(view_row_activated_cb), sk);
495
496     gtk_container_add (GTK_CONTAINER (scrolledwin), view);
497
498     hbox = gtk_hbox_new (FALSE, 8);
499     gtk_box_pack_end (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
500
501     /* TRANSLATORS: check that the accelerators in _Select, _Other and
502      * Do_n't encrypt are different than the one in the stock Cancel
503      * button */
504     gtkut_stock_button_set_create (&bbox, 
505                                    &select_btn, _("_Select"),
506                                    &other_btn, _("_Other"),
507                                    &dont_encrypt_btn, _("Do_n't encrypt"));
508     
509     cancel_btn = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
510     gtk_widget_set_can_default(cancel_btn, TRUE);
511     gtk_box_pack_start(GTK_BOX(bbox), cancel_btn, TRUE, TRUE, 0);
512     gtk_widget_show(cancel_btn);
513     gtk_box_pack_end (GTK_BOX (hbox), bbox, FALSE, FALSE, 0);
514     gtk_widget_grab_default (select_btn);
515
516     g_signal_connect (G_OBJECT (select_btn), "clicked",
517                       G_CALLBACK (select_btn_cb), sk);
518     g_signal_connect (G_OBJECT(cancel_btn), "clicked",
519                       G_CALLBACK (cancel_btn_cb), sk);
520     g_signal_connect (G_OBJECT(dont_encrypt_btn), "clicked",
521                       G_CALLBACK (dont_encrypt_btn_cb), sk);
522     g_signal_connect (G_OBJECT (other_btn), "clicked",
523                       G_CALLBACK (other_btn_cb), sk);
524
525     vbox2 = gtk_vbox_new (FALSE, 4);
526     gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, FALSE, 0);
527
528     sk->window = window;
529     sk->toplabel = GTK_LABEL (label);
530     sk->view  = view;
531 }
532
533
534 /* Function called by gtk_tree_model_foreach() upon dialog close,
535  * which unrefs the gpgme_key_t pointer from each model line */
536 static gboolean
537 close_dialog_foreach_func(GtkTreeModel *model,
538                 GtkTreePath *path,
539                 GtkTreeIter *iter,
540                 gpointer user_data)
541 {
542         gpgme_key_t key;
543
544         gtk_tree_model_get(model, iter, COL_PTR, &key, -1);
545         gpgme_key_unref(key);
546         return FALSE;
547 }
548
549
550 static void
551 open_dialog (struct select_keys_s *sk)
552 {
553     if (!sk->window)
554         create_dialog (sk);
555     manage_window_set_transient (GTK_WINDOW (sk->window));
556     sk->okay = 0;
557     sk->sort_column = N_COL_TITLES; /* use an invalid value */
558     sk->sort_type = GTK_SORT_ASCENDING;
559 }
560
561
562 static void
563 close_dialog (struct select_keys_s *sk)
564 {
565     GtkTreeModel *model;
566     cm_return_if_fail (sk);
567
568     debug_print("pgpcore select-keys dialog closing\n");
569     if (sk->view != NULL) {
570         model = gtk_tree_view_get_model(GTK_TREE_VIEW(sk->view));
571         gtk_tree_model_foreach(model, close_dialog_foreach_func, NULL);
572         gtk_list_store_clear(GTK_LIST_STORE(model));
573     }
574
575     gtk_widget_destroy (sk->window);
576     sk->window = NULL;
577 }
578
579
580 static gint
581 delete_event_cb (GtkWidget *widget, GdkEventAny *event, gpointer data)
582 {
583     struct select_keys_s *sk = data;
584
585     sk->okay = 0;
586     gtk_main_quit ();
587
588     return TRUE;
589 }
590
591
592 static gboolean
593 key_pressed_cb (GtkWidget *widget, GdkEventKey *event, gpointer data)
594 {
595     struct select_keys_s *sk = data;
596
597     cm_return_val_if_fail (sk, FALSE);
598     if (event && event->keyval == GDK_KEY_Escape) {
599         sk->okay = 0;
600         gtk_main_quit ();
601     }
602     return FALSE;
603 }
604
605
606 static void 
607 select_btn_cb (GtkWidget *widget, gpointer data)
608 {
609     struct select_keys_s *sk = data;
610     gboolean use_key;
611     gpgme_key_t key;
612     GtkTreeModel *model;
613     GtkTreeSelection *sel;
614     GtkTreeIter iter;
615
616     cm_return_if_fail (sk);
617                 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(sk->view));
618     if (!gtk_tree_selection_get_selected(sel, &model, &iter)) {
619         debug_print ("** nothing selected\n");
620         return;
621     }
622
623     gtk_tree_model_get(model, &iter, COL_PTR, &key, -1);
624     if (key) {
625         gpgme_user_id_t uid;
626         for (uid = key->uids; uid; uid = uid->next) {
627                 gchar *raw_mail = NULL;
628
629                 if (!uid->email)
630                         continue;
631                 raw_mail = g_strdup(uid->email);
632                 extract_address(raw_mail);
633                 if (sk->pattern && !strcasecmp(sk->pattern, raw_mail)) {
634                         g_free(raw_mail);
635                         break;
636                 }
637                 g_free(raw_mail);
638         }
639         if (!uid)
640                 uid = key->uids;
641
642         if ( uid->validity < GPGME_VALIDITY_FULL ) {
643             use_key = use_untrusted(key, uid, sk->proto);
644             if (!use_key) {
645                 debug_print ("** Key untrusted, will not encrypt\n");
646                 return;
647             }
648         }
649         sk->kset = g_realloc(sk->kset,
650                 sizeof(gpgme_key_t) * (sk->num_keys + 1));
651         gpgme_key_ref(key);
652         sk->kset[sk->num_keys] = key;
653         sk->num_keys++;
654         sk->okay = 1;
655         sk->result = KEY_SELECTION_OK;
656         gtk_main_quit ();
657     }
658 }
659
660
661 static void 
662 cancel_btn_cb (GtkWidget *widget, gpointer data)
663 {
664     struct select_keys_s *sk = data;
665
666     cm_return_if_fail (sk);
667     sk->okay = 0;
668     sk->result = KEY_SELECTION_CANCEL;
669     if (sk->select_ctx)
670         gpgme_cancel (sk->select_ctx);
671     gtk_main_quit ();
672 }
673
674 static void 
675 dont_encrypt_btn_cb (GtkWidget *widget, gpointer data)
676 {
677     struct select_keys_s *sk = data;
678
679     cm_return_if_fail (sk);
680     sk->okay = 0;
681     sk->result = KEY_SELECTION_DONT;
682     if (sk->select_ctx)
683         gpgme_cancel (sk->select_ctx);
684     gtk_main_quit ();
685 }
686
687 static void
688 other_btn_cb (GtkWidget *widget, gpointer data)
689 {
690     struct select_keys_s *sk = data;
691     char *uid;
692
693     cm_return_if_fail (sk);
694     uid = input_dialog ( _("Add key"),
695                          _("Enter another user or key ID:"),
696                          NULL );
697     if (!uid)
698         return;
699     if (fill_view (sk, uid, sk->proto) != NULL) {
700             gpgme_release(sk->select_ctx);
701             sk->select_ctx = NULL;
702     }
703     update_progress (sk, 0, sk->pattern);
704     g_free (uid);
705 }
706
707
708 static gboolean
709 use_untrusted (gpgme_key_t key, gpgme_user_id_t uid, gpgme_protocol_t proto)
710 {
711     AlertValue aval;
712     gchar *buf = NULL;
713     gchar *title = NULL;
714     if (proto != GPGME_PROTOCOL_OpenPGP)
715         return TRUE;
716
717     title = g_strdup_printf(_("Encrypt to %s <%s>"), uid->name, uid->email);
718     buf = g_strdup_printf(_("This encryption key is not fully trusted.\n"
719                "If you choose to encrypt the message with this key, you don't\n"
720                "know for sure that it will go to the person you mean it to.\n\n"
721                "Key details: ID %s, primary identity %s <%s>\n\n"
722                "Do you trust this key enough to use it anyway?"), 
723                key->subkeys->keyid, key->uids->name, key->uids->email);
724     aval = alertpanel(title, buf,
725              GTK_STOCK_NO, GTK_STOCK_YES, NULL, ALERTFOCUS_FIRST);
726     g_free(buf);
727     g_free(title);
728     if (aval == G_ALERTALTERNATE)
729         return TRUE;
730     else
731         return FALSE;
732 }
733
734 #endif /*USE_GPGME*/