2001-11-22 Marcus Brinkmann <marcus@g10code.de>
authorMarcus Brinkmann <mb@g10code.com>
Thu, 22 Nov 2001 03:08:58 +0000 (03:08 +0000)
committerMarcus Brinkmann <mb@g10code.com>
Thu, 22 Nov 2001 03:08:58 +0000 (03:08 +0000)
* rungpg.c (gpg_inbound_handler, write_mem_data, write_cb_data,
gpg_outbound_handler): Moved to ...
* data.c (_gpgme_data_inbound_handler, write_mem_data,
write_cb_data, _gpgme_data_outbound_handler): ... here.  Make the
_gpgme_* ones non-static.
* data.c: Include io.h.

* ops.h (_gpgme_data_inbound_handler): New prototype.
(_gpgme_data_outbound_handler): Likewise.
(_gpgme_gpg_spawn): Use these new functions.

* engine-gpgsm.h (_gpgme_gpgsm_op_decrypt, _gpgme_gpgsm_op_delete,
_gpgme_gpgsm_op_encrypt, _gpgme_gpgsm_op_export,
_gpgme_gpgsm_op_genkey, _gpgme_gpgsm_op_import,
_gpgme_gpgsm_op_keylist, _gpgme_gpgsm_op_sign,
_gpgme_gpgsm_op_trustlist, _gpgme_gpgsm_op_verify,
_gpgme_gpgsm_start, _gpgme_gpgsm_set_status_handler): New prototype.
Include <rungpg.h> for status handler function.

* engine-gpgsm.c (struct gpgsm_object_s): New members input_fd,
input_data, output_fd, output_data, message_fd, message_data, command
and status.
(_gpgme_gpgsm_new): Open input, output and message pipes before
connecting to the client.  Close server's ends afterwards.
(_gpgme_gpgsm_release): Close open file descriptors.  Remove
server process from wait queue.
(_gpgme_gpgsm_op_verify, _gpgme_gpgsm_start,
_gpgme_gpgsm_set_status_handler, gpgms_status_handler): New function.

* engine.c (_gpgme_engine_start): Implement for GPGME_PROTOCOL_CMS.
(_gpgme_engine_set_status_handler): Likewise.
(_gpgme_engine_op_verify): Likewise.

gpgme/ChangeLog
gpgme/data.c
gpgme/engine-gpgsm.c
gpgme/engine-gpgsm.h
gpgme/engine.c
gpgme/ops.h
gpgme/rungpg.c

index 2ee8f90087893a80c1f00e1914c75a8a7fcb4ac4..d2707521a744aab0a384bc618908bc30b445f12b 100644 (file)
@@ -1,3 +1,38 @@
+2001-11-22  Marcus Brinkmann  <marcus@g10code.de>
+
+       * rungpg.c (gpg_inbound_handler, write_mem_data, write_cb_data,
+       gpg_outbound_handler): Moved to ...
+       * data.c (_gpgme_data_inbound_handler, write_mem_data,
+       write_cb_data, _gpgme_data_outbound_handler): ... here.  Make the
+       _gpgme_* ones non-static.
+       * data.c: Include io.h.
+
+       * ops.h (_gpgme_data_inbound_handler): New prototype.
+       (_gpgme_data_outbound_handler): Likewise.
+       (_gpgme_gpg_spawn): Use these new functions.
+
+       * engine-gpgsm.h (_gpgme_gpgsm_op_decrypt, _gpgme_gpgsm_op_delete,
+       _gpgme_gpgsm_op_encrypt, _gpgme_gpgsm_op_export,
+       _gpgme_gpgsm_op_genkey, _gpgme_gpgsm_op_import,
+       _gpgme_gpgsm_op_keylist, _gpgme_gpgsm_op_sign,
+       _gpgme_gpgsm_op_trustlist, _gpgme_gpgsm_op_verify,
+       _gpgme_gpgsm_start, _gpgme_gpgsm_set_status_handler): New prototype.
+       Include <rungpg.h> for status handler function.
+
+       * engine-gpgsm.c (struct gpgsm_object_s): New members input_fd,
+       input_data, output_fd, output_data, message_fd, message_data, command
+       and status.
+       (_gpgme_gpgsm_new): Open input, output and message pipes before
+       connecting to the client.  Close server's ends afterwards.
+       (_gpgme_gpgsm_release): Close open file descriptors.  Remove
+       server process from wait queue.
+       (_gpgme_gpgsm_op_verify, _gpgme_gpgsm_start,
+       _gpgme_gpgsm_set_status_handler, gpgms_status_handler): New function.
+       
+       * engine.c (_gpgme_engine_start): Implement for GPGME_PROTOCOL_CMS.
+       (_gpgme_engine_set_status_handler): Likewise.
+       (_gpgme_engine_op_verify): Likewise.
+
 2001-11-21  Marcus Brinkmann  <marcus@g10code.de>
 
        * context.h: Do not include rungpg.h, but engine.h.
