[Gpa-commits] r894 - trunk/src

scm-commit@wald.intevation.org scm-commit at wald.intevation.org
Fri May 9 06:45:26 CEST 2008


Author: marcus
Date: 2008-05-09 06:45:25 +0200 (Fri, 09 May 2008)
New Revision: 894

Added:
   trunk/src/gpastreamdecryptop.c
   trunk/src/gpastreamdecryptop.h
   trunk/src/gpastreamverifyop.c
   trunk/src/gpastreamverifyop.h
Modified:
   trunk/src/ChangeLog
   trunk/src/Makefile.am
   trunk/src/server.c
Log:
2008-05-09  Marcus Brinkmann  <marcus at g10code.de>

	* Makefile.am (gpa_SOURCES): Add gpastreamverifyop.h,
	gpastreamverifyop.c, gpastreamdecryptop.h and gpastreamdecryptop.c.
	* gpastreamverifyop.h, gpastreamverifyop.c: New files.
	* gpastreamdecryptop.h, gpastreamdecryptop.c: New files.
	* server.c: Include "gpastreamverifyop.h" and "gpastreamdecryptop.h".
	(my_devnull_write_cb): New function.
	(my_devnull_data_cbs): New struct.
	(finish_io_streams, cmd_encrypt, cmd_sign, cmd_decrypt)
	(cmd_verify,reset_notify): Reset CTRL->input_fd and CTRL->output_fd.
	(cont_verify, cmd_verify): Finish implementation.
	(cont_decrypt, cmd_decrypt): Finish implementation.


Modified: trunk/src/ChangeLog
===================================================================
--- trunk/src/ChangeLog	2008-05-08 16:47:48 UTC (rev 893)
+++ trunk/src/ChangeLog	2008-05-09 04:45:25 UTC (rev 894)
@@ -1,3 +1,17 @@
+2008-05-09  Marcus Brinkmann  <marcus at g10code.de>
+
+	* Makefile.am (gpa_SOURCES): Add gpastreamverifyop.h,
+	gpastreamverifyop.c, gpastreamdecryptop.h and gpastreamdecryptop.c.
+	* gpastreamverifyop.h, gpastreamverifyop.c: New files.
+	* gpastreamdecryptop.h, gpastreamdecryptop.c: New files.
+	* server.c: Include "gpastreamverifyop.h" and "gpastreamdecryptop.h".
+	(my_devnull_write_cb): New function.
+	(my_devnull_data_cbs): New struct.
+	(finish_io_streams, cmd_encrypt, cmd_sign, cmd_decrypt)
+	(cmd_verify,reset_notify): Reset CTRL->input_fd and CTRL->output_fd.
+	(cont_verify, cmd_verify): Finish implementation.
+	(cont_decrypt, cmd_decrypt): Finish implementation.
+
 2008-05-08  Werner Koch  <wk at g10code.com>
 
 	* gpgmetools.c (gpa_switch_to_gpg2): New.

Modified: trunk/src/Makefile.am
===================================================================
--- trunk/src/Makefile.am	2008-05-08 16:47:48 UTC (rev 893)
+++ trunk/src/Makefile.am	2008-05-09 04:45:25 UTC (rev 894)
@@ -89,6 +89,8 @@
 	      gpastreamop.h gpastreamop.c  \
 	      gpastreamencryptop.h gpastreamencryptop.c  \
 	      gpastreamsignop.h gpastreamsignop.c  \
+	      gpastreamverifyop.h gpastreamverifyop.c  \
+	      gpastreamdecryptop.h gpastreamdecryptop.c  \
 	      gpafileop.h gpafileop.c \
 	      gpafiledecryptop.h gpafiledecryptop.c \
 	      gpafileencryptop.h gpafileencryptop.c \

