04514be6ce30e285ff66d74551d2b008fd1261cb
[claws.git] / src / select-keys.c
1 /* select-keys.c - GTK+ based key selection
2  *      Copyright (C) 2001 Werner Koch (dd9jn)
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 2 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, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  */
18
19 #ifdef HAVE_CONFIG_H
20 #  include <config.h>
21 #endif
22
23 #ifdef USE_GPGME
24 #include <stdio.h>
25 #include <stdlib.h>
26
27 #include <glib.h>
28 #include <gdk/gdkkeysyms.h>
29 #include <gtk/gtkmain.h>
30 #include <gtk/gtkwidget.h>
31 #include <gtk/gtkwindow.h>
32 #include <gtk/gtkscrolledwindow.h>
33 #include <gtk/gtkvbox.h>
34 #include <gtk/gtkhbox.h>
35 #include <gtk/gtkclist.h>
36 #include <gtk/gtklabel.h>
37 #include <gtk/gtkentry.h>
38 #include <gtk/gtkhbbox.h>
39 #include <gtk/gtkbutton.h>
40 #include <gtk/gtkprogressbar.h>
41 #include <gtk/gtksignal.h>
42
43 #include "intl.h"
44 #include "select-keys.h"
45 #include "utils.h"
46 #include "gtkutils.h"
47
48 enum col_titles { 
49     COL_ALGO,
50     COL_KEYID,
51     COL_NAME,
52     COL_EMAIL,
53     COL_VALIDITY,
54
55     N_COL_TITLES
56 };
57
58 static struct {
59     int okay;
60     GtkWidget *window;
61     GtkLabel *toplabel;
62     GtkCList *clist;
63     GtkProgress *progress;
64     const char *pattern;
65     GpgmeRecipients rset;
66 } select_keys;
67
68
69 static void set_row (GtkCList *clist, GpgmeKey key );
70 static void fill_clist (GtkCList *clist, const char *pattern );
71 static void create_dialog (void);
72 static void open_dialog (void);
73 static void close_dialog (void);
74 static void key_pressed_cb (GtkWidget *widget,
75                             GdkEventKey *event, gpointer data);
76 static void select_btn_cb (GtkWidget *widget, gpointer data);
77 static void cancel_btn_cb (GtkWidget *widget, gpointer data);
78
79
80 static void
81 update_progress (void)
82 {
83     if (select_keys.progress) {
84         gfloat val = gtk_progress_get_value (select_keys.progress);
85
86         val += 1;
87         gtk_progress_set_value (select_keys.progress, val);
88         if ( !GTK_WIDGET_VISIBLE (select_keys.progress) )
89             gtk_widget_show (GTK_WIDGET (select_keys.progress));
90     }
91 }
92
93
94 /**
95  * select_keys_get_recipients:
96  * @recp_names: A list of email addresses
97  * 
98  * Select a list of recipients from a given list of email addresses.
99  * This may pop up a window to present the user a choice, it will also
100  * check that the recipients key are all valid.
101  * 
102  * Return value: NULL on error or a list of list of recipients.
103  **/
104 GpgmeRecipients
105 gpgmegtk_recipient_selection (GSList *recp_names)
106 {
107     GpgmeError err;
108
109     err = gpgme_recipients_new (&select_keys.rset);
110     if (err) {
111         g_message ("** failed to allocate recipients set: %s",
112                    gpgme_strerror (err) );
113         return NULL;
114     }
115         
116     open_dialog ();
117
118     do {
119         select_keys.pattern = recp_names? recp_names->data:NULL;
120         gtk_label_set_text (select_keys.toplabel, select_keys.pattern );
121         gtk_clist_clear (select_keys.clist);
122         fill_clist (select_keys.clist, select_keys.pattern);
123         gtk_main ();
124         if (recp_names)
125             recp_names = recp_names->next;
126     } while (select_keys.okay && recp_names );
127
128     close_dialog ();
129
130     {
131         GpgmeRecipients rset = select_keys.rset;
132         select_keys.rset = NULL;
133         if (!rset) {
134             gpgme_recipients_release (rset);
135             rset = NULL;
136         }
137         return rset;
138     }
139
140
141 static void
142 destroy_key (gpointer data)
143 {
144     GpgmeKey key = data;
145     gpgme_key_release (key);
146 }
147
148 static void
149 set_row (GtkCList *clist, GpgmeKey key )
150 {
151     const char *s;
152     const char *text[N_COL_TITLES];
153     char *algo_buf;
154     int row;
155     
156     algo_buf = g_strdup_printf ("%lu/%s", 
157          gpgme_key_get_ulong_attr (key, GPGME_ATTR_LEN, NULL, 0 ),
158          gpgme_key_get_string_attr (key, GPGME_ATTR_ALGO, NULL, 0 ) );
159     text[COL_ALGO] = algo_buf;
160
161     s = gpgme_key_get_string_attr (key, GPGME_ATTR_KEYID, NULL, 0 );
162     if ( strlen (s) == 16 )
163         s += 8; /* show only the short keyID */
164     text[COL_KEYID] = s;
165
166     s = gpgme_key_get_string_attr (key, GPGME_ATTR_NAME, NULL, 0 );
167     text[COL_NAME] = s;
168
169     s = gpgme_key_get_string_attr (key, GPGME_ATTR_EMAIL, NULL, 0 );
170     text[COL_EMAIL] = s;
171
172     s = gpgme_key_get_string_attr (key, GPGME_ATTR_VALIDITY, NULL, 0 );
173     text[COL_VALIDITY] = s;
174
175     row = gtk_clist_append (clist, (gchar**)text);
176     g_free (algo_buf);
177
178     gtk_clist_set_row_data_full (clist, row, key, destroy_key);
179 }
180
181
182 static void 
183 fill_clist (GtkCList *clist, const char *pattern )
184 {
185     GpgmeCtx ctx;
186     GpgmeError err;
187     GpgmeKey key;
188
189     debug_print ("select_keys:fill_clist:  pattern `%s'\n", pattern );
190
191     /*gtk_clist_freeze (select_keys.clist);*/
192     err = gpgme_new (&ctx);
193     g_assert (!err);
194
195     while (gtk_events_pending ())
196         gtk_main_iteration ();
197
198     err = gpgme_op_keylist_start (ctx, pattern, 0 );
199     if (err) {
200         g_message ("** gpgme_op_keylist_start(%s) failed: %s",
201                    pattern, gpgme_strerror (err));
202         return;
203     }
204     update_progress ();
205     while ( !(err = gpgme_op_keylist_next ( ctx, &key )) ) {
206         debug_print ("%% %s:%d:  insert\n", __FILE__ ,__LINE__ );
207         set_row (clist, key ); key = NULL;
208         update_progress ();
209         while (gtk_events_pending ())
210             gtk_main_iteration ();
211     }
212     debug_print ("%% %s:%d:  ready\n", __FILE__ ,__LINE__ );
213     gtk_widget_hide (GTK_WIDGET (select_keys.progress));
214     if ( err != GPGME_EOF )
215         g_message ("** gpgme_op_keylist_next failed: %s",
216                    gpgme_strerror (err));
217     gpgme_release (ctx);
218     /*gtk_clist_thaw (select_keys.clist);*/
219 }
220
221
222
223
224 static void 
225 create_dialog ()
226 {
227     GtkWidget *window;
228     GtkWidget *vbox, *vbox2, *hbox;
229     GtkWidget *bbox;
230     GtkWidget *scrolledwin;
231     GtkWidget *clist;
232     GtkWidget *label;
233     GtkWidget *progress;
234     GtkWidget *select_btn, *cancel_btn;
235     gchar *titles[N_COL_TITLES];
236
237     g_assert (!select_keys.window);
238     window = gtk_window_new (GTK_WINDOW_DIALOG);
239     gtk_widget_set_usize (window, 500, 320);
240     gtk_container_set_border_width (GTK_CONTAINER (window), 8);
241     gtk_window_set_title (GTK_WINDOW (window), _("Select Keys"));
242     gtk_window_set_modal (GTK_WINDOW (window), TRUE);
243     gtk_signal_connect (GTK_OBJECT (window), "delete_event",
244                         GTK_SIGNAL_FUNC (close_dialog), NULL);
245     gtk_signal_connect (GTK_OBJECT (window), "key_press_event",
246                         GTK_SIGNAL_FUNC (key_pressed_cb), NULL);
247
248     vbox = gtk_vbox_new (FALSE, 8);
249     gtk_container_add (GTK_CONTAINER (window), vbox);
250
251     hbox  = gtk_hbox_new(FALSE, 4);
252     gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
253     label = gtk_label_new ( _("Select key for: ") );
254     gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
255     label = gtk_label_new ( "" );
256     gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
257
258
259     hbox = gtk_hbox_new (FALSE, 8);
260     gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
261     gtk_container_set_border_width (GTK_CONTAINER (hbox), 2);
262
263
264     scrolledwin = gtk_scrolled_window_new (NULL, NULL);
265     gtk_box_pack_start (GTK_BOX (hbox), scrolledwin, TRUE, TRUE, 0);
266     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwin),
267                                     GTK_POLICY_AUTOMATIC,
268                                     GTK_POLICY_AUTOMATIC);
269
270     titles[COL_ALGO]     = _("Size");
271     titles[COL_KEYID]    = _("Key ID");
272     titles[COL_NAME]     = _("Name");
273     titles[COL_EMAIL]    = _("Address");
274     titles[COL_VALIDITY] = _("Val");
275
276     clist = gtk_clist_new_with_titles (N_COL_TITLES, titles);
277     gtk_container_add (GTK_CONTAINER (scrolledwin), clist);
278     gtk_clist_set_column_width (GTK_CLIST(clist), COL_ALGO,      40);
279     gtk_clist_set_column_width (GTK_CLIST(clist), COL_KEYID,     60);
280     gtk_clist_set_column_width (GTK_CLIST(clist), COL_NAME,     100);
281     gtk_clist_set_column_width (GTK_CLIST(clist), COL_EMAIL,    100);
282     gtk_clist_set_column_width (GTK_CLIST(clist), COL_VALIDITY,  20);
283     gtk_clist_set_selection_mode (GTK_CLIST(clist), GTK_SELECTION_BROWSE);
284
285     hbox = gtk_hbox_new (FALSE, 8);
286     gtk_box_pack_end (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
287
288     gtkut_button_set_create (&bbox, &select_btn, _("Select"),
289                              &cancel_btn, _("Cancel"), NULL, NULL);
290     gtk_box_pack_end (GTK_BOX (hbox), bbox, FALSE, FALSE, 0);
291     gtk_widget_grab_default (select_btn);
292
293     gtk_signal_connect (GTK_OBJECT (select_btn), "clicked",
294                         GTK_SIGNAL_FUNC (select_btn_cb), clist);
295     gtk_signal_connect (GTK_OBJECT(cancel_btn), "clicked",
296                         GTK_SIGNAL_FUNC (cancel_btn_cb), NULL);
297
298     vbox2 = gtk_vbox_new (FALSE, 4);
299     gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, FALSE, 0);
300
301     progress = gtk_progress_bar_new ();
302     gtk_box_pack_start (GTK_BOX (vbox2), progress, FALSE, FALSE, 4);
303     gtk_progress_set_activity_mode (GTK_PROGRESS (progress), 1);
304
305     gtk_widget_show_all (window);
306     select_keys.window = window;
307     select_keys.toplabel = GTK_LABEL (label);
308     select_keys.clist  = GTK_CLIST (clist);
309     select_keys.progress = GTK_PROGRESS (progress);
310 }
311
312
313 static void
314 open_dialog ()
315 {
316     if ( !select_keys.window )
317         create_dialog ();
318     select_keys.okay = 0;
319     gtk_widget_show (select_keys.window);
320 }
321
322
323 static void
324 close_dialog ()
325 {
326     gtk_widget_destroy (select_keys.window);
327     select_keys.window = NULL;
328 }
329
330
331 static void 
332 key_pressed_cb (GtkWidget *widget, GdkEventKey *event, gpointer data)
333 {
334     if (event && event->keyval == GDK_Escape) {
335         select_keys.okay = 0;
336         gtk_main_quit ();
337     }
338 }
339
340
341 static void 
342 select_btn_cb (GtkWidget *widget, gpointer data)
343 {
344     GtkCList *clist = GTK_CLIST (data);
345     int row;
346     GpgmeKey key;
347
348     if (!clist->selection) {
349         g_message ("** nothing selected");
350         return;
351     }
352     row = GPOINTER_TO_INT(clist->selection->data);
353     key = gtk_clist_get_row_data(clist, row);
354     if (key) {
355         const char *s = gpgme_key_get_string_attr (key,
356                                                    GPGME_ATTR_FPR,
357                                                    NULL, 0 );
358         g_message ("** FIXME: we are faking the trust calculation");
359         if (!gpgme_recipients_add_name_with_validity (select_keys.rset, s,
360                                                       GPGME_VALIDITY_FULL) ) {
361             select_keys.okay = 1;
362             gtk_main_quit ();
363         }
364     }
365 }
366
367
368 static void 
369 cancel_btn_cb (GtkWidget *widget, gpointer data)
370 {
371     select_keys.okay = 0;
372     gtk_main_quit ();
373 }
374
375 #endif /*USE_GPGME*/