diff options
| -rw-r--r-- | gpgme/ChangeLog | 35 | ||||
| -rw-r--r-- | gpgme/data.c | 139 | ||||
| -rw-r--r-- | gpgme/engine-gpgsm.c | 233 | ||||
| -rw-r--r-- | gpgme/engine-gpgsm.h | 23 | ||||
| -rw-r--r-- | gpgme/engine.c | 8 | ||||
| -rw-r--r-- | gpgme/ops.h | 3 | ||||
| -rw-r--r-- | gpgme/rungpg.c | 134 | 
7 files changed, 427 insertions, 148 deletions
| diff --git a/gpgme/ChangeLog b/gpgme/ChangeLog index 2ee8f900..d2707521 100644 --- a/gpgme/ChangeLog +++ b/gpgme/ChangeLog @@ -1,3 +1,38 @@ +2001-11-22  Marcus Brinkmann  <[email protected]> + +	* 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  <[email protected]>  	* context.h: Do not include rungpg.h, but engine.h. diff --git a/gpgme/data.c b/gpgme/data.c index 6ba853d8..a17ea1d2 100644 --- a/gpgme/data.c +++ b/gpgme/data.c @@ -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; +} diff --git a/gpgme/engine-gpgsm.c b/gpgme/engine-gpgsm.c index 000ad116..87a00393 100644 --- a/gpgme/engine-gpgsm.c +++ b/gpgme/engine-gpgsm.c @@ -23,13 +23,6 @@  #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 @@ -37,11 +30,50 @@  #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 */ diff --git a/gpgme/engine-gpgsm.h b/gpgme/engine-gpgsm.h index 105405bd..5feada86 100644 --- a/gpgme/engine-gpgsm.h +++ b/gpgme/engine-gpgsm.h @@ -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 */ diff --git a/gpgme/engine.c b/gpgme/engine.c index 29c91504..74951058 100644 --- a/gpgme/engine.c +++ b/gpgme/engine.c @@ -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;      } diff --git a/gpgme/ops.h b/gpgme/ops.h index 044bcef5..93103b57 100644 --- a/gpgme/ops.h +++ b/gpgme/ops.h @@ -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 ); diff --git a/gpgme/rungpg.c b/gpgme/rungpg.c index 940f971b..d1c50cc8 100644 --- a/gpgme/rungpg.c +++ b/gpgme/rungpg.c @@ -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 ) @@ -940,135 +937,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 )  {      GpgObject gpg = opaque; | 
