Statistics
| Revision:

root / src / select-keys.c @ 333

History | View | Annotate | Download (15.6 kB)

1 1 hiro
/* select-keys.c - GTK+ based key selection
2 1 hiro
 *      Copyright (C) 2001 Werner Koch (dd9jn)
3 1 hiro
 *
4 1 hiro
 * This program is free software; you can redistribute it and/or modify
5 1 hiro
 * it under the terms of the GNU General Public License as published by
6 1 hiro
 * the Free Software Foundation; either version 2 of the License, or
7 1 hiro
 * (at your option) any later version.
8 1 hiro
 *
9 1 hiro
 * This program is distributed in the hope that it will be useful,
10 1 hiro
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 1 hiro
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 1 hiro
 * GNU General Public License for more details.
13 1 hiro
 *
14 1 hiro
 * You should have received a copy of the GNU General Public License
15 1 hiro
 * along with this program; if not, write to the Free Software
16 1 hiro
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 1 hiro
 */
18 1 hiro
19 1 hiro
#ifdef HAVE_CONFIG_H
20 1 hiro
#  include <config.h>
21 1 hiro
#endif
22 1 hiro
23 1 hiro
#ifdef USE_GPGME
24 1 hiro
#include <stdio.h>
25 1 hiro
#include <stdlib.h>
26 1 hiro
27 1 hiro
#include <glib.h>
28 92 hiro
#include <glib/gi18n.h>
29 1 hiro
#include <gdk/gdkkeysyms.h>
30 1 hiro
#include <gtk/gtkmain.h>
31 1 hiro
#include <gtk/gtkwidget.h>
32 1 hiro
#include <gtk/gtkwindow.h>
33 1 hiro
#include <gtk/gtkscrolledwindow.h>
34 1 hiro
#include <gtk/gtkvbox.h>
35 1 hiro
#include <gtk/gtkhbox.h>
36 1 hiro
#include <gtk/gtkclist.h>
37 1 hiro
#include <gtk/gtklabel.h>
38 1 hiro
#include <gtk/gtkentry.h>
39 1 hiro
#include <gtk/gtkhbbox.h>
40 1 hiro
#include <gtk/gtkbutton.h>
41 36 hiro
#include <gtk/gtkstock.h>
42 1 hiro
43 1 hiro
#include "select-keys.h"
44 1 hiro
#include "utils.h"
45 1 hiro
#include "gtkutils.h"
46 1 hiro
#include "inputdialog.h"
47 1 hiro
#include "manage_window.h"
48 56 hiro
#include "alertpanel.h"
49 1 hiro
50 1 hiro
#define DIM(v) (sizeof(v)/sizeof((v)[0]))
51 1 hiro
#define DIMof(type,member)   DIM(((type *)0)->member)
52 1 hiro
53 1 hiro
54 1 hiro
enum col_titles {
55 1 hiro
    COL_ALGO,
56 1 hiro
    COL_KEYID,
57 1 hiro
    COL_NAME,
58 1 hiro
    COL_EMAIL,
59 1 hiro
    COL_VALIDITY,
60 1 hiro
61 1 hiro
    N_COL_TITLES
62 1 hiro
};
63 1 hiro
64 1 hiro
struct select_keys_s {
65 1 hiro
    int okay;
66 1 hiro
    GtkWidget *window;
67 1 hiro
    GtkLabel *toplabel;
68 1 hiro
    GtkCList *clist;
69 1 hiro
    const char *pattern;
70 56 hiro
    unsigned int num_keys;
71 56 hiro
    gpgme_key_t *kset;
72 56 hiro
    gpgme_ctx_t select_ctx;
73 1 hiro
74 1 hiro
    GtkSortType sort_type;
75 1 hiro
    enum col_titles sort_column;
76 1 hiro
77 1 hiro
};
78 1 hiro
79 1 hiro
80 56 hiro
static void set_row (GtkCList *clist, gpgme_key_t key);
81 1 hiro
static void fill_clist (struct select_keys_s *sk, const char *pattern);
82 1 hiro
static void create_dialog (struct select_keys_s *sk);
83 1 hiro
static void open_dialog (struct select_keys_s *sk);
84 1 hiro
static void close_dialog (struct select_keys_s *sk);
85 1 hiro
static gint delete_event_cb (GtkWidget *widget,
86 1 hiro
                             GdkEventAny *event, gpointer data);