Added: trunk/src/gpastreamdecryptop.c
===================================================================
--- trunk/src/gpastreamdecryptop.c	2008-05-08 16:47:48 UTC (rev 893)
+++ trunk/src/gpastreamdecryptop.c	2008-05-09 04:45:25 UTC (rev 894)
@@ -0,0 +1,459 @@
+/* gpastreamsignop.c - The GpaStreamSignOperation object.
+   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/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <glib.h>
+
+#include "gpgmetools.h"
+#include "gtktools.h"
+#include "verifydlg.h"
+#include "gpastreamdecryptop.h"
+
+
+struct _GpaStreamDecryptOperation 
+{
+  GpaStreamOperation parent;
+
+  GtkWidget *dialog;
+
+  gboolean no_verify;
+
+  gpgme_protocol_t selected_protocol;
+};
+
+
+struct _GpaStreamDecryptOperationClass
+{
+  GpaStreamOperationClass parent_class;
+};
+
+
+
+/* Indentifiers for our properties. */
+enum 
+  {
+    PROP_0,
+    PROP_NO_VERIFY,
+    PROP_PROTOCOL
+  };
+
+
+static gboolean idle_cb (gpointer data);
+static void response_cb (GtkDialog *dialog, gint response, gpointer user_data);
+static void done_error_cb (GpaContext *context, gpg_error_t err,
+                           GpaStreamDecryptOperation *op);
+static void done_cb (GpaContext *context, gpg_error_t err,
+                     GpaStreamDecryptOperation *op);
+
+static GObjectClass *parent_class;
+
+
+
+static void
+gpa_stream_decrypt_operation_get_property (GObject *object, guint prop_id,
+					  GValue *value, GParamSpec *pspec)
+{
+  GpaStreamDecryptOperation *op = GPA_STREAM_DECRYPT_OPERATION (object);
+  
+  switch (prop_id)
+    {
+    case PROP_NO_VERIFY:
+      g_value_set_boolean (value, op->no_verify);
+      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;
+    }
+}
+
+
+static void
+gpa_stream_decrypt_operation_set_property (GObject *object, guint prop_id,
+					  const GValue *value,
+					  GParamSpec *pspec)
+{
+  GpaStreamDecryptOperation *op = GPA_STREAM_DECRYPT_OPERATION (object);
+
+  switch (prop_id)
+    {
+    case PROP_NO_VERIFY:
+      op->no_verify = g_value_get_boolean (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;
+    }
+}
+
+
+static void
+gpa_stream_decrypt_operation_finalize (GObject *object)
+{
+  GpaStreamDecryptOperation *op = GPA_STREAM_DECRYPT_OPERATION (object);
+
+  if (op->dialog)
+    gtk_widget_destroy (op->dialog);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+static void
+gpa_stream_decrypt_operation_init (GpaStreamDecryptOperation *op)
+{
+  op->dialog = NULL;
+}
+
+
+static GObject*
+gpa_stream_decrypt_operation_ctor (GType type, guint n_construct_properties,
+				  GObjectConstructParam *construct_properties)
+{
+  GObject *object;
+  GpaStreamDecryptOperation *op;
+
+  object = parent_class->constructor (type, n_construct_properties,
+				      construct_properties);
+  op = GPA_STREAM_DECRYPT_OPERATION (object);
+
+  /* Start with the first file after going back into the main loop */
+  g_idle_add (idle_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),
+     _("Decrypting message ..."));
+
+  if (! op->no_verify)
+    {
+      op->dialog = gpa_file_verify_dialog_new (GPA_OPERATION (op)->window);
+      g_signal_connect (G_OBJECT (op->dialog), "response",
+			G_CALLBACK (response_cb), op);
+    }
+
+  return object;
+}
+
+
+static void
+gpa_stream_decrypt_operation_class_init (GpaStreamDecryptOperationClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  
+  parent_class = g_type_class_peek_parent (klass);
+
+  object_class->constructor = gpa_stream_decrypt_operation_ctor;
+  object_class->finalize = gpa_stream_decrypt_operation_finalize;
+  object_class->set_property = gpa_stream_decrypt_operation_set_property;
+  object_class->get_property = gpa_stream_decrypt_operation_get_property;
+
+  g_object_class_install_property (object_class, PROP_NO_VERIFY,
+				   g_param_spec_boolean 
+				   ("no-verify", "No Verify",
+				    "Flag requesting no verify operation.",
+				    FALSE,
+				    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));
+
+}
+
+
+GType
+gpa_stream_decrypt_operation_get_type (void)
+{
+  static GType stream_decrypt_operation_type = 0;
+  
+  if (! stream_decrypt_operation_type)
+    {
+      static const GTypeInfo stream_decrypt_operation_info =
+      {
+        sizeof (GpaStreamDecryptOperationClass),
+        (GBaseInitFunc) NULL,
+        (GBaseFinalizeFunc) NULL,
+        (GClassInitFunc) gpa_stream_decrypt_operation_class_init,
+        NULL, /* class_finalize */
+        NULL, /* class_data */
+        sizeof (GpaStreamDecryptOperation),
+        0,    /* n_preallocs */
+        (GInstanceInitFunc) gpa_stream_decrypt_operation_init,
+      };
+      
+      stream_decrypt_operation_type = g_type_register_static 
+	(GPA_STREAM_OPERATION_TYPE, "GpaStreamDecryptOperation",
+	 &stream_decrypt_operation_info, 0);
+    }
+  
+  return stream_decrypt_operation_type;
+}
+
+
+/* The decrypt status dialog has returned.  */
+static void 
+response_cb (GtkDialog *dialog, int response, void *user_data)
+{
+  GpaStreamDecryptOperation *op = user_data;
+
+  gtk_widget_hide (GTK_WIDGET (dialog));
+  
+  g_signal_emit_by_name (GPA_OPERATION (op), "completed", 0);
+}
+
+
+/* Show an error message. */
+static void
+done_error_cb (GpaContext *context, gpg_error_t err,
+               GpaStreamDecryptOperation *op)
+{
+  switch (gpg_err_code (err))
+    {
+    case GPG_ERR_NO_ERROR:
+    case GPG_ERR_CANCELED:
+      /* Ignore these */
+      break;
+    default:
+      gpa_gpgme_warning (err);
+      break;
+    }
+}
+
+
+/* Percent-Escape special characters.  */
+static gchar *
+my_percent_escape (const gchar *src)
+{
+  gchar *esc_str;
+  int new_len = 3 * strlen (src) + 1;
+  gchar *dst;
+
+  esc_str = g_malloc (new_len);
+
+  dst = esc_str;
+  while (*src)
+    {
+      if (*src == '%')
+	{
+	  *(dst++) = '%';
+	  *(dst++) = '2';
+	  *(dst++) = '5';
+	}	  
+      else if (*src == ':')
+	{
+	  /* The colon is used as field separator.  */
+	  *(dst++) = '%';
+	  *(dst++) = '3';
+	  *(dst++) = 'a';
+	}
+      else if (*src == ',')
+	{
+	  /* The comma is used as list separator.  */
+	  *(dst++) = '%';
+	  *(dst++) = '2';
+	  *(dst++) = 'c';
+	}
+      else
+	*(dst++) = *(src);
+      src++;
+    }
+  *dst = '\0';
+  return esc_str;
+}
+
+
+/* Operation is ready.  Tell the server.  */
+static void
+done_cb (GpaContext *context, gpg_error_t err, GpaStreamDecryptOperation *op)
+{
+  gtk_widget_hide (GPA_STREAM_OPERATION (op)->progress_dialog);
+
+  if (! err && ! op->no_verify)
+    {
+      gpgme_verify_result_t res;
+      gpgme_signature_t sig;
+
+      res = gpgme_op_verify_result (GPA_OPERATION (op)->context->ctx);
+      sig = res->signatures;
+
+      while (sig)
+	{
+	  gpgme_key_t key = NULL;
+	  char *keydesc = NULL;
+	  char *sigsum;
+	  char *sigdesc;
+	  char *sigdesc_esc;
+	  const char *sigstatus;
+
+	  if (sig->summary & GPGME_SIGSUM_VALID)
+	    sigsum = "green";
+	  else if (sig->summary & GPGME_SIGSUM_GREEN)
+	    sigsum = "yellow";
+	  else if (sig->summary & GPGME_SIGSUM_KEY_MISSING)
+	    sigsum = "none";
+	  else
+	    sigsum = "red";
+
+	  sigstatus = gpg_strerror (sig->status);
+
+	  if (sig->fpr)
+	    {
+	      gpgme_get_key (GPA_OPERATION (op)->context->ctx,
+			     sig->fpr, &key, 0);
+	      if (key)
+		keydesc = gpa_gpgme_key_get_userid (key->uids);
+	    }
+	  
+	  if (sig->summary & GPGME_SIGSUM_RED)
+	    {
+	      if (keydesc)
+		sigdesc = g_strdup_printf (_("Bad signature by %s: %s"),
+					   keydesc, sigstatus);
+	      else if (sig->fpr)
+		sigdesc = g_strdup_printf (_("Bad signature by unknown key "
+					     "%s: %s"), sig->fpr, sigstatus);
+	      else
+		sigdesc = g_strdup_printf (_("Bad signature by unknown key: "
+					     "%s"), sigstatus);
+	    }
+	  else if (sig->summary & GPGME_SIGSUM_VALID)
+	    {
+	      if (keydesc)
+		sigdesc = g_strdup_printf (_("Good signature by %s: %s"),
+					   keydesc, sigstatus);
+	      else if (sig->fpr)
+		sigdesc = g_strdup_printf (_("Good signature by unknown key "
+					     "%s: %s"), sig->fpr, sigstatus);
+	      else
+		sigdesc = g_strdup_printf (_("Good signature by unknown key: "
+					     "%s"), sigstatus);
+	    }
+	  else
+	    {
+	      if (keydesc)
+		sigdesc = g_strdup_printf (_("Invalid signature by %s: %s"),
+					   keydesc, sigstatus);
+	      else if (sig->fpr)
+		sigdesc = g_strdup_printf (_("Invalid signature by unknown key "
+					     "%s: %s"), sig->fpr, sigstatus);
+	      else
+		sigdesc = g_strdup_printf (_("Invalid signature by unknown "
+					     "key: %s"), sigstatus);
+	    }
+	  
+	  sigdesc_esc = my_percent_escape (sigdesc);
+	  
+	  /* FIXME: Error handling.  */
+	  err = gpa_operation_write_status (GPA_OPERATION (op), "SIGSTATUS",
+					    sigsum, sigdesc_esc, NULL);
+	  
+	  g_free (sigdesc);
+	  g_free (sigdesc_esc);
+	  
+	  if (key)
+	    gpgme_key_unref (key);
+	  if (keydesc)
+	    g_free (keydesc);
+	  
+	  sig = sig->next;
+	}
+
+      if (res->signatures)
+	{
+	  /* Add the file to the result dialog.  */
+	  gpa_file_verify_dialog_add_file
+	    (GPA_FILE_VERIFY_DIALOG (op->dialog),
+	     _("Document"), NULL, NULL, res->signatures);
+	  gtk_widget_show_all (op->dialog);
+
+	  /* We will complete later in response callback.  */
+	  return;
+	}
+    }
+
+  g_signal_emit_by_name (GPA_OPERATION (op), "completed", err);    
+}
+
+
+static gboolean
+idle_cb (gpointer data)
+{
+  GpaStreamDecryptOperation *op = data;
+  GpaStreamOperation *sop = GPA_STREAM_OPERATION (op);
+  gpgme_error_t err;
+
+  gpgme_set_protocol (GPA_OPERATION (op)->context->ctx, op->selected_protocol);
+
+  if (op->no_verify)
+    err = gpgme_op_decrypt_start (GPA_OPERATION (op)->context->ctx,
+				  sop->input_stream, sop->output_stream);
+  else
+    err = gpgme_op_decrypt_verify_start (GPA_OPERATION (op)->context->ctx,
+					 sop->input_stream, sop->output_stream);
+
+  if (err)
+    {
+      gpa_gpgme_warning (err);
+      g_signal_emit_by_name (GPA_OPERATION (op), "completed", err);
+    }
+
+  gtk_widget_show_all (GPA_STREAM_OPERATION (op)->progress_dialog);
+
+  return FALSE;
+}
+
+
+/* Public API.  */
+
+/* FIXME: Doc.  */
+GpaStreamDecryptOperation *
+gpa_stream_decrypt_operation_new (GtkWidget *window,
+				 gpgme_data_t input_stream,
+				 gpgme_data_t output_stream,
+				 gboolean no_verify, gpgme_protocol_t protocol)
+{
+  GpaStreamDecryptOperation *op;
+
+  op = g_object_new (GPA_STREAM_DECRYPT_OPERATION_TYPE,
+		     "window", window,
+		     "input_stream", input_stream,
+		     "output_stream", output_stream,
+                     "no-verify", no_verify,
+                     "protocol", (int) protocol,
+		     NULL);
+
+  return op;
+}

Added: trunk/src/gpastreamdecryptop.h
===================================================================
--- trunk/src/gpastreamdecryptop.h	2008-05-08 16:47:48 UTC (rev 893)
+++ trunk/src/gpastreamdecryptop.h	2008-05-09 04:45:25 UTC (rev 894)
@@ -0,0 +1,65 @@
+/* gpastreamdecryptop.h - The GpaStreamDecryptOperation object.
+   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 GPA_STREAM_DECRYPT_OP_H
+#define GPA_STREAM_DECRYPT_OP_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "gpastreamop.h"
+
+/* GObject stuff.  */
+#define GPA_STREAM_DECRYPT_OPERATION_TYPE	\
+  (gpa_stream_decrypt_operation_get_type ())
+
+#define GPA_STREAM_DECRYPT_OPERATION(obj)				\
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GPA_STREAM_DECRYPT_OPERATION_TYPE, \
+			       GpaStreamDecryptOperation))
+
+#define GPA_STREAM_DECRYPT_OPERATION_CLASS(klass)			\
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GPA_STREAM_DECRYPT_OPERATION_TYPE,	\
+			    GpaStreamDecryptOperationClass))
+
+#define GPA_IS_STREAM_DECRYPT_OPERATION(obj)				\
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GPA_STREAM_DECRYPT_OPERATION_TYPE))
+
+#define GPA_IS_STREAM_DECRYPT_OPERATION_CLASS(klass)			\
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GPA_STREAM_DECRYPT_OPERATION_TYPE))
+
+#define GPA_STREAM_DECRYPT_OPERATION_GET_CLASS(obj)			\
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), GPA_STREAM_DECRYPT_OPERATION_TYPE,	\
+			      GpaStreamDecryptOperationClass))
+
+typedef struct _GpaStreamDecryptOperation GpaStreamDecryptOperation;
+typedef struct _GpaStreamDecryptOperationClass GpaStreamDecryptOperationClass;
+
+GType gpa_stream_decrypt_operation_get_type (void) G_GNUC_CONST;
+
+
+/* Public API.  */
+
+/* Creates a new decrypt operation.  */
+GpaStreamDecryptOperation *
+gpa_stream_decrypt_operation_new (GtkWidget *window,
+				 gpgme_data_t input_stream,
+				 gpgme_data_t output_stream,
+				 gboolean no_verify,
+				 gpgme_protocol_t protocol);
+
+#endif	/* GPA_STREAM_DECRYPT_OP_H */

