[Gpa-commits] r785 - trunk/src

scm-commit@wald.intevation.org scm-commit at wald.intevation.org
Tue Oct 2 20:18:02 CEST 2007


Author: werner
Date: 2007-10-02 20:18:01 +0200 (Tue, 02 Oct 2007)
New Revision: 785

Added:
   trunk/src/gpastreamencryptop.c
   trunk/src/gpastreamencryptop.h
   trunk/src/gpastreamop.c
   trunk/src/gpastreamop.h
   trunk/src/utils.c
Modified:
   trunk/src/ChangeLog
   trunk/src/Makefile.am
   trunk/src/encryptdlg.c
   trunk/src/gpa.c
   trunk/src/gpa.h
   trunk/src/gpacontext.c
   trunk/src/server.c
Log:
New option --cms to enable the X/509/CMS hack.
Started with the implementation of an encrypt server command.


Modified: trunk/src/ChangeLog
===================================================================
--- trunk/src/ChangeLog	2007-09-28 17:50:00 UTC (rev 784)
+++ trunk/src/ChangeLog	2007-10-02 18:18:01 UTC (rev 785)
@@ -1,3 +1,11 @@
+2007-10-02  Werner Koch  <wk at g10code.com>
+
+	* utils.c (translate_sys2libc_fd): New.
+
+2007-10-01  Werner Koch  <wk at g10code.com>
+
+	* utils.c: New to implement xmalloc and xcalloc. 
+
 2007-09-28  Werner Koch  <wk at g10code.com>
 
 	* gpakeyselector.c (gpa_key_selector_next_key): Don't segv is not

Modified: trunk/src/Makefile.am
===================================================================
--- trunk/src/Makefile.am	2007-09-28 17:50:00 UTC (rev 784)
+++ trunk/src/Makefile.am	2007-10-02 18:18:01 UTC (rev 785)
@@ -71,6 +71,8 @@
 	      gpaprogressdlg.h gpaprogressdlg.c \
 	      gparecvkeydlg.h gparecvkeydlg.c \
 	      gpaoperation.h gpaoperation.c \
+	      gpastreamop.h gpastreamop.c  \
+	      gpastreamencryptop.h gpastreamencryptop.c  \
 	      gpafileop.h gpafileop.c \
 	      gpafiledecryptop.h gpafiledecryptop.c \
 	      gpafileencryptop.h gpafileencryptop.c \
@@ -96,7 +98,8 @@
 	      gpabackupop.h gpabackupop.c \
 	      gpakeyselector.h gpakeyselector.c \
 	      server.c \
-	      options.c $(gpa_w32_sources)
+	      options.c \
+	      utils.c $(gpa_w32_sources)
 
 
 dndtest_SOURCES = dndtest.c

Modified: trunk/src/encryptdlg.c
===================================================================
--- trunk/src/encryptdlg.c	2007-09-28 17:50:00 UTC (rev 784)
+++ trunk/src/encryptdlg.c	2007-10-02 18:18:01 UTC (rev 785)
@@ -69,6 +69,7 @@
     }
 }
 
+
 static void
 gpa_file_encrypt_dialog_set_property (GObject     *object,
 				      guint        prop_id,
@@ -89,12 +90,14 @@
     }
 }
 
+
 static void
 gpa_file_encrypt_dialog_finalize (GObject *object)
 {  
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
+
 static void
 gpa_file_encrypt_dialog_class_init (GpaFileEncryptDialogClass *klass)
 {
@@ -115,6 +118,7 @@
 				    G_PARAM_WRITABLE|G_PARAM_CONSTRUCT_ONLY));
 }
 
+
 static void
 gpa_file_encrypt_dialog_init (GpaFileEncryptDialog *dialog)
 {
@@ -197,6 +201,7 @@
 
 }
 
+
 GType
 gpa_file_encrypt_dialog_get_type (void)
 {

Modified: trunk/src/gpa.c
===================================================================
--- trunk/src/gpa.c	2007-09-28 17:50:00 UTC (rev 784)
+++ trunk/src/gpa.c	2007-10-02 18:18:01 UTC (rev 785)
@@ -53,6 +53,7 @@
 /* Global variables */
 gchar *gpa_exec_dir;
 gchar *gnupg_homedir;
+int cms_hack;
 
 #ifdef G_OS_WIN32
 #include <windows.h> 
@@ -360,6 +361,7 @@
   { "server", no_argument, NULL, 's' },
   { "files", no_argument, NULL, 'f' },
   { "options", required_argument, NULL, 'o' },
+  { "cms", no_argument, NULL, 'x' },
   { NULL, 0, NULL, 0 }
 };
 
@@ -376,6 +378,7 @@
   {'f', "files", N_("open filemanager")},
   {'s', "server", N_("start only the UI server")},
   {'o', "options", N_("read options from file")},
+  {'x', "cms", "enable CMS hack"},
   {0, NULL, NULL}
 };
 
@@ -442,6 +445,9 @@
         case 's':
           args->start_only_server = TRUE;
           break;
+        case 'x':
+          cms_hack = 1;
+          break;
         default:
           exit (EXIT_FAILURE);
         }

Modified: trunk/src/gpa.h
===================================================================
--- trunk/src/gpa.h	2007-09-28 17:50:00 UTC (rev 784)
+++ trunk/src/gpa.h	2007-10-02 18:18:01 UTC (rev 785)
@@ -51,6 +51,7 @@
 extern GtkWidget *global_windowTip;
 extern GList *global_defaultRecipients;
 extern gchar *gnupg_homedir;
+extern int cms_hack;
 
 void gpa_open_keyring_editor (void);
 void gpa_open_filemanager (void);
@@ -66,7 +67,16 @@
 
 void gpa_show_backend_config (void);
 
+/*-- utils.c --*/
+/* We are so used to these function thus provide them.  */
+void *xmalloc (size_t n);
+void *xcalloc (size_t n, size_t m);
+char *xstrdup (const char *str);
+#define xfree(a) g_free ((a))
 