87 1 hiro
static gboolean key_pressed_cb (GtkWidget *widget,
88 1 hiro
                                GdkEventKey *event, gpointer data);
89 1 hiro
static void select_btn_cb (GtkWidget *widget, gpointer data);
90 1 hiro
static void cancel_btn_cb (GtkWidget *widget, gpointer data);
91 1 hiro
static void other_btn_cb (GtkWidget *widget, gpointer data);
92 1 hiro
static void sort_keys (struct select_keys_s *sk, enum col_titles column);
93 1 hiro
static void sort_keys_name (GtkWidget *widget, gpointer data);
94 1 hiro
static void sort_keys_email (GtkWidget *widget, gpointer data);
95 1 hiro
96 56 hiro
static gboolean use_untrusted (gpgme_key_t);
97 1 hiro
98 1 hiro
static void
99 1 hiro
update_progress (struct select_keys_s *sk, int running, const char *pattern)
100 1 hiro
{
101 1 hiro
    static int windmill[] = { '-', '\\', '|', '/' };
102 1 hiro
    char *buf;
103 1 hiro
104 1 hiro
    if (!running)
105 1 hiro
        buf = g_strdup_printf (_("Please select key for `%s'"),
106 1 hiro
                               pattern);
107 1 hiro
    else
108 1 hiro
        buf = g_strdup_printf (_("Collecting info for `%s' ... %c"),
109 1 hiro
                               pattern,
110 1 hiro
                               windmill[running%DIM(windmill)]);
111 1 hiro
    gtk_label_set_text (sk->toplabel, buf);
112 1 hiro
    g_free (buf);
113 1 hiro
}
114 1 hiro
115 1 hiro
116 1 hiro
/**
117 56 hiro
 * gpgmegtk_recipient_selection:
118 1 hiro
 * @recp_names: A list of email addresses
119 1 hiro
 *
120 1 hiro
 * Select a list of recipients from a given list of email addresses.
121 1 hiro
 * This may pop up a window to present the user a choice, it will also
122 1 hiro
 * check that the recipients key are all valid.
123 1 hiro
 *
124 1 hiro
 * Return value: NULL on error or a list of list of recipients.
125 1 hiro
 **/