Added: trunk/src/gpastreamverifyop.c
===================================================================
--- trunk/src/gpastreamverifyop.c	2008-05-08 16:47:48 UTC (rev 893)
+++ trunk/src/gpastreamverifyop.c	2008-05-09 04:45:25 UTC (rev 894)
@@ -0,0 +1,463 @@
+/* gpastreamsignop.c - The GpaStreamSignOperation object.
+   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/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <glib.h>
+
+#include "gpgmetools.h"
+#include "gtktools.h"
+#include "verifydlg.h"
+#include "gpastreamverifyop.h"
+
+
+struct _GpaStreamVerifyOperation 
+{
+  GpaStreamOperation parent;
+
+  GtkWidget *dialog;
+
+  gboolean silent;
+
+  gpgme_protocol_t selected_protocol;
+};
+
+
+struct _GpaStreamVerifyOperationClass
+{
+  GpaStreamOperationClass parent_class;
+};
+
+
+
+/* Indentifiers for our properties. */
+enum 
+  {
+    PROP_0,
+    PROP_SILENT,
+    PROP_PROTOCOL
+  };
+
+
+static gboolean idle_cb (gpointer data);
+static void response_cb (GtkDialog *dialog, gint response, gpointer user_data);
+static void done_error_cb (GpaContext *context, gpg_error_t err,
+                           GpaStreamVerifyOperation *op);
+static void done_cb (GpaContext *context, gpg_error_t err,
+                     GpaStreamVerifyOperation *op);
+
+static GObjectClass *parent_class;
+
+
+
+static void
+gpa_stream_verify_operation_get_property (GObject *object, guint prop_id,
+					  GValue *value, GParamSpec *pspec)
+{
+  GpaStreamVerifyOperation *op = GPA_STREAM_VERIFY_OPERATION (object);
+  
+  switch (prop_id)
+    {
+    case PROP_SILENT:
+      g_value_set_boolean (value, op->silent);
+      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;
+    }
+}
+
+
+static void
+gpa_stream_verify_operation_set_property (GObject *object, guint prop_id,
+					  const GValue *value,
+					  GParamSpec *pspec)
+{
+  GpaStreamVerifyOperation *op = GPA_STREAM_VERIFY_OPERATION (object);
+
+  switch (prop_id)
+    {
+    case PROP_SILENT:
+      op->silent = g_value_get_boolean (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;
+    }
+}
+
+
+static void
+gpa_stream_verify_operation_finalize (GObject *object)
+{
+  GpaStreamVerifyOperation *op = GPA_STREAM_VERIFY_OPERATION (object);
+
+  if (op->dialog)
+    gtk_widget_destroy (op->dialog);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+static void
+gpa_stream_verify_operation_init (GpaStreamVerifyOperation *op)
+{
+  op->dialog = NULL;
+}
+
+
+static GObject*
+gpa_stream_verify_operation_ctor (GType type, guint n_construct_properties,
+				  GObjectConstructParam *construct_properties)
+{
+  GObject *object;
+  GpaStreamVerifyOperation *op;
+
+  object = parent_class->constructor (type, n_construct_properties,
+				      construct_properties);
+  op = GPA_STREAM_VERIFY_OPERATION (object);
+
+  /* Start with the first file after going back into the main loop */
+  g_idle_add (idle_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);
+
+  /* FIXME: Implement silent option.  */
+  gtk_window_set_title
+    (GTK_WINDOW (GPA_STREAM_OPERATION (op)->progress_dialog),
+     _("Verifying message ..."));
+
+  if (op->silent)
+    gtk_widget_hide (GPA_STREAM_OPERATION (op)->progress_dialog);
+  else
+    {
+      op->dialog = gpa_file_verify_dialog_new (GPA_OPERATION (op)->window);
+      g_signal_connect (G_OBJECT (op->dialog), "response",
+			G_CALLBACK (response_cb), op);
+    }
+
+  return object;
+}
+
+
+static void
+gpa_stream_verify_operation_class_init (GpaStreamVerifyOperationClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  
+  parent_class = g_type_class_peek_parent (klass);
+
+  object_class->constructor = gpa_stream_verify_operation_ctor;
+  object_class->finalize = gpa_stream_verify_operation_finalize;
+  object_class->set_property = gpa_stream_verify_operation_set_property;
+  object_class->get_property = gpa_stream_verify_operation_get_property;
+
+  g_object_class_install_property (object_class, PROP_SILENT,
+				   g_param_spec_boolean 
+				   ("silent", "Silent",
+				    "Flag requesting silent operation.", FALSE,
+				    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));
+
+}
+
+
+GType
+gpa_stream_verify_operation_get_type (void)
+{
+  static GType stream_verify_operation_type = 0;
+  
+  if (! stream_verify_operation_type)
+    {
+      static const GTypeInfo stream_verify_operation_info =
+      {
+        sizeof (GpaStreamVerifyOperationClass),
+        (GBaseInitFunc) NULL,
+        (GBaseFinalizeFunc) NULL,
+        (GClassInitFunc) gpa_stream_verify_operation_class_init,
+        NULL, /* class_finalize */
+        NULL, /* class_data */
+        sizeof (GpaStreamVerifyOperation),
+        0,    /* n_preallocs */
+        (GInstanceInitFunc) gpa_stream_verify_operation_init,
+      };
+      
+      stream_verify_operation_type = g_type_register_static 
+	(GPA_STREAM_OPERATION_TYPE, "GpaStreamVerifyOperation",
+	 &stream_verify_operation_info, 0);
+    }
+  
+  return stream_verify_operation_type;
+}
+
+
+/* The verify status dialog has returned.  */
+static void 
+response_cb (GtkDialog *dialog, int response, void *user_data)
+{
+  GpaStreamVerifyOperation *op = user_data;
+
+  gtk_widget_hide (GTK_WIDGET (dialog));
+  
+  g_signal_emit_by_name (GPA_OPERATION (op), "completed", 0);
+}
+
+
+/* Show an error message. */
+static void
+done_error_cb (GpaContext *context, gpg_error_t err,
+               GpaStreamVerifyOperation *op)
+{
+  switch (gpg_err_code (err))
+    {
+    case GPG_ERR_NO_ERROR:
+    case GPG_ERR_CANCELED:
+      /* Ignore these */
+      break;
+    default:
+      gpa_gpgme_warning (err);
+      break;
+    }
+}
+
+
+/* Percent-Escape special characters.  */
+static gchar *
+my_percent_escape (const gchar *src)
+{
+  gchar *esc_str;
+  int new_len = 3 * strlen (src) + 1;
+  gchar *dst;
+
+  esc_str = g_malloc (new_len);
+
+  dst = esc_str;
+  while (*src)
+    {
+      if (*src == '%')
+	{
+	  *(dst++) = '%';
+	  *(dst++) = '2';
+	  *(dst++) = '5';
+	}	  
+      else if (*src == ':')
+	{
+	  /* The colon is used as field separator.  */
+	  *(dst++) = '%';
+	  *(dst++) = '3';
+	  *(dst++) = 'a';
+	}
+      else if (*src == ',')
+	{
+	  /* The comma is used as list separator.  */
+	  *(dst++) = '%';
+	  *(dst++) = '2';
+	  *(dst++) = 'c';
+	}
+      else
+	*(dst++) = *(src);
+      src++;
+    }
+  *dst = '\0';
+  return esc_str;
+}
+
+
+/* Operation is ready.  Tell the server.  */
+static void
+done_cb (GpaContext *context, gpg_error_t err, GpaStreamVerifyOperation *op)
+{
+  if (! op->silent)
+    gtk_widget_hide (GPA_STREAM_OPERATION (op)->progress_dialog);
+
+  if (! err)
+    {
+      gpgme_verify_result_t res;
+      gpgme_signature_t sig;
+
+      res = gpgme_op_verify_result (GPA_OPERATION (op)->context->ctx);
+      sig = res->signatures;
+
+      while (sig)
+	{
+	  gpgme_key_t key = NULL;
+	  char *keydesc = NULL;
+	  char *sigsum;
+	  char *sigdesc;
+	  char *sigdesc_esc;
+	  const char *sigstatus;
+
+	  if (sig->summary & GPGME_SIGSUM_VALID)
+	    sigsum = "green";
+	  else if (sig->summary & GPGME_SIGSUM_GREEN)
+	    sigsum = "yellow";
+	  else if (sig->summary & GPGME_SIGSUM_KEY_MISSING)
+	    sigsum = "none";
+	  else
+	    sigsum = "red";
+
+	  sigstatus = gpg_strerror (sig->status);
+
+	  if (sig->fpr)
+	    {
+	      gpgme_get_key (GPA_OPERATION (op)->context->ctx,
+			     sig->fpr, &key, 0);
+	      if (key)
+		keydesc = gpa_gpgme_key_get_userid (key->uids);
+	    }
+	  
+	  if (sig->summary & GPGME_SIGSUM_RED)
+	    {
+	      if (keydesc)
+		sigdesc = g_strdup_printf (_("Bad signature by %s: %s"),
+					   keydesc, sigstatus);
+	      else if (sig->fpr)
+		sigdesc = g_strdup_printf (_("Bad signature by unknown key "
+					     "%s: %s"), sig->fpr, sigstatus);
+	      else
+		sigdesc = g_strdup_printf (_("Bad signature by unknown key: "
+					     "%s"), sigstatus);
+	    }
+	  else if (sig->summary & GPGME_SIGSUM_VALID)
+	    {
+	      if (keydesc)
+		sigdesc = g_strdup_printf (_("Good signature by %s: %s"),
+					   keydesc, sigstatus);
+	      else if (sig->fpr)
+		sigdesc = g_strdup_printf (_("Good signature by unknown key "
+					     "%s: %s"), sig->fpr, sigstatus);
+	      else
+		sigdesc = g_strdup_printf (_("Good signature by unknown key: "
+					     "%s"), sigstatus);
+	    }
+	  else
+	    {
+	      if (keydesc)
+		sigdesc = g_strdup_printf (_("Invalid signature by %s: %s"),
+					   keydesc, sigstatus);
+	      else if (sig->fpr)
+		sigdesc = g_strdup_printf (_("Invalid signature by unknown key "
+					     "%s: %s"), sig->fpr, sigstatus);
+	      else
+		sigdesc = g_strdup_printf (_("Invalid signature by unknown "
+					     "key: %s"), sigstatus);
+	    }
+	  
+	  sigdesc_esc = my_percent_escape (sigdesc);
+	  
+	  /* FIXME: Error handling.  */
+	  err = gpa_operation_write_status (GPA_OPERATION (op), "SIGSTATUS",
+					    sigsum, sigdesc_esc, NULL);
+	  
+	  g_free (sigdesc);
+	  g_free (sigdesc_esc);
+	  
+	  if (key)
+	    gpgme_key_unref (key);
+	  if (keydesc)
+	    g_free (keydesc);
+	  
+	  sig = sig->next;
+	}
+    }
+
+  if (err || op->silent)
+    g_signal_emit_by_name (GPA_OPERATION (op), "completed", err);    
+  else
+    {
+      gpgme_verify_result_t result;
+      
+      result = gpgme_op_verify_result (GPA_OPERATION (op)->context->ctx);
+      /* Add the file to the result dialog.  */
+      gpa_file_verify_dialog_add_file (GPA_FILE_VERIFY_DIALOG (op->dialog),
+				       _("Document"), NULL, NULL,
+				       result->signatures);
+
+      gtk_widget_show_all (op->dialog);     
+    }
+}
+
+
+static gboolean
+idle_cb (gpointer data)
+{
+  GpaStreamVerifyOperation *op = data;
+  GpaStreamOperation *sop = GPA_STREAM_OPERATION (op);
+  gpgme_error_t err;
+
+  gpgme_set_protocol (GPA_OPERATION (op)->context->ctx, op->selected_protocol);
+
+  err = gpgme_op_verify_start (GPA_OPERATION (op)->context->ctx,
+			       sop->input_stream, sop->message_stream,
+			       sop->output_stream);
+  if (err)
+    {
+      gpa_gpgme_warning (err);
+      g_signal_emit_by_name (GPA_OPERATION (op), "completed", err);
+    }
+  else if (! op->silent)
+    {
+      gtk_widget_show_all (GPA_STREAM_OPERATION (op)->progress_dialog);
+    }
+
+  return FALSE;
+}
+
+
+/* Public API.  */
+
+/* FIXME: Doc.  */
+GpaStreamVerifyOperation *
+gpa_stream_verify_operation_new (GtkWidget *window,
+				 gpgme_data_t input_stream,
+				 gpgme_data_t message_stream,
+				 gpgme_data_t output_stream,
+				 gboolean silent, gpgme_protocol_t protocol)
+{
+  GpaStreamVerifyOperation *op;
+
+  op = g_object_new (GPA_STREAM_VERIFY_OPERATION_TYPE,
+		     "window", window,
+		     "input_stream", input_stream,
+		     "message_stream", message_stream,
+		     "output_stream", output_stream,
+                     "silent", silent,
+                     "protocol", (int) protocol,
+		     NULL);
+
+  return op;
+}

Added: trunk/src/gpastreamverifyop.h
===================================================================
--- trunk/src/gpastreamverifyop.h	2008-05-08 16:47:48 UTC (rev 893)
+++ trunk/src/gpastreamverifyop.h	2008-05-09 04:45:25 UTC (rev 894)
@@ -0,0 +1,66 @@
+/* gpastreamverifyop.h - The GpaStreamVerifyOperation object.
+   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 GPA_STREAM_VERIFY_OP_H
+#define GPA_STREAM_VERIFY_OP_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "gpastreamop.h"
+
+/* GObject stuff.  */
+#define GPA_STREAM_VERIFY_OPERATION_TYPE	\
+  (gpa_stream_verify_operation_get_type ())
+
+#define GPA_STREAM_VERIFY_OPERATION(obj)				\
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GPA_STREAM_VERIFY_OPERATION_TYPE, \
+			       GpaStreamVerifyOperation))
+
+#define GPA_STREAM_VERIFY_OPERATION_CLASS(klass)			\
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GPA_STREAM_VERIFY_OPERATION_TYPE,	\
+			    GpaStreamVerifyOperationClass))
+
+#define GPA_IS_STREAM_VERIFY_OPERATION(obj)				\
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GPA_STREAM_VERIFY_OPERATION_TYPE))
+
+#define GPA_IS_STREAM_VERIFY_OPERATION_CLASS(klass)			\
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GPA_STREAM_VERIFY_OPERATION_TYPE))
+
+#define GPA_STREAM_VERIFY_OPERATION_GET_CLASS(obj)			\
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), GPA_STREAM_VERIFY_OPERATION_TYPE,	\
+			      GpaStreamVerifyOperationClass))
+
+typedef struct _GpaStreamVerifyOperation GpaStreamVerifyOperation;
+typedef struct _GpaStreamVerifyOperationClass GpaStreamVerifyOperationClass;
+
+GType gpa_stream_verify_operation_get_type (void) G_GNUC_CONST;
+
+
+/* Public API.  */
+
+/* Creates a new verify operation.  */
+GpaStreamVerifyOperation *
+gpa_stream_verify_operation_new (GtkWidget *window,
+				 gpgme_data_t input_stream,
+				 gpgme_data_t message_stream,
+				 gpgme_data_t output_stream,
+				 gboolean silent,
+				 gpgme_protocol_t protocol);
+
+#endif	/* GPA_STREAM_VERIFY_OP_H */

