From: Sergey Vlasov Date: Sat, 21 Apr 2001 13:18:13 +0000 (+0000) Subject: Enhanced GnuPG key selection support. X-Git-Tag: custom-headers~5 X-Git-Url: http://git.claws-mail.org/?p=claws.git;a=commitdiff_plain;h=af2d08928764e0dca21a49d512dc26b536be6d7f Enhanced GnuPG key selection support. --- diff --git a/ChangeLog.claws b/ChangeLog.claws index 23e8f4d75..408b63f2d 100644 --- a/ChangeLog.claws +++ b/ChangeLog.claws @@ -1,6 +1,8 @@ 2001-04-21 - * tag name claws added to prevent confusion with main branch [alfons] + * enhanced GnuPG key selection support [sergey] + + * tag name claws added to prevent confusion with main branch [alfons] * Sync with sylpheed-0.4.65cvs4 and made it compile. [sergey] diff --git a/src/compose.c b/src/compose.c index 9a0a68631..51137ef1c 100644 --- a/src/compose.c +++ b/src/compose.c @@ -1588,7 +1588,7 @@ static gint compose_write_to_file(Compose *compose, const gchar *file, #if USE_GPGME if (compose->use_signing) { - if (rfc2015_sign(file) < 0) { + if (rfc2015_sign(file, compose->account) < 0) { unlink(file); return -1; } diff --git a/src/prefs_account.c b/src/prefs_account.c index c91b9f75e..886503a67 100644 --- a/src/prefs_account.c +++ b/src/prefs_account.c @@ -104,6 +104,15 @@ static struct Compose { GtkWidget *sigpath_entry; } compose; +#if USE_GPGME +static struct Privacy { + GtkWidget *defaultkey_radiobtn; + GtkWidget *emailkey_radiobtn; + GtkWidget *customkey_radiobtn; + GtkWidget *customkey_entry; +} privacy; +#endif /* USE_GPGME */ + static struct Advanced { GtkWidget *smtpport_chkbtn; GtkWidget *smtpport_entry; @@ -116,6 +125,10 @@ static struct Advanced { static void prefs_account_protocol_set_data_from_optmenu(PrefParam *pparam); static void prefs_account_protocol_set_optmenu (PrefParam *pparam); static void prefs_account_protocol_activated (GtkMenuItem *menuitem); +#if USE_GPGME +static void prefs_account_sign_key_set_data_from_radiobtn (PrefParam *pparam); +static void prefs_account_sign_key_set_radiobtn (PrefParam *pparam); +#endif /* USE_GPGME */ static PrefParam param[] = { /* Basic */ @@ -228,6 +241,17 @@ static PrefParam param[] = { &compose.sigpath_entry, prefs_set_data_from_entry, prefs_set_entry}, +#if USE_GPGME + /* Privacy */ + {"sign_key", NULL, &tmp_ac_prefs.sign_key, P_ENUM, + &privacy.defaultkey_radiobtn, + prefs_account_sign_key_set_data_from_radiobtn, + prefs_account_sign_key_set_radiobtn}, + {"sign_key_id", "", &tmp_ac_prefs.sign_key_id, P_STRING, + &privacy.customkey_entry, + prefs_set_data_from_entry, prefs_set_entry}, +#endif /* USE_GPGME */ + /* Advanced */ {"set_smtpport", "FALSE", &tmp_ac_prefs.set_smtpport, P_BOOL, &advanced.smtpport_chkbtn, @@ -261,6 +285,9 @@ static void prefs_account_basic_create (void); static void prefs_account_receive_create (void); static void prefs_account_send_create (void); static void prefs_account_compose_create (void); +#if USE_GPGME +static void prefs_account_privacy_create (void); +#endif /* USE_GPGME */ static void prefs_account_advanced_create (void); static void prefs_account_key_pressed (GtkWidget *widget, @@ -459,6 +486,10 @@ static void prefs_account_create(void) SET_NOTEBOOK_LABEL(dialog.notebook, _("Send"), page++); prefs_account_compose_create(); SET_NOTEBOOK_LABEL(dialog.notebook, _("Compose"), page++); +#if USE_GPGME + prefs_account_privacy_create(); + SET_NOTEBOOK_LABEL(dialog.notebook, _("Privacy"), page++); +#endif /* USE_GPGME */ prefs_account_advanced_create(); SET_NOTEBOOK_LABEL(dialog.notebook, _("Advanced"), page++); @@ -903,6 +934,84 @@ static void prefs_account_compose_create(void) compose.sigpath_entry = sigpath_entry; } +#if USE_GPGME +static void prefs_account_privacy_create(void) +{ + GtkWidget *vbox1; + GtkWidget *frame1; + GtkWidget *vbox2; + GtkWidget *hbox1; + GtkWidget *label; + GtkWidget *defaultkey_radiobtn; + GtkWidget *emailkey_radiobtn; + GtkWidget *customkey_radiobtn; + GtkWidget *customkey_entry; + + vbox1 = gtk_vbox_new (FALSE, VSPACING); + gtk_widget_show (vbox1); + gtk_container_add (GTK_CONTAINER (dialog.notebook), vbox1); + gtk_container_set_border_width (GTK_CONTAINER (vbox1), BOX_BORDER); + + PACK_FRAME (vbox1, frame1, _("Sign key")); + + vbox2 = gtk_vbox_new (FALSE, VSPACING_NARROW); + gtk_widget_show (vbox2); + gtk_container_add (GTK_CONTAINER (frame1), vbox2); + gtk_container_set_border_width (GTK_CONTAINER (vbox2), 8); + + defaultkey_radiobtn = gtk_radio_button_new_with_label + (NULL, _("Use default GnuPG key")); + gtk_widget_show (defaultkey_radiobtn); + gtk_box_pack_start (GTK_BOX (vbox2), defaultkey_radiobtn, + FALSE, FALSE, 0); + gtk_object_set_user_data (GTK_OBJECT (defaultkey_radiobtn), + GINT_TO_POINTER (SIGN_KEY_DEFAULT)); + + emailkey_radiobtn = gtk_radio_button_new_with_label_from_widget + (GTK_RADIO_BUTTON (defaultkey_radiobtn), + _("Select key by your email address")); + gtk_widget_show (emailkey_radiobtn); + gtk_box_pack_start (GTK_BOX (vbox2), emailkey_radiobtn, + FALSE, FALSE, 0); + gtk_object_set_user_data (GTK_OBJECT (emailkey_radiobtn), + GINT_TO_POINTER (SIGN_KEY_BY_FROM)); + + customkey_radiobtn = gtk_radio_button_new_with_label_from_widget + (GTK_RADIO_BUTTON (defaultkey_radiobtn), + _("Specify key manually")); + gtk_widget_show (customkey_radiobtn); + gtk_box_pack_start (GTK_BOX (vbox2), customkey_radiobtn, + FALSE, FALSE, 0); + gtk_object_set_user_data (GTK_OBJECT (customkey_radiobtn), + GINT_TO_POINTER (SIGN_KEY_CUSTOM)); + + hbox1 = gtk_hbox_new (FALSE, 8); + gtk_widget_show (hbox1); + gtk_box_pack_start (GTK_BOX (vbox2), hbox1, FALSE, FALSE, 0); + + label = gtk_label_new (""); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox1), label, FALSE, FALSE, 0); + gtk_widget_set_usize (label, 16, -1); + + label = gtk_label_new (_("User or key ID:")); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox1), label, FALSE, FALSE, 0); + + customkey_entry = gtk_entry_new (); + gtk_widget_show (customkey_entry); + gtk_box_pack_start (GTK_BOX (hbox1), customkey_entry, + TRUE, TRUE, 0); + + SET_TOGGLE_SENSITIVITY (customkey_radiobtn, customkey_entry); + + privacy.defaultkey_radiobtn = defaultkey_radiobtn; + privacy.emailkey_radiobtn = emailkey_radiobtn; + privacy.customkey_radiobtn = customkey_radiobtn; + privacy.customkey_entry = customkey_entry; +} +#endif /* USE_GPGME */ + static void prefs_account_advanced_create(void) { GtkWidget *vbox1; @@ -1033,6 +1142,48 @@ static void prefs_account_cancel(void) gtk_main_quit(); } +#if USE_GPGME + +static void prefs_account_sign_key_set_data_from_radiobtn(PrefParam *pparam) +{ + GtkRadioButton *radiobtn; + GSList *group; + + radiobtn = GTK_RADIO_BUTTON (*pparam->widget); + group = gtk_radio_button_group (radiobtn); + while (group != NULL) { + GtkToggleButton *btn = GTK_TOGGLE_BUTTON (group->data); + if (gtk_toggle_button_get_active (btn)) { + *((SignKeyType *)pparam->data) = GPOINTER_TO_INT + (gtk_object_get_user_data (GTK_OBJECT (btn))); + break; + } + group = group->next; + } +} + +static void prefs_account_sign_key_set_radiobtn(PrefParam *pparam) +{ + GtkRadioButton *radiobtn; + GSList *group; + gpointer data; + + data = GINT_TO_POINTER (*((RecvProtocol *)pparam->data)); + radiobtn = GTK_RADIO_BUTTON (*pparam->widget); + group = gtk_radio_button_group (radiobtn); + while (group != NULL) { + GtkToggleButton *btn = GTK_TOGGLE_BUTTON (group->data); + gpointer data1 = gtk_object_get_user_data (GTK_OBJECT (btn)); + if (data1 == data) { + gtk_toggle_button_set_active (btn, TRUE); + break; + } + group = group->next; + } +} + +#endif /* USE_GPGME */ + static void prefs_account_protocol_set_data_from_optmenu(PrefParam *pparam) { GtkWidget *menu; diff --git a/src/prefs_account.h b/src/prefs_account.h index f8c6a0dd6..0881c7c36 100644 --- a/src/prefs_account.h +++ b/src/prefs_account.h @@ -35,6 +35,14 @@ typedef enum { A_LOCAL } RecvProtocol; +#if USE_GPGME +typedef enum { + SIGN_KEY_DEFAULT, + SIGN_KEY_BY_FROM, + SIGN_KEY_CUSTOM +} SignKeyType; +#endif /* USE_GPGME */ + struct _PrefsAccount { gchar *account_name; @@ -79,6 +87,12 @@ struct _PrefsAccount /* Compose */ gchar *sig_path; +#if USE_GPGME + /* Privacy */ + SignKeyType sign_key; + gchar *sign_key_id; +#endif /* USE_GPGME */ + /* Advanced */ gboolean set_smtpport; gushort smtpport; diff --git a/src/rfc2015.c b/src/rfc2015.c index d064ec541..3791441cc 100644 --- a/src/rfc2015.c +++ b/src/rfc2015.c @@ -867,12 +867,73 @@ failure: return -1; /* error */ } +static int +set_signers (GpgmeCtx ctx, PrefsAccount *ac) +{ + GSList *key_list = NULL; + GpgmeCtx list_ctx = NULL; + const char *keyid = NULL; + GSList *p; + GpgmeError err; + GpgmeKey key; + + if (ac == NULL) + return 0; + + switch (ac->sign_key) { + case SIGN_KEY_DEFAULT: + return 0; /* nothing to do */ + + case SIGN_KEY_BY_FROM: + keyid = ac->address; + break; + + case SIGN_KEY_CUSTOM: + keyid = ac->sign_key_id; + break; + + default: + g_assert_not_reached (); + } + + err = gpgme_new (&list_ctx); + if (err) + goto leave; + err = gpgme_op_keylist_start (list_ctx, keyid, 1); + if (err) + goto leave; + while ( !(err = gpgme_op_keylist_next (list_ctx, &key)) ) { + key_list = g_slist_append (key_list, key); + } + if (err != GPGME_EOF) + goto leave; + if (key_list == NULL) { + g_warning ("no keys found for keyid \"%s\"", keyid); + } + gpgme_signers_clear (ctx); + for (p = key_list; p != NULL; p = p->next) { + err = gpgme_signers_add (ctx, (GpgmeKey) p->data); + if (err) + goto leave; + } + +leave: + if (err) + g_message ("** set_signers failed: %s", gpgme_strerror (err)); + for (p = key_list; p != NULL; p = p->next) + gpgme_key_unref ((GpgmeKey) p->data); + g_slist_free (key_list); + if (list_ctx) + gpgme_release (list_ctx); + return err; +} + /* * plain contains an entire mime object. Sign it and return an * GpgmeData object with the signature of it or NULL in case of error. */ static GpgmeData -pgp_sign (GpgmeData plain) +pgp_sign (GpgmeData plain, PrefsAccount *ac) { GpgmeCtx ctx = NULL; GpgmeError err; @@ -894,6 +955,9 @@ pgp_sign (GpgmeData plain) } gpgme_set_textmode (ctx, 1); gpgme_set_armor (ctx, 1); + err = set_signers (ctx, ac); + if (err) + goto leave; err = gpgme_op_sign (ctx, plain, sig, GPGME_SIG_MODE_DETACH); leave: @@ -914,7 +978,7 @@ leave: * Sign the file and replace its content with the signed one. */ int -rfc2015_sign (const char *file) +rfc2015_sign (const char *file, PrefsAccount *ac) { FILE *fp = NULL; char buf[BUFFSIZE]; @@ -996,7 +1060,7 @@ rfc2015_sign (const char *file) goto failure; } - sigdata = pgp_sign (plain); + sigdata = pgp_sign (plain, ac); if (!sigdata) goto failure; diff --git a/src/rfc2015.h b/src/rfc2015.h index 6fd192111..98115b996 100644 --- a/src/rfc2015.h +++ b/src/rfc2015.h @@ -24,6 +24,7 @@ #include #include "procmime.h" +#include "prefs_account.h" void rfc2015_secure_remove (const char *fname); MimeInfo * rfc2015_find_signature (MimeInfo *mimeinfo); @@ -32,6 +33,6 @@ void rfc2015_check_signature (MimeInfo *mimeinfo, FILE *fp); int rfc2015_is_encrypted (MimeInfo *mimeinfo); void rfc2015_decrypt_message (MsgInfo *msginfo, MimeInfo *mimeinfo, FILE *fp); int rfc2015_encrypt (const char *file, GSList *recp_list); -int rfc2015_sign (const char *file); +int rfc2015_sign (const char *file, PrefsAccount *ac); #endif /* __RFC2015_H__ */ diff --git a/src/select-keys.c b/src/select-keys.c index 04514be6c..b397ef875 100644 --- a/src/select-keys.c +++ b/src/select-keys.c @@ -37,13 +37,17 @@ #include #include #include -#include #include #include "intl.h" #include "select-keys.h" #include "utils.h" #include "gtkutils.h" +#include "inputdialog.h" + +#define DIM(v) (sizeof(v)/sizeof((v)[0])) +#define DIMof(type,member) DIM(((type *)0)->member) + enum col_titles { COL_ALGO, @@ -55,39 +59,51 @@ enum col_titles { N_COL_TITLES }; -static struct { +struct select_keys_s { int okay; GtkWidget *window; GtkLabel *toplabel; GtkCList *clist; - GtkProgress *progress; const char *pattern; GpgmeRecipients rset; -} select_keys; + GpgmeCtx select_ctx; + + GtkSortType sort_type; + enum col_titles sort_column; + +}; static void set_row (GtkCList *clist, GpgmeKey key ); -static void fill_clist (GtkCList *clist, const char *pattern ); -static void create_dialog (void); -static void open_dialog (void); -static void close_dialog (void); +static void fill_clist (struct select_keys_s *sk, const char *pattern ); +static void create_dialog (struct select_keys_s *sk); +static void open_dialog (struct select_keys_s *sk); +static void close_dialog (struct select_keys_s *sk); static void key_pressed_cb (GtkWidget *widget, GdkEventKey *event, gpointer data); static void select_btn_cb (GtkWidget *widget, gpointer data); static void cancel_btn_cb (GtkWidget *widget, gpointer data); +static void other_btn_cb (GtkWidget *widget, gpointer data); +static void sort_keys ( struct select_keys_s *sk, enum col_titles column); +static void sort_keys_name (GtkWidget *widget, gpointer data); +static void sort_keys_email (GtkWidget *widget, gpointer data); static void -update_progress (void) +update_progress (struct select_keys_s *sk, int running, const char *pattern) { - if (select_keys.progress) { - gfloat val = gtk_progress_get_value (select_keys.progress); - - val += 1; - gtk_progress_set_value (select_keys.progress, val); - if ( !GTK_WIDGET_VISIBLE (select_keys.progress) ) - gtk_widget_show (GTK_WIDGET (select_keys.progress)); - } + static int windmill[] = { '-', '\\', '|', '/' }; + char *buf; + + if (!running) + buf = g_strdup_printf (_("Please select key for `%s'"), + pattern); + else + buf = g_strdup_printf (_("Collecting info for `%s' ... %c"), + pattern, + windmill[running%DIM(windmill)] ); + gtk_label_set_text (sk->toplabel, buf ); + g_free (buf); } @@ -104,38 +120,37 @@ update_progress (void) GpgmeRecipients gpgmegtk_recipient_selection (GSList *recp_names) { + struct select_keys_s sk; GpgmeError err; - err = gpgme_recipients_new (&select_keys.rset); + memset ( &sk, 0, sizeof sk); + + err = gpgme_recipients_new (&sk.rset); if (err) { g_message ("** failed to allocate recipients set: %s", gpgme_strerror (err) ); return NULL; } - open_dialog (); + open_dialog (&sk); do { - select_keys.pattern = recp_names? recp_names->data:NULL; - gtk_label_set_text (select_keys.toplabel, select_keys.pattern ); - gtk_clist_clear (select_keys.clist); - fill_clist (select_keys.clist, select_keys.pattern); + sk.pattern = recp_names? recp_names->data:NULL; + gtk_clist_clear (sk.clist); + fill_clist (&sk, sk.pattern); + update_progress (&sk, 0, sk.pattern); gtk_main (); if (recp_names) recp_names = recp_names->next; - } while (select_keys.okay && recp_names ); + } while (sk.okay && recp_names ); - close_dialog (); + close_dialog (&sk); - { - GpgmeRecipients rset = select_keys.rset; - select_keys.rset = NULL; - if (!rset) { - gpgme_recipients_release (rset); - rset = NULL; - } - return rset; + if (!sk.okay) { + gpgme_recipients_release (sk.rset); + sk.rset = NULL; } + return sk.rset; } static void @@ -180,18 +195,31 @@ set_row (GtkCList *clist, GpgmeKey key ) static void -fill_clist (GtkCList *clist, const char *pattern ) +fill_clist (struct select_keys_s *sk, const char *pattern ) { + GtkCList *clist; GpgmeCtx ctx; GpgmeError err; GpgmeKey key; + int running=0; + + g_return_if_fail (sk); + clist = sk->clist; + g_return_if_fail (clist); debug_print ("select_keys:fill_clist: pattern `%s'\n", pattern ); /*gtk_clist_freeze (select_keys.clist);*/ err = gpgme_new (&ctx); - g_assert (!err); + if (err) { + g_message ("** gpgme_new failed: %s", + gpgme_strerror (err)); + return; + } + sk->select_ctx = ctx; + + update_progress (sk, ++running, pattern); while (gtk_events_pending ()) gtk_main_iteration (); @@ -199,21 +227,23 @@ fill_clist (GtkCList *clist, const char *pattern ) if (err) { g_message ("** gpgme_op_keylist_start(%s) failed: %s", pattern, gpgme_strerror (err)); + sk->select_ctx = NULL; + gpgme_release (ctx); return; } - update_progress (); + update_progress (sk, ++running, pattern); while ( !(err = gpgme_op_keylist_next ( ctx, &key )) ) { debug_print ("%% %s:%d: insert\n", __FILE__ ,__LINE__ ); set_row (clist, key ); key = NULL; - update_progress (); + update_progress (sk, ++running, pattern); while (gtk_events_pending ()) gtk_main_iteration (); } debug_print ("%% %s:%d: ready\n", __FILE__ ,__LINE__ ); - gtk_widget_hide (GTK_WIDGET (select_keys.progress)); if ( err != GPGME_EOF ) g_message ("** gpgme_op_keylist_next failed: %s", gpgme_strerror (err)); + sk->select_ctx = NULL; gpgme_release (ctx); /*gtk_clist_thaw (select_keys.clist);*/ } @@ -222,7 +252,7 @@ fill_clist (GtkCList *clist, const char *pattern ) static void -create_dialog () +create_dialog (struct select_keys_s *sk) { GtkWidget *window; GtkWidget *vbox, *vbox2, *hbox; @@ -230,28 +260,25 @@ create_dialog () GtkWidget *scrolledwin; GtkWidget *clist; GtkWidget *label; - GtkWidget *progress; - GtkWidget *select_btn, *cancel_btn; - gchar *titles[N_COL_TITLES]; + GtkWidget *other_btn, *select_btn, *cancel_btn; + const char *titles[N_COL_TITLES]; - g_assert (!select_keys.window); + g_assert (!sk->window); window = gtk_window_new (GTK_WINDOW_DIALOG); gtk_widget_set_usize (window, 500, 320); gtk_container_set_border_width (GTK_CONTAINER (window), 8); gtk_window_set_title (GTK_WINDOW (window), _("Select Keys")); gtk_window_set_modal (GTK_WINDOW (window), TRUE); gtk_signal_connect (GTK_OBJECT (window), "delete_event", - GTK_SIGNAL_FUNC (close_dialog), NULL); + GTK_SIGNAL_FUNC (close_dialog), sk); gtk_signal_connect (GTK_OBJECT (window), "key_press_event", - GTK_SIGNAL_FUNC (key_pressed_cb), NULL); + GTK_SIGNAL_FUNC (key_pressed_cb), sk); vbox = gtk_vbox_new (FALSE, 8); gtk_container_add (GTK_CONTAINER (window), vbox); hbox = gtk_hbox_new(FALSE, 4); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); - label = gtk_label_new ( _("Select key for: ") ); - gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); label = gtk_label_new ( "" ); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); @@ -273,7 +300,7 @@ create_dialog () titles[COL_EMAIL] = _("Address"); titles[COL_VALIDITY] = _("Val"); - clist = gtk_clist_new_with_titles (N_COL_TITLES, titles); + clist = gtk_clist_new_with_titles (N_COL_TITLES, (char**)titles); gtk_container_add (GTK_CONTAINER (scrolledwin), clist); gtk_clist_set_column_width (GTK_CLIST(clist), COL_ALGO, 40); gtk_clist_set_column_width (GTK_CLIST(clist), COL_KEYID, 60); @@ -281,58 +308,70 @@ create_dialog () gtk_clist_set_column_width (GTK_CLIST(clist), COL_EMAIL, 100); gtk_clist_set_column_width (GTK_CLIST(clist), COL_VALIDITY, 20); gtk_clist_set_selection_mode (GTK_CLIST(clist), GTK_SELECTION_BROWSE); + gtk_signal_connect (GTK_OBJECT(GTK_CLIST(clist)->column[COL_NAME].button), + "clicked", + GTK_SIGNAL_FUNC(sort_keys_name), sk); + gtk_signal_connect (GTK_OBJECT(GTK_CLIST(clist)->column[COL_EMAIL].button), + "clicked", + GTK_SIGNAL_FUNC(sort_keys_email), sk); hbox = gtk_hbox_new (FALSE, 8); gtk_box_pack_end (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); - gtkut_button_set_create (&bbox, &select_btn, _("Select"), - &cancel_btn, _("Cancel"), NULL, NULL); + gtkut_button_set_create (&bbox, + &other_btn, _("Other"), + &select_btn, _("Select"), + &cancel_btn, _("Cancel")); gtk_box_pack_end (GTK_BOX (hbox), bbox, FALSE, FALSE, 0); gtk_widget_grab_default (select_btn); + gtk_signal_connect (GTK_OBJECT (other_btn), "clicked", + GTK_SIGNAL_FUNC (other_btn_cb), sk); gtk_signal_connect (GTK_OBJECT (select_btn), "clicked", - GTK_SIGNAL_FUNC (select_btn_cb), clist); + GTK_SIGNAL_FUNC (select_btn_cb), sk); gtk_signal_connect (GTK_OBJECT(cancel_btn), "clicked", - GTK_SIGNAL_FUNC (cancel_btn_cb), NULL); + GTK_SIGNAL_FUNC (cancel_btn_cb), sk); + vbox2 = gtk_vbox_new (FALSE, 4); gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, FALSE, 0); - progress = gtk_progress_bar_new (); - gtk_box_pack_start (GTK_BOX (vbox2), progress, FALSE, FALSE, 4); - gtk_progress_set_activity_mode (GTK_PROGRESS (progress), 1); - gtk_widget_show_all (window); - select_keys.window = window; - select_keys.toplabel = GTK_LABEL (label); - select_keys.clist = GTK_CLIST (clist); - select_keys.progress = GTK_PROGRESS (progress); + sk->window = window; + sk->toplabel = GTK_LABEL (label); + sk->clist = GTK_CLIST (clist); } static void -open_dialog () +open_dialog (struct select_keys_s *sk) { - if ( !select_keys.window ) - create_dialog (); - select_keys.okay = 0; - gtk_widget_show (select_keys.window); + if ( !sk->window ) + create_dialog (sk); + sk->okay = 0; + sk->sort_column = N_COL_TITLES; /* use an invalid value */ + sk->sort_type = GTK_SORT_ASCENDING; + gtk_widget_show (sk->window); } static void -close_dialog () +close_dialog (struct select_keys_s *sk) { - gtk_widget_destroy (select_keys.window); - select_keys.window = NULL; + g_return_if_fail (sk); + gtk_widget_destroy (sk->window); + sk->window = NULL; } static void key_pressed_cb (GtkWidget *widget, GdkEventKey *event, gpointer data) { + struct select_keys_s *sk = data; + + g_return_if_fail (sk); if (event && event->keyval == GDK_Escape) { - select_keys.okay = 0; + sk->okay = 0; gtk_main_quit (); } } @@ -341,24 +380,28 @@ key_pressed_cb (GtkWidget *widget, GdkEventKey *event, gpointer data) static void select_btn_cb (GtkWidget *widget, gpointer data) { - GtkCList *clist = GTK_CLIST (data); + struct select_keys_s *sk = data; int row; GpgmeKey key; - if (!clist->selection) { + g_return_if_fail (sk); + if (!sk->clist->selection) { g_message ("** nothing selected"); return; } - row = GPOINTER_TO_INT(clist->selection->data); - key = gtk_clist_get_row_data(clist, row); + row = GPOINTER_TO_INT(sk->clist->selection->data); + key = gtk_clist_get_row_data(sk->clist, row); if (key) { const char *s = gpgme_key_get_string_attr (key, GPGME_ATTR_FPR, NULL, 0 ); - g_message ("** FIXME: we are faking the trust calculation"); - if (!gpgme_recipients_add_name_with_validity (select_keys.rset, s, + if ( gpgme_key_get_ulong_attr (key, GPGME_ATTR_VALIDITY, NULL, 0 ) + < GPGME_VALIDITY_FULL ) { + g_message ("** FIXME: we are faking the trust calculation"); + } + if (!gpgme_recipients_add_name_with_validity (sk->rset, s, GPGME_VALIDITY_FULL) ) { - select_keys.okay = 1; + sk->okay = 1; gtk_main_quit (); } } @@ -368,8 +411,102 @@ select_btn_cb (GtkWidget *widget, gpointer data) static void cancel_btn_cb (GtkWidget *widget, gpointer data) { - select_keys.okay = 0; + struct select_keys_s *sk = data; + + g_return_if_fail (sk); + sk->okay = 0; + if (sk->select_ctx) + gpgme_cancel (sk->select_ctx); gtk_main_quit (); } + +static void +other_btn_cb (GtkWidget *widget, gpointer data) +{ + struct select_keys_s *sk = data; + char *uid; + + g_return_if_fail (sk); + uid = input_dialog ( _("Add key"), + _("Enter another user or key ID\n"), + NULL ); + if (!uid) + return; + fill_clist (sk, uid); + update_progress (sk, 0, sk->pattern); + g_free (uid); +} + + +static gint +cmp_attr (gconstpointer pa, gconstpointer pb, GpgmeAttr attr) +{ + GpgmeKey a = ((GtkCListRow *)pa)->data; + GpgmeKey b = ((GtkCListRow *)pb)->data; + const char *sa, *sb; + + sa = a? gpgme_key_get_string_attr (a, attr, NULL, 0 ) : NULL; + sb = b? gpgme_key_get_string_attr (b, attr, NULL, 0 ) : NULL; + if (!sa) + return !!sb; + if (!sb) + return -1; + return strcasecmp(sa, sb); +} + +static gint +cmp_name (GtkCList *clist, gconstpointer pa, gconstpointer pb) +{ + return cmp_attr (pa, pb, GPGME_ATTR_NAME); +} + +static gint +cmp_email (GtkCList *clist, gconstpointer pa, gconstpointer pb) +{ + return cmp_attr (pa, pb, GPGME_ATTR_EMAIL); +} + +static void +sort_keys ( struct select_keys_s *sk, enum col_titles column) +{ + GtkCList *clist = sk->clist; + + switch (column) { + case COL_NAME: + gtk_clist_set_compare_func (clist, cmp_name); + break; + case COL_EMAIL: + gtk_clist_set_compare_func (clist, cmp_email); + break; + default: + return; + } + + /* column clicked again: toggle as-/decending */ + if ( sk->sort_column == column) { + sk->sort_type = sk->sort_type == GTK_SORT_ASCENDING ? + GTK_SORT_DESCENDING : GTK_SORT_ASCENDING; + } + else + sk->sort_type = GTK_SORT_ASCENDING; + + sk->sort_column = column; + gtk_clist_set_sort_type (clist, sk->sort_type); + gtk_clist_sort (clist); +} + +static void +sort_keys_name (GtkWidget *widget, gpointer data) +{ + sort_keys ( (struct select_keys_s*)data, COL_NAME ); +} + +static void +sort_keys_email (GtkWidget *widget, gpointer data) +{ + sort_keys ( (struct select_keys_s*)data, COL_EMAIL ); +} + + #endif /*USE_GPGME*/