126 56 hiro
gpgme_key_t *
127 1 hiro
gpgmegtk_recipient_selection (GSList *recp_names)
128 1 hiro
{
129 1 hiro
    struct select_keys_s sk;
130 1 hiro
131 1 hiro
    memset (&sk, 0, sizeof sk);
132 1 hiro
133 1 hiro
    open_dialog (&sk);
134 1 hiro
135 1 hiro
    do {
136 1 hiro
        sk.pattern = recp_names? recp_names->data:NULL;
137 1 hiro
        gtk_clist_clear (sk.clist);
138 1 hiro
        fill_clist (&sk, sk.pattern);
139 1 hiro
        update_progress (&sk, 0, sk.pattern);
140 1 hiro
        gtk_main ();
141 1 hiro
        if (recp_names)
142 1 hiro
            recp_names = recp_names->next;
143 1 hiro
    } while (sk.okay && recp_names);
144 1 hiro
145 1 hiro
    close_dialog (&sk);
146 1 hiro
147 1 hiro
    if (!sk.okay) {
148 56 hiro
        g_free(sk.kset);
149 56 hiro
        sk.kset = NULL;
150 56 hiro
    } else {
151 56 hiro
        sk.kset = g_realloc(sk.kset, sizeof(gpgme_key_t) * (sk.num_keys + 1));
152 56 hiro
        sk.kset[sk.num_keys] = NULL;
153 1 hiro
    }
154 56 hiro
    return sk.kset;
155 1 hiro
}
156 1 hiro
157 1 hiro
static void
158 1 hiro
destroy_key (gpointer data)
159 1 hiro
{
160 56 hiro
    gpgme_key_t key = data;
161 1 hiro
    gpgme_key_release (key);
162 1 hiro
}
163 1 hiro
164 1 hiro
static void
165 56 hiro
set_row (GtkCList *clist, gpgme_key_t key)
166 1 hiro
{
167 1 hiro
    const char *s;
168 1 hiro
    const char *text[N_COL_TITLES];
169 1 hiro
    char *algo_buf;
170 1 hiro
    int row;
171 1 hiro
172 1 hiro
    /* first check whether the key is capable of encryption which is not
173 1 hiro
     * the case for revoked, expired or sign-only keys */
174 56 hiro
    if (!key->can_encrypt)
175 1 hiro
        return;
176 56 hiro
    algo_buf = g_strdup_printf ("%du/%s",
177 56 hiro
         key->subkeys->length,
178 56 hiro
         gpgme_pubkey_algo_name(key->subkeys->pubkey_algo) );
179 1 hiro
    text[COL_ALGO] = algo_buf;
180 1 hiro
181 56 hiro
    s = key->subkeys->keyid;
182 1 hiro
    if (strlen (s) == 16)
183 1 hiro
        s += 8; /* show only the short keyID */
184 1 hiro
    text[COL_KEYID] = s;
185 1 hiro
186 56 hiro
    s = key->uids->name;
187 1 hiro
    text[COL_NAME] = s;
188 1 hiro
189 56 hiro
    s = key->uids->email;
190 1 hiro
    text[COL_EMAIL] = s;
191 1 hiro
192 56 hiro
    switch (key->uids->validity)
193 56 hiro
      {
194 56 hiro
      case GPGME_VALIDITY_UNDEFINED:
195 56 hiro
        s = "q";
196 56 hiro
        break;
197 56 hiro
      case GPGME_VALIDITY_NEVER:
198 56 hiro
        s = "n";
199 56 hiro
        break;
200 56 hiro
      case GPGME_VALIDITY_MARGINAL:
201 56 hiro
        s = "m";
202 56 hiro
        break;
203 56 hiro
      case GPGME_VALIDITY_FULL:
204 56 hiro
        s = "f";
205 56 hiro
        break;
206 56 hiro
      case GPGME_VALIDITY_ULTIMATE:
207 56 hiro
        s = "u";
208 56 hiro
        break;
209 56 hiro
      case GPGME_VALIDITY_UNKNOWN:
210 56 hiro
      default:
211 56 hiro
        s = "?";
212 56 hiro
        break;
213 56 hiro
      }
214 1 hiro
    text[COL_VALIDITY] = s;
215 1 hiro
216 1 hiro
    row = gtk_clist_append (clist, (gchar**)text);
217 1 hiro
    g_free (algo_buf);
218 1 hiro
219 1 hiro
    gtk_clist_set_row_data_full (clist, row, key, destroy_key);
220 1 hiro
}
221 1 hiro
222 1 hiro
static void
223 1 hiro
fill_clist (struct select_keys_s *sk, const char *pattern)
224 1 hiro
{
225 1 hiro
    GtkCList *clist;
226 56 hiro
    gpgme_ctx_t ctx;
227 56 hiro
    gpgme_error_t err;
228 56 hiro
    gpgme_key_t key;
229 1 hiro
    int running=0;
230 1 hiro
231 1 hiro
    g_return_if_fail (sk);
232 1 hiro
    clist = sk->clist;
233 1 hiro
    g_return_if_fail (clist);
234 1 hiro
235 1 hiro
    debug_print ("select_keys:fill_clist:  pattern `%s'\n", pattern);
236 1 hiro
237 1 hiro
    /*gtk_clist_freeze (select_keys.clist);*/
238 1 hiro
    err = gpgme_new (&ctx);
239 1 hiro
    g_assert (!err);
240 1 hiro
241 1 hiro
    sk->select_ctx = ctx;
242 1 hiro
243 1 hiro
    update_progress (sk, ++running, pattern);
244 1 hiro
    while (gtk_events_pending ())
245 1 hiro
        gtk_main_iteration ();
246 1 hiro
247 1 hiro
    err = gpgme_op_keylist_start (ctx, pattern, 0);
248 1 hiro
    if (err) {
249 1 hiro
        debug_print ("** gpgme_op_keylist_start(%s) failed: %s",
250 1 hiro
                     pattern, gpgme_strerror (err));
251 1 hiro
        sk->select_ctx = NULL;
252 56 hiro
        gpgme_release(ctx);
253 1 hiro
        return;
254 1 hiro
    }
255 1 hiro
    update_progress (sk, ++running, pattern);
256 1 hiro
    while ( !(err = gpgme_op_keylist_next ( ctx, &key )) ) {
257 1 hiro
        debug_print ("%% %s:%d:  insert\n", __FILE__ ,__LINE__ );
258 1 hiro
        set_row (clist, key ); key = NULL;
259 1 hiro
        update_progress (sk, ++running, pattern);
260 1 hiro
        while (gtk_events_pending ())
261 1 hiro
            gtk_main_iteration ();
262 1 hiro
    }
263 1 hiro
    debug_print ("%% %s:%d:  ready\n", __FILE__ ,__LINE__ );
264 56 hiro
    if (gpgme_err_code(err) != GPG_ERR_EOF) {
265 1 hiro
        debug_print ("** gpgme_op_keylist_next failed: %s",
266 1 hiro
                     gpgme_strerror (err));
267 56 hiro
        gpgme_op_keylist_end(ctx);
268 56 hiro
    }
269 1 hiro
    sk->select_ctx = NULL;
270 1 hiro
    gpgme_release (ctx);
271 1 hiro
    /*gtk_clist_thaw (select_keys.clist);*/
272 1 hiro
}
273 1 hiro
274 1 hiro
275 1 hiro
static void
276 1 hiro
create_dialog (struct select_keys_s *sk)
277 1 hiro
{
278 1 hiro
    GtkWidget *window;
279 1 hiro
    GtkWidget *vbox, *vbox2, *hbox;
280 1 hiro
    GtkWidget *bbox;
281 1 hiro
    GtkWidget *scrolledwin;
282 1 hiro
    GtkWidget *clist;
283 1 hiro
    GtkWidget *label;
284 1 hiro
    GtkWidget *select_btn, *cancel_btn, *other_btn;
285 1 hiro
    const char *titles[N_COL_TITLES];
286 1 hiro
287 1 hiro
    g_assert (!sk->window);
288 1 hiro
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
289 1 hiro
    gtk_widget_set_size_request (window, 520, 280);
290 1 hiro
    gtk_container_set_border_width (GTK_CONTAINER (window), 8);
291 1 hiro
    gtk_window_set_title (GTK_WINDOW (window), _("Select Keys"));
292 1 hiro
    gtk_window_set_modal (GTK_WINDOW (window), TRUE);
293 1 hiro
    g_signal_connect (G_OBJECT (window), "delete_event",
294 1 hiro
                      G_CALLBACK (delete_event_cb), sk);
295 1 hiro
    g_signal_connect (G_OBJECT (window), "key_press_event",
296 1 hiro
                      G_CALLBACK (key_pressed_cb), sk);
297 1 hiro
    MANAGE_WINDOW_SIGNALS_CONNECT (window);
298 1 hiro
299 1 hiro
    vbox = gtk_vbox_new (FALSE, 8);
300 1 hiro
    gtk_container_add (GTK_CONTAINER (window), vbox);
301 1 hiro
302 1 hiro
    hbox  = gtk_hbox_new(FALSE, 4);
303 1 hiro
    gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
304 1 hiro
    label = gtk_label_new ( "" );
305 1 hiro
    gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
306 1 hiro
307 1 hiro
    hbox = gtk_hbox_new (FALSE, 8);
308 1 hiro
    gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
309 1 hiro
    gtk_container_set_border_width (GTK_CONTAINER (hbox), 2);
310 1 hiro
311 1 hiro
    scrolledwin = gtk_scrolled_window_new (NULL, NULL);
312 1 hiro
    gtk_box_pack_start (GTK_BOX (hbox), scrolledwin, TRUE, TRUE, 0);
313 1 hiro
    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwin),