index 6ba853d89f0424e96f76d845b18c26702ab7fe13..a17ea1d2d334ad8b327aa2169d5ada989890d48f 100644 (file)
@@ -32,6 +32,7 @@
 #include "util.h"
 #include "context.h"
 #include "ops.h"
+#include "io.h"
 
 #define ALLOC_CHUNK 1024
 #define my_isdigit(a)  ( (a) >='0' && (a) <= '9' )
@@ -757,9 +758,6 @@ hextobyte( const byte *s )
     return c;
 }
 
-
-
-
 /* 
  * Append a string with percent style (%XX) escape characters as XML
  */
@@ -785,3 +783,138 @@ _gpgme_data_append_percentstring_for_xml ( GpgmeData dh, const char *string )
     xfree (buf);
     return err;
 }
+
+/* Functions to support the wait interface.  */
+
+int
+_gpgme_data_inbound_handler (void *opaque, int pid, int fd)
+{
+  GpgmeData dh = opaque;
+  GpgmeError err;
+  int nread;
+  char buf[200];
+
+  assert (_gpgme_data_get_mode (dh) == GPGME_DATA_MODE_IN);
+
+  nread = _gpgme_io_read (fd, buf, 200);
+  if (nread < 0)
+    {
+      DEBUG3 ("read_mem_data: read failed on fd %d (n=%d): %s",
+             fd, nread, strerror (errno) );
+      return 1;
+    }
+  else if (!nread)
+    return 1; /* eof */
+
+  /* We could improve this with a GpgmeData function which takes
+   * the read function or provides a memory area for writing to it.
+   */
+    
+  err = _gpgme_data_append (dh, buf, nread);
+  if (err)
+    {
+      DEBUG1 ("_gpgme_append_data failed: %s\n",
+             gpgme_strerror(err));
+      /* Fixme: we should close the pipe or read it to /dev/null in
+       * this case. Returnin EOF is not sufficient */
+      return 1;
+    }
+
+  return 0;
+}
+
+static int
+write_mem_data (GpgmeData dh, int fd)
+{
+  size_t nbytes;
+  int nwritten; 
+
+  nbytes = dh->len - dh->readpos;
+  if (!nbytes)
+    {
+      _gpgme_io_close (fd);
+      return 1;
+    }
+    
+  /* FIXME: Arggg, the pipe blocks on large write request, although
+   * select told us that it is okay to write - need to figure out
+   * why this happens?  Stevens says nothing about this problem (or
+   * is it my Linux kernel 2.4.0test1)
+   * To avoid that we have set the pipe to nonblocking.
+   */
+
+  nwritten = _gpgme_io_write (fd, dh->data+dh->readpos, nbytes);
+  if (nwritten == -1 && errno == EAGAIN)
+    return 0;
+  if (nwritten < 1)
+    {
+      DEBUG3 ("write_mem_data(%d): write failed (n=%d): %s",
+             fd, nwritten, strerror (errno));
+      _gpgme_io_close (fd);
+      return 1;
+    }
+
+  dh->readpos += nwritten;
+  return 0;
+}
+
+static int
+write_cb_data (GpgmeData dh, int fd)
+{
+  size_t nbytes;
+  int  err, nwritten; 
+  char buffer[512];
+
+  err = gpgme_data_read (dh, buffer, DIM(buffer), &nbytes);
+  if (err == GPGME_EOF)
+    {
+      _gpgme_io_close (fd);
+      return 1;
+    }
+    
+  nwritten = _gpgme_io_write (fd, buffer, nbytes);
+  if (nwritten == -1 && errno == EAGAIN )
+    return 0;
+  if (nwritten < 1)
+    {
+      DEBUG3 ("write_cb_data(%d): write failed (n=%d): %s",
+             fd, nwritten, strerror (errno));
+      _gpgme_io_close (fd);
+      return 1;
+    }
+
+  if (nwritten < nbytes)
+    {
+      /* ugly, ugly: It does currently only for for MEM type data */
+      if (_gpgme_data_unread (dh, buffer + nwritten, nbytes - nwritten))
+       DEBUG1 ("wite_cb_data: unread of %d bytes failed\n",
+               nbytes - nwritten);
+      _gpgme_io_close (fd);
+      return 1;
+    }
+  
+  return 0;
+}
+
+int
+_gpgme_data_outbound_handler (void *opaque, int pid, int fd)
+{
+  GpgmeData dh = opaque;
+
+  assert (_gpgme_data_get_mode (dh) == GPGME_DATA_MODE_OUT);
+  switch (gpgme_data_get_type (dh))
+    {
+    case GPGME_DATA_TYPE_MEM:
+      if (write_mem_data (dh, fd))
+       return 1; /* ready */
+      break;
+    case GPGME_DATA_TYPE_CB:
+      if (write_cb_data (dh, fd))
+       return 1; /* ready */
+      break;
+    default:
+      assert (0);
+    }
+  
+  return 0;
+}
index 000ad116834c1e86c94997e2773bd03824da9e90..87a00393904dd3dc682956c7cb0aba7abc863bec 100644 (file)
 #include <config.h>
 #endif
 