+int translate_sys2libc_fd (assuan_fd_t fd, int for_write);
+
+
 /*-- Convenience macros. -- */
 #define DIM(v)		     (sizeof(v)/sizeof((v)[0]))
 #define DIMof(type,member)   DIM(((type *)0)->member)

Modified: trunk/src/gpacontext.c
===================================================================
--- trunk/src/gpacontext.c	2007-09-28 17:50:00 UTC (rev 784)
+++ trunk/src/gpacontext.c	2007-10-02 18:18:01 UTC (rev 785)
@@ -22,6 +22,7 @@
 
 #include <glib.h>
 #include <gpgme.h>
+#include "gpa.h"
 #include "gpgmetools.h"
 #include "gpacontext.h"
 
@@ -167,7 +168,6 @@
 {
   gpg_error_t err;
 
-  g_debug ("gpa_context_init: enter");
   context->busy = FALSE;
 
   /* The callback queue */
@@ -193,7 +193,8 @@
   /* Set the callbacks */
   gpgme_set_io_cbs (context->ctx, context->io_cbs);
 
-  gpgme_set_protocol (context->ctx, GPGME_PROTOCOL_CMS);
+  if (cms_hack)
+    gpgme_set_protocol (context->ctx, GPGME_PROTOCOL_CMS);
 }
 
 static void
@@ -280,7 +281,6 @@
 #ifdef G_OS_WIN32
   /* We have to ask GPGME for the GIOChannel to use.  The "file
      descriptor" may not be a system file descriptor.  */
-  g_debug ("calling gpgme_get_fdptr (%d)", cb->fd);
   channel = gpgme_get_giochannel (cb->fd);
   g_assert (channel);
 #else
@@ -357,7 +357,6 @@
   struct gpa_io_cb_data *cb = g_malloc (sizeof (struct gpa_io_cb_data));
 
 
-  g_debug ("gpa_context_register callback allocated tag %p", cb);
   cb->registered = FALSE;
   cb->fd = fd;
   cb->dir = dir;  