Modified: trunk/src/server.c
===================================================================
--- trunk/src/server.c	2008-05-08 16:47:48 UTC (rev 893)
+++ trunk/src/server.c	2008-05-09 04:45:25 UTC (rev 894)
@@ -1,24 +1,25 @@
 /* server.c -  The UI server part of GPA.
- * Copyright (C) 2007, 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/>.
- */
+   Copyright (C) 2007, 2008 g10 Code GmbH
 
-#include <config.h>
+   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/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <assert.h>
@@ -28,6 +29,7 @@
 # include <sys/socket.h>
 # include <sys/un.h>
 #endif /*HAVE_W32_SYSTEM*/
+
 #include <gpgme.h>
 #include <glib.h>
 #include <assuan.h>
@@ -36,9 +38,10 @@
 #include "i18n.h"
 #include "gpastreamencryptop.h"
 #include "gpastreamsignop.h"
+#include "gpastreamdecryptop.h"
+#include "gpastreamverifyop.h"
 
 
-
 #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.  */
@@ -242,6 +245,7 @@
     NULL
   };
 
+
 static ssize_t
 my_gpgme_message_read_cb (void *opaque, void *buffer, size_t size)
 {
@@ -280,6 +284,21 @@
   };
 
 
+static ssize_t
+my_devnull_write_cb (void *opaque, const void *buffer, size_t size)
+{
+  return size;
+}
+
+
+static struct gpgme_data_cbs my_devnull_data_cbs =
+  { 
+    NULL,
+    my_devnull_write_cb,
+    NULL,
+    NULL
+  };
+
 
 /* Release the recipients stored in the connection context. */
 static void