314 1 hiro
                                    GTK_POLICY_AUTOMATIC,
315 1 hiro
                                    GTK_POLICY_AUTOMATIC);
316 1 hiro
317 1 hiro
    titles[COL_ALGO]     = _("Size");
318 1 hiro
    titles[COL_KEYID]    = _("Key ID");
319 1 hiro
    titles[COL_NAME]     = _("Name");
320 1 hiro
    titles[COL_EMAIL]    = _("Address");
321 1 hiro
    titles[COL_VALIDITY] = _("Val");
322 1 hiro
323 1 hiro
    clist = gtk_clist_new_with_titles (N_COL_TITLES, (char**)titles);
324 1 hiro
    gtk_container_add (GTK_CONTAINER (scrolledwin), clist);
325 1 hiro
    gtk_clist_set_column_width (GTK_CLIST(clist), COL_ALGO,      72);
326 1 hiro
    gtk_clist_set_column_width (GTK_CLIST(clist), COL_KEYID,     76);
327 1 hiro
    gtk_clist_set_column_width (GTK_CLIST(clist), COL_NAME,     130);
328 1 hiro
    gtk_clist_set_column_width (GTK_CLIST(clist), COL_EMAIL,    130);
329 1 hiro
    gtk_clist_set_column_width (GTK_CLIST(clist), COL_VALIDITY,  20);