@@ -385,10 +384,8 @@
 {
   struct gpa_io_cb_data *cb = tag;
 
-  g_debug ("gpa_context_remove callback for tag %p called", cb);
   if (cb->registered)
     {
-      g_debug ("   really removed");
       g_source_remove (cb->watch);
     }
   cb->context->cbs = g_list_remove (cb->context->cbs, cb);
@@ -409,25 +406,20 @@
   switch (type)
     {
     case GPGME_EVENT_START:
-      g_debug ("gpgme event START");
       g_signal_emit (context, signals[START], 0);
       break;
     case GPGME_EVENT_DONE:
       err = type_data;
-      g_debug ("gpgme event DONE");
       g_signal_emit (context, signals[DONE], 0, *err);
       break;
     case GPGME_EVENT_NEXT_KEY:
-      g_debug ("gpgme event NEXT_KEY");
       g_signal_emit (context, signals[NEXT_KEY], 0, type_data);
       break;
     case GPGME_EVENT_NEXT_TRUSTITEM:
-      g_debug ("gpgme event TRUSTITEM");
       g_signal_emit (context, signals[NEXT_TRUST_ITEM], 0,
                      type_data);
       break;
     default:
-      g_debug ("gpgme event no=%d", type);
       /* Ignore unsupported event types */
       break;
     }

Added: trunk/src/gpastreamencryptop.c
===================================================================
--- trunk/src/gpastreamencryptop.c	2007-09-28 17:50:00 UTC (rev 784)
+++ trunk/src/gpastreamencryptop.c	2007-10-02 18:18:01 UTC (rev 785)
@@ -0,0 +1,526 @@
+/* gpastreamdecryptop.c - The GpaOperation object.
+ *	Copyright (C) 2007 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 <glib.h>
+
+#include "gpgmetools.h"
+#include "encryptdlg.h"
+#include "gpawidgets.h"
+#include "gpapastrings.h"
+#include "gpastreamencryptop.h"
+
+static void response_cb (GtkDialog *dialog,
+                         gint response,
+                         gpointer user_data);
+static void done_error_cb (GpaContext *context, gpg_error_t err,
+                           GpaStreamEncryptOperation *op);
+static void done_cb (GpaContext *context, gpg_error_t err,
+                     GpaStreamEncryptOperation *op);
+
+static GObjectClass *parent_class;
+
+
+/* Helper to be used as a GFunc for free. */
+static void
+free_func (void *p, void *dummy)
+{
+  (void)dummy;
+  g_free (p);
+}
+
+
+
+
+static void
+gpa_stream_encrypt_operation_finalize (GObject *object)
+{  
+/*   GpaStreamEncryptOperation *op = GPA_STREAM_ENCRYPT_OPERATION (object); */
+
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+static void
+gpa_stream_encrypt_operation_init (GpaStreamEncryptOperation *op)
+{
+  op->encrypt_dialog = NULL;
+}
+
+
+static GObject*
+gpa_stream_encrypt_operation_constructor 
+	(GType type,
+         guint n_construct_properties,
+         GObjectConstructParam *construct_properties)
+{
+  GObject *object;
+  GpaStreamEncryptOperation *op;
+
+  object = parent_class->constructor (type,
+				      n_construct_properties,
+				      construct_properties);
+  op = GPA_STREAM_ENCRYPT_OPERATION (object);
+
+  /* Create the "Encrypt" dialog */
+  op->encrypt_dialog = gpa_file_encrypt_dialog_new
+    (GPA_OPERATION (op)->window);
+
+  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",
+		    G_CALLBACK (done_error_cb), op);
+  g_signal_connect (G_OBJECT (GPA_OPERATION (op)->context), "done",
+		    G_CALLBACK (done_cb), op);
+
+  gtk_window_set_title 
+    (GTK_WINDOW (GPA_STREAM_OPERATION (op)->progress_dialog),
+			_("Encrypting message ..."));
+
+  gtk_widget_show_all (op->encrypt_dialog);
+
+  return object;
+}
+
+
+static void
+gpa_stream_encrypt_operation_class_init (GpaStreamEncryptOperationClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  
+  parent_class = g_type_class_peek_parent (klass);
+
+  object_class->constructor = gpa_stream_encrypt_operation_constructor;
+  object_class->finalize = gpa_stream_encrypt_operation_finalize;
+}
+
+
+GType
+gpa_stream_encrypt_operation_get_type (void)
+{
+  static GType stream_encrypt_operation_type = 0;
+  
+  if (!stream_encrypt_operation_type)
+    {
+      static const GTypeInfo stream_encrypt_operation_info =
+      {
+        sizeof (GpaStreamEncryptOperationClass),
+        (GBaseInitFunc) NULL,
+        (GBaseFinalizeFunc) NULL,
+        (GClassInitFunc) gpa_stream_encrypt_operation_class_init,
+        NULL, /* class_finalize */
+        NULL, /* class_data */
+        sizeof (GpaStreamEncryptOperation),
+        0,    /* n_preallocs */
+        (GInstanceInitFunc) gpa_stream_encrypt_operation_init,
+      };
+      
+      stream_encrypt_operation_type = g_type_register_static 
+	(GPA_STREAM_OPERATION_TYPE, "GpaStreamEncryptOperation",
+	 &stream_encrypt_operation_info, 0);
+    }
+  
+  return stream_encrypt_operation_type;
+}
+
+
+static gpg_error_t
+start_encryption (GpaStreamEncryptOperation *op, gpgme_key_t *keys)
+{
+  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;
+    }
+
+  /* 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;
+}
+
+
+
+/*
+ * 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
+   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.
+ */
+static gpg_error_t
+parse_recipients (GpaStreamEncryptOperation *op, GSList *recipients,
+                  gpgme_key_t **r_found, GSList **r_unknown)
+{
+  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;
+
+  *r_found = NULL;
+  *r_unknown = NULL;
+
+  err = gpgme_new (&ctx);
+  if (err)
+    return err; 
+
+  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)
+        {
+          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;
+            }
+        }
+      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)
+        {
+          gpgme_key_ref (key);
+          found[found_idx++] = key;
+        }
+      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);
+    }
+  gpgme_release (ctx);
+
+  *r_found = found;
+  *r_unknown = unknown;
+  return 0;
+}
+
+
+/*
+ * The 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;
+
+  gtk_widget_hide (GTK_WIDGET (dialog));
+  
+  if (response != GTK_RESPONSE_OK)
+    {
+      /* The dialog was canceled, so we do nothing and complete the
+       * operation */
+      gpa_operation_server_finish (GPA_OPERATION (op), 
+                                   gpg_error (GPG_ERR_CANCELED));
+      g_signal_emit_by_name (GPA_OPERATION (op), "completed");
+      return;
+    }
+
+  recipients = g_slist_append (NULL, xstrdup ("wk at gnupg.org"));
+
+/* gpa_stream_encrypt_dialog_recipients */
+/*     (GPA_STREAM_ENCRYPT_DIALOG (op->encrypt_dialog)); */
+      
+  err = parse_recipients (op, recipients, &keys, &unknown_recp);
+  if (err)
+    goto leave;
+
+
+  /* Our streams work all in ascii armored mode (Either PGP or PEM) */
+  gpgme_set_armor (GPA_OPERATION (op)->context->ctx, 1);
+  err = start_encryption (op, keys);
+
+ 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)
+    {
+      gpa_operation_server_finish (GPA_OPERATION (op), err);
+      g_signal_emit_by_name (GPA_OPERATION (op), "completed");
+    }
+}
+
+
+
+/*Show an error message. */
+static void
+done_error_cb (GpaContext *context, gpg_error_t err,
+               GpaStreamEncryptOperation *op)
+{
+  switch (gpg_err_code (err))
+    {
+    case GPG_ERR_NO_ERROR:
+    case GPG_ERR_CANCELED:
+      /* Ignore these */
+      break;
+/*     case GPG_ERR_BAD_PASSPHRASE: */
+/*       gpa_window_error (_("Wrong passphrase!"), GPA_OPERATION (op)->window); */
+/*       break; */
+    default:
+      gpa_gpgme_warning (err);
+      break;
+    }
+}
+
+/* Operation is ready.  Tell the server.  */
+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.  */
+  gpa_operation_server_finish (GPA_OPERATION (op), err);
+  g_signal_emit_by_name (GPA_OPERATION (op), "completed");
+}
+
+
+
+
+/* API */
+
+GpaStreamEncryptOperation*
+gpa_stream_encrypt_operation_new (GtkWidget *window,
+                                  gpgme_data_t input_stream,
+                                  gpgme_data_t output_stream,
+                                  void *server_ctx)
+{
+  GpaStreamEncryptOperation *op;
+  
+  op = g_object_new (GPA_STREAM_ENCRYPT_OPERATION_TYPE,
+		     "window", window,
+		     "input_stream", input_stream,
+		     "output_stream", output_stream,
+                     "server-ctx", server_ctx,
+		     NULL);
+
+  return op;
+}
+