-#include "gpgme.h"
-#include "util.h"
-#include "types.h"
-#include "ops.h"
-
-#include "engine-gpgsm.h"
-
 /* FIXME: Correct check?  */
 #ifdef GPGSM_PATH
 #define ENABLE_GPGSM 1
 
 #ifdef ENABLE_GPGSM
 
+#include <sys/types.h>
+#include <assert.h>
+
+/* FIXME */
+#include "../assuan/assuan-defs.h"
+#undef xtrymalloc
+#undef xtrycalloc
+#undef xtryrealloc
+#undef xfree
+
+#include "gpgme.h"
+#include "util.h"
+#include "types.h"
+#include "ops.h"
+#include "wait.h"
+#include "io.h"
+
+#include "engine-gpgsm.h"
+
 #include "assuan.h"
 
 struct gpgsm_object_s
 {
   ASSUAN_CONTEXT assuan_ctx;
+
+  /* Input, output etc are from the servers perspective.  */
+  int input_fd;
+  int input_fd_server;
+  GpgmeData input_data;
+  int output_fd;
+  int output_fd_server;
+  GpgmeData output_data;
+  int message_fd;
+  int message_fd_server;
+  GpgmeData message_data;
+
+  char *command;
+
+  struct
+  {
+    GpgStatusHandler fnc;
+    void *fnc_value;
+  } status;
+  
 };
 
 const char *
@@ -70,6 +102,9 @@ _gpgme_gpgsm_new (GpgsmObject *r_gpgsm)
   GpgmeError err = 0;
   GpgsmObject gpgsm;
   char *argv[] = { "gpgsm", "--server", NULL };
+  int ip[2] = { -1, -1 };
+  int op[2] = { -1, -1 };
+  int mp[2] = { -1, -1 };
 
   *r_gpgsm = NULL;
   gpgsm = xtrycalloc (1, sizeof *gpgsm);
@@ -79,10 +114,39 @@ _gpgme_gpgsm_new (GpgsmObject *r_gpgsm)
       goto leave;
     }
 
+  if (_gpgme_io_pipe (ip, 0) < 0)
+    {
+      err = mk_error (General_Error);
+      goto leave;
+    }
+  gpgsm->input_fd = ip[1];
+  gpgsm->input_fd_server = ip[0];
+  if (_gpgme_io_pipe (op, 1) < 0)
+    {
+      err = mk_error (General_Error);
+      goto leave;
+    }
+  gpgsm->output_fd = op[0];
+  gpgsm->output_fd_server = op[1];
+  if (_gpgme_io_pipe (mp, 0) < 0)
+    {
+      err = mk_error (General_Error);
+      goto leave;
+    }
+  gpgsm->message_fd = mp[1];
+  gpgsm->message_fd_server = mp[0];
+
   err = assuan_pipe_connect (&gpgsm->assuan_ctx,
                             _gpgme_get_gpgsm_path (), argv);
 
  leave:
+  if (ip[0] != -1)
+    _gpgme_io_close (ip[0]);
+  if (op[1] != -1)
+    _gpgme_io_close (op[1]);
+  if (mp[0] != -1)
+    _gpgme_io_close (mp[0]);
+
   if (err)
     _gpgme_gpgsm_release (gpgsm);
   else
@@ -94,13 +158,156 @@ _gpgme_gpgsm_new (GpgsmObject *r_gpgsm)
 void
 _gpgme_gpgsm_release (GpgsmObject gpgsm)
 {
+  pid_t pid;
+
   if (!gpgsm)
     return;
 
+  pid = assuan_get_pid (gpgsm->assuan_ctx);
+  if (pid != -1)
+    _gpgme_remove_proc_from_wait_queue (pid);
+
+  if (gpgsm->input_fd != -1)
+    _gpgme_io_close (gpgsm->input_fd);
+  if (gpgsm->output_fd != -1)
+    _gpgme_io_close (gpgsm->output_fd);
+  if (gpgsm->message_fd != -1)
+    _gpgme_io_close (gpgsm->message_fd);
+
   assuan_pipe_disconnect (gpgsm->assuan_ctx);
   xfree (gpgsm);
 }
 
+#define COMMANDLINELEN 40
+static AssuanError
+gpgsm_set_fd (ASSUAN_CONTEXT ctx, const char *which, int fd)
+{
+  AssuanError err;
+  char line[COMMANDLINELEN];
+
+  snprintf (line, COMMANDLINELEN, "%s FD=%i", which, fd);
+  err = _assuan_write_line (ctx, line);
+  if (err)
+    return err;
+
+  do
+    {
+      err = _assuan_read_line (ctx);
+      if (err)
+       return err;
+    }
+  while (*ctx->inbound.line == '#' || !ctx->inbound.linelen);
+  
+  if (ctx->inbound.linelen >= 2
+      && ctx->inbound.line[0] == 'O' && ctx->inbound.line[1] == 'K'
+      && (ctx->inbound.line[2] == '\0' || ctx->inbound.line[2] == ' '))
+    return 0;
+  else
+    return ASSUAN_General_Error;
+}
+
+GpgmeError
+_gpgme_gpgsm_op_verify (GpgsmObject gpgsm, GpgmeData sig, GpgmeData text)
+{
+  AssuanError err;
+
+  if (!gpgsm)
+    return mk_error (Invalid_Value);
+
+  gpgsm->input_data = sig;
+  err = gpgsm_set_fd (gpgsm->assuan_ctx, "INPUT", gpgsm->input_fd_server);
+  if (err)
+    return mk_error (General_Error);   /* FIXME */
+  gpgsm->message_data = sig;
+  err = gpgsm_set_fd (gpgsm->assuan_ctx, "MESSAGE", gpgsm->message_fd_server);
+  if (err)
+    return mk_error (General_Error);   /* FIXME */
+  _gpgme_io_close (gpgsm->output_fd);
+  gpgsm->output_fd = -1;
+
+  gpgsm->command = "VERIFY";
+  return 0;
+}
+
+static int
+gpgsm_status_handler (void *opaque, int pid, int fd)
+{
+  int err;
+  GpgsmObject gpgsm = opaque;
+  ASSUAN_CONTEXT actx = gpgsm->assuan_ctx;
+
+ assert (fd == gpgsm->assuan_ctx->inbound.fd);
+
+  err = _assuan_read_line (gpgsm->assuan_ctx);
+
+  if (actx->inbound.line[0] == '#' || !actx->inbound.linelen)
+    return 0;  /* FIXME */
+
+  if (actx->inbound.linelen >= 2
+      && actx->inbound.line[0] == 'O' && actx->inbound.line[1] == 'K'
+      && (actx->inbound.line[2] == '\0' || actx->inbound.line[2] == ' '))
+    {
+      if (gpgsm->status.fnc)
+       gpgsm->status.fnc (gpgsm->status.fnc_value, STATUS_EOF, "");
+      return 1;
+    }
+  /* FIXME: Parse the status and call the handler.  */
+
+  fprintf (stderr, "[UNCAUGHT STATUS]%s", actx->inbound.line);
+  return 0;
+}
+
+void
+_gpgme_gpgsm_set_status_handler (GpgsmObject gpgsm,
+                                GpgStatusHandler fnc, void *fnc_value) 
+{
+  assert (gpgsm);
+
+  gpgsm->status.fnc = fnc;
+  gpgsm->status.fnc_value = fnc_value;
+}
+
+GpgmeError
+_gpgme_gpgsm_start (GpgsmObject gpgsm, void *opaque)
+{
+  GpgmeError err = 0;
+  pid_t pid;
+
+  if (!gpgsm)
+    return mk_error (Invalid_Value);
+
+  pid = assuan_get_pid (gpgsm->assuan_ctx);
+
+  err = _gpgme_register_pipe_handler (opaque, gpgsm_status_handler, gpgsm, pid,
+                                     gpgsm->assuan_ctx->inbound.fd, 1);
+
+  if (gpgsm->input_fd != -1)
+    {
+      err = _gpgme_register_pipe_handler (opaque, _gpgme_data_outbound_handler,
+                                         gpgsm->input_data, pid,
+                                         gpgsm->input_fd, 0);
+      if (!err)        /* FIXME Kludge around poll() problem.  */
+       err = _gpgme_io_set_nonblocking (gpgsm->input_fd);
+    }
+  if (!err && gpgsm->output_fd != -1)
+    err = _gpgme_register_pipe_handler (opaque, _gpgme_data_inbound_handler,
+                                       gpgsm->output_data, pid,
+                                       gpgsm->output_fd, 1);
+  if (!err && gpgsm->message_fd != -1)
+    {
+      err = _gpgme_register_pipe_handler (opaque, _gpgme_data_outbound_handler,
+                                         gpgsm->message_data, pid,
+                                         gpgsm->message_fd, 0);
+      if (!err)        /* FIXME Kludge around poll() problem.  */
+       err = _gpgme_io_set_nonblocking (gpgsm->message_fd);
+    }
+
+  if (!err)
+    err = _assuan_write_line (gpgsm->assuan_ctx, gpgsm->command);
+
+  return err;
+}
+
 #else  /* ENABLE_GPGSM */
 
 const char *
