[balsa/gtk3] Pop up key selection dialogue with all keys
- From: Peter Bloomfield <peterb src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [balsa/gtk3] Pop up key selection dialogue with all keys
- Date: Tue, 17 May 2016 01:13:40 +0000 (UTC)
commit fc02a5c0307e6eaf6952a3d0221413ebc808809a
Author: Peter Bloomfield <PeterBloomfield bellsouth net>
Date: Mon May 16 21:03:26 2016 -0400
Pop up key selection dialogue with all keys
* libbalsa/libbalsa-gpgme-cb.c (lb_gpgme_select_key),
(key_selection_changed_cb), (sort_iter_cmp_fn):
* libbalsa/libbalsa-gpgme-cb.h:
* libbalsa/libbalsa-gpgme.c (get_key_from_name), (get_pubkey),
(gpgme_add_signer), (gpgme_build_recipients):
* libbalsa/libbalsa-gpgme.h:
ChangeLog | 15 ++++++
libbalsa/libbalsa-gpgme-cb.c | 114 ++++++++++++++++++++++++++++++++----------
libbalsa/libbalsa-gpgme-cb.h | 9 +++-
libbalsa/libbalsa-gpgme.c | 90 ++++++++++++++++++++++++++-------
libbalsa/libbalsa-gpgme.h | 3 +-
5 files changed, 184 insertions(+), 47 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 4b56aa1..6931a22 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,20 @@
2016-05-16 Albrecht Dreß
+ With this patch, Balsa will pop up the key selection dialogue
+ containing /all/ keys which may be used for encryption in this
+ case. The user can either select a key, or cancel the
+ operation. This basically is the same behaviour as of
+ Thunderbird.
+
+ * libbalsa/libbalsa-gpgme-cb.c (lb_gpgme_select_key),
+ (key_selection_changed_cb), (sort_iter_cmp_fn):
+ * libbalsa/libbalsa-gpgme-cb.h:
+ * libbalsa/libbalsa-gpgme.c (get_key_from_name), (get_pubkey),
+ (gpgme_add_signer), (gpgme_build_recipients):
+ * libbalsa/libbalsa-gpgme.h:
+
+2016-05-16 Albrecht Dreß
+
* libbalsa/gmime-gpgme-signature.c
(libbalsa_cert_subject_readable):
This trivial patch makes sure that the GPG key or S/MIME
diff --git a/libbalsa/libbalsa-gpgme-cb.c b/libbalsa/libbalsa-gpgme-cb.c
index c360be0..327afab 100644
--- a/libbalsa/libbalsa-gpgme-cb.c
+++ b/libbalsa/libbalsa-gpgme-cb.c
@@ -71,6 +71,8 @@ typedef struct {
static void key_selection_changed_cb(GtkTreeSelection * selection,
gpgme_key_t * key);
+static gint sort_iter_cmp_fn(GtkTreeModel *model, GtkTreeIter *a,
+ GtkTreeIter *b, gpointer data);
static gchar *get_passphrase_real(const gchar * uid_hint,
const gchar * passphrase_info,
int prev_was_bad, GtkWindow * parent);
@@ -139,7 +141,7 @@ lb_gpgme_passphrase(void *hook, const gchar * uid_hint,
gpgme_key_t
-lb_gpgme_select_key(const gchar * user_name, gboolean secret, GList * keys,
+lb_gpgme_select_key(const gchar * user_name, lb_key_sel_md_t mode, GList * keys,
gpgme_protocol_t protocol, GtkWindow * parent)
{
static const gchar *col_titles[] =
@@ -149,13 +151,15 @@ lb_gpgme_select_key(const gchar * user_name, gboolean secret, GList * keys,
GtkWidget *label;
GtkWidget *scrolled_window;
GtkWidget *tree_view;
- GtkTreeStore *model;
+ GtkListStore *model;
+ GtkTreeSortable *sortable;
GtkTreeSelection *selection;
GtkTreeIter iter;
gint i, last_col;
gchar *prompt;
gchar *upcase_name;
gpgme_key_t use_key = NULL;
+ gint width, height;
/* FIXME: create dialog according to the Gnome HIG */
dialog = gtk_dialog_new_with_buttons(_("Select key"),
@@ -165,22 +169,38 @@ lb_gpgme_select_key(const gchar * user_name, gboolean secret, GList * keys,
_("_OK"), GTK_RESPONSE_OK,
_("_Cancel"), GTK_RESPONSE_CANCEL,
NULL);
+ gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_CANCEL);
+ gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog), GTK_RESPONSE_OK, FALSE);
#if HAVE_MACOSX_DESKTOP
libbalsa_macosx_menu_for_parent(dialog, parent);
#endif
vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12);
+ gtk_widget_set_vexpand (vbox, TRUE);
gtk_container_add(GTK_CONTAINER
(gtk_dialog_get_content_area(GTK_DIALOG(dialog))),
vbox);
- gtk_container_set_border_width(GTK_CONTAINER(vbox), 12);
- if (secret)
- prompt =
- g_strdup_printf(_("Select the private key for the signer %s"),
- user_name);
- else
- prompt = g_strdup_printf(_
- ("Select the public key for the recipient %s"),
- user_name);
+ gtk_container_set_border_width(GTK_CONTAINER(vbox), 12);
+ switch (mode) {
+ case LB_SELECT_PRIVATE_KEY:
+ prompt =
+ g_strdup_printf(_("Select the private key for the signer %s"),
+ user_name);
+ break;
+ case LB_SELECT_PUBLIC_KEY_USER:
+ prompt =
+ g_strdup_printf(_("Select the public key for the recipient %s"),
+ user_name);
+ break;
+ case LB_SELECT_PUBLIC_KEY_ANY:
+ prompt =
+ g_strdup_printf(_("There seems to be no public key for recipient "
+ "%s in your key ring.\nIf you are sure that the "
+ "recipient owns a different key, select it from "
+ "the list."), user_name);
+ break;
+ default:
+ g_assert_not_reached();
+ }
label = gtk_label_new(prompt);
gtk_widget_set_halign(label, GTK_ALIGN_START);
g_free(prompt);
@@ -191,17 +211,22 @@ lb_gpgme_select_key(const gchar * user_name, gboolean secret, GList * keys,
(scrolled_window),
GTK_SHADOW_ETCHED_IN);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
- GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_box_pack_start(GTK_BOX(vbox), scrolled_window, TRUE, TRUE, 0);
- model = gtk_tree_store_new(GPG_KEY_NUM_COLUMNS, G_TYPE_STRING, /* user ID */
+ model = gtk_list_store_new(GPG_KEY_NUM_COLUMNS, G_TYPE_STRING, /* user ID */
G_TYPE_STRING, /* key ID */
G_TYPE_INT, /* length */
G_TYPE_STRING, /* validity (gpg encrypt only) */
G_TYPE_POINTER); /* key */
+ sortable = GTK_TREE_SORTABLE(model);
+ gtk_tree_sortable_set_sort_func(sortable, 0, sort_iter_cmp_fn, NULL, NULL);
+ gtk_tree_sortable_set_sort_column_id(sortable, 0, GTK_SORT_ASCENDING);
tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
+ g_object_set_data(G_OBJECT(selection), "dialog", dialog);
+ g_object_set_data(G_OBJECT(selection), "first", GUINT_TO_POINTER(1));
gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
g_signal_connect(G_OBJECT(selection), "changed",
G_CALLBACK(key_selection_changed_cb), &use_key);
@@ -216,9 +241,11 @@ lb_gpgme_select_key(const gchar * user_name, gboolean secret, GList * keys,
gboolean uid_found;
/* find the relevant subkey */
- while (subkey && ((secret && !subkey->can_sign) ||
- (!secret && !subkey->can_encrypt)))
+ while (subkey &&
+ (((mode == LB_SELECT_PRIVATE_KEY) && !subkey->can_sign) ||
+ ((mode != LB_SELECT_PRIVATE_KEY) && !subkey->can_encrypt))) {
subkey = subkey->next;
+ }
/* find the relevant uid */
uid_found = FALSE;
@@ -227,7 +254,9 @@ lb_gpgme_select_key(const gchar * user_name, gboolean secret, GList * keys,
uid_info = libbalsa_cert_subject_readable(uid->uid);
/* check the email field which may or may not be present */
- if (uid->email && !g_ascii_strcasecmp(uid->email, user_name))
+ if (uid->email &&
+ ((mode == LB_SELECT_PUBLIC_KEY_ANY) ||
+ !g_ascii_strcasecmp(uid->email, user_name)))
uid_found = TRUE;
else {
/* no email or no match, check the uid */
@@ -242,9 +271,9 @@ lb_gpgme_select_key(const gchar * user_name, gboolean secret, GList * keys,
}
/* append the element */
- if (subkey && uid) {
- gtk_tree_store_append(GTK_TREE_STORE(model), &iter, NULL);
- gtk_tree_store_set(GTK_TREE_STORE(model), &iter,
+ if (subkey && uid && uid_info) {
+ gtk_list_store_append(model, &iter);
+ gtk_list_store_set(model, &iter,
GPG_KEY_USER_ID_COLUMN, uid_info,
GPG_KEY_ID_COLUMN, subkey->keyid,
GPG_KEY_LENGTH_COLUMN, subkey->length,
@@ -260,7 +289,7 @@ lb_gpgme_select_key(const gchar * user_name, gboolean secret, GList * keys,
g_object_unref(G_OBJECT(model));
/* show the validity only if we are asking for a gpg public key */
- last_col = (protocol == GPGME_PROTOCOL_CMS || secret) ?
+ last_col = (protocol == GPGME_PROTOCOL_CMS || (mode == LB_SELECT_PRIVATE_KEY)) ?
GPG_KEY_LENGTH_COLUMN : GPG_KEY_VALIDITY_COLUMN;
for (i = 0; i <= last_col; i++) {
GtkCellRenderer *renderer;
@@ -272,11 +301,14 @@ lb_gpgme_select_key(const gchar * user_name, gboolean secret, GList * keys,
renderer, "text", i,
NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), column);
- gtk_tree_view_column_set_resizable(column, TRUE);
+ gtk_tree_view_column_set_resizable(column, (i == 0) ? TRUE : FALSE);
}
gtk_container_add(GTK_CONTAINER(scrolled_window), tree_view);
- gtk_window_set_default_size(GTK_WINDOW(dialog), 500, 300);
+
+ /* set window size to 2/3 of the parent */
+ gtk_window_get_size(parent, &width, &height);
+ gtk_window_set_default_size(GTK_WINDOW(dialog), (2 * width) / 3, (2 * height) / 3);
gtk_widget_show_all(gtk_dialog_get_content_area(GTK_DIALOG(dialog)));
if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_OK)
@@ -425,9 +457,37 @@ get_passphrase_idle(gpointer data)
static void
key_selection_changed_cb(GtkTreeSelection * selection, gpgme_key_t * key)
{
- GtkTreeIter iter;
- GtkTreeModel *model;
-
- if (gtk_tree_selection_get_selected(selection, &model, &iter))
- gtk_tree_model_get(model, &iter, GPG_KEY_PTR_COLUMN, key, -1);
+ GtkDialog *dialog =
+ GTK_DIALOG(g_object_get_data(G_OBJECT(selection), "dialog"));
+
+ if (GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(selection), "first")) != 0) {
+ gtk_tree_selection_unselect_all(selection);
+ g_object_set_data(G_OBJECT(selection), "first", GUINT_TO_POINTER(0));
+ } else {
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+
+ if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
+ gtk_tree_model_get(model, &iter, GPG_KEY_PTR_COLUMN, key, -1);
+ gtk_dialog_set_response_sensitive(dialog, GTK_RESPONSE_OK, TRUE);
+ } else {
+ gtk_dialog_set_response_sensitive(dialog, GTK_RESPONSE_OK, FALSE);
+ }
+ }
}
+
+/* compare function for the key list */
+static gint
+sort_iter_cmp_fn(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b,
+ gpointer data)
+{
+ gchar *name1, *name2;
+ gint result;
+
+ gtk_tree_model_get(model, a, 0, &name1, -1);
+ gtk_tree_model_get(model, b, 0, &name2, -1);
+ result = g_utf8_collate(name1, name2);
+ g_free(name1);
+ g_free(name2);
+ return result;
+ }
diff --git a/libbalsa/libbalsa-gpgme-cb.h b/libbalsa/libbalsa-gpgme-cb.h
index 802ce5f..c16f59e 100644
--- a/libbalsa/libbalsa-gpgme-cb.h
+++ b/libbalsa/libbalsa-gpgme-cb.h
@@ -37,10 +37,17 @@ extern "C" {
#endif /* __cplusplus */
+typedef enum {
+ LB_SELECT_PRIVATE_KEY = 1,
+ LB_SELECT_PUBLIC_KEY_USER,
+ LB_SELECT_PUBLIC_KEY_ANY
+} lb_key_sel_md_t;
+
+
gpgme_error_t lb_gpgme_passphrase(void *hook, const gchar * uid_hint,
const gchar * passphrase_info,
int prev_was_bad, int fd);
-gpgme_key_t lb_gpgme_select_key(const gchar * user_name, gboolean secret,
+gpgme_key_t lb_gpgme_select_key(const gchar * user_name, lb_key_sel_md_t mode,
GList * keys, gpgme_protocol_t protocol,
GtkWindow * parent);
gboolean lb_gpgme_accept_low_trust_key(const gchar * user_name,
diff --git a/libbalsa/libbalsa-gpgme.c b/libbalsa/libbalsa-gpgme.c
index 1110677..f22cf2c 100644
--- a/libbalsa/libbalsa-gpgme.c
+++ b/libbalsa/libbalsa-gpgme.c
@@ -823,8 +823,9 @@ get_key_from_name(gpgme_ctx_t ctx, const gchar * name, gboolean secret,
if (g_list_length(keys) > 1) {
if (select_key_cb)
key =
- select_key_cb(name, secret, keys, gpgme_get_protocol(ctx),
- parent);
+ select_key_cb(name,
+ secret ? LB_SELECT_PRIVATE_KEY : LB_SELECT_PUBLIC_KEY_USER,
+ keys, gpgme_get_protocol(ctx), parent);
else {
if (error)
g_set_error(error, GPGME_ERROR_QUARK,
@@ -885,6 +886,57 @@ get_key_from_name(gpgme_ctx_t ctx, const gchar * name, gboolean secret,
}
+static gpgme_key_t
+get_pubkey(gpgme_ctx_t ctx, const gchar * name, gboolean accept_all,
+ GtkWindow * parent, GError ** error)
+{
+ GList *keys = NULL;
+ gpgme_key_t key;
+ gpgme_error_t err;
+ time_t now = time(NULL);
+
+ /* let gpgme list keys */
+ if ((err = gpgme_op_keylist_start(ctx, NULL, 0)) != GPG_ERR_NO_ERROR) {
+ gchar *msg = g_strdup_printf(_("could not list keys"));
+
+ g_set_error_from_gpgme(error, err, msg);
+ g_free(msg);
+ return NULL;
+ }
+
+ while ((err = gpgme_op_keylist_next(ctx, &key)) == GPG_ERR_NO_ERROR) {
+ /* check if this key and the relevant subkey are usable */
+ if (check_key(key, 0, now))
+ keys = g_list_append(keys, key);
+ }
+
+ if (gpg_err_code(err) != GPG_ERR_EOF || !keys) {
+ gchar *msg = g_strdup_printf(_("could not list keys"));
+
+ g_set_error_from_gpgme(error, err, msg);
+ g_free(msg);
+ gpgme_op_keylist_end(ctx);
+ g_list_foreach(keys, (GFunc) gpgme_key_unref, NULL);
+ g_list_free(keys);
+ return NULL;
+ }
+ gpgme_op_keylist_end(ctx);
+
+ /* let the user select a key from the list, even if there is only one */
+ if (select_key_cb)
+ key = select_key_cb(name, LB_SELECT_PUBLIC_KEY_ANY, keys,
+ gpgme_get_protocol(ctx), parent);
+ else
+ key = NULL;
+ if (key) {
+ gpgme_key_ref(key);
+ g_list_foreach(keys, (GFunc) gpgme_key_unref, NULL);
+ }
+ g_list_free(keys);
+ return key;
+}
+
+
/*
* Add signer to ctx's list of signers and return TRUE on success or FALSE
* on error.
@@ -893,19 +945,20 @@ static gboolean
gpgme_add_signer(gpgme_ctx_t ctx, const gchar * signer, GtkWindow * parent,
GError ** error)
{
- gpgme_key_t key;
+ gboolean result = FALSE;
+ gpgme_key_t key;
/* note: private (secret) key has never low trust... */
- if (!
- (key = get_key_from_name(ctx, signer, TRUE, FALSE, parent, error)))
- return FALSE;
-
- /* set the key (the previous operation guaranteed that it exists, no
- * need 2 check return values...) */
- gpgme_signers_add(ctx, key);
- gpgme_key_unref(key);
+ key = get_key_from_name(ctx, signer, TRUE, FALSE, parent, error);
+ if (key != NULL) {
+ /* set the key (the previous operation guaranteed that it exists, no
+ * need 2 check return values...) */
+ gpgme_signers_add(ctx, key);
+ gpgme_key_unref(key);
+ result = TRUE;
+ }
- return TRUE;
+ return result;
}
@@ -927,12 +980,13 @@ gpgme_build_recipients(gpgme_ctx_t ctx, GPtrArray * rcpt_list,
gchar *name = (gchar *) g_ptr_array_index(rcpt_list, num_rcpts);
gpgme_key_t key;
- if (!
- (key =
- get_key_from_name(ctx, name, FALSE, accept_low_trust, parent,
- error))) {
- release_keylist(rcpt);
- return NULL;
+ key = get_key_from_name(ctx, name, FALSE, accept_low_trust, parent, error);
+ if (key == NULL) {
+ key = get_pubkey(ctx, name, accept_low_trust, parent, error);
+ if (key == NULL) {
+ release_keylist(rcpt);
+ return NULL;
+ }
}
/* set the recipient */
diff --git a/libbalsa/libbalsa-gpgme.h b/libbalsa/libbalsa-gpgme.h
index b58f0a2..3eccf47 100644
--- a/libbalsa/libbalsa-gpgme.h
+++ b/libbalsa/libbalsa-gpgme.h
@@ -31,6 +31,7 @@
#include <glib.h>
#include <gtk/gtk.h>
#include <gmime/gmime.h>
+#include "libbalsa-gpgme-cb.h"
#include "gmime-gpgme-signature.h"
@@ -55,7 +56,7 @@ extern "C" {
* - parent window
*/
typedef gpgme_key_t(*lbgpgme_select_key_cb) (const gchar *,
- gboolean,
+ lb_key_sel_md_t,
GList *,
gpgme_protocol_t,
GtkWindow *);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]