330 1 hiro
    gtk_clist_set_selection_mode (GTK_CLIST(clist), GTK_SELECTION_BROWSE);
331 1 hiro
    g_signal_connect (G_OBJECT(GTK_CLIST(clist)->column[COL_NAME].button),
332 1 hiro
                      "clicked",
333 1 hiro
                      G_CALLBACK(sort_keys_name), sk);
334 1 hiro
    g_signal_connect (G_OBJECT(GTK_CLIST(clist)->column[COL_EMAIL].button),
335 1 hiro
                      "clicked",
336 1 hiro
                      G_CALLBACK(sort_keys_email), sk);
337 1 hiro
338 1 hiro
    hbox = gtk_hbox_new (FALSE, 8);
339 1 hiro
    gtk_box_pack_end (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
340 1 hiro
341 31 hiro
    gtkut_stock_button_set_create (&bbox,
342 31 hiro
                                   &select_btn, _("Select"),
343 31 hiro
                                   &cancel_btn, GTK_STOCK_CANCEL,
344 31 hiro
                                   &other_btn,  _("Other"));
345 1 hiro
    gtk_box_pack_end (GTK_BOX (hbox), bbox, FALSE, FALSE, 0);
346 1 hiro
    gtk_widget_grab_default (select_btn);
347 1 hiro
348 1 hiro
    g_signal_connect (G_OBJECT (select_btn), "clicked",
349 1 hiro
                      G_CALLBACK (select_btn_cb), sk);
350 1 hiro
    g_signal_connect (G_OBJECT(cancel_btn), "clicked",
351 1 hiro
                      G_CALLBACK (cancel_btn_cb), sk);
352 1 hiro
    g_signal_connect (G_OBJECT (other_btn), "clicked",
353 1 hiro
                      G_CALLBACK (other_btn_cb), sk);
354 1 hiro
355 1 hiro
    vbox2 = gtk_vbox_new (FALSE, 4);
356 1 hiro
    gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, FALSE, 0);
357 1 hiro
358 1 hiro
    gtk_widget_show_all (window);
359 1 hiro
360 1 hiro
    sk->window = window;
361 1 hiro
    sk->toplabel = GTK_LABEL (label);
362 1 hiro
    sk->clist  = GTK_CLIST (clist);