@@ -127,4 +334,16 @@ _gpgme_gpgsm_release (GpgsmObject gpgsm)
   return;
 }
 
+GpgmeError
+ _gpgme_gpgsm_op_verify (GpgsmObject gpgsm, GpgmeData sig, GpgmeData text)
+{
+  return mk_error (Invalid_Engine);
+}
+
+GpgmeError
+_gpgme_gpgsm_start (GpgsmObject gpgsm, void *opaque)
+{
+  return mk_error (Invalid_Engine);
+}
+
 #endif /* ! ENABLE_GPGSM */
index 105405bd2f66b881e6acbc097215ba3bc3bfcdda..5feada86537993f0915cd01eab36093960a40d8a 100644 (file)
@@ -23,6 +23,7 @@
 #define ENGINE_GPGSM_H
 
 #include "types.h"
+#include "rungpg.h" /* FIXME statusHandler */
 
 const char *_gpgme_gpgsm_get_version (void);
 GpgmeError _gpgme_gpgsm_check_version (void);
@@ -30,4 +31,26 @@ GpgmeError _gpgme_gpgsm_check_version (void);
 GpgmeError _gpgme_gpgsm_new (GpgsmObject *r_gpg);
 void _gpgme_gpgsm_release (GpgsmObject gpg);
 
+void _gpgme_gpgsm_set_status_handler (GpgsmObject gpgsm,
+                                     GpgStatusHandler fnc, void *fnc_value);
+GpgmeError _gpgme_gpgsm_op_decrypt (GpgsmObject gpgsm, GpgmeData ciph,
+                                 GpgmeData plain);
+GpgmeError _gpgme_gpgsm_op_delete (GpgsmObject gpgsm, GpgmeKey key, int allow_secret);
+GpgmeError _gpgme_gpgsm_op_encrypt (GpgsmObject gpgsm, GpgmeRecipients recp,
+                                 GpgmeData plain, GpgmeData ciph,
+                                 int use_armor);
+GpgmeError _gpgme_gpgsm_op_export (GpgsmObject gpgsm, GpgmeRecipients recp,
+                                GpgmeData keydata, int use_armor);
+GpgmeError _gpgme_gpgsm_op_genkey (GpgsmObject gpgsm, GpgmeData help_data,
+                                int use_armor);
+GpgmeError _gpgme_gpgsm_op_import (GpgsmObject gpgsm, GpgmeData keydata);
+GpgmeError _gpgme_gpgsm_op_keylist (GpgsmObject gpgsm, const char *pattern,
+                                 int secret_only, int keylist_mode);
+GpgmeError _gpgme_gpgsm_op_sign (GpgsmObject gpgsm, GpgmeData in, GpgmeData out,
+                              GpgmeSigMode mode, int use_armor,
+                              int use_textmode, GpgmeCtx ctx /* FIXME */);
+GpgmeError _gpgme_gpgsm_op_trustlist (GpgsmObject gpgsm, const char *pattern);
+GpgmeError _gpgme_gpgsm_op_verify (GpgsmObject gpgsm, GpgmeData sig, GpgmeData text);
+GpgmeError _gpgme_gpgsm_start (GpgsmObject gpgsm, void *opaque);
+
 #endif /* ENGINE_GPGSM_H */
