[Gpa-commits] r835 - trunk/src
scm-commit@wald.intevation.org
scm-commit at wald.intevation.org
Wed Mar 5 11:12:58 CET 2008
Author: werner
Date: 2008-03-05 11:12:57 +0100 (Wed, 05 Mar 2008)
New Revision: 835
Modified:
trunk/src/ChangeLog
trunk/src/gpastreamencryptop.c
trunk/src/gpastreamencryptop.h
trunk/src/recipientdlg.c
trunk/src/recipientdlg.h
trunk/src/server.c
Log:
Various rewrites for the server mode.
Modified: trunk/src/ChangeLog
===================================================================
--- trunk/src/ChangeLog 2008-03-04 16:46:03 UTC (rev 834)
+++ trunk/src/ChangeLog 2008-03-05 10:12:57 UTC (rev 835)
@@ -1,3 +1,9 @@
+2008-03-05 Werner Koch <wk at g10code.com>
+
+ * server.c (struct conn_ctrl_s): Add field GPA_OP.
+ * gpastreamencryptop.c: Major rewrite.
+ * recipientdlg.c, recipientdlg.h: Add more stuff.
+
2008-03-04 Marcus Brinkmann <marcus at g10code.de>
* gpafileverifyop.c (gpa_file_verify_operation_done_cb): Use
Modified: trunk/src/gpastreamencryptop.c
===================================================================
--- trunk/src/gpastreamencryptop.c 2008-03-04 16:46:03 UTC (rev 834)
+++ trunk/src/gpastreamencryptop.c 2008-03-05 10:12:57 UTC (rev 835)
@@ -28,11 +28,32 @@
#include "gpastreamencryptop.h"
+
+struct _GpaStreamEncryptOperation
+{
+ GpaStreamOperation parent;
+
+ RecipientDlg *recp_dialog;
+ GSList *recipients;
+ gpgme_key_t *keys;
+ gpgme_protocol_t selected_protocol;
+};
+
+
+struct _GpaStreamEncryptOperationClass
+{
+ GpaStreamOperationClass parent_class;
+};
+
+
+
/* Indentifiers for our properties. */
enum
{
PROP_0,
- PROP_RECIPIENTS
+ PROP_RECIPIENTS,
+ PROP_RECIPIENT_KEYS,
+ PROP_PROTOCOL
};
@@ -40,6 +61,7 @@
static void response_cb (GtkDialog *dialog,
gint response,
gpointer user_data);
+static gboolean start_encryption_cb (gpointer data);
static void done_error_cb (GpaContext *context, gpg_error_t err,
GpaStreamEncryptOperation *op);
static void done_cb (GpaContext *context, gpg_error_t err,
@@ -48,6 +70,7 @@
static GObjectClass *parent_class;
+
/* Helper to be used as a GFunc for free. */
static void
free_func (void *p, void *dummy)
@@ -57,8 +80,72 @@
}
+static void
+release_recipients (GSList *recipients)
+{
+ if (recipients)
+ {
+ g_slist_foreach (recipients, free_func, NULL);
+ g_slist_free (recipients);
+ }
+}
+
+/* Return a deep copy of the recipients list. */
+static GSList *
+copy_recipients (GSList *recipients)
+{
+ GSList *recp, *newlist;
+
+ newlist= NULL;
+ for (recp = recipients; recp; recp = g_slist_next (recp))
+ newlist = g_slist_append (newlist, g_strdup (recp->data));
+
+ return newlist;
+}
+
+
static void
+release_keys (gpgme_key_t *keys)
+{
+ if (keys)
+ {
+ int idx;
+
+ for (idx=0; keys[idx]; idx++)
+ gpgme_key_unref (keys[idx]);
+ g_free (keys);
+ }
+}
+
+
+/* Return a copy of the key array. */
+static gpgme_key_t *
+copy_keys (gpgme_key_t *keys)
+{
+ gpgme_key_t *newarray;
+ int idx;
+
+ if (!keys)
+ return NULL;
+
+ for (idx=0; keys[idx]; idx++)
+ ;
+ idx++;
+ newarray = g_new (gpgme_key_t, idx);
+ for (idx=0; keys[idx]; idx++)
+ {
+ gpgme_key_ref (keys[idx]);
+ newarray[idx] = keys[idx];
+ }
+ newarray[idx] = NULL;
+
+ return newarray;
+}
+
+
+
+static void
gpa_stream_encrypt_operation_get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
{
@@ -69,6 +156,12 @@
case PROP_RECIPIENTS:
g_value_set_pointer (value, op->recipients);
break;
+ case PROP_RECIPIENT_KEYS:
+ g_value_set_pointer (value, op->keys);
+ break;
+ case PROP_PROTOCOL:
+ g_value_set_int (value, op->selected_protocol);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -88,6 +181,12 @@
case PROP_RECIPIENTS:
op->recipients = (GSList*)g_value_get_pointer (value);
break;
+ case PROP_RECIPIENT_KEYS:
+ op->keys = (gpgme_key_t*)g_value_get_pointer (value);
+ break;
+ case PROP_PROTOCOL:
+ op->selected_protocol = g_value_get_int (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -100,12 +199,10 @@
{
GpaStreamEncryptOperation *op = GPA_STREAM_ENCRYPT_OPERATION (object);
- if (op->recipients)
- {
- g_slist_foreach (op->recipients, free_func, NULL);
- g_slist_free (op->recipients);
- op->recipients = NULL;
- }
+ release_recipients (op->recipients);
+ op->recipients = NULL;
+ release_keys(op->keys);
+ op->keys = NULL;
G_OBJECT_CLASS (parent_class)->finalize (object);
}
@@ -114,8 +211,9 @@
static void
gpa_stream_encrypt_operation_init (GpaStreamEncryptOperation *op)
{
- op->encrypt_dialog = NULL;
+ op->recp_dialog = NULL;
op->recipients = NULL;
+ op->keys = NULL;
op->selected_protocol = GPGME_PROTOCOL_UNKNOWN;
}
@@ -134,13 +232,21 @@
construct_properties);
op = GPA_STREAM_ENCRYPT_OPERATION (object);
- /* Create the "Encrypt" dialog */
- op->encrypt_dialog = recipient_dlg_new (GPA_OPERATION (op)->window);
+ /* Create the recipient key selection dialog if we don't know the
+ keys yet. */
+ if (!op->keys)
+ {
+ op->recp_dialog = recipient_dlg_new (GPA_OPERATION (op)->window);
+ recipient_dlg_set_recipients (op->recp_dialog,
+ op->recipients,
+ op->selected_protocol);
+ g_signal_connect (G_OBJECT (op->recp_dialog), "response",
+ G_CALLBACK (response_cb), op);
+ }
+ else
+ g_idle_add (start_encryption_cb, op);
- recipient_dlg_set_recipients (op->encrypt_dialog, op->recipients);
- g_signal_connect (G_OBJECT (op->encrypt_dialog), "response",
- G_CALLBACK (response_cb), op);
/* We connect the done signal to two handles. The error handler is
called first. */
g_signal_connect (G_OBJECT (GPA_OPERATION (op)->context), "done",
@@ -152,7 +258,8 @@
(GTK_WINDOW (GPA_STREAM_OPERATION (op)->progress_dialog),
_("Encrypting message ..."));
- gtk_widget_show_all (op->encrypt_dialog);
+ if (op->recp_dialog)
+ gtk_widget_show_all (GTK_WIDGET (op->recp_dialog));
return object;
}
@@ -176,6 +283,19 @@
("recipients", "Recipients",
"A list of recipients in rfc-822 mailbox format.",
G_PARAM_WRITABLE|G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property
+ (object_class, PROP_RECIPIENT_KEYS,
+ g_param_spec_pointer
+ ("recipient-keys", "Recipient-keys",
+ "An array of gpgme_key_t with the selected keys.",
+ G_PARAM_WRITABLE|G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property
+ (object_class, PROP_PROTOCOL,
+ g_param_spec_int
+ ("protocol", "Protocol",
+ "The gpgme protocol currently selected.",
+ GPGME_PROTOCOL_OpenPGP, GPGME_PROTOCOL_UNKNOWN, GPGME_PROTOCOL_UNKNOWN,
+ G_PARAM_WRITABLE|G_PARAM_CONSTRUCT_ONLY));
}
@@ -209,184 +329,106 @@
}
-static gpg_error_t
-start_encryption (GpaStreamEncryptOperation *op, gpgme_key_t *keys)
+/* Return true if all keys are matching the protocol. */
+static int
+keys_match_protocol_p (gpgme_key_t *keys, gpgme_protocol_t protocol)
{
- gpg_error_t err;
-
- /* Start the operation */
- /* Always trust keys, because any untrusted keys were already confirmed
- * by the user.
- */
-/* if (gpa_file_encrypt_dialog_sign */
-/* (GPA_FILE_ENCRYPT_DIALOG (op->encrypt_dialog))) */
-/* { */
-/* /\* Signing was request as well. *\/ */
-/* err = gpgme_op_encrypt_sign_start (GPA_OPERATION (op)->context->ctx, */
-/* op->rset, GPGME_ENCRYPT_ALWAYS_TRUST, */
-/* op->plain, op->cipher); */
-/* } */
-/* else */
- {
- /* Plain encryption. */
- err = gpgme_op_encrypt_start (GPA_OPERATION (op)->context->ctx,
- keys, GPGME_ENCRYPT_ALWAYS_TRUST,
- GPA_STREAM_OPERATION (op)->input_stream,
- GPA_STREAM_OPERATION (op)->output_stream);
- }
- if (err)
- {
- gpa_gpgme_warning (err);
- return err;
- }
+ int idx;
- /* Show and update the progress dialog */
- gtk_widget_show_all (GPA_STREAM_OPERATION (op)->progress_dialog);
- gpa_progress_dialog_set_label (GPA_PROGRESS_DIALOG
- (GPA_STREAM_OPERATION (op)->progress_dialog),
- _("Message encryption"));
- return 0;
+ if (!keys)
+ return 1; /* No keys: assume match. */
+ for (idx = 0; keys[idx]; idx++)
+ if (keys[idx]->protocol != protocol)
+ return 0;
+ return 1;
}
-
-/* Given a list of strings, each describing one recipient, parse them
- to detect duplicates, check the validity of each key and ask the
- user whether he wants to use an invalid key.
-
- Try to find a key for each item in RECIPIENT. Items not found are
- stored in the newly allocated list R_UNKNOWN. Found keys are
- stored in the newly allocated and NULL terminated gpgme_key_t array
- R_FOUND. Caller needs to release R_FOUND and R_UNKNOWN.
+/*
+ * Fire up the encryption.
*/
-static gpg_error_t
-parse_recipients (GpaStreamEncryptOperation *op, GSList *recipients,
- gpgme_key_t **r_found, GSList **r_unknown)
+static void
+start_encryption (GpaStreamEncryptOperation *op)
{
- gpgme_error_t err;
- GSList *recp;
- gpgme_ctx_t ctx;
- size_t n;
- gpgme_key_t *found;
- GSList *unknown = NULL;
- int found_idx;
- gpgme_key_t key, key2;
- const char *name;
- gpgme_protocol_t used_proto = GPGME_PROTOCOL_UNKNOWN;
+ gpg_error_t err;
+ int prep_only = 0;
- *r_found = NULL;
- *r_unknown = NULL;
+ if (!op->keys || !op->keys[0])
+ {
+ err = gpg_error (GPG_ERR_NO_PUBKEY);
+ goto leave;
+ }
- err = gpgme_new (&ctx);
+ if (op->selected_protocol == GPGME_PROTOCOL_OpenPGP)
+ err = gpa_operation_write_status (GPA_OPERATION (op), "PROTOCOL",
+ "OpenPGP", NULL);
+ else if (op->selected_protocol == GPGME_PROTOCOL_CMS)
+ err = gpa_operation_write_status (GPA_OPERATION (op), "PROTOCOL",
+ "CMS", NULL);
+ else
+ err = gpg_error (GPG_ERR_NO_PUBKEY);
if (err)
- return err;
+ goto leave;
- /* Fixme: Add rfc-822 mailbox parsing. */
+ /* Set the output encoding. */
+ if (GPA_STREAM_OPERATION (op)->input_stream
+ && GPA_STREAM_OPERATION (op)->output_stream)
+ {
+ if (op->selected_protocol == GPGME_PROTOCOL_CMS)
+ gpgme_data_set_encoding (GPA_STREAM_OPERATION (op)->output_stream,
+ GPGME_DATA_ENCODING_BASE64);
+ else
+ gpgme_set_armor (GPA_OPERATION (op)->context->ctx, 1);
- for (n=0, recp = recipients; recp; recp = g_slist_next (recp))
- n++;
-
- found = xcalloc (n+1, sizeof *found);
- found_idx = 0;
- for (recp = recipients; recp; recp = g_slist_next (recp))
- {
- name = recp->data;
- if (!name)
- continue;
- key = NULL;
- err = gpgme_op_keylist_start (ctx, name, 0);
- if (!err)
+ if (!keys_match_protocol_p (op->keys, op->selected_protocol))
{
- err = gpgme_op_keylist_next (ctx, &key);
- if (!err && !gpgme_op_keylist_next (ctx, &key2))
- {
- /* Not found or ambiguous key specification. */
- gpgme_key_unref (key);
- gpgme_key_unref (key2);
- key = key2 = NULL;
- }
+ g_debug ("the selected keys do not match the protocol");
+ err = gpg_error (GPG_ERR_CONFLICT);
+ goto leave;
}
- gpgme_op_keylist_end (ctx);
+
+ gpgme_set_protocol (GPA_OPERATION (op)->context->ctx,
+ op->selected_protocol);
- /* If a usable key has been found, put it into the list of good
- keys. All other keys end up in the list of unknown keys. We
- select the protocol to use from the frist found key. Fixme:
- We might want to have a different logic to select the
- protocol. */
- if (key
- && used_proto != GPGME_PROTOCOL_UNKNOWN
- && used_proto != key->protocol)
+ /* We always trust the keys because the recipient selection
+ dialog has already sorted unusable out. */
+ err = gpgme_op_encrypt_start (GPA_OPERATION (op)->context->ctx,
+ op->keys, GPGME_ENCRYPT_ALWAYS_TRUST,
+ GPA_STREAM_OPERATION (op)->input_stream,
+ GPA_STREAM_OPERATION (op)->output_stream);
+ if (err)
{
- /* We can't use this key becuase it does not match the
- selected protocol. */
- char *p;
- const char *warn = _("wrong protocol");
-
- n = strlen (name) + 3 + strlen (warn);
- p = xmalloc (n+1);
- snprintf (p, n, "%s (%s)", name, warn);
- unknown = g_slist_append (unknown, p);
+ gpa_gpgme_warning (err);
+ goto leave;
}
- else if (key && !key->revoked && !key->disabled && !key->expired)
- {
- gpgme_key_ref (key);
- found[found_idx++] = key;
- if (used_proto == GPGME_PROTOCOL_UNKNOWN)
- used_proto = key->protocol;
- }
- else if (key)
- {
- char *p;
- const char *warn = (key->revoked? "revoked" :
- key->expired? "expired" : "disabled");
-
- n = strlen (name) + 3 + strlen (warn);
- p = xmalloc (n+1);
- snprintf (p, n, "%s (%s)", name, warn);
- unknown = g_slist_append (unknown, p);
- }
- else /* Not found or ambiguous. */
- unknown = g_slist_append (unknown, xstrdup (name));
- gpgme_key_unref (key);
+ /* Show and update the progress dialog. */
+ gtk_widget_show_all (GPA_STREAM_OPERATION (op)->progress_dialog);
+ gpa_progress_dialog_set_label
+ (GPA_PROGRESS_DIALOG (GPA_STREAM_OPERATION (op)->progress_dialog),
+ _("Message encryption"));
}
- gpgme_release (ctx);
-
- if (err)
- ;
- else if (used_proto == GPGME_PROTOCOL_OpenPGP)
+ else
{
- op->selected_protocol = used_proto;
- err = gpa_operation_write_status (GPA_OPERATION (op), "PROTOCOL",
- "OpenPGP", NULL);
+ /* We are just preparing an encryption. */
+ prep_only = 1;
+ err = 0;
}
- else if (used_proto == GPGME_PROTOCOL_CMS)
+
+ leave:
+ if (err || prep_only)
{
- op->selected_protocol = used_proto;
- err = gpa_operation_write_status (GPA_OPERATION (op), "PROTOCOL",
- "CMS", NULL);
+ gpa_operation_server_finish (GPA_OPERATION (op), err);
+ g_signal_emit_by_name (GPA_OPERATION (op), "completed");
}
- else
- err = 0;
-
- *r_found = found;
- *r_unknown = unknown;
- return err;
}
-/*
- * The key selection dialog has returned.
- */
+/* The recipient key selection dialog has returned. */
static void
response_cb (GtkDialog *dialog, int response, void *user_data)
{
- gpg_error_t err;
- GSList *recipients;
GpaStreamEncryptOperation *op = user_data;
- gpgme_key_t *keys;
- GSList *unknown_recp;
- int prep_only = 0;
gtk_widget_hide (GTK_WIDGET (dialog));
@@ -400,59 +442,28 @@
return;
}
- recipients = g_slist_append (NULL, xstrdup ("wk at gnupg.org"));
+ /* Get the keys. */
+ release_keys (op->keys);
+ op->keys = NULL;
+ op->keys = recipient_dlg_get_keys (op->recp_dialog, &op->selected_protocol);
-/* gpa_stream_encrypt_dialog_recipients */
-/* (GPA_STREAM_ENCRYPT_DIALOG (op->encrypt_dialog)); */
-
- err = parse_recipients (op, recipients, &keys, &unknown_recp);
- if (err)
- goto leave;
+ start_encryption (op);
+}
- /* Set the output encoding. */
- if (GPA_STREAM_OPERATION (op)->input_stream
- && GPA_STREAM_OPERATION (op)->output_stream)
- {
- if (op->selected_protocol == GPGME_PROTOCOL_CMS)
- {
- gpgme_data_set_encoding (GPA_STREAM_OPERATION (op)->output_stream,
- GPGME_DATA_ENCODING_BASE64);
- }
- else
- {
- gpgme_set_armor (GPA_OPERATION (op)->context->ctx, 1);
- }
- err = start_encryption (op, keys);
- }
- else
- {
- /* We are just preparing an encryption. */
- prep_only = 1;
- err = 0;
- }
- leave:
- if (keys)
- {
- int idx;
-
- for (idx=0; keys[idx]; idx++)
- gpgme_key_unref (keys[idx]);
- xfree (keys);
- }
- g_slist_foreach (unknown_recp, free_func, NULL);
- g_slist_free (unknown_recp);
- g_slist_foreach (recipients, free_func, NULL);
- g_slist_free (recipients);
- if (err || prep_only)
- {
- gpa_operation_server_finish (GPA_OPERATION (op), err);
- g_signal_emit_by_name (GPA_OPERATION (op), "completed");
- }
+/* This is the idle function used to start the encryption if no
+ recipient key selection dialog has been requested. */
+static gboolean
+start_encryption_cb (void *user_data)
+{
+ GpaStreamEncryptOperation *op = user_data;
+
+ start_encryption (op);
+
+ return FALSE; /* Remove this callback from the event loop. */
}
-
/*Show an error message. */
static void
done_error_cb (GpaContext *context, gpg_error_t err,
@@ -477,7 +488,6 @@
static void
done_cb (GpaContext *context, gpg_error_t err, GpaStreamEncryptOperation *op)
{
-
gtk_widget_hide (GPA_STREAM_OPERATION (op)->progress_dialog);
/* Tell the server that we finished and delete ourself. */
@@ -487,44 +497,60 @@
+
+/************************************************************
+ ********************** Public API ************************
+ ************************************************************/
-/* API */
-
/* Start encrypting INPUT_STREAM to OUTPUT_STREAM using SERVER_CTX and
WINDOW. RECIPIENTS gives a list of recipients and the function
- matches them with existing keys and selects appropriate keys. The
- ownership of RECIPIENTS is taken by this function. If it is not
- possible to unambigiously select keys and SILENT is not given, a
- key selection dialog offers the user a way to manually select keys.
- INPUT_STREAM and OUTPUT_STREAM may be given as NULL in which case
- the function skips the actual encryption step and just verifies the
- recipients. */
-/* FIXME: We need to offer a way to return the actual selected list of
- recipients so that repeating this command with that list instantly
- starts the decryption. */
+ matches them with existing keys and selects appropriate keys.
+ RECP_KEYS is either NULL or an array with gpgme keys which will
+ then immediatley be used and suppresses the recipient key selection
+ dialog.
+
+ If it is not possible to unambigiously select keys and SILENT is
+ not given, a key selection dialog offers the user a way to manually
+ select keys. INPUT_STREAM and OUTPUT_STREAM may be given as NULL
+ in which case the function skips the actual encryption step and
+ just verifies the recipients. */
GpaStreamEncryptOperation*
gpa_stream_encrypt_operation_new (GtkWidget *window,
gpgme_data_t input_stream,
gpgme_data_t output_stream,
GSList *recipients,
+ gpgme_key_t *recp_keys,
+ gpgme_protocol_t protocol,
int silent,
void *server_ctx)
{
GpaStreamEncryptOperation *op;
-
+
+ /* Fixme: SILENT is not yet implemented. */
+
op = g_object_new (GPA_STREAM_ENCRYPT_OPERATION_TYPE,
"window", window,
"input_stream", input_stream,
"output_stream", output_stream,
- "recipients", recipients,
+ "recipients", copy_recipients (recipients),
+ "recipient-keys", copy_keys (recp_keys),
+ "protocol", (int)protocol,
"server-ctx", server_ctx,
NULL);
- if (!op)
- {
- g_slist_foreach (recipients, free_func, NULL);
- g_slist_free (recipients);
- }
return op;
}
+
+/* Return an array of keys for the set of recipients of this object.
+ The function also returns the selected protocol. */
+gpgme_key_t *
+gpa_stream_encrypt_operation_get_keys (GpaStreamEncryptOperation *op,
+ gpgme_protocol_t *r_protocol)
+{
+ g_return_val_if_fail (op, NULL);
+
+ if (r_protocol)
+ *r_protocol = op->selected_protocol;
+ return copy_keys (op->keys);
+}
Modified: trunk/src/gpastreamencryptop.h
===================================================================
--- trunk/src/gpastreamencryptop.h 2008-03-04 16:46:03 UTC (rev 834)
+++ trunk/src/gpastreamencryptop.h 2008-03-05 10:12:57 UTC (rev 835)
@@ -55,25 +55,11 @@
typedef struct _GpaStreamEncryptOperationClass GpaStreamEncryptOperationClass;
-struct _GpaStreamEncryptOperation
-{
- GpaStreamOperation parent;
-
- GtkWidget *encrypt_dialog;
- GSList *recipients;
- gpgme_protocol_t selected_protocol;
-};
-
-
-struct _GpaStreamEncryptOperationClass
-{
- GpaStreamOperationClass parent_class;
-};
-
-
GType gpa_stream_encrypt_operation_get_type (void) G_GNUC_CONST;
-/* API */
+/************************************
+ ************ Public API ************
+ ************************************/
/* Creates a new encryption operation. */
GpaStreamEncryptOperation *
@@ -81,9 +67,14 @@
gpgme_data_t input_stream,
gpgme_data_t output_stream,
GSList *recipients,
+ gpgme_key_t *recp_keys,
+ gpgme_protocol_t protocol,
int silent,
void *server_ctx);
+gpgme_key_t *gpa_stream_encrypt_operation_get_keys
+(GpaStreamEncryptOperation *op, gpgme_protocol_t *r_protocol);
+
#endif /*GPA_STREAM_ENCRYPT_OP_H*/
Modified: trunk/src/recipientdlg.c
===================================================================
--- trunk/src/recipientdlg.c 2008-03-04 16:46:03 UTC (rev 834)
+++ trunk/src/recipientdlg.c 2008-03-05 10:12:57 UTC (rev 835)
@@ -32,6 +32,21 @@
GtkDialog parent;
GtkWidget *clist_keys;
+ GtkWidget *statushint;
+ GtkWidget *radio_pgp;
+ GtkWidget *radio_x509;
+ GtkWidget *radio_auto;
+
+ /* Flag to disable updates of the status hint. This is actual a
+ counter with updates allowed if it is zero. */
+ int disable_update_statushint;
+
+ /* Set if this dialog has usable key to be passed back to the
+ caller. You need to call update_statushint to set it. */
+ int usable;
+
+ /* The selected protocol. This is also set by update_statushint. */
+ gpgme_protocol_t selected_protocol;
};
@@ -55,6 +70,43 @@
};
+/* For performance reasons we truncate the listing of ambiguous keys
+ at a reasonable value. */
+#define TRUNCATE_KEYSEARCH_AT 40
+
+
+/* Na object to keep information about keys. */
+struct keyinfo_s
+{
+ /* An array with associated key(s) or NULL if none found/selected. */
+ gpgme_key_t *keys;
+
+ /* The allocated size of the KEYS array. This included the
+ terminating NULL entry. */
+ unsigned int dimof_keys;
+
+ /* If set, indicates that the KEYS array has been truncated. */
+ int truncated:1;
+};
+
+
+/* Management information for each recipient. This data is used per
+ recipient. */
+struct userdata_s
+{
+ /* Information about PGP keys. */
+ struct keyinfo_s pgp;
+
+ /* Information about X.509 keys. */
+ struct keyinfo_s x509;
+
+ /* If the user has set this field, no encryption key will be
+ required for the recipient. */
+ int ignore_recipient;
+
+};
+
+
/* Identifiers for the columns of the RECPLIST. */
enum
{
@@ -64,6 +116,9 @@
RECPLIST_HAS_X509, /* An X.509 certificate is available. */
RECPLIST_KEYID, /* The key ID of the associated key. */
+ RECPLIST_USERDATA, /* Pointer to management information (struct
+ userdata_s *). */
+
RECPLIST_N_COLUMNS
};
@@ -107,7 +162,9 @@
G_TYPE_STRING,
G_TYPE_BOOLEAN,
G_TYPE_BOOLEAN,
- G_TYPE_STRING);
+ G_TYPE_STRING,
+ G_TYPE_POINTER);
+
list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (list), TRUE);
@@ -123,15 +180,16 @@
renderer = gtk_cell_renderer_toggle_new ();
column = gtk_tree_view_column_new_with_attributes
(NULL, renderer, "active", RECPLIST_HAS_PGP, NULL);
- set_column_title (column, "P", _("Checked if at least one matching"
- " OpenPGP certificate has been found."));
+ set_column_title (column, "PGP", _("Checked if at least one matching"
+ " OpenPGP certificate has been found."));
gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
renderer = gtk_cell_renderer_toggle_new ();
column = gtk_tree_view_column_new_with_attributes
(NULL, renderer, "active", RECPLIST_HAS_X509, NULL);
- set_column_title (column, "X", _("Checked if at least one matching"
- " X.509 certificate has been found."));
+ set_column_title (column, "X.509", _("Checked if at least one matching"
+ " X.509 certificate for use with S/MIME"
+ " has been found."));
gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
renderer = gtk_cell_renderer_text_new ();
@@ -147,86 +205,248 @@
}
+/* Compute and display a new help text for the statushint. */
+static void
+update_statushint (RecipientDlg *dialog)
+{
+ gpgme_protocol_t req_protocol, sel_protocol;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ int missing_keys = 0;
+ int ambiguous_pgp_keys = 0;
+ int ambiguous_x509_keys = 0;
+ int n_pgp_keys = 0;
+ int n_x509_keys = 0;
+ int n_keys = 0;
+ const char *hint;
+ int okay = 0;
+
+ if (dialog->disable_update_statushint)
+ return;
+
+ g_debug ("update_statushint called");
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->clist_keys));
+
+ if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->radio_pgp)))
+ req_protocol = GPGME_PROTOCOL_OpenPGP;
+ else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON
+ (dialog->radio_x509)))
+ req_protocol = GPGME_PROTOCOL_CMS;
+ else
+ req_protocol = GPGME_PROTOCOL_UNKNOWN;
+
+ sel_protocol = GPGME_PROTOCOL_UNKNOWN;
+
+ if (gtk_tree_model_get_iter_first (model, &iter))
+ {
+ do
+ {
+ gboolean has_pgp, has_x509;
+ struct userdata_s *info;
+
+ gtk_tree_model_get (model, &iter,
+ RECPLIST_HAS_PGP, &has_pgp,
+ RECPLIST_HAS_X509, &has_x509,
+ RECPLIST_USERDATA, &info,
+ -1);
+ if (!info)
+ missing_keys++; /* Oops */
+ else if (info->ignore_recipient)
+ ;
+ else if (!info->pgp.keys && !info->x509.keys)
+ missing_keys++;
+ else if ((req_protocol == GPGME_PROTOCOL_OpenPGP && !has_pgp)
+ ||(req_protocol == GPGME_PROTOCOL_CMS && !has_x509))
+ ; /* Not of the requested protocol. */
+ else
+ {
+ n_keys++;
+ if (info->pgp.keys && info->pgp.keys[0])
+ {
+ n_pgp_keys++;
+ if (info->pgp.keys[1])
+ ambiguous_pgp_keys++;
+ }
+ if (info->x509.keys && info->x509.keys[0])
+ {
+ n_x509_keys++;
+ if (info->x509.keys[1])
+ ambiguous_x509_keys++;
+ }
+ }
+ }
+ while (gtk_tree_model_iter_next (model, &iter));
+ }
+
+ if (req_protocol == GPGME_PROTOCOL_UNKNOWN)
+ {
+ /* We select the protocol with the most available keys,
+ preferring PGP. */
+ if (n_pgp_keys >= n_x509_keys)
+ sel_protocol = GPGME_PROTOCOL_OpenPGP;
+ else if (n_x509_keys)
+ sel_protocol = GPGME_PROTOCOL_CMS;
+ }
+ else
+ sel_protocol = req_protocol;
+
+
+ if (missing_keys)
+ hint = _("You need to select a key for each recipient.\n"
+ "To select a key you click on the respective line.");
+ else if ((sel_protocol == GPGME_PROTOCOL_OpenPGP
+ && ambiguous_pgp_keys)
+ || (sel_protocol == GPGME_PROTOCOL_CMS
+ && ambiguous_x509_keys)
+ || (sel_protocol == GPGME_PROTOCOL_UNKNOWN
+ && (ambiguous_pgp_keys || ambiguous_x509_keys )))
+ hint = _("You need to select exactly one key for each recipient.\n"
+ "To select a key you click on the respective line.");
+ else if ((sel_protocol == GPGME_PROTOCOL_OpenPGP
+ && n_keys != n_pgp_keys)
+ || (sel_protocol == GPGME_PROTOCOL_CMS
+ && n_keys != n_x509_keys)
+ || (sel_protocol == GPGME_PROTOCOL_UNKNOWN))
+ hint = _("Although you selected keys for all recipients "
+ "a common encryption protocol can't be used. "
+ "Please decide on one protocol by clicking one "
+ "of the above radio buttons.");
+ else if (sel_protocol == GPGME_PROTOCOL_OpenPGP)
+ {
+ hint = _("Using OpenPGP for encryption.");
+ okay = 1;
+ }
+ else if (sel_protocol == GPGME_PROTOCOL_CMS)
+ {
+ hint = _("Using S/MIME for encryption.");
+ okay = 1;
+ }
+ else
+ hint = _("No recipients - encryption is not possible");
+
+ gtk_label_set_text (GTK_LABEL (dialog->statushint), hint);
+ gtk_label_set_line_wrap (GTK_LABEL (dialog->statushint), TRUE);
+
+ dialog->usable = okay;
+ dialog->selected_protocol = sel_protocol;
+ gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK,
+ okay);
+}
+
+
+/* Add KEY to the keyarray of KEYINFO. Owvership of KEY is moved to
+ KEYARRAY. Returns the number of keys in KEYINFO. */
+static unsigned int
+append_key_to_keyinfo (struct keyinfo_s *keyinfo, gpgme_key_t key)
+{
+ unsigned int nkeys;
+
+ if (!keyinfo->keys)
+ {
+ keyinfo->dimof_keys = 5; /* Space for 4 keys. */
+ keyinfo->keys = g_new (gpgme_key_t, keyinfo->dimof_keys);
+ keyinfo->keys[0] = NULL;
+ }
+ for (nkeys=0; keyinfo->keys[nkeys]; nkeys++)
+ ;
+ /* Note that we silently skip KEY of NULL becuase we can't store
+ them in the array. */
+ if (key)
+ {
+ if (nkeys+1 >= keyinfo->dimof_keys)
+ {
+ keyinfo->dimof_keys += 10;
+ keyinfo->keys = g_renew (gpgme_key_t, keyinfo->keys,
+ keyinfo->dimof_keys);
+ }
+ keyinfo->keys[nkeys++] = key;
+ keyinfo->keys[nkeys] = NULL;
+ }
+ return nkeys;
+}
+
+
/* Parse one recipient, this is the working horse of parse_recipeints. */
static void
parse_one_recipient (gpgme_ctx_t ctx, GtkListStore *store, GtkTreeIter *iter,
const char *mailbox)
{
- gpgme_key_t key, key2;
- int any_pgp = 0, any_x509 = 0, any_ambiguous = 0, any_unusable = 0;
+ gpgme_key_t key;
+ int any_pgp = 0, any_x509 = 0;
char *infostr = NULL;
+ struct userdata_s *info;
key = NULL;
+ info = g_malloc0 (sizeof *info);
gpgme_set_protocol (ctx, GPGME_PROTOCOL_OpenPGP);
if (!gpgme_op_keylist_start (ctx, mailbox, 0))
{
- if (!gpgme_op_keylist_next (ctx, &key))
+ while (!gpgme_op_keylist_next (ctx, &key))
{
- any_pgp++;
- if (!gpgme_op_keylist_next (ctx, &key2))
+ if (key->revoked || key->disabled || key->expired)
+ gpgme_key_unref (key);
+ else if (append_key_to_keyinfo (&info->pgp, key)
+ >= TRUNCATE_KEYSEARCH_AT)
{
- any_ambiguous++;
- gpgme_key_unref (key);
- gpgme_key_unref (key2);
- key = key2 = NULL;
+ /* Note that the truncation flag is not 100 correct. In
+ case the next iteration would not yield a new key we
+ have not actually truncated the search. */
+ info->pgp.truncated = 1;
+ break;
}
}
}
gpgme_op_keylist_end (ctx);
- if (key)
- {
- /* fixme: We should put the key into a list. It would be best
- to use a hidden columnin the store. Need to figure out how
- to do that. */
- if (key->revoked || key->disabled || key->expired)
- any_unusable++;
- else if (!infostr)
- infostr = gpa_gpgme_key_get_userid (key->uids);
- }
- gpgme_key_unref (key);
- key = NULL;
-
gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
if (!gpgme_op_keylist_start (ctx, mailbox, 0))
{
- if (!gpgme_op_keylist_next (ctx, &key))
+ while (!gpgme_op_keylist_next (ctx, &key))
{
- any_x509++;
- if (!gpgme_op_keylist_next (ctx, &key2))
+ if (key->revoked || key->disabled || key->expired)
+ gpgme_key_unref (key);
+ else if (append_key_to_keyinfo (&info->x509,key)
+ >= TRUNCATE_KEYSEARCH_AT)
{
- any_ambiguous++;
- gpgme_key_unref (key);
- gpgme_key_unref (key2);
- key = key2 = NULL;
+ info->x509.truncated = 1;
+ break;
}
}
}
gpgme_op_keylist_end (ctx);
- if (key)
+
+
+ if (info->pgp.keys && info->pgp.keys[0])
+ any_pgp = 1;
+ if (info->x509.keys && info->x509.keys[0])
+ any_x509 = 1;
+
+ if (any_pgp && any_x509 && info->pgp.keys[1] && info->x509.keys[1])
+ infostr = g_strdup (_("[ambiguous keys - click to select]"));
+ else if (any_pgp && info->pgp.keys[1])
+ infostr = g_strdup (_("[ambiguous PGP key - click to select]"));
+ else if (any_x509 && info->x509.keys[1])
+ infostr = g_strdup (_("[ambiguous X.509 key - click to select]"));
+ else if (any_pgp && !info->pgp.keys[1])
{
- /* fixme: We should put the key into a list. It would be best
- to use a hidden column in the store. Need to figure out how
- to do that. */
- if (key->revoked || key->disabled || key->expired)
- any_unusable++;
- else if (!infostr)
- infostr = gpa_gpgme_key_get_userid (key->uids);
+ /* Exactly one key found. */
+ key = info->pgp.keys[0];
+ infostr = gpa_gpgme_key_get_userid (key->uids);
}
- gpgme_key_unref (key);
+ else if (any_x509 && !info->x509.keys[1])
+ {
+ key = info->x509.keys[0];
+ infostr = gpa_gpgme_key_get_userid (key->uids);
+ }
+ else
+ infostr = g_strdup (_("[click to select]"));
- if (!infostr)
- infostr = g_strdup (any_ambiguous?
- _("[ambiguous key - click to select]"):
- any_unusable?
- _("[unusable key - click to select another one]"):
- _("[click to select]"));
-
g_print (" pgp=%d x509=%d infostr=`%s'\n", any_pgp, any_x509, infostr);
gtk_list_store_set (store, iter,
RECPLIST_HAS_PGP, any_pgp,
RECPLIST_HAS_X509, any_x509,
RECPLIST_KEYID, infostr,
+ RECPLIST_USERDATA, info,
-1);
g_free (infostr);
}
@@ -246,9 +466,10 @@
if (err)
gpa_gpgme_error (err);
-
+
model = GTK_TREE_MODEL (store);
/* Walk through the list, reading each row. */
+
if (gtk_tree_model_get_iter_first (model, &iter))
do
{
@@ -259,7 +480,7 @@
-1);
/* Do something with the data */
- g_print ("mailbox `%s'\n", mailbox);
+ g_print ("parsing mailbox `%s'\n", mailbox);
parse_one_recipient (ctx, store, &iter, mailbox);
g_free (mailbox);
}
@@ -268,15 +489,13 @@
gpgme_release (ctx);
}
-
-
static void
recplist_row_activated_cb (GtkTreeView *tree_view,
GtkTreePath *path,
GtkTreeViewColumn *column,
gpointer user_data)
{
- RecipientDlg *dialog = user_data;
+ /*RecipientDlg *dialog = user_data;*/
GtkTreeIter iter;
GtkTreeModel *model;
char *mailbox;
@@ -289,12 +508,57 @@
gtk_tree_model_get (model, &iter,
RECPLIST_MAILBOX, &mailbox,
-1);
-
g_print (" mailbox is `%s'\n", mailbox);
g_free (mailbox);
}
+static void
+recplist_row_changed_cb (GtkTreeModel *model, GtkTreePath *path,
+ GtkTreeIter *changediter, gpointer user_data)
+{
+ RecipientDlg *dialog = user_data;
+
+ g_print ("row changed signal received\n");
+ g_return_if_fail (dialog);
+ update_statushint (dialog);
+}
+
+
+static void
+rbutton_toggled_cb (GtkToggleButton *button, gpointer user_data)
+{
+ RecipientDlg *dialog = user_data;
+ GtkTreeViewColumn *column;
+ int pgp = FALSE;
+ int x509 = FALSE;
+
+ if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->radio_pgp)))
+ {
+ pgp = TRUE;
+ }
+ else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON
+ (dialog->radio_x509)))
+ {
+ x509 = TRUE;
+ }
+ else
+ {
+ pgp = TRUE;
+ x509 = TRUE;
+ }
+
+ column = gtk_tree_view_get_column (GTK_TREE_VIEW (dialog->clist_keys),
+ RECPLIST_HAS_PGP);
+ gtk_tree_view_column_set_visible (column, pgp);
+ column = gtk_tree_view_get_column (GTK_TREE_VIEW (dialog->clist_keys),
+ RECPLIST_HAS_X509);
+ gtk_tree_view_column_set_visible (column, x509);
+ update_statushint (dialog);
+}
+
+
+
/************************************************************
****************** Object Management ********************
@@ -348,7 +612,7 @@
static void
recipient_dlg_init (RecipientDlg *dialog)
{
-
+ dialog->disable_update_statushint = 0;
}
@@ -358,8 +622,10 @@
{
GObject *object;
RecipientDlg *dialog;
- GtkAccelGroup *accelGroup;
- GtkWidget *vboxEncrypt;
+ GtkAccelGroup *accel_group;
+ GtkWidget *vbox;
+ GtkWidget *hbox;
+ GtkWidget *widget;
GtkWidget *labelKeys;
GtkWidget *scrollerKeys;
GtkWidget *clistKeys;
@@ -380,34 +646,73 @@
FALSE);
gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
- accelGroup = gtk_accel_group_new ();
- gtk_window_add_accel_group (GTK_WINDOW (dialog), accelGroup);
+ accel_group = gtk_accel_group_new ();
+ gtk_window_add_accel_group (GTK_WINDOW (dialog), accel_group);
- vboxEncrypt = GTK_DIALOG (dialog)->vbox;
- gtk_container_set_border_width (GTK_CONTAINER (vboxEncrypt), 5);
+ vbox = GTK_DIALOG (dialog)->vbox;
+ gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
labelKeys = gtk_label_new ("");
gtk_misc_set_alignment (GTK_MISC (labelKeys), 0.0, 0.5);
- gtk_box_pack_start (GTK_BOX (vboxEncrypt), labelKeys, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (vbox), labelKeys, FALSE, FALSE, 0);
scrollerKeys = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrollerKeys),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
- gtk_box_pack_start (GTK_BOX (vboxEncrypt), scrollerKeys, TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (vbox), scrollerKeys, TRUE, TRUE, 0);
gtk_widget_set_size_request (scrollerKeys, 400, 200);
clistKeys = recplist_window_new ();
- g_signal_connect (G_OBJECT (GTK_TREE_VIEW (clistKeys)),
- "row-activated",
- G_CALLBACK (recplist_row_activated_cb), dialog);
dialog->clist_keys = clistKeys;
gtk_container_add (GTK_CONTAINER (scrollerKeys), clistKeys);
- gpa_connect_by_accelerator (GTK_LABEL (labelKeys), clistKeys, accelGroup,
+ gpa_connect_by_accelerator (GTK_LABEL (labelKeys), clistKeys, accel_group,
_("_Recipient list"));
+ dialog->radio_pgp = gtk_radio_button_new_with_mnemonic
+ (NULL, _("Use _PGP"));
+ dialog->radio_x509 = gtk_radio_button_new_with_mnemonic
+ (gtk_radio_button_get_group (GTK_RADIO_BUTTON (dialog->radio_pgp)),
+ _("Use _X.509"));
+ dialog->radio_auto = gtk_radio_button_new_with_mnemonic
+ (gtk_radio_button_get_group (GTK_RADIO_BUTTON (dialog->radio_pgp)),
+ _("_Auto selection"));
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->radio_auto), TRUE);
+
+ hbox = gtk_hbox_new (FALSE, 0);
+ gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
+ gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (hbox), dialog->radio_pgp, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (hbox), dialog->radio_x509, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (hbox), dialog->radio_auto, FALSE, FALSE, 0);
+
+ widget = gtk_hseparator_new ();
+ gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0);
+
+ dialog->statushint = gtk_label_new (NULL);
+ gtk_box_pack_start (GTK_BOX (vbox), dialog->statushint, FALSE, FALSE, 0);
+
+
+ g_signal_connect (G_OBJECT (GTK_TREE_VIEW (dialog->clist_keys)),
+ "row-activated",
+ G_CALLBACK (recplist_row_activated_cb), dialog);
+ g_signal_connect (G_OBJECT (gtk_tree_view_get_model
+ (GTK_TREE_VIEW (dialog->clist_keys))),
+ "row-changed",
+ G_CALLBACK (recplist_row_changed_cb), dialog);
+ g_signal_connect (G_OBJECT (dialog->radio_pgp),
+ "toggled",
+ G_CALLBACK (rbutton_toggled_cb), dialog);
+ g_signal_connect (G_OBJECT (dialog->radio_x509),
+ "toggled",
+ G_CALLBACK (rbutton_toggled_cb), dialog);
+ g_signal_connect (G_OBJECT (dialog->radio_auto),
+ "toggled",
+ G_CALLBACK (rbutton_toggled_cb), dialog);
+
+
return object;
}
@@ -470,7 +775,7 @@
********************** Public API ************************
************************************************************/
-GtkWidget *
+RecipientDlg *
recipient_dlg_new (GtkWidget *parent)
{
RecipientDlg *dialog;
@@ -479,23 +784,40 @@
"window", parent,
NULL);
- return GTK_WIDGET(dialog);
+ return dialog;
}
-/* Put the recipients into the list. */
+/* Put RECIPIENTS into the list. PROTOCOL select the defualt protocol. */
void
-recipient_dlg_set_recipients (GtkWidget *object, GSList *recipients)
+recipient_dlg_set_recipients (RecipientDlg *dialog, GSList *recipients,
+ gpgme_protocol_t protocol)
{
- RecipientDlg *dialog;
GtkListStore *store;
GSList *recp;
GtkTreeIter iter;
const char *name;
+ GtkWidget *widget;
- g_return_if_fail (object);
- dialog = RECIPIENT_DLG (object);
+ g_return_if_fail (dialog);
+ dialog->disable_update_statushint++;
+
+ if (protocol == GPGME_PROTOCOL_OpenPGP)
+ widget = dialog->radio_pgp;
+ else if (protocol == GPGME_PROTOCOL_CMS)
+ widget = dialog->radio_x509;
+ else
+ widget = dialog->radio_auto;
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
+
+ if (widget != dialog->radio_auto)
+ {
+ gtk_widget_set_sensitive (GTK_WIDGET (dialog->radio_pgp), FALSE);
+ gtk_widget_set_sensitive (GTK_WIDGET (dialog->radio_x509), FALSE);
+ gtk_widget_set_sensitive (GTK_WIDGET (dialog->radio_auto), FALSE);
+ }
+
store = GTK_LIST_STORE (gtk_tree_view_get_model
(GTK_TREE_VIEW (dialog->clist_keys)));
@@ -511,11 +833,89 @@
RECPLIST_HAS_PGP, FALSE,
RECPLIST_HAS_X509, FALSE,
RECPLIST_KEYID, "",
+ RECPLIST_USERDATA, NULL,
-1);
}
}
+
parse_recipients (store);
+ dialog->disable_update_statushint--;
+ update_statushint (dialog);
}
+/* Return the selected keys as well as the selected protocol. */
+gpgme_key_t *
+recipient_dlg_get_keys (RecipientDlg *dialog, gpgme_protocol_t *r_protocol)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ size_t idx, nkeys;
+ gpgme_key_t key, *keyarray;
+ gpgme_protocol_t protocol;
+
+ g_return_val_if_fail (dialog, NULL);
+ if (!dialog->usable)
+ return NULL; /* No valid keys available. */
+ protocol = dialog->selected_protocol;
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->clist_keys));
+
+ /* Count the number of possible keys. */
+ nkeys = 0;
+ if (gtk_tree_model_get_iter_first (model, &iter))
+ {
+ do
+ nkeys++;
+ while (gtk_tree_model_iter_next (model, &iter));
+ }
+ keyarray = g_new (gpgme_key_t, nkeys+1);
+ idx = 0;
+ if (gtk_tree_model_get_iter_first (model, &iter))
+ {
+ do
+ {
+ char *mailbox;
+ struct userdata_s *info;
+
+ if (idx >= nkeys)
+ {
+ g_debug ("key list grew unexpectedly\n");
+ break;
+ }
+
+ gtk_tree_model_get (model, &iter,
+ RECPLIST_MAILBOX, &mailbox,
+ RECPLIST_USERDATA, &info,
+ -1);
+ if (info && !info->ignore_recipient)
+ {
+ if (protocol == GPGME_PROTOCOL_OpenPGP && info->pgp.keys)
+ key = info->pgp.keys[0];
+ else if (protocol == GPGME_PROTOCOL_CMS && info->x509.keys)
+ key = info->x509.keys[0];
+ else
+ key = NULL;
+ if (key)
+ {
+ g_print ("returning key for recipient '%s'\n", mailbox);
+ gpgme_key_ref (key);
+ keyarray[idx++] = key;
+ }
+ }
+ g_free (mailbox);
+ }
+ while (gtk_tree_model_iter_next (model, &iter));
+ }
+ g_assert (idx < nkeys+1);
+ keyarray[idx] = NULL;
+
+ if (r_protocol)
+ *r_protocol = protocol;
+
+ return keyarray;
+}
+
+
+
Modified: trunk/src/recipientdlg.h
===================================================================
--- trunk/src/recipientdlg.h 2008-03-04 16:46:03 UTC (rev 834)
+++ trunk/src/recipientdlg.h 2008-03-05 10:12:57 UTC (rev 835)
@@ -59,10 +59,12 @@
************ Public API ************
************************************/
-GtkWidget *recipient_dlg_new (GtkWidget *parent);
-void recipient_dlg_set_recipients (GtkWidget *list, GSList *recipients);
+RecipientDlg *recipient_dlg_new (GtkWidget *parent);
+void recipient_dlg_set_recipients (RecipientDlg *dialog, GSList *recipients,
+ gpgme_protocol_t protocol);
+gpgme_key_t *recipient_dlg_get_keys (RecipientDlg *dialog,
+ gpgme_protocol_t *r_protocol);
-
#endif /*RECIPIENTDLG_H*/
Modified: trunk/src/server.c
===================================================================
--- trunk/src/server.c 2008-03-04 16:46:03 UTC (rev 834)
+++ trunk/src/server.c 2008-03-05 10:12:57 UTC (rev 835)
@@ -59,6 +59,9 @@
comes from our command handler. */
int is_unfinished;
+ /* An GPAOperation object. */
+ GpaOperation *gpa_op;
+
/* File descriptors used by the gpgme callbacks. */
int input_fd;
int output_fd;
@@ -70,6 +73,12 @@
/* List of collected recipients. */
GSList *recipients;
+ /* Array of keys already prepared for RECIPIENTS. */
+ gpgme_key_t *recipient_keys;
+
+ /* The protocol as selected by the user. */
+ gpgme_protocol_t selected_protocol;
+
/* The current sender address (malloced). */
char *sender;
};
@@ -227,21 +236,30 @@
}
}
-/* Return a deep copy of the recipients list. */
-static GSList *
-copy_recipients (conn_ctrl_t ctrl)
+static void
+release_keys (gpgme_key_t *keys)
{
- GSList *recp, *newlist;
-
- newlist= NULL;
- for (recp = ctrl->recipients; recp; recp = g_slist_next (recp))
- newlist = g_slist_append (newlist, xstrdup (recp->data));
+ if (keys)
+ {
+ int idx;
+
+ for (idx=0; keys[idx]; idx++)
+ gpgme_key_unref (keys[idx]);
+ g_free (keys);
+ }
+}
- return newlist;
+
+/* Reset already prepared keys. */
+static void
+reset_prepared_keys (conn_ctrl_t ctrl)
+{
+ release_keys (ctrl->recipient_keys);
+ ctrl->recipient_keys = NULL;
+ ctrl->selected_protocol = GPGME_PROTOCOL_UNKNOWN;
}
-
/* RECIPIENT <recipient>
@@ -256,6 +274,8 @@
conn_ctrl_t ctrl = assuan_get_pointer (ctx);
gpg_error_t err = 0;
+ reset_prepared_keys (ctrl);
+
if (*line)
ctrl->recipients = g_slist_append (ctrl->recipients, xstrdup (line));
@@ -320,6 +340,13 @@
goto leave;
}
+ if (protocol != ctrl->selected_protocol)
+ {
+ if (ctrl->selected_protocol != GPGME_PROTOCOL_UNKNOWN)
+ g_debug ("note: protocol does not macth the one from PREP_ENCRYPT");
+ reset_prepared_keys (ctrl);
+ }
+
line = skip_options (line);
if (*line)
{
@@ -378,7 +405,10 @@
ctrl->cont_cmd = cont_encrypt;
op = gpa_stream_encrypt_operation_new (NULL, input_data, output_data,
- copy_recipients (ctrl), 0, ctx);
+ ctrl->recipients,
+ ctrl->recipient_keys,
+ protocol,
+ 0, ctx);
input_data = output_data = NULL;
g_signal_connect (G_OBJECT (op), "completed",
G_CALLBACK (g_object_unref), NULL);
@@ -405,6 +435,36 @@
+/* Continuation for cmd_prep_encrypt. */
+static void
+cont_prep_encrypt (assuan_context_t ctx, gpg_error_t err)
+{
+ conn_ctrl_t ctrl = assuan_get_pointer (ctx);
+
+ g_debug ("cont_prep_encrypt called with with ERR=%s <%s>",
+ gpg_strerror (err), gpg_strsource (err));
+
+ if (!err)
+ {
+ release_keys (ctrl->recipient_keys);
+ ctrl->recipient_keys = gpa_stream_encrypt_operation_get_keys
+ (GPA_STREAM_ENCRYPT_OPERATION (ctrl->gpa_op),
+ &ctrl->selected_protocol);
+
+ if (ctrl->recipient_keys)
+ g_print ("received some keys\n");
+ else
+ g_print ("received no keys\n");
+ }
+
+ if (ctrl->gpa_op)
+ {
+ g_object_unref (ctrl->gpa_op);
+ ctrl->gpa_op = NULL;
+ }
+ assuan_process_done (ctx, err);
+}
+
/* PREP_ENCRYPT [--protocol=OpenPGP|CMS]
Dummy encryption command used to check whether the given recipients
@@ -414,11 +474,11 @@
{
conn_ctrl_t ctrl = assuan_get_pointer (ctx);
gpg_error_t err;
- gpgme_protocol_t protocol = GPGME_PROTOCOL_OpenPGP;
+ gpgme_protocol_t protocol = GPGME_PROTOCOL_UNKNOWN;
GpaStreamEncryptOperation *op;
if (has_option (line, "--protocol=OpenPGP"))
- ; /* This is the default. */
+ protocol = GPGME_PROTOCOL_OpenPGP;
else if (has_option (line, "--protocol=CMS"))
protocol = GPGME_PROTOCOL_CMS;
else if (has_option_name (line, "--protocol"))
@@ -434,11 +494,27 @@
goto leave;
}
- ctrl->cont_cmd = NULL;
+ reset_prepared_keys (ctrl);
+
+ if (ctrl->gpa_op)
+ {
+ g_debug ("Oops: there is still an GPA_OP active\n");
+ g_object_unref (ctrl->gpa_op);
+ ctrl->gpa_op = NULL;
+ }
+ ctrl->cont_cmd = cont_prep_encrypt;
op = gpa_stream_encrypt_operation_new (NULL, NULL, NULL,
- copy_recipients (ctrl), 0, ctx);
+ ctrl->recipients,
+ ctrl->recipient_keys,
+ protocol,
+ 0, ctx);
+ /* Store that instance for later use but also install a signal
+ handler to unref it. */
+ g_object_ref (op);
+ ctrl->gpa_op = GPA_OPERATION (op);
g_signal_connect (G_OBJECT (op), "completed",
G_CALLBACK (g_object_unref), NULL);
+
return not_finished (ctrl);
leave:
@@ -670,6 +746,7 @@
{
conn_ctrl_t ctrl = assuan_get_pointer (ctx);
+ reset_prepared_keys (ctrl);
release_recipients (ctrl);
xfree (ctrl->sender);
ctrl->sender = NULL;
@@ -685,6 +762,11 @@
}
assuan_close_input_fd (ctx);
assuan_close_output_fd (ctx);
+ if (ctrl->gpa_op)
+ {
+ g_object_unref (ctrl->gpa_op);
+ ctrl->gpa_op = NULL;
+ }
}
@@ -792,7 +874,7 @@
g_debug ("no continuation defined; using default");
assuan_process_done (ctx, err);
}
- else if (!ctrl->client_died)
+ else if (ctrl->client_died)
{
g_debug ("not running continuation as client has disconnected");
connection_finish (ctx);
More information about the Gpa-commits
mailing list