363 1 hiro
}
364 1 hiro
365 1 hiro
366 1 hiro
static void
367 1 hiro
open_dialog (struct select_keys_s *sk)
368 1 hiro
{
369 1 hiro
    if (!sk->window)
370 1 hiro
        create_dialog (sk);
371 1 hiro
    manage_window_set_transient (GTK_WINDOW (sk->window));
372 1 hiro
    sk->okay = 0;
373 1 hiro
    sk->sort_column = N_COL_TITLES; /* use an invalid value */
374 1 hiro
    sk->sort_type = GTK_SORT_ASCENDING;
375 1 hiro
    gtk_widget_show (sk->window);
376 1 hiro
}
377 1 hiro
378 1 hiro
379 1 hiro
static void
380 1 hiro
close_dialog (struct select_keys_s *sk)
381 1 hiro
{
382 1 hiro
    g_return_if_fail (sk);
383 1 hiro
    gtk_widget_destroy (sk->window);
384 1 hiro
    sk->window = NULL;
385 1 hiro
}
386 1 hiro
387 1 hiro
388 1 hiro
static gint
389 1 hiro
delete_event_cb (GtkWidget *widget, GdkEventAny *event, gpointer data)
390 1 hiro
{
391 1 hiro
    struct select_keys_s *sk = data;
392 1 hiro
393 1 hiro
    sk->okay = 0;
394 1 hiro
    gtk_main_quit ();
395 1 hiro
396 1 hiro
    return TRUE;
397 1 hiro
}
398 1 hiro
399 1 hiro
400 1 hiro
static gboolean
401 1 hiro
key_pressed_cb (GtkWidget *widget, GdkEventKey *event, gpointer data)
402 1 hiro
{
403 1 hiro
    struct select_keys_s *sk = data;
404 1 hiro
405 1 hiro
    g_return_val_if_fail (sk, FALSE);
406 1 hiro
    if (event && event->keyval == GDK_Escape) {
407 1 hiro
        sk->okay = 0;
408 1 hiro
        gtk_main_quit ();
409 1 hiro
    }
410 1 hiro
    return FALSE;
411 1 hiro
}
412 1 hiro
413 1 hiro
414 1 hiro
static void
415 1 hiro
select_btn_cb (GtkWidget *widget, gpointer data)
416 1 hiro
{
417 1 hiro
    struct select_keys_s *sk = data;
418 1 hiro
    int row;
419 56 hiro
    gboolean use_key;
420 56 hiro
    gpgme_key_t key;
421 1 hiro
422 1 hiro
    g_return_if_fail (sk);
423 1 hiro
    if (!sk->clist->selection) {
424 1 hiro
        debug_print ("** nothing selected");
425 1 hiro
        return;
426 1 hiro
    }
427 1 hiro
    row = GPOINTER_TO_INT(sk->clist->selection->data);
428 1 hiro
    key = gtk_clist_get_row_data(sk->clist, row);
429 1 hiro
    if (key) {
430 56 hiro
        if ( key->uids->validity < GPGME_VALIDITY_FULL ) {
431 56 hiro
            use_key = use_untrusted(key);
432 56 hiro
            if (!use_key) {
433 56 hiro
                debug_print ("** Key untrusted, will not encrypt");
434 56 hiro
                return;
435 56 hiro
            }
436 1 hiro
        }
437 56 hiro
        sk->kset = g_realloc(sk->kset,
438 56 hiro
                sizeof(gpgme_key_t) * (sk->num_keys + 1));
439 56 hiro
        gpgme_key_ref(key);
440 56 hiro
        sk->kset[sk->num_keys] = key;
441 56 hiro
        sk->num_keys++;
442 1 hiro
            sk->okay = 1;
443 1 hiro
            gtk_main_quit ();
444 1 hiro
        }
445 1 hiro
}
446 1 hiro
447 1 hiro
448 1 hiro
static void
449 1 hiro
cancel_btn_cb (GtkWidget *widget, gpointer data)
450 1 hiro
{
451 1 hiro
    struct select_keys_s *sk = data;
452 1 hiro
453 1 hiro
    g_return_if_fail (sk);
454 1 hiro
    sk->okay = 0;
455 1 hiro
    if (sk->select_ctx)
456 1 hiro
        gpgme_cancel (sk->select_ctx);
457 1 hiro
    gtk_main_quit ();
458 1 hiro
}
459 1 hiro
460 1 hiro
461 1 hiro
static void
462 1 hiro
other_btn_cb (GtkWidget *widget, gpointer data)
463 1 hiro
{
464 1 hiro
    struct select_keys_s *sk = data;
465 1 hiro
    char *uid;
466 1 hiro
467 1 hiro
    g_return_if_fail (sk);
468 1 hiro
    uid = input_dialog ( _("Add key"),
469 1 hiro
                         _("Enter another user or key ID:"),
470 1 hiro
                         NULL );
471 1 hiro
    if (!uid)
472 1 hiro
        return;
473 1 hiro
    fill_clist (sk, uid);
474 1 hiro
    update_progress (sk, 0, sk->pattern);
475 1 hiro
    g_free (uid);
476 1 hiro
}
477 1 hiro
478 1 hiro
479 56 hiro
static gboolean
480 56 hiro
use_untrusted (gpgme_key_t key)
481 56 hiro
{
482 56 hiro
    AlertValue aval;
483 56 hiro
484 56 hiro
    aval = alertpanel
485 56 hiro
            (_("Trust key"),
486 56 hiro
             _("The selected key is not fully trusted.\n"
487 56 hiro
               "If you choose to encrypt the message with this key you don't\n"
488 56 hiro
               "know for sure that it will go to the person you mean it to.\n"
489 56 hiro
               "Do you trust it enough to use it anyway?"),
490 56 hiro
             GTK_STOCK_YES, GTK_STOCK_NO, NULL);
491 56 hiro
    if (aval == G_ALERTDEFAULT)
492 56 hiro
        return TRUE;
493 56 hiro
    else
494 56 hiro
        return FALSE;
495 56 hiro
}
496 56 hiro
497 56 hiro
498 1 hiro
static gint
499 56 hiro
cmp_name (GtkCList *clist, gconstpointer pa, gconstpointer pb)
500 1 hiro
{
501 56 hiro
    gpgme_key_t a = ((GtkCListRow *)pa)->data;
502 56 hiro
    gpgme_key_t b = ((GtkCListRow *)pb)->data;
503 1 hiro
    const char *sa, *sb;
504 1 hiro
505 56 hiro
    sa = a? a->uids->name : NULL;
506 56 hiro
    sb = b? b->uids->name : NULL;
507 1 hiro
    if (!sa)
508 1 hiro
        return !!sb;
509 1 hiro
    if (!sb)
510 1 hiro
        return -1;
511 333 hiro
    return g_ascii_strcasecmp(sa, sb);
512 1 hiro
}
513 1 hiro
514 1 hiro
static gint
515 1 hiro
cmp_email (GtkCList *clist, gconstpointer pa, gconstpointer pb)
516 1 hiro
{
517 56 hiro
    gpgme_key_t a = ((GtkCListRow *)pa)->data;
518 56 hiro
    gpgme_key_t b = ((GtkCListRow *)pb)->data;
519 56 hiro
    const char *sa, *sb;
520 56 hiro
521 56 hiro
    sa = a? a->uids->email : NULL;
522 56 hiro
    sb = b? b->uids->email : NULL;
523 56 hiro
    if (!sa)
524 56 hiro
        return !!sb;
525 56 hiro
    if (!sb)
526 56 hiro
        return -1;
527 333 hiro
    return g_ascii_strcasecmp(sa, sb);
528 1 hiro
}
529 1 hiro
530 1 hiro
static void
531 1 hiro
sort_keys ( struct select_keys_s *sk, enum col_titles column)
532 1 hiro
{
533 1 hiro
    GtkCList *clist = sk->clist;
534 1 hiro
535 1 hiro
    switch (column) {
536 1 hiro
      case COL_NAME:
537 1 hiro
        gtk_clist_set_compare_func (clist, cmp_name);
538 1 hiro
        break;
539 1 hiro
      case COL_EMAIL:
540 1 hiro
        gtk_clist_set_compare_func (clist, cmp_email);
541 1 hiro
        break;
542 1 hiro
      default:
543 1 hiro
        return;
544 1 hiro
    }
545 1 hiro
546 1 hiro
    /* column clicked again: toggle as-/decending */
547 1 hiro
    if ( sk->sort_column == column) {
548 1 hiro
        sk->sort_type = sk->sort_type == GTK_SORT_ASCENDING ?
549 1 hiro
                        GTK_SORT_DESCENDING : GTK_SORT_ASCENDING;
550 1 hiro
    }
551 1 hiro
    else
552 1 hiro
        sk->sort_type = GTK_SORT_ASCENDING;
553 1 hiro
554 1 hiro
    sk->sort_column = column;
555 1 hiro
    gtk_clist_set_sort_type (clist, sk->sort_type);
556 1 hiro
    gtk_clist_sort (clist);
557 1 hiro
}
558 1 hiro
559 1 hiro
static void
560 1 hiro
sort_keys_name (GtkWidget *widget, gpointer data)
561 1 hiro
{
562 1 hiro
    sort_keys ((struct select_keys_s*)data, COL_NAME);
563 1 hiro
}
564 1 hiro
565 1 hiro
static void
566 1 hiro
sort_keys_email (GtkWidget *widget, gpointer data)
567 1 hiro
{
568 1 hiro
    sort_keys ((struct select_keys_s*)data, COL_EMAIL);
569 1 hiro
}
570 1 hiro
571 1 hiro
#endif /*USE_GPGME*/