index 29c915047986baa61b148440ab272b418b781e3a..749510582a7527eef055983b2b36960551a3fa52 100644 (file)
@@ -189,7 +189,7 @@ _gpgme_engine_set_status_handler (EngineObject engine,
       _gpgme_gpg_set_status_handler (engine->engine.gpg, fnc, fnc_value);
       break;
     case GPGME_PROTOCOL_CMS:
-      /* FIXME */
+      _gpgme_gpgsm_set_status_handler (engine->engine.gpgsm, fnc, fnc_value);
       break;
     default:
       break;
@@ -428,8 +428,7 @@ _gpgme_engine_op_verify (EngineObject engine, GpgmeData sig, GpgmeData text)
     case GPGME_PROTOCOL_OpenPGP:
       return _gpgme_gpg_op_verify (engine->engine.gpg, sig, text);
     case GPGME_PROTOCOL_CMS:
-      /* FIXME */
-      break;
+      return _gpgme_gpgsm_op_verify (engine->engine.gpgsm, sig, text);
     default:
       break;
     }
@@ -446,8 +445,7 @@ GpgmeError _gpgme_engine_start (EngineObject engine, void *opaque)
     case GPGME_PROTOCOL_OpenPGP:
       return _gpgme_gpg_spawn (engine->engine.gpg, opaque);
     case GPGME_PROTOCOL_CMS:
-      /* FIXME */
-      break;
+      return _gpgme_gpgsm_start (engine->engine.gpgsm, opaque);
     default:
       break;
     }