Added: trunk/src/gpastreamencryptop.h
===================================================================
--- trunk/src/gpastreamencryptop.h	2007-09-28 17:50:00 UTC (rev 784)
+++ trunk/src/gpastreamencryptop.h	2007-10-02 18:18:01 UTC (rev 785)
@@ -0,0 +1,85 @@
+/* gpastreamencryptop.h - The GpaStreamEncryptOperation object.
+ *	Copyright (C) 2007 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 GPA_STREAM_ENCRYPT_OP_H
+#define GPA_STREAM_ENCRYPT_OP_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include "gpastreamop.h"
+
+/* GObject stuff */
+#define GPA_STREAM_ENCRYPT_OPERATION_TYPE	\
+          (gpa_stream_encrypt_operation_get_type ())
+
+#define GPA_STREAM_ENCRYPT_OPERATION(obj)	      \
+          (G_TYPE_CHECK_INSTANCE_CAST                 \
+            ((obj), GPA_STREAM_ENCRYPT_OPERATION_TYPE,\
+             GpaStreamEncryptOperation))
+
+#define GPA_STREAM_ENCRYPT_OPERATION_CLASS(klass) \
+          (G_TYPE_CHECK_CLASS_CAST ((klass),      \
+                                    GPA_STREAM_ENCRYPT_OPERATION_TYPE, \
+                                    GpaStreamEncryptOperationClass))
+
+#define GPA_IS_STREAM_ENCRYPT_OPERATION(obj) \
+          (G_TYPE_CHECK_INSTANCE_TYPE ((obj),\
+                                       GPA_STREAM_ENCRYPT_OPERATION_TYPE))
+
+#define GPA_IS_STREAM_ENCRYPT_OPERATION_CLASS(klass) \
+          (G_TYPE_CHECK_CLASS_TYPE ((klass),         \
+                                    GPA_STREAM_ENCRYPT_OPERATION_TYPE))
+
+#define GPA_STREAM_ENCRYPT_OPERATION_GET_CLASS(obj) \
+          (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+                                      GPA_STREAM_ENCRYPT_OPERATION_TYPE, \
+                                      GpaStreamEncryptOperationClass))
+
+typedef struct _GpaStreamEncryptOperation GpaStreamEncryptOperation;
+typedef struct _GpaStreamEncryptOperationClass GpaStreamEncryptOperationClass;
+
+
+struct _GpaStreamEncryptOperation 
+{
+  GpaStreamOperation parent;
+  
+  GtkWidget *encrypt_dialog;
+};
+
+
+struct _GpaStreamEncryptOperationClass 
+{
+  GpaStreamOperationClass parent_class;
+};
+
+
+GType gpa_stream_encrypt_operation_get_type (void) G_GNUC_CONST;
+
+/* API */
+
+/* Creates a new encryption operation. */
+GpaStreamEncryptOperation *
+gpa_stream_encrypt_operation_new (GtkWidget *window, 
+                                  gpgme_data_t input_stream,
+                                  gpgme_data_t output_stream,
+                                  void *server_ctx);
+
+
+
+#endif /*GPA_STREAM_ENCRYPT_OP_H*/