@@ -375,6 +394,12 @@
       g_io_channel_shutdown (ctrl->message_channel, 0, NULL);
       ctrl->message_channel = NULL;
     }
+
+  close_message_fd (ctrl);
+  assuan_close_input_fd (ctx);
+  assuan_close_output_fd (ctx);
+  ctrl->input_fd = -1;
+  ctrl->output_fd = -1;
 }
 
 
@@ -461,22 +486,22 @@
       g_io_channel_set_buffered (ctrl->message_channel, FALSE);
     }
 
-  if (ctrl->input_fd != -1 && r_input_data)
+  if (ctrl->input_channel)
     {
       err = gpgme_data_new_from_cbs (r_input_data, &my_gpgme_data_cbs, ctrl);
       if (err)
         goto leave;
     }
-  if (ctrl->output_fd != -1 && r_output_data)
+  if (ctrl->output_channel)
     {
       err = gpgme_data_new_from_cbs (r_output_data, &my_gpgme_data_cbs, ctrl);
       if (err)
         goto leave;
     }
-  if (ctrl->message_fd != -1 && r_message_data)
+  if (ctrl->message_channel)
     {
       err = gpgme_data_new_from_cbs (r_message_data,
-                                     &my_gpgme_message_cbs, ctrl);
+				     &my_gpgme_message_cbs, ctrl);
       if (err)
         goto leave;
     }
