[Gpa-commits] r827 - trunk/src

scm-commit@wald.intevation.org scm-commit at wald.intevation.org
Thu Feb 28 19:27:28 CET 2008


Author: werner
Date: 2008-02-28 19:27:27 +0100 (Thu, 28 Feb 2008)
New Revision: 827

Added:
   trunk/src/recipientdlg.c
   trunk/src/recipientdlg.h
Modified:
   trunk/src/ChangeLog
   trunk/src/Makefile.am
   trunk/src/gpastreamencryptop.c
   trunk/src/gpastreamencryptop.h
   trunk/src/keyring.c
   trunk/src/server.c
Log:
Minor bug fix to the server mode.
Started with a recipients dialog.


Modified: trunk/src/ChangeLog
===================================================================
--- trunk/src/ChangeLog	2008-02-20 18:53:28 UTC (rev 826)
+++ trunk/src/ChangeLog	2008-02-28 18:27:27 UTC (rev 827)
@@ -1,3 +1,14 @@
+2008-02-28  Werner Koch  <wk at g10code.com>
+
+	* server.c (struct conn_ctrl_s): Add fields is_unfinished and
+	client_died.
+	(not_finished): New. Use that instead of GPG_ERR_UNFINISHED.
+	(gpa_run_server_continuation, receive_cb): Handle dead client with
+	pending continuation.
+
+	* gpastreamencryptop.c: Add recipients property.
+	* recipientdlg.c, recipientdlg.h: New.
+
 2008-02-20  Werner Koch  <wk at g10code.com>
 
 	* server.c (cmd_start_keymanager): New.

Modified: trunk/src/Makefile.am
===================================================================
--- trunk/src/Makefile.am	2008-02-20 18:53:28 UTC (rev 826)
+++ trunk/src/Makefile.am	2008-02-28 18:27:27 UTC (rev 827)
@@ -46,6 +46,7 @@
 	      filesigndlg.c filesigndlg.h \
 	      encryptdlg.c encryptdlg.h \
 	      verifydlg.c verifydlg.h \
+              recipientdlg.c recipientdlg.h \
 	      keyring.c keyring.h \
 	      ownertrustdlg.c ownertrustdlg.h \
 	      keysigndlg.c keysigndlg.h \

Modified: trunk/src/gpastreamencryptop.c
===================================================================
--- trunk/src/gpastreamencryptop.c	2008-02-20 18:53:28 UTC (rev 826)
+++ trunk/src/gpastreamencryptop.c	2008-02-28 18:27:27 UTC (rev 827)
@@ -22,11 +22,21 @@
 #include <glib.h>
 
 #include "gpgmetools.h"
-#include "encryptdlg.h"
+#include "recipientdlg.h"
 #include "gpawidgets.h"
 #include "gpapastrings.h"
 #include "gpastreamencryptop.h"
 
+
+/* Indentifiers for our properties. */
+enum 
+  {
+    PROP_0,
+    PROP_RECIPIENTS
+  };
+
+
+
 static void response_cb (GtkDialog *dialog,
                          gint response,
                          gpointer user_data);
@@ -48,8 +58,44 @@
 
 
 
