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