@@ -646,6 +671,8 @@
   close_message_fd (ctrl);
   assuan_close_input_fd (ctx);
   assuan_close_output_fd (ctx);
+  ctrl->input_fd = -1;
+  ctrl->output_fd = -1;
   return assuan_process_done (ctx, err);
 }
 
@@ -835,6 +862,8 @@
   close_message_fd (ctrl);
   assuan_close_input_fd (ctx);
   assuan_close_output_fd (ctx);
+  ctrl->input_fd = -1;
+  ctrl->output_fd = -1;
   return assuan_process_done (ctx, err);
 }
 
@@ -850,11 +879,6 @@
            gpg_strerror (err), gpg_strsource (err));
 
   finish_io_streams (ctx, NULL, NULL, NULL);
-  if (!err)
-    {
-      xfree (ctrl->sender);
-      ctrl->sender = NULL;
-    }
   assuan_process_done (ctx, err);
 }
 
@@ -866,8 +890,7 @@
 
    If the option --no-verify is given, the server should not try to
    verify a signature, in case the input data is an OpenPGP combined
-   message.
-*/
+   message.  */
 static int 
 cmd_decrypt (assuan_context_t ctx, char *line)
 {
@@ -875,7 +898,7 @@
   gpg_error_t err;
   gpgme_protocol_t protocol = 0;
   int no_verify;
-  GpaStreamSignOperation *op;  /* Fixme: use GpaStreamDecryptOperatio!!!*/
+  GpaStreamDecryptOperation *op;
   gpgme_data_t input_data = NULL;
   gpgme_data_t output_data = NULL;
 
@@ -883,7 +906,7 @@
   if (err)
     goto leave;
 
-  no_verify= has_option (line, "--no-verify");
+  no_verify = has_option (line, "--no-verify");
 
   line = skip_options (line);
   if (*line)
@@ -901,9 +924,8 @@
 
   ctrl->cont_cmd = cont_decrypt;
 
-#warning  FIXME:  Use decrypt.
-  op = gpa_stream_sign_operation_new (NULL, input_data, output_data,
-                                      ctrl->sender, protocol, 1);
+  op = gpa_stream_decrypt_operation_new (NULL, input_data, output_data,
+					 no_verify, protocol);
 
   input_data = output_data = NULL;
   g_signal_connect_swapped (G_OBJECT (op), "completed",
@@ -920,6 +942,8 @@
   close_message_fd (ctrl);
   assuan_close_input_fd (ctx);
   assuan_close_output_fd (ctx);
+  ctrl->input_fd = -1;
+  ctrl->output_fd = -1;
   return assuan_process_done (ctx, err);
 }
 
@@ -936,11 +960,6 @@
            gpg_strerror (err), gpg_strsource (err));
 
   finish_io_streams (ctx, NULL, NULL, NULL);