+static void
+gpa_stream_encrypt_operation_get_property (GObject *object, guint prop_id,
+                                           GValue *value, GParamSpec *pspec)
+{
+  GpaStreamEncryptOperation *op = GPA_STREAM_ENCRYPT_OPERATION (object);
+  
+  switch (prop_id)
+    {
+    case PROP_RECIPIENTS:
+      g_value_set_pointer (value, op->recipients);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
 
+
 static void
+gpa_stream_encrypt_operation_set_property (GObject *object, guint prop_id,
+                                           const GValue *value,
+                                           GParamSpec *pspec)
+{
+  GpaStreamEncryptOperation *op = GPA_STREAM_ENCRYPT_OPERATION (object);
+
+  switch (prop_id)
+    {
+    case PROP_RECIPIENTS:
+      op->recipients = (GSList*)g_value_get_pointer (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+
+static void
 gpa_stream_encrypt_operation_finalize (GObject *object)
 {  
   GpaStreamEncryptOperation *op = GPA_STREAM_ENCRYPT_OPERATION (object);
@@ -69,6 +115,8 @@
 gpa_stream_encrypt_operation_init (GpaStreamEncryptOperation *op)
 {
   op->encrypt_dialog = NULL;
+  op->recipients = NULL;
+  op->selected_protocol = GPGME_PROTOCOL_UNKNOWN;
 }
 
 
@@ -87,9 +135,10 @@
   op = GPA_STREAM_ENCRYPT_OPERATION (object);
 
   /* Create the "Encrypt" dialog */
-  op->encrypt_dialog = gpa_file_encrypt_dialog_new
-    (GPA_OPERATION (op)->window, FALSE);
+  op->encrypt_dialog = recipient_dlg_new (GPA_OPERATION (op)->window);
 
+  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
@@ -118,6 +167,16 @@
 
   object_class->constructor = gpa_stream_encrypt_operation_constructor;
   object_class->finalize = gpa_stream_encrypt_operation_finalize;
+  object_class->set_property = gpa_stream_encrypt_operation_set_property;
+  object_class->get_property = gpa_stream_encrypt_operation_get_property;
+
+  g_object_class_install_property 
+    (object_class, PROP_RECIPIENTS,
+     g_param_spec_pointer 
+     ("recipients", "Recipients",
+      "A list of recipients in rfc-822 mailbox format.",
+      G_PARAM_WRITABLE|G_PARAM_CONSTRUCT_ONLY));
+
 }
 
 
@@ -191,152 +250,14 @@
 
 
 
-/*
- * Setting the recipients for the context.
- */
-
-/* static GtkResponseType */
-/* ignore_key_trust (gpgme_key_t key, GtkWidget *parent) */
-/* { */
-/*   GtkWidget *dialog; */
-/*   GtkWidget *key_info; */
-/*   GtkWidget *vbox; */
-/*   GtkWidget *hbox; */
-/*   GtkWidget *label; */
-/*   GtkWidget *image; */
-/*   GtkResponseType response; */
-
-/*   dialog = gtk_dialog_new_with_buttons (_("Unknown Key"), GTK_WINDOW(parent), */
-/* 					GTK_DIALOG_MODAL,  */
-/* 					_("_Yes"), GTK_RESPONSE_YES, */
-/* 					_("_No"), GTK_RESPONSE_NO, */
-/* 					NULL); */
-/*   gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_YES); */
-/*   gtk_container_set_border_width (GTK_CONTAINER (dialog), 5); */
-
-/*   hbox = gtk_hbox_new (FALSE, 6); */
-/*   image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, */
-/* 				    GTK_ICON_SIZE_DIALOG); */
-/*   gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, TRUE, 0); */
-/*   vbox = gtk_vbox_new (FALSE, 6); */
-/*   gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); */
-/*   gtk_box_pack_start_defaults (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox); */
-
-/*   label = gtk_label_new (_("You are going to encrypt a stream using " */
-/* 			   "the following key:")); */
-/*   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); */
-/*   gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 5); */
-/*   key_info = gpa_key_info_new (key); */
-/*   gtk_box_pack_start (GTK_BOX (vbox), key_info, FALSE, TRUE, 5); */
-/*   label = gtk_label_new (_("However, it is not certain that the key belongs " */
-/* 			   "to that person.")); */
-/*   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); */
-/*   gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 5); */
-/*   label = gtk_label_new (NULL); */
-/*   gtk_label_set_markup (GTK_LABEL (label),  */
-/* 			_("Do you <b>really</b> want to use this key?")); */
-/*   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); */
-/*   gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 5); */
-
-/*   gtk_widget_show_all (dialog); */
-/*   response = gtk_dialog_run (GTK_DIALOG (dialog)); */
-
-/*   gtk_widget_destroy (dialog); */
-/*   return response; */
-/* } */
-
-/* static void */
-/* revoked_key (gpgme_key_t key, GtkWidget *parent) */
-/* { */
-/*   GtkWidget *dialog; */
-/*   GtkWidget *key_info; */
-/*   GtkWidget *vbox; */
-/*   GtkWidget *hbox; */
-/*   GtkWidget *label; */
-/*   GtkWidget *image; */
-
-/*   dialog = gtk_dialog_new_with_buttons (_("Revoked Key"), GTK_WINDOW(parent), */
-/* 					GTK_DIALOG_MODAL,  */
-/* 					_("_Close"), GTK_RESPONSE_CLOSE, */
-/* 					NULL); */
-/*   gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE); */
-/*   gtk_container_set_border_width (GTK_CONTAINER (dialog), 5); */
-
-/*   hbox = gtk_hbox_new (FALSE, 6); */
-/*   image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_ERROR, */
-/* 				    GTK_ICON_SIZE_DIALOG); */
-/*   gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, TRUE, 0); */
-/*   vbox = gtk_vbox_new (FALSE, 6); */
-/*   gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); */
-/*   gtk_box_pack_start_defaults (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox); */
-
-/*   label = gtk_label_new (_("The following key has been revoked by it's owner:")); */
-/*   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); */
-/*   gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 5); */
-/*   key_info = gpa_key_info_new (key); */
-/*   gtk_box_pack_start (GTK_BOX (vbox), key_info, FALSE, TRUE, 5); */
-/*   label = gtk_label_new (_("And can not be used for encryption.")); */
-/*   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); */
-/*   gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 5); */
-
-/*   gtk_widget_show_all (dialog); */
-/*   gtk_dialog_run (GTK_DIALOG (dialog)); */
-/*   gtk_widget_destroy (dialog); */
-/* } */
-
-/* static void */
-/* expired_key (gpgme_key_t key, GtkWidget *parent) */
-/* { */
-/*   GtkWidget *dialog; */
-/*   GtkWidget *key_info; */
-/*   GtkWidget *vbox; */
-/*   GtkWidget *hbox; */
-/*   GtkWidget *label; */
-/*   GtkWidget *image; */
-/*   gchar *message; */
-
-/*   dialog = gtk_dialog_new_with_buttons (_("Revoked Key"), GTK_WINDOW(parent), */
-/* 					GTK_DIALOG_MODAL,  */
-/* 					_("_Close"), GTK_RESPONSE_CLOSE, */
-/* 					NULL); */
-/*   gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE); */
-/*   gtk_container_set_border_width (GTK_CONTAINER (dialog), 5); */
-
-/*   hbox = gtk_hbox_new (FALSE, 6); */
-/*   image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_ERROR, */
-/* 				    GTK_ICON_SIZE_DIALOG); */
-/*   gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, TRUE, 0); */
-/*   vbox = gtk_vbox_new (FALSE, 6); */
-/*   gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); */
-/*   gtk_box_pack_start_defaults (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox); */
-
-/*   message = g_strdup_printf (_("The following key expired on %s:"), */
-/*                              gpa_expiry_date_string  */
-/*                              (key->subkeys->expires)); */
-/*   label = gtk_label_new (message); */
-/*   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); */
-/*   gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 5); */
-/*   key_info = gpa_key_info_new (key); */
-/*   gtk_box_pack_start (GTK_BOX (vbox), key_info, FALSE, TRUE, 5); */
-/*   label = gtk_label_new (_("And can not be used for encryption.")); */
-/*   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); */
-/*   gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 5); */
-
-/*   gtk_widget_show_all (dialog); */
-/*   gtk_dialog_run (GTK_DIALOG (dialog)); */
-/*   gtk_widget_destroy (dialog); */
-/* } */
-
-
-/* Given a list of strings, each describing one recipient parse them
+/* 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 array NAMES. Items not found are
-   stored as malloced strings in the newly allocated array UNKNOWN.
-   Found keys are stored in the newly allocated array FOUND.  Both
-   arrays are terminated by a NULL entry.  Caller needs to release
-   FOUND and UNKNOWN.
+   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.
  */
 static gpg_error_t
 parse_recipients (GpaStreamEncryptOperation *op, GSList *recipients,
@@ -360,6 +281,8 @@
   if (err)
     return err; 
 
+  /* Fixme: Add rfc-822 mailbox parsing.  */
+
   for (n=0, recp = recipients; recp; recp = g_slist_next (recp))
     n++;
 
@@ -386,9 +309,26 @@
       gpgme_op_keylist_end (ctx);
 
       /* 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 key.  */
-      if (key && !key->revoked && !key->disabled && !key->expired)
+         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 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);
+        }
+      else if (key && !key->revoked && !key->disabled && !key->expired)
+        {
           gpgme_key_ref (key);
           found[found_idx++] = key;
           if (used_proto == GPGME_PROTOCOL_UNKNOWN)
@@ -415,11 +355,17 @@
   if (err)
     ;
   else if (used_proto == GPGME_PROTOCOL_OpenPGP)
-    err = gpa_operation_write_status (GPA_OPERATION (op), "PROTOCOL",
-                                      "OpenPGP", NULL);
+    {
+      op->selected_protocol = used_proto;
+      err = gpa_operation_write_status (GPA_OPERATION (op), "PROTOCOL",
+                                        "OpenPGP", NULL);
+    }
   else if (used_proto == GPGME_PROTOCOL_CMS)
-    err = gpa_operation_write_status (GPA_OPERATION (op), "PROTOCOL",
-                                      "CMS", NULL);
+    {
+      op->selected_protocol = used_proto;
+      err = gpa_operation_write_status (GPA_OPERATION (op), "PROTOCOL",
+                                        "CMS", NULL);
+    }
   else 
     err = 0;
 
@@ -447,7 +393,7 @@
   if (response != GTK_RESPONSE_OK)
     {
       /* The dialog was canceled, so we do nothing and complete the
-       * operation */
+       * operation.  */
       gpa_operation_server_finish (GPA_OPERATION (op), 
                                    gpg_error (GPG_ERR_CANCELED));
       g_signal_emit_by_name (GPA_OPERATION (op), "completed");
@@ -463,10 +409,19 @@
   if (err)
     goto leave;
 
-  /* Our streams work all in ascii armored mode (Either PGP or PEM) */
-  if (GPA_STREAM_OPERATION (op)->input_stream)
+  /* Set the output encoding.  */
+  if (GPA_STREAM_OPERATION (op)->input_stream 
+      && GPA_STREAM_OPERATION (op)->output_stream)
     {
-      gpgme_set_armor (GPA_OPERATION (op)->context->ctx, 1);
+      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
@@ -537,12 +492,13 @@
 
 /* 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.  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
-   input 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.  */
+   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.  */
@@ -560,10 +516,14 @@
 		     "window", window,
 		     "input_stream", input_stream,
 		     "output_stream", output_stream,
+                     "recipients", recipients,
                      "server-ctx", server_ctx,
 		     NULL);
-  if (op)
-    op->recipients = recipients;
+  if (!op)
+    {
+      g_slist_foreach (recipients, free_func, NULL);
+      g_slist_free (recipients);
+    }
 
   return op;
 }

Modified: trunk/src/gpastreamencryptop.h
===================================================================
--- trunk/src/gpastreamencryptop.h	2008-02-20 18:53:28 UTC (rev 826)
+++ trunk/src/gpastreamencryptop.h	2008-02-28 18:27:27 UTC (rev 827)
@@ -61,6 +61,7 @@
   
   GtkWidget *encrypt_dialog;
   GSList *recipients;
+  gpgme_protocol_t selected_protocol;
 };
 
 

Modified: trunk/src/keyring.c
===================================================================
--- trunk/src/keyring.c	2008-02-20 18:53:28 UTC (rev 826)
+++ trunk/src/keyring.c	2008-02-28 18:27:27 UTC (rev 827)
@@ -1237,7 +1237,7 @@
 }
 
 /* Fill the details page of the details notebook with the properties
-   of the publix key key */
+   of the public key.  */
 static void
 keyring_details_page_fill_key (GPAKeyringEditor * editor, gpgme_key_t key)
 {

Added: trunk/src/recipientdlg.c
===================================================================
--- trunk/src/recipientdlg.c	2008-02-20 18:53:28 UTC (rev 826)
+++ trunk/src/recipientdlg.c	2008-02-28 18:27:27 UTC (rev 827)
@@ -0,0 +1,365 @@
+/* recipientdlg.c - A dialog to select a mail recipient.
+ * Copyright (C) 2008 g10 Code GmbH.
+ *
+ * This file is part of GPA
+ *
+ * GPA is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GPA is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include "gpa.h"
+#include "i18n.h"
+
+#include "gtktools.h"
+#include "gpakeyselector.h"
+#include "recipientdlg.h"
+
+
+struct _RecipientDlg 
+{
+  GtkDialog parent;
+  
+  GtkWidget *clist_keys;
+  GtkWidget *check_sign;
+  GtkWidget *check_armor;
+  GtkWidget *clist_who;
+  GtkWidget *scroller_who;
+};
+
+
+struct _RecipientDlgClass 
+{
+  GtkDialogClass parent_class;
+
+};
+
+
+/* The parent class.  */
+static GObjectClass *parent_class;
+
+
+/* Indentifiers for our properties. */
+enum 
+  {
+    PROP_0,
+    PROP_WINDOW,
+    PROP_FORCE_ARMOR
+  };
+
+
+/* Identifiers for the columns of the RECPLIST.  */
+enum
+  {
+    RECPLIST_MAILBOX,   /* The rfc822 mailbox to whom a key needs to
+                           be associated.  */
+    RECPLIST_HAS_PGP,   /* A PGP certificate is available.  */
+    RECPLIST_HAS_X509,  /* An X.509 certificate is available.  */
+    RECPLIST_KEYID,     /* The key ID of the associated key. */
+
+    RECPLIST_N_COLUMNS
+  };
+
+
+
+/* Create the main list of this dialog.  */
+static GtkWidget *
+recplist_window_new (void)
+{
+  GtkListStore *store;
+  GtkWidget *list;
+  GtkCellRenderer *renderer;
+  GtkTreeViewColumn *column;
+  
+  /* Create a model and associate a view.  */
+  store = gtk_list_store_new (RECPLIST_N_COLUMNS,
+			      G_TYPE_STRING,
+                              G_TYPE_BOOLEAN,
+                              G_TYPE_BOOLEAN,
+			      G_TYPE_STRING);
+  list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
+  gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (list), TRUE);
+
+  /* Define the columns.  */
+  renderer = gtk_cell_renderer_text_new ();
+  column = gtk_tree_view_column_new_with_attributes 
+    (_("Recipient"), renderer, "text", RECPLIST_MAILBOX, NULL);
+  gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
+
+  renderer = gtk_cell_renderer_toggle_new ();
+  column = gtk_tree_view_column_new_with_attributes
+    (_("PGP"), renderer, "active", RECPLIST_HAS_PGP, NULL);
+  gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
+
+  renderer = gtk_cell_renderer_toggle_new ();
+  column = gtk_tree_view_column_new_with_attributes
+    (_("X.509"), renderer, "active", RECPLIST_HAS_X509, NULL);
+  gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
+
+  renderer = gtk_cell_renderer_text_new ();
+  column = gtk_tree_view_column_new_with_attributes 
+    (_("Key ID"), renderer, "text", RECPLIST_KEYID, NULL);
+  gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
+
+
+  return list;
+}
+
+
+
+
+static void
+changed_select_row_cb (GtkTreeSelection *treeselection, gpointer user_data)
+{
+/*   RecipientDlg *dialog = user_data; */
+  
+/*   if (gpa_key_selector_has_selection (GPA_KEY_SELECTOR (dialog->clist_keys))) */
+/*     { */
+/*       gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), */
+/* 					 GTK_RESPONSE_OK, TRUE); */
+/*     } */
+/*   else */
+/*     { */
+/*       gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), */
+/* 					 GTK_RESPONSE_OK, FALSE); */
+/*     } */
+}
+
+
+
+
+
+/************************************************************ 
+ ******************   Object Management  ********************
+ ************************************************************/
+
+static void
+recipient_dlg_get_property (GObject *object, guint prop_id,
+                            GValue *value, GParamSpec *pspec)
+{
+  RecipientDlg *dialog = RECIPIENT_DLG (object);
+  
+  switch (prop_id)
+    {
+    case PROP_WINDOW:
+      g_value_set_object (value,
+			  gtk_window_get_transient_for (GTK_WINDOW (dialog)));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+
+static void
+recipient_dlg_set_property (GObject *object, guint prop_id,
+                            const GValue *value, GParamSpec *pspec)
+{
+  RecipientDlg *dialog = RECIPIENT_DLG (object);
+
+  switch (prop_id)
+    {
+    case PROP_WINDOW:
+      gtk_window_set_transient_for (GTK_WINDOW (dialog),
+				    g_value_get_object (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+
+static void
+recipient_dlg_finalize (GObject *object)
+{  
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+static void
+recipient_dlg_init (RecipientDlg *dialog)
+{
+
+}
+
+
+static GObject*
+recipient_dlg_constructor (GType type, guint n_construct_properties,
+                           GObjectConstructParam *construct_properties)
+{
+  GObject *object;
+  RecipientDlg *dialog;
+  GtkAccelGroup *accelGroup;
+  GtkWidget *vboxEncrypt;
+  GtkWidget *labelKeys;
+  GtkWidget *scrollerKeys;
+  GtkWidget *clistKeys;
+
+  object = parent_class->constructor (type,
+				      n_construct_properties,
+				      construct_properties);
+  dialog = RECIPIENT_DLG (object);
+
+
+  gtk_dialog_add_buttons (GTK_DIALOG (dialog),
+			  GTK_STOCK_OK, GTK_RESPONSE_OK,
+			  _("_Cancel"), GTK_RESPONSE_CANCEL, NULL);
+  gtk_window_set_title (GTK_WINDOW (dialog),
+                        _("Select keys for recipients"));
+  gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+  gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, 
+				     FALSE);
+  gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+
+  accelGroup = gtk_accel_group_new ();
+  gtk_window_add_accel_group (GTK_WINDOW (dialog), accelGroup);
+
+  vboxEncrypt = GTK_DIALOG (dialog)->vbox;
+  gtk_container_set_border_width (GTK_CONTAINER (vboxEncrypt), 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);
+
+  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_widget_set_size_request (scrollerKeys, 400, 200);
+
+  clistKeys = recplist_window_new ();
+  g_signal_connect (G_OBJECT (gtk_tree_view_get_selection 
+			      (GTK_TREE_VIEW (clistKeys))),
+		    "changed", G_CALLBACK (changed_select_row_cb),
+		    dialog);
+  dialog->clist_keys = clistKeys;
+  gtk_container_add (GTK_CONTAINER (scrollerKeys), clistKeys);
+  gpa_connect_by_accelerator (GTK_LABEL (labelKeys), clistKeys, accelGroup,
+			      _("_Recipient list"));
+
+ 
+
+  return object;
+}
+
+
+static void
+recipient_dlg_class_init (RecipientDlgClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  
+  parent_class = g_type_class_peek_parent (klass);
+  
+  object_class->constructor = recipient_dlg_constructor;
+  object_class->finalize = recipient_dlg_finalize;
+  object_class->set_property = recipient_dlg_set_property;
+  object_class->get_property = recipient_dlg_get_property;
+
+  g_object_class_install_property
+    (object_class,
+     PROP_WINDOW,
+     g_param_spec_object 
+     ("window", "Parent window",
+      "Parent window", GTK_TYPE_WIDGET,
+      G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+
+}
+
+
+GType
+recipient_dlg_get_type (void)
+{
+  static GType this_type;
+  
+  if (!this_type)
+    {
+      static const GTypeInfo this_info =
+	{
+	  sizeof (RecipientDlgClass),
+	  (GBaseInitFunc) NULL,
+	  (GBaseFinalizeFunc) NULL,
+	  (GClassInitFunc) recipient_dlg_class_init,
+	  NULL, /* class_finalize */
+	  NULL, /* class_data */
+
+	  sizeof (RecipientDlg),
+	  0,    /* n_preallocs */
+	  (GInstanceInitFunc) recipient_dlg_init,
+	};
+      
+      this_type = g_type_register_static (GTK_TYPE_DIALOG,
+                                          "RecipientDlg",
+                                          &this_info, 0);
+    }
+  
+  return this_type;
+}
+
+
+
+/************************************************************ 
+ **********************  Public API  ************************
+ ************************************************************/
+
+GtkWidget *
+recipient_dlg_new (GtkWidget *parent)
+{
+  RecipientDlg *dialog;
+  
+  dialog = g_object_new (RECIPIENT_DLG_TYPE,
+			 "window", parent,
+			 NULL);
+
+  return GTK_WIDGET(dialog);
+}
+
+
+/* Put the recipients into the list.  */
+void 
+recipient_dlg_set_recipients (GtkWidget *object, GSList *recipients)
+{
+  RecipientDlg *dialog;
+  GtkListStore *store;
+  GSList *recp;
+  GtkTreeIter iter;
+  const char *name;
+
+  g_return_if_fail (object);
+  dialog = RECIPIENT_DLG (object);
+
+  store = GTK_LIST_STORE (gtk_tree_view_get_model
+                          (GTK_TREE_VIEW (dialog->clist_keys)));
+
+  gtk_list_store_clear (store);
+  for (recp = recipients; recp; recp = g_slist_next (recp))
+    {
+      name = recp->data;
+      if (name && *name)
+        {
+          gtk_list_store_append (store, &iter);
+          gtk_list_store_set (store, &iter,
+                              RECPLIST_MAILBOX, name,
+                              RECPLIST_HAS_PGP, FALSE,
+                              RECPLIST_HAS_X509, (*name == 'f'),
+                              RECPLIST_KEYID,  "[click to select]",
+                              -1);
+        }    
+    }
+}
+
+
+

Added: trunk/src/recipientdlg.h
===================================================================
--- trunk/src/recipientdlg.h	2008-02-20 18:53:28 UTC (rev 826)
+++ trunk/src/recipientdlg.h	2008-02-28 18:27:27 UTC (rev 827)
@@ -0,0 +1,68 @@
+/* recipientdlg.h - A dialog to select a mail recipient.
+ * Copyright (C) 2008 g10 Code GmbH.
+ *
+ * This file is part of GPA
+ *
+ * GPA is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GPA is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef RECIPIENTDLG_H
+#define RECIPIENTDLG_H
+
+
+/* Definitions to define the object.  */
+#define RECIPIENT_DLG_TYPE \
+          (recipient_dlg_get_type ())
+
+#define RECIPIENT_DLG(obj) \
+          (G_TYPE_CHECK_INSTANCE_CAST \
+            ((obj), RECIPIENT_DLG_TYPE,\
+              RecipientDlg))
+
+#define RECIPIENT_DLG_CLASS(klass) \
+          (G_TYPE_CHECK_CLASS_CAST \
+            ((klass), RECIPIENT_DLG_TYPE, \
+              RecipientDlgClass))
+
+#define IS_RECIPIENT_DLG(obj) \
+          (G_TYPE_CHECK_INSTANCE_TYPE \
+            ((obj), RECIPIENT_DLG_TYPE))
+
+#define IS_RECIPIENT_DLG_CLASS(klass) \
+          (G_TYPE_CHECK_CLASS_TYPE \
+            ((klass), RECIPIENT_DLG_TYPE))
+
+#define RECIPIENT_DLG_GET_CLASS(obj) \
+          (G_TYPE_INSTANCE_GET_CLASS \
+            ((obj), RECIPIENT_DLG_TYPE, \
+              RecipientDlgClass))
+
+typedef struct _RecipientDlg RecipientDlg;
+typedef struct _RecipientDlgClass RecipientDlgClass;
+
+
+GType recipient_dlg_get_type (void) G_GNUC_CONST;
+
+
+/************************************
+ ************ Public API ************
+ ************************************/
+
+GtkWidget *recipient_dlg_new (GtkWidget *parent);
+void recipient_dlg_set_recipients (GtkWidget *list, GSList *recipients);
+
+
+
+
+#endif /*RECIPIENTDLG_H*/

Modified: trunk/src/server.c
===================================================================
--- trunk/src/server.c	2008-02-20 18:53:28 UTC (rev 826)
+++ trunk/src/server.c	2008-02-28 18:27:27 UTC (rev 827)
@@ -40,7 +40,6 @@
 
 #define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
 
-
 /* The object used to keep track of the a connection's state.  */
 struct conn_ctrl_s;
 typedef struct conn_ctrl_s *conn_ctrl_t;
@@ -52,6 +51,14 @@
   /* NULL or continuation function for a command.  */
   void (*cont_cmd) (assuan_context_t, gpg_error_t);
 
+  /* Flag indicating that the client died while a continuation was
+     still registyered.  */
+  int client_died;
+
+  /* This is a helper to detect that the unfinished erroe code actually
+     comes from our command handler.  */
+  int is_unfinished;
+
   /* File descriptors used by the gpgme callbacks.  */
   int input_fd;
   int output_fd;
@@ -68,12 +75,23 @@
 };
 
 
-
+/* The nonce used by the server connection.  This nonce is required
+   uner Windows to emulate Unix Domain Sockets.  This is managed by
+   libassuan but we need to store the nonce in the application.  Under
+   Unix this is just a stub.  */
 static assuan_sock_nonce_t socket_nonce;
 
 
 
 
+static int
+not_finished (conn_ctrl_t ctrl)
+{
+  ctrl->is_unfinished = 1;
+  return gpg_error (GPG_ERR_UNFINISHED);
+}
+
+
 /* Test whether LINE contains thye option NAME.  An optional argument
    of the option is ignored.  For example with NAME being "--protocol"
    this function returns true for "--protocol" as well as for
@@ -229,10 +247,9 @@
 
   Set the recipient for the encryption.  <recipient> is an RFC2822
   recipient name.  This command may or may not check the recipient for
-  validity right away; if it does not (as implemented in GPA) all
-  recipients are checked at the time of the ENCRYPT command.  All
-  RECIPIENT commands are cumulative until a RESET or an successful
-  ENCRYPT command.  */
+  validity right away; if it does not (as here) all recipients are
+  checked at the time of the ENCRYPT command.  All RECIPIENT commands
+  are cumulative until a RESET or an successful ENCRYPT command.  */
 static int
 cmd_recipient (assuan_context_t ctx, char *line)
 {
@@ -365,8 +382,9 @@
   input_data = output_data = NULL;
   g_signal_connect (G_OBJECT (op), "completed",
                     G_CALLBACK (g_object_unref), NULL);
-  return gpg_error (GPG_ERR_UNFINISHED);
 
+  return not_finished (ctrl);
+
  leave:
   gpgme_data_release (input_data); 
   gpgme_data_release (output_data);
@@ -390,7 +408,7 @@
 /* PREP_ENCRYPT [--protocol=OpenPGP|CMS]
 
    Dummy encryption command used to check whether the given recipients
-   are all valid and to tell the cleint the preferred protocol.  */
+   are all valid and to tell the client the preferred protocol.  */
 static int 
 cmd_prep_encrypt (assuan_context_t ctx, char *line)
 {
@@ -421,7 +439,7 @@
                                          copy_recipients (ctrl), 0, ctx);
   g_signal_connect (G_OBJECT (op), "completed",
                     G_CALLBACK (g_object_unref), NULL);
-  return gpg_error (GPG_ERR_UNFINISHED);
+  return not_finished (ctrl);
 
  leave:
   return assuan_process_done (ctx, err);
@@ -576,7 +594,7 @@
 /*   input_data = output_data = NULL; */
 /*   g_signal_connect (G_OBJECT (op), "completed", */
 /*                     G_CALLBACK (g_object_unref), NULL); */
-/*   return gpg_error (GPG_ERR_UNFINISHED); */
+/*   return not_finished (ctrl); */
 
  leave:
   gpgme_data_release (input_data); 
@@ -774,6 +792,11 @@
       g_debug ("no continuation defined; using default");
       assuan_process_done (ctx, err);
     }
+  else if (!ctrl->client_died)
+    {
+      g_debug ("not running continuation as client has disconnected");
+      connection_finish (ctx);
+    }
   else
     {
       cont_cmd = ctrl->cont_cmd;
@@ -818,18 +841,22 @@
             ; /* Ignore.  */
           else if (gpg_err_code (err) == GPG_ERR_EOF || err == -1)
             {
-              connection_finish (ctx);
-              /* FIXME: what about the socket? */
+              if (ctrl->cont_cmd)
+                ctrl->client_died = 1; /* Need to delay the cleanup.  */
+              else
+                connection_finish (ctx);
               return FALSE; /* Remove from the watch.  */
             }
           else if (gpg_err_code (err) == GPG_ERR_UNFINISHED)
             {
-              if ( !ctrl->cont_cmd)
+              if (!ctrl->is_unfinished)
                 {
                   /* It is quite possible that some other subsystem
                      returns that error code.  Tell the user about
                      this curiosity and finish the command.  */
                   g_debug ("note: Unfinished error code not emitted by us");
+                  if (ctrl->cont_cmd)
+                    g_debug ("OOPS: pending continuation!");
                   assuan_process_done (ctx, err);
                 }
             }



More information about the Gpa-commits mailing list