Added: trunk/src/gpastreamop.c
===================================================================
--- trunk/src/gpastreamop.c	2007-09-28 17:50:00 UTC (rev 784)
+++ trunk/src/gpastreamop.c	2007-10-02 18:18:01 UTC (rev 785)
@@ -0,0 +1,206 @@
+/* gpastreamop.c - The GpaStreamOperation object.
+ *	Copyright (C) 2007 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 "i18n.h"
+#include "gtktools.h"
+#include "gpastreamop.h"
+
+/* Signals */
+enum
+{
+  LAST_SIGNAL
+};
+
+/* Properties */
+enum
+{
+  PROP_0,
+  PROP_INPUT_STREAM,
+  PROP_OUTPUT_STREAM,
+  PROP_MESSAGE_STREAM
+};
+
+static GObjectClass *parent_class;
+/* static guint signals[LAST_SIGNAL]; */
+
+
+static void
+gpa_stream_operation_get_property (GObject     *object,
+                                   guint        prop_id,
+                                   GValue      *value,
+                                   GParamSpec  *pspec)
+{
+  GpaStreamOperation *op = GPA_STREAM_OPERATION (object);
+
+  switch (prop_id)
+    {
+    case PROP_INPUT_STREAM:
+      g_value_set_pointer (value, op->input_stream);
+      break;
+    case PROP_OUTPUT_STREAM:
+      g_value_set_pointer (value, op->output_stream);
+      break;
+    case PROP_MESSAGE_STREAM:
+      g_value_set_pointer (value, op->message_stream);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+
+static void
+gpa_stream_operation_set_property (GObject     *object,
+				 guint        prop_id,
+				 const GValue      *value,
+				 GParamSpec  *pspec)
+{
+  GpaStreamOperation *op = GPA_STREAM_OPERATION (object);
+
+  switch (prop_id)
+    {
+    case PROP_INPUT_STREAM:
+      op->input_stream = (gpgme_data_t)g_value_get_pointer (value);
+      break;
+    case PROP_OUTPUT_STREAM:
+      op->output_stream = (gpgme_data_t)g_value_get_pointer (value);
+      break;
+    case PROP_MESSAGE_STREAM:
+      op->message_stream = (gpgme_data_t)g_value_get_pointer (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+
+static void
+gpa_stream_operation_finalize (GObject *object)
+{
+  GpaStreamOperation *op = GPA_STREAM_OPERATION (object);
+
+  gpgme_data_release (op->input_stream);
+  gpgme_data_release (op->output_stream);
+  gpgme_data_release (op->output_stream);
+  gtk_widget_destroy (op->progress_dialog);
+  
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+static void
+gpa_stream_operation_init (GpaStreamOperation *op)
+{
+  op->input_stream = NULL;
+  op->output_stream = NULL;
+  op->message_stream = NULL;
+
+  op->progress_dialog = NULL;
+}
+
+
+static GObject*
+gpa_stream_operation_constructor (GType type,
+                                  guint n_construct_properties,
+                                  GObjectConstructParam *construct_properties)
+{
+  GObject *object;
+  GpaStreamOperation *op;
+
+  object = parent_class->constructor (type,
+				      n_construct_properties,
+				      construct_properties);
+  op = GPA_STREAM_OPERATION (object);
+
+  op->progress_dialog = gpa_progress_dialog_new (GPA_OPERATION(op)->window,
+						 GPA_OPERATION(op)->context);
+
+  return object;
+}
+
+
+static void
+gpa_stream_operation_class_init (GpaStreamOperationClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  
+  parent_class = g_type_class_peek_parent (klass);
+
+  object_class->constructor  = gpa_stream_operation_constructor;
+  object_class->finalize     = gpa_stream_operation_finalize;
+  object_class->set_property = gpa_stream_operation_set_property;
+  object_class->get_property = gpa_stream_operation_get_property;
+
+  /* Signals */
+  /* Properties */
+  g_object_class_install_property (object_class,
+				   PROP_INPUT_STREAM,
+				   g_param_spec_pointer 
+				   ("input_stream", "Input Stream",
+				    "Data read by gpg/gpgsm",
+				    G_PARAM_WRITABLE|G_PARAM_CONSTRUCT_ONLY));
+  g_object_class_install_property (object_class,
+				   PROP_OUTPUT_STREAM,
+				   g_param_spec_pointer 
+				   ("output_stream", "Output Stream",
+				    "Data written by gpg/gpgsm",
+				    G_PARAM_WRITABLE|G_PARAM_CONSTRUCT_ONLY));
+  g_object_class_install_property (object_class,
+				   PROP_INPUT_STREAM,
+				   g_param_spec_pointer 
+				   ("message_stream", "Message Stream",
+				    "Message data read by gpg/gpgsm",
+				    G_PARAM_WRITABLE|G_PARAM_CONSTRUCT_ONLY));
+}
+
+
+GType
+gpa_stream_operation_get_type (void)
+{
+  static GType stream_operation_type = 0;
+  
+  if (!stream_operation_type)
+    {
+      static const GTypeInfo stream_operation_info =
+      {
+        sizeof (GpaStreamOperationClass),
+        (GBaseInitFunc)NULL,
+        (GBaseFinalizeFunc)NULL,
+        (GClassInitFunc)gpa_stream_operation_class_init,
+        NULL, /* class_finalize */
+        NULL, /* class_data */
+        sizeof (GpaStreamOperation),
+        0,    /* n_preallocs */
+        (GInstanceInitFunc)gpa_stream_operation_init,
+      };
+      
+      stream_operation_type = g_type_register_static 
+        (GPA_OPERATION_TYPE, "GpaStreamOperation",
+         &stream_operation_info, 0);
+    }
+  
+  return stream_operation_type;
+}
+
+
+

Added: trunk/src/gpastreamop.h
===================================================================
--- trunk/src/gpastreamop.h	2007-09-28 17:50:00 UTC (rev 784)
+++ trunk/src/gpastreamop.h	2007-10-02 18:18:01 UTC (rev 785)
@@ -0,0 +1,72 @@
+/* gpastreamop.h - The GpaStreamOperation object.
+ *	Copyright (C) 2007 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 GPA_STREAM_OP_H
+#define GPA_STREAM_OP_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include "gpa.h"
+#include "gpaoperation.h"
+#include "gpaprogressdlg.h"
+
+/* GObject stuff */
+#define GPA_STREAM_OPERATION_TYPE \
+            (gpa_stream_operation_get_type ())
+#define GPA_STREAM_OPERATION(obj)       \
+            (G_TYPE_CHECK_INSTANCE_CAST \
+             ((obj), GPA_STREAM_OPERATION_TYPE, GpaStreamOperation))
+#define GPA_STREAM_OPERATION_CLASS(klass)         \
+            (G_TYPE_CHECK_CLASS_CAST              \
+             ((klass), GPA_STREAM_OPERATION_TYPE, \
+              GpaStreamOperationClass))
+#define GPA_IS_STREAM_OPERATION(obj)    \
+	    (G_TYPE_CHECK_INSTANCE_TYPE \
+             ((obj), GPA_STREAM_OPERATION_TYPE))
+#define GPA_IS_STREAM_OPERATION_CLASS(klass) \
+            (G_TYPE_CHECK_CLASS_TYPE ((klass), GPA_STREAM_OPERATION_TYPE))
+#define GPA_STREAM_OPERATION_GET_CLASS(obj) \
+            (G_TYPE_INSTANCE_GET_CLASS      \
+             ((obj), GPA_STREAM_OPERATION_TYPE, GpaStreamOperationClass))
+
+typedef struct _GpaStreamOperation GpaStreamOperation;
+typedef struct _GpaStreamOperationClass GpaStreamOperationClass;
+
+struct _GpaStreamOperation {
+  GpaOperation parent;
+
+  gpgme_data_t input_stream;
+  gpgme_data_t output_stream;
+  gpgme_data_t message_stream;
+
+  GtkWidget *progress_dialog;
+};
+
+struct _GpaStreamOperationClass {
+  GpaOperationClass parent_class;
+
+};
+
+GType gpa_stream_operation_get_type (void) G_GNUC_CONST;
+
+/*** API ***/
+
+
+
+#endif /*GPA_STREAM_OP_H*/

Modified: trunk/src/server.c
===================================================================
--- trunk/src/server.c	2007-09-28 17:50:00 UTC (rev 784)
+++ trunk/src/server.c	2007-10-02 18:18:01 UTC (rev 785)
@@ -29,23 +29,11 @@
 #include <glib.h>
 #include <assuan.h>
 
-#ifdef HAVE_W32_SYSTEM
-# include "w32-afunix.h"
-#else
-# include <sys/socket.h>
-# include <sys/un.h>
-#endif
-
 #include "gpa.h"
 #include "i18n.h"
-#include "gpafileencryptop.h"
+#include "gpastreamencryptop.h"
 
 
-#ifdef HAVE_W32_SYSTEM
-#define myclosesock(a)  _w32_close ((a))
-#else
-#define myclosesock(a)  close ((a))
-#endif
 
 #define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
 
@@ -55,12 +43,32 @@
 typedef struct conn_ctrl_s *conn_ctrl_t;
 struct conn_ctrl_s
 {
-  /* NULL or continuation function or a command.  */
+  /* True if we are currently processing a command.  */
+  int in_command;
+
+  /* NULL or continuation function for a command.  */
   void (*cont_cmd) (assuan_context_t, gpg_error_t);
+
+  /* File descriptors used by the gpgme callbacks.  */
+  int input_fd;
+  int output_fd;
+
+  /* Channels used with the gpgme callbacks.  */
+  GIOChannel *input_channel;
+  GIOChannel *output_channel;
+
+  /* Gpgme Data objects.  */
+  gpgme_data_t input_data;
+  gpgme_data_t output_data;
+
 };
 
 
 
+static assuan_sock_nonce_t socket_nonce;
+
+
+
 
 /* Test whether LINE contains thye option NAME.  An optional argument
    of the option is ignored.  For example with NAME being "--protocol"
@@ -109,7 +117,75 @@
 
 
 
+static ssize_t
+my_gpgme_read_cb (void *opaque, void *buffer, size_t size)
+{
+  conn_ctrl_t ctrl = opaque;
+  GIOStatus  status;
+  size_t nread;
+  int retval;
 
+  status = g_io_channel_read_chars (ctrl->input_channel, buffer, size,
+                                    &nread, NULL);
+  if (status == G_IO_STATUS_AGAIN
+      || (status == G_IO_STATUS_NORMAL && !nread))
+    {
+      errno = EAGAIN;
+      retval = -1;
+    }
+  else if (status == G_IO_STATUS_NORMAL)
+    retval = (int)nread;
+  else if (status == G_IO_STATUS_EOF)
+    retval = 0;
+  else
+    {
+      errno = EIO;
+      retval = 1;
+    }
+
+  return retval;
+}
+
+
+static ssize_t
+my_gpgme_write_cb (void *opaque, const void *buffer, size_t size)
+{
+  conn_ctrl_t ctrl = opaque;
+  GIOStatus  status;
+  size_t nwritten;
+  int retval;
+
+  status = g_io_channel_write_chars (ctrl->output_channel, buffer, size,
+                                     &nwritten, NULL);
+  if (status == G_IO_STATUS_AGAIN)
+    {
+      errno = EAGAIN;
+      retval = -1;
+    }
+  else if (status == G_IO_STATUS_NORMAL)
+    retval = (int)nwritten;
+  else
+    {
+      errno = EIO;
+      retval = 1;
+    }
+
+  return retval;
+}
+
+
+static struct gpgme_data_cbs my_gpgme_data_cbs =
+  { 
+    my_gpgme_read_cb,
+    my_gpgme_write_cb,
+    NULL,
+    NULL
+  };
+
+
+
+
+
 
 /* Continuation for cmd_encrypt.  */
 void
@@ -120,6 +196,18 @@
   g_debug ("cont_encrypt called with with ERR=%s <%s>",
            gpg_strerror (err), gpg_strsource (err));
 
+  gpgme_data_release (ctrl->input_data); ctrl->input_data = NULL;
+  gpgme_data_release (ctrl->output_data); ctrl->output_data = NULL;
+  if (ctrl->input_channel)
+    {
+      g_io_channel_shutdown (ctrl->input_channel, 0, NULL);
+      ctrl->input_channel = NULL;
+    }
+  if (ctrl->output_channel)
+    {
+      g_io_channel_shutdown (ctrl->output_channel, 0, NULL);
+      ctrl->output_channel = NULL;
+    }
   assuan_process_done (ctx, err);
 }
 
@@ -134,8 +222,9 @@
   conn_ctrl_t ctrl = assuan_get_pointer (ctx);
   gpg_error_t err;
   gpgme_protocol_t protocol = GPGME_PROTOCOL_OpenPGP;
-  int inp_fd, out_fd;
+  GpaStreamEncryptOperation *op;
 
+
   if (has_option (line, "--protocol=OpenPGP"))
     ; /* This is the default.  */
   else if (has_option (line, "--protocol=CMS"))
@@ -153,31 +242,75 @@
       goto leave;
     }
 
-/*   inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0); */
-/*   if (inp_fd == -1) */
-/*     { */
-/*       err = set_error (GPG_ERR_ASS_NO_INPUT, NULL); */
-/*       goto leave; */
-/*     } */
-/*   out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1); */
-/*   if (out_fd == -1) */
-/*     { */
-/*       err = set_error (GPG_ERR_ASS_NO_OUTPUT, NULL); */
-/*       goto leave; */
-/*     } */
+  ctrl->input_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
+  if (ctrl->input_fd == -1)
+    {
+      err = set_error (GPG_ERR_ASS_NO_INPUT, NULL);
+      goto leave;
+    }
+  ctrl->output_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
+  if (ctrl->output_fd == -1)
+    {
+      err = set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
+      goto leave;
+    }
 
+#ifdef HAVE_W32_SYSTEM
+  ctrl->input_channel = g_io_channel_win32_new_socket (ctrl->input_fd);
+#else
+  ctrl->input_channel = g_io_channel_unix_new (ctrl->input_fd);
+#endif
+  if (!ctrl->input_channel)
+    {
+      g_debug ("error creating input channel");
+      err = GPG_ERR_EIO;
+      goto leave;
+    }
+  g_io_channel_set_encoding (ctrl->input_channel, NULL, NULL);
+  g_io_channel_set_buffered (ctrl->input_channel, FALSE);
+
+#ifdef HAVE_W32_SYSTEM
+  ctrl->output_channel = g_io_channel_win32_new_socket (ctrl->output_fd);
+#else
+  ctrl->output_channel = g_io_channel_unix_new (ctrl->output_fd);
+#endif
+  if (!ctrl->output_channel)
+    {
+      g_debug ("error creating output channel");
+      err = GPG_ERR_EIO;
+      goto leave;
+    }
+  g_io_channel_set_encoding (ctrl->output_channel, NULL, NULL);
+  g_io_channel_set_buffered (ctrl->output_channel, FALSE);
+
+
+  err = gpgme_data_new_from_cbs (&ctrl->input_data, &my_gpgme_data_cbs, ctrl);
+  if (err)
+    goto leave;
+  err = gpgme_data_new_from_cbs (&ctrl->output_data, &my_gpgme_data_cbs, ctrl);
+  if (err)
+    goto leave;
+
   ctrl->cont_cmd = cont_encrypt;
-  {
-    GList *files = g_list_append (NULL, g_strdup ("test.txt"));
-    GpaFileEncryptOperation *op;
-
-    op = gpa_file_encrypt_operation_new_for_server (files, ctx);
-    g_signal_connect (G_OBJECT (op), "completed",
-                      G_CALLBACK (g_object_unref), NULL);
-  }
+  op = gpa_stream_encrypt_operation_new (NULL, ctrl->input_data, 
+                                         ctrl->output_data, ctx);
+  g_signal_connect (G_OBJECT (op), "completed",
+                    G_CALLBACK (g_object_unref), NULL);
   return gpg_error (GPG_ERR_UNFINISHED);
 
  leave:
+  gpgme_data_release (ctrl->input_data); ctrl->input_data = NULL;
+  gpgme_data_release (ctrl->output_data); ctrl->output_data = NULL;
+  if (ctrl->input_channel)
+    {
+      g_io_channel_shutdown (ctrl->input_channel, 0, NULL);
+      ctrl->input_channel = NULL;
+    }
+  if (ctrl->output_channel)
+    {
+      g_io_channel_shutdown (ctrl->output_channel, 0, NULL);
+      ctrl->output_channel = NULL;
+    }
   assuan_close_input_fd (ctx);
   assuan_close_output_fd (ctx);
   return assuan_process_done (ctx, err);
@@ -192,6 +325,7 @@
    Supported values for WHAT are:
 
      version     - Return the version of the program.
+     pid         - Return the process id of the server.
  */
 static int
 cmd_getinfo (assuan_context_t ctx, char *line)
@@ -203,6 +337,13 @@
       const char *s = PACKAGE_NAME " " PACKAGE_VERSION;
       err = assuan_send_data (ctx, s, strlen (s));
     }
+  else if (!strcmp (line, "pid"))
+    {
+      char numbuf[50];
+
+      snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
+      err = assuan_send_data (ctx, numbuf, strlen (numbuf));
+    }
   else
     err = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
 
@@ -220,8 +361,10 @@
     const char *name;
     int (*handler)(assuan_context_t, char *line);
   } table[] = {
-    { "ENCRYPT",        cmd_encrypt },
-    { "GETINFO",        cmd_getinfo },
+    { "INPUT",   NULL },
+    { "OUTPUT",   NULL },
+    { "ENCRYPT", cmd_encrypt },
+    { "GETINFO", cmd_getinfo },
     { NULL }
   };
   int i, rc;
@@ -247,7 +390,7 @@
 
   /* Get an assuan context for the already accepted file descriptor
      FD.  */
-  err = assuan_init_socket_server_ext (&ctx, fd, 2);
+  err = assuan_init_socket_server_ext (&ctx, ASSUAN_INT2FD(fd), 2);
   if (err)
     {
       g_debug ("failed to initialize the new connection: %s",
@@ -279,7 +422,19 @@
   if (ctx)
     {
       conn_ctrl_t ctrl = assuan_get_pointer (ctx);
-      
+
+      gpgme_data_release (ctrl->input_data);
+      gpgme_data_release (ctrl->output_data);
+      if (ctrl->input_channel)
+        {
+          g_io_channel_shutdown (ctrl->input_channel, 0, NULL);
+          ctrl->input_channel = NULL;
+        }
+      if (ctrl->output_channel)
+        {
+          g_io_channel_shutdown (ctrl->output_channel, 0, NULL);
+          ctrl->output_channel = NULL;
+        }
       assuan_deinit_server (ctx);
       g_free (ctrl);
     }
@@ -330,9 +485,16 @@
           g_debug ("  input received while waiting for continuation");
           g_usleep (2000000);
         }
+      else if (ctrl->in_command)
+        {
+          g_debug ("  input received while still processing command");
+          g_usleep (2000000);
+        }
       else
         {
+          ctrl->in_command++;
           err = assuan_process_next (ctx);
+          ctrl->in_command--;
           g_debug ("assuan_process_next returned: %s",
                    err == -1? "EOF": gpg_strerror (err));
           if (gpg_err_code (err) == GPG_ERR_EOF || err == -1)
@@ -341,14 +503,19 @@
               /* FIXME: what about the socket? */
               return FALSE; /* Remove from the watch.  */
             }
-          else if (gpg_err_code (err) == GPG_ERR_UNFINISHED
-                   && !ctrl->cont_cmd)
+          else if (gpg_err_code (err) == GPG_ERR_UNFINISHED)
             {
-              /* It is quite possible that some other subsystem
-                 retruns that erro code.  Note the user about this
-                 curiosity.  */
-              g_debug ("note: Unfinished error code not emitted by us");
+              if ( !ctrl->cont_cmd)
+                {
+                  /* 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");
+                  assuan_process_done (ctx, err);
+                }
             }
+          else 
+            assuan_process_done (ctx, err);
         }
     }
   return TRUE;
@@ -382,6 +549,11 @@
       g_debug ("error accepting connection: %s", strerror (errno));
       goto leave;
     }
+  if (assuan_sock_check_nonce (ASSUAN_INT2FD(fd), &socket_nonce))
+    {
+      g_debug ("new connection at fd %d refused", fd); 
+      goto leave;
+    }
 
   g_debug ("new connection at fd %d", fd);
   ctx = connection_startup (fd);
@@ -420,7 +592,7 @@
 
  leave:
   if (fd != -1)
-    myclosesock (fd);
+    assuan_sock_close (ASSUAN_INT2FD (fd));
   return TRUE; /* Keep the listen_fd in the event loop.  */
 }
 
@@ -432,7 +604,7 @@
 {
   char *socket_name;
   int rc;
-  int fd;
+  assuan_fd_t fd;
   struct sockaddr_un serv_addr;
   socklen_t serv_addr_len = sizeof serv_addr;
   GIOChannel *channel;
@@ -447,12 +619,8 @@
     }
   g_debug ("using server socket `%s'", socket_name);
     
-#ifdef HAVE_W32_SYSTEM
-  fd = _w32_sock_new (AF_UNIX, SOCK_STREAM, 0);
-#else
-  fd = socket (AF_UNIX, SOCK_STREAM, 0);
-#endif
-  if (fd == -1)
+  fd = assuan_sock_new (AF_UNIX, SOCK_STREAM, 0);
+  if (fd == ASSUAN_INVALID_FD)
     {
       g_debug ("can't create socket: %s\n", strerror(errno));
       g_free (socket_name);
@@ -465,48 +633,42 @@
   serv_addr_len = (offsetof (struct sockaddr_un, sun_path)
                    + strlen(serv_addr.sun_path) + 1);
 
-#ifdef HAVE_W32_SYSTEM
-  rc = _w32_sock_bind (fd, (struct sockaddr*) &serv_addr, serv_addr_len);
-  if (rc == -1 && errno == WSAEADDRINUSE)
-    {
-      remove (socket_name);
-      rc = _w32_sock_bind (fd, (struct sockaddr*) &serv_addr, serv_addr_len);
-    }
-#else
-  rc = bind (fd, (struct sockaddr*)&serv_addr, serv_addr_len);
+  rc = assuan_sock_bind (fd, (struct sockaddr*) &serv_addr, serv_addr_len);
   if (rc == -1 && errno == EADDRINUSE)
     {
       remove (socket_name);
-      rc = bind (fd, (struct sockaddr*)&serv_addr, serv_addr_len);
+      rc = assuan_sock_bind (fd, (struct sockaddr*) &serv_addr, serv_addr_len);
     }
-#endif
+  if (rc != -1 && (rc=assuan_sock_get_nonce ((struct sockaddr*) &serv_addr,
+                                             serv_addr_len, &socket_nonce)))
+    g_debug ("error getting nonce for the socket");
   if (rc == -1)
     {
       g_debug ("error binding socket to `%s': %s\n",
                serv_addr.sun_path, strerror (errno) );
-      myclosesock (fd);
+      assuan_sock_close (fd);
       g_free (socket_name);
       return;
     }
   g_free (socket_name);
   socket_name = NULL;
 
-  if (listen (fd, 5) == -1)
+  if (listen (ASSUAN_FD2INT (fd), 5) == -1)
     {
       g_debug ("listen() failed: %s\n", strerror (errno));
-      myclosesock (fd);
+      assuan_sock_close (fd);
       return;
     }
 
 #ifdef HAVE_W32_SYSTEM
-  channel = g_io_channel_win32_new_socket (fd);
+  channel = g_io_channel_win32_new_socket (ASSUAN_FD2INT(fd));
 #else
   channel = g_io_channel_unix_new (fd);
 #endif
   if (!channel)
     {
       g_debug ("error creating a new listening channel\n");
-      myclosesock (fd);
+      assuan_sock_close (fd);
       return;
     }
   g_io_channel_set_encoding (channel, NULL, NULL);
@@ -517,7 +679,7 @@
     {
       g_debug ("error creating watch for listening channel\n");
       g_io_channel_shutdown (channel, 0, NULL);
-      myclosesock (fd);
+      assuan_sock_close (fd);
       return;
     }
 

Added: trunk/src/utils.c
===================================================================
--- trunk/src/utils.c	2007-09-28 17:50:00 UTC (rev 784)
+++ trunk/src/utils.c	2007-10-02 18:18:01 UTC (rev 785)
@@ -0,0 +1,104 @@
+/* utilis.c -  Utility functions for GPA.
+ * Copyright (C) 2007 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 <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <errno.h>
+#include <glib.h>
+
+#include "gpa.h"
+
+
+/* We want our usual xmalloc function.  */
+void *
+xmalloc (size_t n)
+{
+  if (!n)
+    n++;
+  return g_malloc (n);
+}
+
+
+/* We want an xcalloc.  The similar g_new0 macro is not correclty
+   implemented as it allows an integer overflow.  */
+void *
+xcalloc (size_t n, size_t m)
+{
+  size_t nbytes;
+  void *p;
+
+  nbytes = n * m;
+  if ( m && nbytes / m != n)
+    {
+      errno = ENOMEM;
+      p = NULL;
+    }
+  else
+    p = g_malloc (nbytes);
+  if (p)
+    memset (p, 0, nbytes);
+  else
+    {
+      g_error ("%s: failed to allocate %lu bytes", 
+               G_STRLOC, (unsigned long)nbytes);
+      abort (); /* Just in case g_error returns.  */
+    }
+
+  return p;
+}
+
+
+char *
+xstrdup (const char *str)
+{
+  char *buf = g_malloc (strlen(str) + 1);
+  strcpy (buf, str);
+  return buf;
+}
+
+
+
+/* This function is a NOP for POSIX systems but required under Windows
+   as the file handles as returned by OS calls (like CreateFile) are
+   different from the libc file descriptors (like open). This function
+   translates system file handles to libc file handles.  FOR_WRITE
+   gives the direction of the handle.  */
+int
+translate_sys2libc_fd (assuan_fd_t fd, int for_write)
+{
+#ifdef HAVE_W32_SYSTEM
+  int x;
+
+  if (fd == ASSUAN_INVALID_FD)
+    return -1;
+  
+  /* Note that _open_osfhandle is currently defined to take and return
+     a long.  */
+  x = _open_osfhandle ((long)fd, for_write ? 1 : 0);
+  if (x == -1)
+    g_debug ("failed to translate osfhandle %p\n", (void *) fd);
+  return x;
+#else /*!HAVE_W32_SYSTEM */
+  return fd;
+#endif
+}



More information about the Gpa-commits mailing list