-  if (!err)
-    {
-      xfree (ctrl->sender);
-      ctrl->sender = NULL;
-    }
   assuan_process_done (ctx, err);
 }
 
@@ -987,8 +1006,7 @@
         The signature is not valid. 
 
    The DISPLAYSTRING is a percent-and-plus-encoded string with a short
-   human readable description of the status.
-*/
+   human readable description of the status.  */
 static int 
 cmd_verify (assuan_context_t ctx, char *line)
 {
@@ -996,10 +1014,11 @@
   gpg_error_t err;
   gpgme_protocol_t protocol = 0;
   int silent;
-  GpaStreamSignOperation *op;  /* Fixme: use GpaStreamDecryptOperatio!!!*/
+  GpaStreamVerifyOperation *op;
   gpgme_data_t input_data = NULL;
   gpgme_data_t output_data = NULL;
   gpgme_data_t message_data = NULL;
+  enum { VERIFY_DETACH, VERIFY_OPAQUE, VERIFY_OPAQUE_WITH_OUTPUT } op_mode;
 
   err = parse_protocol_option (ctx, line, 1, &protocol);
   if (err)
@@ -1014,19 +1033,19 @@
       goto leave;
     }
 
-  /* Note: We can't use translate_io_streams becuase that returns an
+  /* Note: We can't use translate_io_streams because that returns an
      error if one is not opened but that is not an error here.  */
   ctrl->input_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
   ctrl->output_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
   if (ctrl->message_fd != -1 && ctrl->input_fd != -1 
       && ctrl->output_fd == -1)