index 044bcef5c8780000a40c577e0a71ceb90b7c1b02..93103b57bfbd2b38fa71886ba3b1a2c3a7183288 100644 (file)
@@ -59,6 +59,9 @@ GpgmeError    _gpgme_data_append_percentstring_for_xml ( GpgmeData dh,
 GpgmeError    _gpgme_data_unread (GpgmeData dh,
                                   const char *buffer, size_t length );
 
+int _gpgme_data_inbound_handler (void *opaque, int pid, int fd);
+int _gpgme_data_outbound_handler (void *opaque, int pid, int fd);
+
 
 /*-- key.c --*/
 GpgmeError _gpgme_key_new ( GpgmeKey *r_key );
index 940f971b93f0ef6f9a4e40ea5e49490c3457724d..d1c50cc81efeaf76c515052c16b17276572ca6ec 100644 (file)
@@ -132,9 +132,6 @@ DEFINE_STATIC_LOCK (reap_list_lock);
 static void free_argv ( char **argv );
 static void free_fd_data_map ( struct fd_data_map_s *fd_data_map );
 
-static int gpg_inbound_handler ( void *opaque, int pid, int fd );
-static int gpg_outbound_handler ( void *opaque, int pid, int fd );
-
 static int gpg_status_handler ( void *opaque, int pid, int fd );
 static GpgmeError read_status ( GpgObject gpg );
 
@@ -919,7 +916,7 @@ _gpgme_gpg_spawn( GpgObject gpg, void *opaque )
         if ( _gpgme_register_pipe_handler (
                  opaque, 
                  gpg->fd_data_map[i].inbound?
-                       gpg_inbound_handler:gpg_outbound_handler,
+                _gpgme_data_inbound_handler:_gpgme_data_outbound_handler,
                  gpg->fd_data_map[i].data,
                  pid, gpg->fd_data_map[i].fd,
                  gpg->fd_data_map[i].inbound )
@@ -939,135 +936,6 @@ _gpgme_gpg_spawn( GpgObject gpg, void *opaque )
 }
 
 
-static int
-gpg_inbound_handler ( void *opaque, int pid, int fd )
-{
-    GpgmeData dh = opaque;
-    GpgmeError err;
-    int nread;
-    char buf[200];
-
-    assert ( _gpgme_data_get_mode (dh) == GPGME_DATA_MODE_IN );
-
-    nread = _gpgme_io_read (fd, buf, 200 );
-    if ( nread < 0 ) {
-        DEBUG3 ("read_mem_data: read failed on fd %d (n=%d): %s",
-                 fd, nread, strerror (errno) );
-        return 1;
-    }
-    else if (!nread)
-        return 1; /* eof */
-
-    /* We could improve this with a GpgmeData function which takes
-     * the read function or provides a memory area for writing to it.
-     */
-    
-    err = _gpgme_data_append ( dh, buf, nread );
-    if ( err ) {
-        DEBUG1 ("_gpgme_append_data failed: %s\n",
-                 gpgme_strerror(err));
-        /* Fixme: we should close the pipe or read it to /dev/null in
-         * this case. Returnin EOF is not sufficient */
-        return 1;
-    }
-
-    return 0;
-}
-
-
-static int
-write_mem_data ( GpgmeData dh, int fd )
-{
-    size_t nbytes;
-    int  nwritten; 
-
-    nbytes = dh->len - dh->readpos;
-    if ( !nbytes ) {
-        _gpgme_io_close (fd);
-        return 1;
-    }
-    
-    /* FIXME: Arggg, the pipe blocks on large write request, although
-     * select told us that it is okay to write - need to figure out
-     * why this happens?  Stevens says nothing about this problem (or
-     * is it my Linux kernel 2.4.0test1)
-     * To avoid that we have set the pipe to nonblocking.
-     */
-
-    nwritten = _gpgme_io_write ( fd, dh->data+dh->readpos, nbytes );
-    if (nwritten == -1 && errno == EAGAIN )
-        return 0;
-    if ( nwritten < 1 ) {
-        DEBUG3 ("write_mem_data(%d): write failed (n=%d): %s",
-                fd, nwritten, strerror (errno) );
-        _gpgme_io_close (fd);
-        return 1;
-    }
-
-    dh->readpos += nwritten;
-    return 0;
-}
-
-static int
-write_cb_data ( GpgmeData dh, int fd )
-{
-    size_t nbytes;
-    int  err, nwritten; 
-    char buffer[512];
-
-    err = gpgme_data_read ( dh, buffer, DIM(buffer), &nbytes );
-    if (err == GPGME_EOF) {
-        _gpgme_io_close (fd);
-        return 1;
-    }
-    
-    nwritten = _gpgme_io_write ( fd, buffer, nbytes );
-    if (nwritten == -1 && errno == EAGAIN )
-        return 0;
-    if ( nwritten < 1 ) {
-        DEBUG3 ("write_cb_data(%d): write failed (n=%d): %s",
-                fd, nwritten, strerror (errno) );
-        _gpgme_io_close (fd);
-        return 1;
-    }
-
-    if ( nwritten < nbytes ) {
-        /* ugly, ugly: It does currently only for for MEM type data */
-        if ( _gpgme_data_unread (dh, buffer + nwritten, nbytes - nwritten ) )
-            DEBUG1 ("wite_cb_data: unread of %d bytes failed\n",
-                     nbytes - nwritten );
-        _gpgme_io_close (fd);
-        return 1;
-    }
-
-    return 0;
-}
-
-
-static int
-gpg_outbound_handler ( void *opaque, int pid, int fd )
-{
-    GpgmeData dh = opaque;
-
-    assert ( _gpgme_data_get_mode (dh) == GPGME_DATA_MODE_OUT );
-    switch ( gpgme_data_get_type (dh) ) {
-      case GPGME_DATA_TYPE_MEM:
-        if ( write_mem_data ( dh, fd ) )
-            return 1; /* ready */
-        break;
-      case GPGME_DATA_TYPE_CB:
-        if (write_cb_data (dh, fd))
-            return 1; /* ready */
-        break;
-      default:
-        assert (0);
-    }
-
-    return 0;
-}
-
-
-
 static int
 gpg_status_handler ( void *opaque, int pid, int fd )
 {