-    ; /* Mode = detached. */
+    op_mode = VERIFY_DETACH;
   else if (ctrl->message_fd == -1 && ctrl->input_fd != -1 
            && ctrl->output_fd == -1)
-    ; /* Mode = opaque. */
+    op_mode = VERIFY_OPAQUE;
   else if (ctrl->message_fd == -1 && ctrl->input_fd != -1 
            && ctrl->output_fd != -1)
-    ; /* Mode = opaque with output. */
+    op_mode = VERIFY_OPAQUE_WITH_OUTPUT;
   else
     {
       err = set_error (GPG_ERR_CONFLICT, "invalid verify mode");
@@ -1034,14 +1053,15 @@
     }
   
   err = prepare_io_streams (ctx, &input_data, &output_data, &message_data);
+  if (! err && op_mode == VERIFY_OPAQUE)
+    err = gpgme_data_new_from_cbs (&output_data, &my_devnull_data_cbs, ctrl);
   if (err)
     goto leave;
 
-  ctrl->cont_cmd = cont_decrypt;
+  ctrl->cont_cmd = cont_verify;
 
-#warning  FIXME:  Use verify.
-  op = gpa_stream_sign_operation_new (NULL, input_data, output_data,
-                                      ctrl->sender, protocol, 1);
+  op = gpa_stream_verify_operation_new (NULL, input_data, message_data,
+					output_data, silent, protocol);
 
   input_data = output_data = message_data = NULL;
   g_signal_connect_swapped (G_OBJECT (op), "completed",
@@ -1058,6 +1078,8 @@
   close_message_fd (ctrl);
   assuan_close_input_fd (ctx);
   assuan_close_output_fd (ctx);
+  ctrl->input_fd = -1;
+  ctrl->output_fd = -1;
   return assuan_process_done (ctx, err);
 }
 
@@ -1125,6 +1147,8 @@
   close_message_fd (ctrl);
   assuan_close_input_fd (ctx);
   assuan_close_output_fd (ctx);
+  ctrl->input_fd = -1;
+  ctrl->output_fd = -1;
   if (ctrl->gpa_op)
     {
       g_object_unref (ctrl->gpa_op);



More information about the Gpa-commits mailing list