diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 80 | ||||
| -rw-r--r-- | src/context.h | 2 | ||||
| -rw-r--r-- | src/data.c | 6 | ||||
| -rw-r--r-- | src/engine-assuan.c | 72 | ||||
| -rw-r--r-- | src/engine-backend.h | 6 | ||||
| -rw-r--r-- | src/engine-g13.c | 32 | ||||
| -rw-r--r-- | src/engine-gpg.c | 13 | ||||
| -rw-r--r-- | src/engine-gpgsm.c | 8 | ||||
| -rw-r--r-- | src/engine.c | 20 | ||||
| -rw-r--r-- | src/engine.h | 4 | ||||
| -rw-r--r-- | src/g13.c | 105 | ||||
| -rw-r--r-- | src/gpgme.c | 47 | ||||
| -rw-r--r-- | src/gpgme.def | 6 | ||||
| -rw-r--r-- | src/gpgme.h.in | 92 | ||||
| -rw-r--r-- | src/keylist.c | 2 | ||||
| -rw-r--r-- | src/libgpgme.vers | 7 | ||||
| -rw-r--r-- | src/opassuan.c | 157 | ||||
| -rw-r--r-- | src/ops.h | 7 | ||||
| -rw-r--r-- | src/trustlist.c | 2 | ||||
| -rw-r--r-- | src/wait-global.c | 50 | ||||
| -rw-r--r-- | src/wait-private.c | 52 | ||||
| -rw-r--r-- | src/wait-user.c | 16 | ||||
| -rw-r--r-- | src/wait.c | 14 | ||||
| -rw-r--r-- | src/wait.h | 18 | 
24 files changed, 526 insertions, 292 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index 024c7713..f1ac7b4d 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,85 @@  2009-10-26  Marcus Brinkmann  <[email protected]> +	* gpgme.h.in (struct gpgme_io_event_done_data) +	(gpgme_io_event_done_data_t): New types. +	(struct _gpgme_op_assuan_result): Deprecate the err member. +	(gpgme_op_assuan_result): Deprecate (for now). +	(gpgme_op_assuan_transact_ext): New prototype. +	(gpgme_op_assuan_transact): Deprecate. +	(struct _gpgme_op_g13_result): Replace with ... +	(struct _gpgme_op_vfs_mount_result): ... this. +	(gpgme_op_g13_mount): Replace with ... +	(gpgme_op_vfs_mount): ... this. +	* gpgme.def (gpgme_op_assuan_transact_ext, gpgme_wait_ext) +	(gpgme_op_vfs_mount_result, gpgme_op_vfs_mount): New. +	(gpgme_op_g13_mount): Remove. +	* libgpgme.vers: Likewise. +	* engine-backend.h (struct engine_ops): Remove RESULT_CB and +	RESULT_CB_VALUE args in opassuan_transact member.  Add CANCEL_OP +	member. +	* ops.h (_gpgme_cancel_with_err, _gpgme_wait_on_condition): Add +	OP_ERR argument. +	(_gpgme_wait_one_ext): New prototype. +	* context.h (ctx_op_data_id_t): Add OPDATA_VFS_MOUNT. +	* engine-g13.c (g13_cancel_op): New function. +	(parse_status): Remove declaration. +	(g13_assuan_simple_command): Do nothing with status lines for now. +	(status_handler): Update opaque value access. +	(_gpgme_engine_ops_g13): Add new cancel_op member. +	* gpgme.c (_gpgme_cancel_with_err): Add new parameter OP_ERR. +	Handle operational errors. +	(gpgme_cancel, gpgme_io_read, gpgme_io_write): Add debug output. +	* data.c (_gpgme_data_inbound_handler) +	(_gpgme_data_outbound_handler): Adjust opaque value access. +	* engine-gpg.c (command_handler, status_handler) +	(colon_line_handler): Likewise. +	* engine-gpgsm.c (status_handler): Likewise. +	* engine-gpg.c (_gpgme_engine_ops_gpg): Add cancel_op member. +	* engine-gpgsm.c (_gpgme_engine_ops_gpgsm): Likewise. +	* g13.c: Rewritten (and will be rewritten again). +	* engine.h (_gpgme_engine_op_assuan_transact): Remove result_cb +	and result_cb_value parameters from prototype. +	(_gpgme_engine_cancel_op): New prototype. +	* engine.c (engine_ops) [! ENABLE_ASSUAN]: Add missing comma. +	(_gpgme_engine_op_assuan_transact): Remove result_cb and +	result_cb_value parameter. +	(_gpgme_engine_cancel_op): New function. +	* wait.h (_gpgme_run_io_cb): Add new argument OP_ERR. +	(struct io_cb_data): New struct to pass opaque data and get a +	op_err return value.  Needed because we can't modify I/O callback +	handler signature because it is exposed to the user. +	* wait.c (_gpgme_run_io_cb): Add OP_ERR parameter.  Handle +	operational errors. +	* wait-user.c (_gpgme_user_io_cb_handler): Handle operational +	errors. +	* wait-private.c (_gpgme_wait_on_condition): New argument to +	retrieve the operational result.  Handle operational errors in +	session based protocols. +	(_gpgme_wait_one_ext): New function. +	(_gpgme_wait_one): Pass argument in invocation of +	_gpgme_wait_on_condition. +	* wait-global.c (struct ctx_list_item): Add member OP_ERR. +	(ctx_done): New argument OP_ERR. +	(ctx_wait): New argument OP_ERR. +	(gpgme_wait_ext): New function based on gpgme_wait but handling +	operational errors. +	(gpgme_wait): Implement in term of gpgme_wait_ext. +	* keylist.c (gpgme_op_keylist_next): Pass argument in invocation +	of _gpgme_wait_on_condition. +	* trustlist.c (gpgme_op_trustlist_next): Pass argument in +	invocation of _gpgme_wait_on_condition. +	* engine-assuan.c (struct engine_llass): Replace members RESULT_CB +	and RESULT_CB_VALUE by LAST_OP_ERR. +	(_gpgme_engine_assuan_last_op_err): Add this hack function. +	(llass_cancel_op): New function. +	(_gpgme_engine_llass_ops): Add cancel_op member. +	(llass_status_handler): Update opaque value access. +	(llass_transact): Remove RESULT_CB and RESULT_CB_VALUE arguments. +	* opassuan.c: Move compat hacks to the end of file. +	(opassuan_start): Do not set OPD->result.err. +	Do not pass RESULT_Cb and CTX to _gpgme_engine_op_assuan_transact. +	(gpgme_op_assuan_transact_ext): New function. +  	* debug.h (DEBUG_GLOBAL): New debug level.  	* conversion.c (gnupg_errors, _gpgme_map_gnupg_error): Removed.  	* data-user.c (gpgme_data_new_from_cbs): Add debug output. diff --git a/src/context.h b/src/context.h index e98e7bea..6818e7e4 100644 --- a/src/context.h +++ b/src/context.h @@ -38,7 +38,7 @@ typedef enum    {      OPDATA_DECRYPT, OPDATA_SIGN, OPDATA_ENCRYPT, OPDATA_PASSPHRASE,      OPDATA_IMPORT, OPDATA_GENKEY, OPDATA_KEYLIST, OPDATA_EDIT, -    OPDATA_VERIFY, OPDATA_TRUSTLIST, OPDATA_ASSUAN +    OPDATA_VERIFY, OPDATA_TRUSTLIST, OPDATA_ASSUAN, OPDATA_VFS_MOUNT    } ctx_op_data_id_t; @@ -247,7 +247,8 @@ gpgme_data_get_file_name (gpgme_data_t dh)  gpgme_error_t  _gpgme_data_inbound_handler (void *opaque, int fd)  { -  gpgme_data_t dh = (gpgme_data_t) opaque; +  struct io_cb_data *data = (struct io_cb_data *) opaque; +  gpgme_data_t dh = (gpgme_data_t) data->handler_value;    char buffer[BUFFER_SIZE];    char *bufp = buffer;    ssize_t buflen; @@ -279,7 +280,8 @@ _gpgme_data_inbound_handler (void *opaque, int fd)  gpgme_error_t  _gpgme_data_outbound_handler (void *opaque, int fd)  { -  gpgme_data_t dh = (gpgme_data_t) opaque; +  struct io_cb_data *data = (struct io_cb_data *) opaque; +  gpgme_data_t dh = (gpgme_data_t) data->handler_value;    ssize_t nwritten;    TRACE_BEG1 (DEBUG_CTX, "_gpgme_data_outbound_handler", dh,  	      "fd=0x%x", fd); diff --git a/src/engine-assuan.c b/src/engine-assuan.c index 07a21fa0..92e1e05d 100644 --- a/src/engine-assuan.c +++ b/src/engine-assuan.c @@ -70,9 +70,8 @@ struct engine_llass    struct gpgme_io_cbs io_cbs; -  /* Internal callbacks.  */ -  engine_assuan_result_cb_t result_cb; -  void *result_cb_value;  +  /* Hack for old opassuan.c interface, see there the result struct.  */ +  gpg_error_t last_op_err;    /* User provided callbacks.  */    struct { @@ -95,6 +94,12 @@ struct engine_llass  typedef struct engine_llass *engine_llass_t; +gpg_error_t _gpgme_engine_assuan_last_op_err (void *engine) +{ +  engine_llass_t llass = engine; +  return llass->last_op_err; +} +  /* Prototypes.  */  static void llass_io_event (void *engine, @@ -169,6 +174,21 @@ llass_cancel (void *engine)  } +static gpgme_error_t +llass_cancel_op (void *engine) +{ +  engine_llass_t llass = engine; + +  if (!llass) +    return gpg_error (GPG_ERR_INV_VALUE); + +  if (llass->status_cb.fd != -1) +    _gpgme_io_close (llass->status_cb.fd); + +  return 0; +} + +  static void  llass_release (void *engine)  { @@ -408,8 +428,9 @@ inquire_cb (engine_llass_t llass, const char *keyword, const char *args)  static gpgme_error_t  llass_status_handler (void *opaque, int fd)  { +  struct io_cb_data *data = (struct io_cb_data *) opaque; +  engine_llass_t llass = (engine_llass_t) data->handler_value;    gpgme_error_t err = 0; -  engine_llass_t llass = opaque;    char *line;    size_t linelen; @@ -459,8 +480,6 @@ llass_status_handler (void *opaque, int fd)            if (linelen && llass->user.data_cb)              err = llass->user.data_cb (llass->user.data_cb_value,                                         src, linelen); -          else -            err = 0;            TRACE2 (DEBUG_CTX, "gpgme:llass_status_handler", llass,  		  "fd 0x%x: D inlinedata; status from cb: %s", @@ -474,8 +493,6 @@ llass_status_handler (void *opaque, int fd)            /* END received.  Tell the data callback.  */            if (llass->user.data_cb)              err = llass->user.data_cb (llass->user.data_cb_value, NULL, 0); -          else -            err = 0;            TRACE2 (DEBUG_CTX, "gpgme:llass_status_handler", llass,  		  "fd 0x%x: END line; status from cb: %s", @@ -502,8 +519,6 @@ llass_status_handler (void *opaque, int fd)            if (llass->user.status_cb)              err = llass->user.status_cb (llass->user.status_cb_value,                                           src, args); -          else -            err = 0;            TRACE3 (DEBUG_CTX, "gpgme:llass_status_handler", llass,  		  "fd 0x%x: S line (%s) - status from cb: %s", @@ -554,17 +569,15 @@ llass_status_handler (void *opaque, int fd)            TRACE2 (DEBUG_CTX, "gpgme:llass_status_handler", llass,  		  "fd 0x%x: ERR line: %s",                    fd, err ? gpg_strerror (err) : "ok"); +  	  /* Command execution errors are not fatal, as we use  	     a session based protocol.  */ -          if (llass->result_cb) -            err = llass->result_cb (llass->result_cb_value, err); -          else -            err = 0; -          if (!err) -            { -              _gpgme_io_close (llass->status_cb.fd); -              return 0; -            } +	  data->op_err = err; +	  llass->last_op_err = err; + +	  /* The caller will do the rest (namely, call cancel_op, +	     which closes status_fd).  */ +	  return 0;  	}        else if (linelen >= 2  	       && line[0] == 'O' && line[1] == 'K' @@ -572,15 +585,11 @@ llass_status_handler (void *opaque, int fd)  	{            TRACE1 (DEBUG_CTX, "gpgme:llass_status_handler", llass,  		  "fd 0x%x: OK line", fd); -          if (llass->result_cb) -            err = llass->result_cb (llass->result_cb_value, 0); -          else -            err = 0; -          if (!err) -            { -              _gpgme_io_close (llass->status_cb.fd); -              return 0; -            } + +	  llass->last_op_err = 0; + +	  _gpgme_io_close (llass->status_cb.fd); +	  return 0;  	}        else          { @@ -667,8 +676,6 @@ start (engine_llass_t llass, const char *command)  static gpgme_error_t  llass_transact (void *engine,                  const char *command, -                engine_assuan_result_cb_t result_cb, -                void *result_cb_value,                  gpgme_assuan_data_cb_t data_cb,                  void *data_cb_value,                  gpgme_assuan_inquire_cb_t inq_cb, @@ -682,8 +689,6 @@ llass_transact (void *engine,    if (!llass || !command || !*command)      return gpg_error (GPG_ERR_INV_VALUE); -  llass->result_cb = result_cb; -  llass->result_cb_value = result_cb_value;    llass->user.data_cb = data_cb;    llass->user.data_cb_value = data_cb_value;    llass->user.inq_cb = inq_cb; @@ -754,5 +759,6 @@ struct engine_ops _gpgme_engine_ops_assuan =      NULL,		/* conf_save */      llass_set_io_cbs,      llass_io_event, -    llass_cancel +    llass_cancel, +    llass_cancel_op    }; diff --git a/src/engine-backend.h b/src/engine-backend.h index fa539a3f..bb938d0f 100644 --- a/src/engine-backend.h +++ b/src/engine-backend.h @@ -98,8 +98,6 @@ struct engine_ops                                   unsigned int flags);    gpgme_error_t  (*opassuan_transact) (void *engine,                                          const char *command, -                                       engine_assuan_result_cb_t result_cb, -                                       void *result_cb_value,                                         gpgme_assuan_data_cb_t data_cb,                                         void *data_cb_value,                                         gpgme_assuan_inquire_cb_t inq_cb, @@ -113,7 +111,11 @@ struct engine_ops    void (*set_io_cbs) (void *engine, gpgme_io_cbs_t io_cbs);    void (*io_event) (void *engine, gpgme_event_io_t type, void *type_data); +  /* Cancel the whole engine session.  */    gpgme_error_t (*cancel) (void *engine); + +  /* Cancel only the current operation, not the whole session.  */ +  gpgme_error_t (*cancel_op) (void *engine);  }; diff --git a/src/engine-g13.c b/src/engine-g13.c index f957691a..358efc17 100644 --- a/src/engine-g13.c +++ b/src/engine-g13.c @@ -180,6 +180,21 @@ g13_cancel (void *engine)  } +static gpgme_error_t +g13_cancel_op (void *engine) +{ +  engine_g13_t g13 = engine; + +  if (!g13) +    return gpg_error (GPG_ERR_INV_VALUE); + +  if (g13->status_cb.fd != -1) +    _gpgme_io_close (g13->status_cb.fd); + +  return 0; +} + +  static void  g13_release (void *engine)  { @@ -385,9 +400,6 @@ g13_set_locale (void *engine, int category, const char *value)  } -/* Forward declaration.  */ -static gpgme_status_code_t parse_status (const char *name); -  static gpgme_error_t  g13_assuan_simple_command (assuan_context_t ctx, char *cmd,  			     engine_status_handler_t status_fnc, @@ -422,7 +434,6 @@ g13_assuan_simple_command (assuan_context_t ctx, char *cmd,  	       && line[0] == 'S' && line[1] == ' ')  	{  	  char *rest; -	  gpgme_status_code_t r;  	  rest = strchr (line + 2, ' ');  	  if (!rest) @@ -430,12 +441,7 @@ g13_assuan_simple_command (assuan_context_t ctx, char *cmd,  	  else  	    *(rest++) = 0; -	  r = parse_status (line + 2); - -	  if (r >= 0 && status_fnc) -	    err = status_fnc (status_fnc_value, r, rest); -	  else -	    err = gpg_error (GPG_ERR_GENERAL); +	  /* Nothing to do with status lines.  */  	}        else  	err = gpg_error (GPG_ERR_GENERAL); @@ -449,8 +455,9 @@ g13_assuan_simple_command (assuan_context_t ctx, char *cmd,  static gpgme_error_t  status_handler (void *opaque, int fd)  { +  struct io_cb_data *data = (struct io_cb_data *) opaque; +  engine_g13_t g13 = (engine_g13_t) data->handler_value;    gpgme_error_t err = 0; -  engine_g13_t g13 = opaque;    char *line;    size_t linelen; @@ -792,5 +799,6 @@ struct engine_ops _gpgme_engine_ops_g13 =      NULL,		/* conf_save */      g13_set_io_cbs,      g13_io_event, -    g13_cancel +    g13_cancel, +    g13_cancel_op,    }; diff --git a/src/engine-gpg.c b/src/engine-gpg.c index dba49a9c..6d6ec47c 100644 --- a/src/engine-gpg.c +++ b/src/engine-gpg.c @@ -646,10 +646,10 @@ gpg_set_colon_line_handler (void *engine, engine_colon_line_handler_t fnc,  static gpgme_error_t  command_handler (void *opaque, int fd)  { +  struct io_cb_data *data = (struct io_cb_data *) opaque; +  engine_gpg_t gpg = (engine_gpg_t) data->handler_value;    gpgme_error_t err; -  engine_gpg_t gpg = (engine_gpg_t) opaque;    int processed = 0; -    assert (gpg->cmd.used);    assert (gpg->cmd.code);    assert (gpg->cmd.fnc); @@ -1139,7 +1139,8 @@ read_status (engine_gpg_t gpg)  static gpgme_error_t  status_handler (void *opaque, int fd)  { -  engine_gpg_t gpg = opaque; +  struct io_cb_data *data = (struct io_cb_data *) opaque; +  engine_gpg_t gpg = (engine_gpg_t) data->handler_value;    int err;    assert (fd == gpg->status.fd[0]); @@ -1246,7 +1247,8 @@ read_colon_line (engine_gpg_t gpg)  static gpgme_error_t  colon_line_handler (void *opaque, int fd)  { -  engine_gpg_t gpg = opaque; +  struct io_cb_data *data = (struct io_cb_data *) opaque; +  engine_gpg_t gpg = (engine_gpg_t) data->handler_value;    gpgme_error_t rc = 0;    assert (fd == gpg->colon.fd[0]); @@ -2365,5 +2367,6 @@ struct engine_ops _gpgme_engine_ops_gpg =      NULL,		/* conf_save */      gpg_set_io_cbs,      gpg_io_event, -    gpg_cancel +    gpg_cancel, +    NULL		/* cancel_op */    }; diff --git a/src/engine-gpgsm.c b/src/engine-gpgsm.c index 1d25190a..04f49ed9 100644 --- a/src/engine-gpgsm.c +++ b/src/engine-gpgsm.c @@ -761,8 +761,9 @@ parse_status (const char *name)  static gpgme_error_t  status_handler (void *opaque, int fd)  { +  struct io_cb_data *data = (struct io_cb_data *) opaque; +  engine_gpgsm_t gpgsm = (engine_gpgsm_t) data->handler_value;    gpgme_error_t err = 0; -  engine_gpgsm_t gpgsm = opaque;    char *line;    size_t linelen; @@ -799,7 +800,7 @@ status_handler (void *opaque, int fd)  	    err = gpgsm->status.fnc (gpgsm->status.fnc_value,  				     GPGME_STATUS_EOF, ""); -	  if (!err && gpgsm->colon.fnc && gpgsm->colon.any ) +	  if (!err && gpgsm->colon.fnc && gpgsm->colon.any)              {                /* We must tell a colon function about the EOF. We do                   this only when we have seen any data lines.  Note @@ -1939,5 +1940,6 @@ struct engine_ops _gpgme_engine_ops_gpgsm =      NULL,		/* conf_save */      gpgsm_set_io_cbs,      gpgsm_io_event, -    gpgsm_cancel +    gpgsm_cancel, +    NULL		/* cancel_op */    }; diff --git a/src/engine.c b/src/engine.c index b1d815ac..69128592 100644 --- a/src/engine.c +++ b/src/engine.c @@ -58,7 +58,7 @@ static struct engine_ops *engine_ops[] =  #ifdef ENABLE_ASSUAN      &_gpgme_engine_ops_assuan,		/* Low-Level Assuan.  */  #else -    NULL +    NULL,  #endif  #ifdef ENABLE_G13      &_gpgme_engine_ops_g13		/* Crypto VFS.  */ @@ -777,8 +777,6 @@ _gpgme_engine_op_getauditlog (engine_t engine, gpgme_data_t output,  gpgme_error_t  _gpgme_engine_op_assuan_transact (engine_t engine,                                     const char *command, -                                  engine_assuan_result_cb_t result_cb, -                                  void *result_cb_value,                                    gpgme_assuan_data_cb_t data_cb,                                    void *data_cb_value,                                    gpgme_assuan_inquire_cb_t inq_cb, @@ -794,7 +792,6 @@ _gpgme_engine_op_assuan_transact (engine_t engine,    return (*engine->ops->opassuan_transact) (engine->engine,                                               command, -                                            result_cb, result_cb_value,                                              data_cb, data_cb_value,                                              inq_cb, inq_cb_value,                                              status_cb, status_cb_value); @@ -848,6 +845,7 @@ _gpgme_engine_io_event (engine_t engine,  } +/* Cancel the session and the pending operation if any.  */  gpgme_error_t  _gpgme_engine_cancel (engine_t engine)  { @@ -859,3 +857,17 @@ _gpgme_engine_cancel (engine_t engine)    return (*engine->ops->cancel) (engine->engine);  } + + +/* Cancel the pending operation, but not the complete session.  */ +gpgme_error_t +_gpgme_engine_cancel_op (engine_t engine) +{ +  if (!engine) +    return gpg_error (GPG_ERR_INV_VALUE); + +  if (!engine->ops->cancel_op) +    return 0; + +  return (*engine->ops->cancel_op) (engine->engine); +} diff --git a/src/engine.h b/src/engine.h index ca746c8a..86a3d422 100644 --- a/src/engine.h +++ b/src/engine.h @@ -133,8 +133,6 @@ gpgme_error_t _gpgme_engine_op_getauditlog (engine_t engine,  gpgme_error_t _gpgme_engine_op_assuan_transact                   (engine_t engine,                    const char *command, -                 engine_assuan_result_cb_t result_cb, -                 void *result_cb_value,                   gpgme_assuan_data_cb_t data_cb,                   void *data_cb_value,                   gpgme_assuan_inquire_cb_t inq_cb, @@ -154,4 +152,6 @@ void _gpgme_engine_io_event (engine_t engine,  gpgme_error_t _gpgme_engine_cancel (engine_t engine); +gpgme_error_t _gpgme_engine_cancel_op (engine_t engine); +  #endif /* ENGINE_H */ @@ -31,41 +31,19 @@  typedef struct  { -  struct _gpgme_op_g13_result result; +  struct _gpgme_op_vfs_mount_result result;  } *op_data_t; -/* This callback is used to return the status of the assuan command -   back rather than transmission errors.  */ -static gpgme_error_t -result_cb (void *priv, gpgme_error_t result) -{ -  gpgme_ctx_t ctx = (gpgme_ctx_t)priv; -  gpgme_error_t err; -  void *hook; -  op_data_t opd; - -  err = _gpgme_op_data_lookup (ctx, OPDATA_ASSUAN, &hook, -1, NULL); -  opd = hook; -  if (err) -    return err; -  if (!opd) -    return gpg_error (GPG_ERR_INTERNAL); - -  opd->result.err = result; -  return 0; -} - - -gpgme_g13_result_t -gpgme_op_g13_result (gpgme_ctx_t ctx) +gpgme_vfs_mount_result_t +gpgme_op_vfs_mount_result (gpgme_ctx_t ctx)  {    gpgme_error_t err;    void *hook;    op_data_t opd; -  err = _gpgme_op_data_lookup (ctx, OPDATA_ASSUAN, &hook, -1, NULL); +  err = _gpgme_op_data_lookup (ctx, OPDATA_VFS_MOUNT, &hook, -1, NULL);    opd = hook;    /* Check in case this function is used without having run a command       before.  */ @@ -77,14 +55,14 @@ gpgme_op_g13_result (gpgme_ctx_t ctx)  static gpgme_error_t -opg13_start (gpgme_ctx_t ctx, int synchronous, -                const char *command, -                gpgme_assuan_data_cb_t data_cb, -                void *data_cb_value, -                gpgme_assuan_inquire_cb_t inq_cb, -                void *inq_cb_value, -                gpgme_assuan_status_cb_t status_cb, -                void *status_cb_value) +vfs_start (gpgme_ctx_t ctx, int synchronous, +	   const char *command, +	   gpgme_assuan_data_cb_t data_cb, +	   void *data_cb_value, +	   gpgme_assuan_inquire_cb_t inq_cb, +	   void *inq_cb_value, +	   gpgme_assuan_status_cb_t status_cb, +	   void *status_cb_value)  {    gpgme_error_t err;    void *hook; @@ -99,14 +77,13 @@ opg13_start (gpgme_ctx_t ctx, int synchronous,    if (err)      return err; -  err = _gpgme_op_data_lookup (ctx, OPDATA_ASSUAN, &hook, sizeof (*opd), NULL); +  err = _gpgme_op_data_lookup (ctx, OPDATA_VFS_MOUNT, &hook, sizeof (*opd), +			       NULL);    opd = hook;    if (err)      return err; -  opd->result.err = gpg_error (GPG_ERR_UNFINISHED);    return _gpgme_engine_op_assuan_transact (ctx->engine, command, -					   result_cb, ctx,  					   data_cb, data_cb_value,  					   inq_cb, inq_cb_value,  					   status_cb, status_cb_value); @@ -116,7 +93,7 @@ opg13_start (gpgme_ctx_t ctx, int synchronous,  /* XXXX.  This is the asynchronous variant. */  static gpgme_error_t -gpgme_op_g13_transact_start (gpgme_ctx_t ctx,  +gpgme_op_vfs_transact_start (gpgme_ctx_t ctx,   			     const char *command,  			     gpgme_assuan_data_cb_t data_cb,  			     void *data_cb_value, @@ -125,59 +102,52 @@ gpgme_op_g13_transact_start (gpgme_ctx_t ctx,  			     gpgme_assuan_status_cb_t status_cb,  			     void *status_cb_value)  { -  return opg13_start (ctx, 0, command, data_cb, data_cb_value, -		      inq_cb, inq_cb_value, status_cb, status_cb_value); +  return vfs_start (ctx, 0, command, data_cb, data_cb_value, +		    inq_cb, inq_cb_value, status_cb, status_cb_value);  }  /* XXXX.  This is the synchronous variant. */  static gpgme_error_t -gpgme_op_g13_transact (gpgme_ctx_t ctx, +gpgme_op_vfs_transact (gpgme_ctx_t ctx,  		       const char *command,  		       gpgme_assuan_data_cb_t data_cb,  		       void *data_cb_value,  		       gpgme_assuan_inquire_cb_t inq_cb,  		       void *inq_cb_value,  		       gpgme_assuan_status_cb_t status_cb, -		       void *status_cb_value) +		       void *status_cb_value, +		       gpgme_error_t *op_err)  {    gpgme_error_t err; -  err = opg13_start (ctx, 1, command, data_cb, data_cb_value, -		     inq_cb, inq_cb_value, status_cb, status_cb_value); +  err = vfs_start (ctx, 1, command, data_cb, data_cb_value, +		   inq_cb, inq_cb_value, status_cb, status_cb_value);    if (!err) -    err = _gpgme_wait_one (ctx); +    err = _gpgme_wait_one_ext (ctx, op_err);    return err;  }  /* The actual exported interface follows.  */ -static gpg_error_t -get_err (gpgme_ctx_t ctx) -{ -  gpgme_g13_result_t res; - -  res = gpgme_op_g13_result (ctx); -  if (! res) -    return gpg_error (GPG_ERR_GENERAL); - -  return res->err; -} - -  /* The container is automatically unmounted when the context is reset     or destroyed.  This is a synchronous convenience interface, which     automatically returns an operation error if there is no     transmission error.  */  gpgme_error_t -gpgme_op_g13_mount (gpgme_ctx_t ctx, const char *container_file, -		    const char *mount_dir, int flags) +gpgme_op_vfs_mount (gpgme_ctx_t ctx, const char *container_file, +		    const char *mount_dir, int flags, gpgme_error_t *op_err)  {    gpg_error_t err;    char *cmd;    char *container_file_esc = NULL; -   + +  /* We want to encourage people to check error values, so not getting +     them is discouraged here.  Also makes our code easier.  */ +  if (! op_err) +    return gpg_error (GPG_ERR_INV_VALUE); +    err = _gpgme_encode_percent_string (container_file, &container_file_esc, 0);    if (err)      return err; @@ -190,11 +160,10 @@ gpgme_op_g13_mount (gpgme_ctx_t ctx, const char *container_file,      }    free (container_file_esc); -  err = gpgme_op_g13_transact (ctx, cmd, NULL, NULL, NULL, NULL, -			       NULL, NULL); +  err = gpgme_op_vfs_transact (ctx, cmd, NULL, NULL, NULL, NULL, +			       NULL, NULL, op_err);    free (cmd); -  err = err || get_err (ctx); -  if (err) +  if (err || *op_err)      return err;    if (mount_dir) @@ -219,11 +188,9 @@ gpgme_op_g13_mount (gpgme_ctx_t ctx, const char *container_file,  	return gpg_error_from_syserror ();      } -  err = gpgme_op_g13_transact (ctx, cmd, NULL, NULL, NULL, NULL, -			       NULL, NULL); +  err = gpgme_op_vfs_transact (ctx, cmd, NULL, NULL, NULL, NULL, +			       NULL, NULL, op_err);    free (cmd); -  /* Note: in symmetry with the asynchronous variant, we don't return  -     the error in the result structure here, if any.  */    return err;  } diff --git a/src/gpgme.c b/src/gpgme.c index 071b394c..52e14d7c 100644 --- a/src/gpgme.c +++ b/src/gpgme.c @@ -46,7 +46,7 @@ static char *def_lc_messages;  gpgme_error_t _gpgme_selftest = GPG_ERR_NOT_OPERATIONAL;  /* Protects all reference counters in result structures.  All other -   accesses to a key are read only.  */ +   accesses to a result structure are read only.  */  DEFINE_STATIC_LOCK (result_ref_lock); @@ -118,17 +118,32 @@ gpgme_new (gpgme_ctx_t *r_ctx)  gpgme_error_t -_gpgme_cancel_with_err (gpgme_ctx_t ctx, gpg_error_t ctx_err) +_gpgme_cancel_with_err (gpgme_ctx_t ctx, gpg_error_t ctx_err, +			gpg_error_t op_err)  {    gpgme_error_t err; -  TRACE_BEG1 (DEBUG_CTX, "_gpgme_cancel_with_err", ctx, "ctx_err=%i", -	      ctx_err); +  struct gpgme_io_event_done_data data; -  err = _gpgme_engine_cancel (ctx->engine); -  if (err) -    return TRACE_ERR (err); +  TRACE_BEG2 (DEBUG_CTX, "_gpgme_cancel_with_err", ctx, "ctx_err=%i, op_err=%i", +	      ctx_err, op_err); -  _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_DONE, &ctx_err); +  if (ctx_err) +    { +      err = _gpgme_engine_cancel (ctx->engine); +      if (err) +	return TRACE_ERR (err); +    } +  else +    { +      err = _gpgme_engine_cancel_op (ctx->engine); +      if (err) +	return TRACE_ERR (err); +    } + +  data.err = ctx_err; +  data.op_err = op_err; + +  _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_DONE, &data);    return TRACE_ERR (0);  } @@ -138,7 +153,13 @@ _gpgme_cancel_with_err (gpgme_ctx_t ctx, gpg_error_t ctx_err)  gpgme_error_t  gpgme_cancel (gpgme_ctx_t ctx)  { -  return _gpgme_cancel_with_err (ctx, gpg_error (GPG_ERR_CANCELED)); +  gpg_error_t err; + +  TRACE_BEG (DEBUG_CTX, "gpgme_cancel", ctx); + +  err = _gpgme_cancel_with_err (ctx, gpg_error (GPG_ERR_CANCELED), 0); + +  return TRACE_ERR (err);  } @@ -486,10 +507,12 @@ ssize_t  gpgme_io_read (int fd, void *buffer, size_t count)  {    int ret; +  TRACE_BEG2 (DEBUG_GLOBAL, "gpgme_io_read", fd, +	      "buffer=%p, count=%u", buffer, count);    ret = _gpgme_io_read (fd, buffer, count); -  return ret; +  return TRACE_SYSRES (ret);  } @@ -500,10 +523,12 @@ ssize_t  gpgme_io_write (int fd, const void *buffer, size_t count)  {    int ret; +  TRACE_BEG2 (DEBUG_GLOBAL, "gpgme_io_write", fd, +	      "buffer=%p, count=%u", buffer, count);    ret = _gpgme_io_write (fd, buffer, count); -  return ret; +  return TRACE_SYSRES (ret);  } diff --git a/src/gpgme.def b/src/gpgme.def index 5089a275..6d223f4d 100644 --- a/src/gpgme.def +++ b/src/gpgme.def @@ -185,7 +185,11 @@ EXPORTS      gpgme_op_export_keys                  @142      gpgme_op_export_keys_start            @143 -    gpgme_op_g13_mount			  @144 +    gpgme_op_assuan_transact_ext	  @144 + +    gpgme_wait_ext			  @145 +    gpgme_op_vfs_mount_result		  @146 +    gpgme_op_vfs_mount			  @147  ; END diff --git a/src/gpgme.h.in b/src/gpgme.h.in index 45f5c128..42b9237f 100644 --- a/src/gpgme.h.in +++ b/src/gpgme.h.in @@ -960,6 +960,17 @@ typedef enum    }  gpgme_event_io_t; +struct gpgme_io_event_done_data +{ +  /* A fatal IPC error or an operational error in state-less +     protocols.  */ +  gpgme_error_t err; + +  /* An operational errors in session-based protocols.  */ +  gpgme_error_t op_err; +}; +typedef struct gpgme_io_event_done_data *gpgme_io_event_done_data_t; +  /* The type of a function that is called when a context finished an     operation.  */  typedef void (*gpgme_event_io_cb_t) (void *data, gpgme_event_io_t type, @@ -990,6 +1001,9 @@ ssize_t gpgme_io_write (int fd, const void *buffer, size_t count);     the pending operation to finish.  */  gpgme_ctx_t gpgme_wait (gpgme_ctx_t ctx, gpgme_error_t *status, int hang); +gpgme_ctx_t gpgme_wait_ext (gpgme_ctx_t ctx, gpgme_error_t *status, +			    gpgme_error_t *op_err, int hang); +  /* Functions to handle data objects.  */ @@ -1733,21 +1747,6 @@ typedef gpgme_error_t (*gpgme_assuan_inquire_cb_t)  typedef gpgme_error_t (*gpgme_assuan_status_cb_t)       (void *opaque, const char *status, const char *args); -struct _gpgme_op_assuan_result -{ -  /* The result of the actual assuan command.  An OK is indicated by a -     value of 0 and an ERR by the respective error error value.  This -     is required because assuan operations use a session-based -     interface.  The error code of the GPGME function calls just -     reflects transmission errors.  */ -  gpgme_error_t err; -}; -typedef struct _gpgme_op_assuan_result *gpgme_assuan_result_t; - - -/* Return the result of the last Assuan command. */ -gpgme_assuan_result_t gpgme_op_assuan_result (gpgme_ctx_t ctx); -  /* Send the Assuan COMMAND and return results via the callbacks.     Asynchronous variant. */  gpgme_error_t gpgme_op_assuan_transact_start (gpgme_ctx_t ctx,  @@ -1761,35 +1760,56 @@ gpgme_error_t gpgme_op_assuan_transact_start (gpgme_ctx_t ctx,  /* Send the Assuan COMMAND and return results via the callbacks.     Synchronous variant. */ -gpgme_error_t gpgme_op_assuan_transact (gpgme_ctx_t ctx,  -                                        const char *command, -                                        gpgme_assuan_data_cb_t data_cb, -                                        void *data_cb_value, -                                        gpgme_assuan_inquire_cb_t inq_cb, -                                        void *inq_cb_value, -                                        gpgme_assuan_status_cb_t stat_cb, -                                        void *stat_cb_value); +gpgme_error_t gpgme_op_assuan_transact_ext (gpgme_ctx_t ctx,  +					    const char *command, +					    gpgme_assuan_data_cb_t data_cb, +					    void *data_cb_value, +					    gpgme_assuan_inquire_cb_t inq_cb, +					    void *inq_cb_value, +					    gpgme_assuan_status_cb_t stat_cb, +					    void *stat_cb_value, +					    gpgme_error_t *op_err); + +/* Compat.  */ +struct _gpgme_op_assuan_result +{ +  /* Deprecated.  Use the second value in a DONE event or the +     synchronous variant gpgme_op_assuan_transact_ext.  */ +  gpgme_error_t err _GPGME_DEPRECATED_OUTSIDE_GPGME; +}; +typedef struct _gpgme_op_assuan_result *gpgme_assuan_result_t; + +/* Return the result of the last Assuan command. */ +gpgme_assuan_result_t gpgme_op_assuan_result (gpgme_ctx_t ctx) +  _GPGME_DEPRECATED; + +gpgme_error_t +gpgme_op_assuan_transact (gpgme_ctx_t ctx, +			      const char *command, +			      gpgme_assuan_data_cb_t data_cb, +			      void *data_cb_value, +			      gpgme_assuan_inquire_cb_t inq_cb, +			      void *inq_cb_value, +			      gpgme_assuan_status_cb_t status_cb, +			      void *status_cb_value) _GPGME_DEPRECATED;  /* Crypto container support.  */ -struct _gpgme_op_g13_result +struct _gpgme_op_vfs_mount_result  { -  /* The result of the actual assuan command.  An OK is indicated by a -     value of 0 and an ERR by the respective error error value.  This -     is required because assuan operations use a session-based -     interface.  The error code of the GPGME function calls just -     reflects transmission errors.  */ -  gpgme_error_t err; +  char *mount_dir;  }; -typedef struct _gpgme_op_g13_result *gpgme_g13_result_t; +typedef struct _gpgme_op_vfs_mount_result *gpgme_vfs_mount_result_t; + +gpgme_vfs_mount_result_t gpgme_op_vfs_mount_result (gpgme_ctx_t ctx);  /* The container is automatically unmounted when the context is reset -   or destroyed.  This is a synchronous convenience interface, which -   automatically returns an operation error if there is no -   transmission error.  */ -gpgme_error_t gpgme_op_g13_mount (gpgme_ctx_t ctx, const char *container_file, -				  const char *mount_dir, int flags); +   or destroyed.  Transmission errors are returned directly, +   operational errors are returned in OP_ERR.  */ +gpgme_error_t gpgme_op_vfs_mount (gpgme_ctx_t ctx, const char *container_file, +				  const char *mount_dir, int flags, +				  gpgme_error_t *op_err);  /* Interface to gpgconf(1).  */ diff --git a/src/keylist.c b/src/keylist.c index 55351ee4..926b7623 100644 --- a/src/keylist.c +++ b/src/keylist.c @@ -928,7 +928,7 @@ gpgme_op_keylist_next (gpgme_ctx_t ctx, gpgme_key_t *r_key)    if (!opd->key_queue)      { -      err = _gpgme_wait_on_condition (ctx, &opd->key_cond); +      err = _gpgme_wait_on_condition (ctx, &opd->key_cond, NULL);        if (err)  	return err; diff --git a/src/libgpgme.vers b/src/libgpgme.vers index 7f65d6e6..9989c75b 100644 --- a/src/libgpgme.vers +++ b/src/libgpgme.vers @@ -65,7 +65,12 @@ GPGME_1.1 {      gpgme_op_export_keys;      gpgme_op_export_keys_start; -    gpgme_op_g13_mount; +    gpgme_op_assuan_transact_ext; + +    gpgme_wait_ext; + +    gpgme_op_vfs_mount_result; +    gpgme_op_vfs_mount;  }; diff --git a/src/opassuan.c b/src/opassuan.c index 09f69ee8..2db9f6cf 100644 --- a/src/opassuan.c +++ b/src/opassuan.c @@ -26,58 +26,6 @@  #include "ops.h"  #include "util.h" - -typedef struct -{ -  struct _gpgme_op_assuan_result result; - -} *op_data_t; - - - - -/* This callback is used to return the status of the assuan command -   back.  Note that this is different from the error code returned -   from gpgme_op_assuan_transact because the later only reflects error -   with the connection.  */ -static gpgme_error_t -result_cb (void *priv, gpgme_error_t result) -{ -  gpgme_ctx_t ctx = (gpgme_ctx_t)priv; -  gpgme_error_t err; -  void *hook; -  op_data_t opd; - -  err = _gpgme_op_data_lookup (ctx, OPDATA_ASSUAN, &hook, -1, NULL); -  opd = hook; -  if (err) -    return err; -  if (!opd) -    return gpg_error (GPG_ERR_INTERNAL); - -  opd->result.err = result; -  return 0; -} - - -gpgme_assuan_result_t -gpgme_op_assuan_result (gpgme_ctx_t ctx) -{ -  gpgme_error_t err; -  void *hook; -  op_data_t opd; - -  err = _gpgme_op_data_lookup (ctx, OPDATA_ASSUAN, &hook, -1, NULL); -  opd = hook; -  /* Check in case this function is used without having run a command -     before.  */ -  if (err || !opd) -    return NULL; - -  return &opd->result; -} - -  static gpgme_error_t  opassuan_start (gpgme_ctx_t ctx, int synchronous,                  const char *command, @@ -89,8 +37,6 @@ opassuan_start (gpgme_ctx_t ctx, int synchronous,                  void *status_cb_value)  {    gpgme_error_t err; -  void *hook; -  op_data_t opd;    if (!command || !*command)      return gpg_error (GPG_ERR_INV_VALUE); @@ -101,14 +47,7 @@ opassuan_start (gpgme_ctx_t ctx, int synchronous,    if (err)      return err; -  err = _gpgme_op_data_lookup (ctx, OPDATA_ASSUAN, &hook, sizeof (*opd), NULL); -  opd = hook; -  if (err) -    return err; -  opd->result.err = gpg_error (GPG_ERR_UNFINISHED); -    return _gpgme_engine_op_assuan_transact (ctx->engine, command, -                                           result_cb, ctx,                                             data_cb, data_cb_value,                                             inq_cb, inq_cb_value,                                             status_cb, status_cb_value); @@ -119,13 +58,13 @@ opassuan_start (gpgme_ctx_t ctx, int synchronous,  /* XXXX.  This is the asynchronous variant. */  gpgme_error_t  gpgme_op_assuan_transact_start (gpgme_ctx_t ctx,  -                                const char *command, -                                gpgme_assuan_data_cb_t data_cb, -                                void *data_cb_value, -                                gpgme_assuan_inquire_cb_t inq_cb, -                                void *inq_cb_value, -                                gpgme_assuan_status_cb_t status_cb, -                                void *status_cb_value) +				const char *command, +				gpgme_assuan_data_cb_t data_cb, +				void *data_cb_value, +				gpgme_assuan_inquire_cb_t inq_cb, +				void *inq_cb_value, +				gpgme_assuan_status_cb_t status_cb, +				void *status_cb_value)  {    return opassuan_start (ctx, 0, command,                            data_cb, data_cb_value, @@ -136,14 +75,15 @@ gpgme_op_assuan_transact_start (gpgme_ctx_t ctx,  /* XXXX.  This is the synchronous variant. */  gpgme_error_t -gpgme_op_assuan_transact (gpgme_ctx_t ctx, -                          const char *command, -                          gpgme_assuan_data_cb_t data_cb, -                          void *data_cb_value, -                          gpgme_assuan_inquire_cb_t inq_cb, -                          void *inq_cb_value, -                          gpgme_assuan_status_cb_t status_cb, -                          void *status_cb_value) +gpgme_op_assuan_transact_ext (gpgme_ctx_t ctx, +			      const char *command, +			      gpgme_assuan_data_cb_t data_cb, +			      void *data_cb_value, +			      gpgme_assuan_inquire_cb_t inq_cb, +			      void *inq_cb_value, +			      gpgme_assuan_status_cb_t status_cb, +			      void *status_cb_value, +			      gpgme_error_t *op_err)  {    gpgme_error_t err; @@ -152,7 +92,70 @@ gpgme_op_assuan_transact (gpgme_ctx_t ctx,                          inq_cb, inq_cb_value,                          status_cb, status_cb_value);    if (!err) -    err = _gpgme_wait_one (ctx); +    err = _gpgme_wait_one_ext (ctx, op_err);    return err;  } + + + +/* Compatibility code for old interface.  */ + +/* Evil hack breaking abstractions for the purpose of localizing our +   other hack.  This is copied from engine.c.  */ +struct engine +{ +  struct engine_ops *ops; +  void *engine; +}; + +typedef struct +{ +  struct _gpgme_op_assuan_result result; +} *op_data_t; + +gpg_error_t _gpgme_engine_assuan_last_op_err (void *engine); + +gpgme_assuan_result_t +gpgme_op_assuan_result (gpgme_ctx_t ctx) +{ +  gpgme_error_t err; +  void *hook; +  op_data_t opd; + +  err = _gpgme_op_data_lookup (ctx, OPDATA_ASSUAN, &hook, -1, NULL); +  opd = hook; +  /* Check in case this function is used without having run a command +     before.  */ +  if (err || !opd) +    return NULL; + +  /* All of this is a hack for the old style interface.  The new style +     interface returns op errors directly.  */ +  opd->result.err = _gpgme_engine_assuan_last_op_err (ctx->engine->engine); + +  return &opd->result; +} + + +gpgme_error_t +gpgme_op_assuan_transact (gpgme_ctx_t ctx, +			  const char *command, +			  gpgme_assuan_data_cb_t data_cb, +			  void *data_cb_value, +			  gpgme_assuan_inquire_cb_t inq_cb, +			  void *inq_cb_value, +			  gpgme_assuan_status_cb_t status_cb, +			  void *status_cb_value) +{ +  gpgme_error_t op_err; +  gpgme_error_t err; + +  /* Users of the old-style session based interfaces need to look at +     the result structure.  */ +  gpgme_op_assuan_transact_ext (ctx, command, data_cb, data_cb_value, +				inq_cb, inq_cb_value, +				status_cb, status_cb_value, &op_err); + +  return err; +} @@ -27,14 +27,17 @@  /* From gpgme.c.  */ -gpgme_error_t _gpgme_cancel_with_err (gpgme_ctx_t ctx, gpg_error_t ctx_err); +gpgme_error_t _gpgme_cancel_with_err (gpgme_ctx_t ctx, gpg_error_t ctx_err, +				      gpg_error_t op_err);  void _gpgme_release_result (gpgme_ctx_t ctx);  /* From wait.c.  */  gpgme_error_t _gpgme_wait_one (gpgme_ctx_t ctx); -gpgme_error_t _gpgme_wait_on_condition (gpgme_ctx_t ctx, volatile int *cond); +gpgme_error_t _gpgme_wait_one_ext (gpgme_ctx_t ctx, gpgme_error_t *op_err); +gpgme_error_t _gpgme_wait_on_condition (gpgme_ctx_t ctx, volatile int *cond, +					gpgme_error_t *op_err);  /* From data.c.  */ diff --git a/src/trustlist.c b/src/trustlist.c index e8cdb66e..23da08c5 100644 --- a/src/trustlist.c +++ b/src/trustlist.c @@ -220,7 +220,7 @@ gpgme_op_trustlist_next (gpgme_ctx_t ctx, gpgme_trust_item_t *r_item)    if (!opd->trust_queue)      { -      err = _gpgme_wait_on_condition (ctx, &opd->trust_cond); +      err = _gpgme_wait_on_condition (ctx, &opd->trust_cond, NULL);        if (err)  	return err;        if (!opd->trust_cond) diff --git a/src/wait-global.c b/src/wait-global.c index ececc1bc..77fd47f2 100644 --- a/src/wait-global.c +++ b/src/wait-global.c @@ -74,6 +74,7 @@ struct ctx_list_item    gpgme_ctx_t ctx;    /* The status is set when the ctx is moved to the done list.  */    gpgme_error_t status; +  gpgme_error_t op_err;  };  /* The active list contains all contexts that are in the global event @@ -112,7 +113,7 @@ ctx_active (gpgme_ctx_t ctx)  /* Enter the context CTX into the done list with status STATUS.  */  static void -ctx_done (gpgme_ctx_t ctx, gpgme_error_t status) +ctx_done (gpgme_ctx_t ctx, gpgme_error_t status, gpgme_error_t op_err)  {    struct ctx_list_item *li; @@ -131,6 +132,7 @@ ctx_done (gpgme_ctx_t ctx, gpgme_error_t status)      ctx_active_list = li->next;    li->status = status; +  li->op_err = op_err;    /* Add LI to done list.  */    li->next = ctx_done_list; @@ -147,7 +149,7 @@ ctx_done (gpgme_ctx_t ctx, gpgme_error_t status)     If a matching context could be found, return it.  Return NULL if no     context could be found.  */  static gpgme_ctx_t -ctx_wait (gpgme_ctx_t ctx, gpgme_error_t *status) +ctx_wait (gpgme_ctx_t ctx, gpgme_error_t *status, gpgme_error_t *op_err)  {    struct ctx_list_item *li; @@ -164,6 +166,8 @@ ctx_wait (gpgme_ctx_t ctx, gpgme_error_t *status)        ctx = li->ctx;        if (status)  	*status = li->status; +      if (op_err) +	*op_err = li->op_err;        /* Remove LI from done list.  */        if (li->next) @@ -203,15 +207,16 @@ _gpgme_wait_global_event_cb (void *data, gpgme_event_io_t type,  	if (err)  	  /* An error occured.  Close all fds in this context, and  	     send the error in a done event.  */ -	  _gpgme_cancel_with_err (ctx, err); +	  _gpgme_cancel_with_err (ctx, err, 0);        }        break;      case GPGME_EVENT_DONE:        { -	gpgme_error_t *errp = (gpgme_error_t *) type_data; -	assert (errp); -	ctx_done (ctx, *errp); +	gpgme_io_event_done_data_t done_data = +	  (gpgme_io_event_done_data_t) type_data; + +	ctx_done (ctx, done_data->err, done_data->op_err);        }        break; @@ -246,7 +251,8 @@ _gpgme_wait_global_event_cb (void *data, gpgme_event_io_t type,     error occurs, NULL is returned and *STATUS is set to the error     value.  */  gpgme_ctx_t -gpgme_wait (gpgme_ctx_t ctx, gpgme_error_t *status, int hang) +gpgme_wait_ext (gpgme_ctx_t ctx, gpgme_error_t *status, +		gpgme_error_t *op_err, int hang)  {    do      { @@ -266,6 +272,8 @@ gpgme_wait (gpgme_ctx_t ctx, gpgme_error_t *status, int hang)  	  UNLOCK (ctx_list_lock);  	  if (status)  	    *status = gpg_error_from_errno (saved_errno); +	  if (op_err) +	    *op_err = 0;  	  return NULL;  	}        fdt.size = i; @@ -285,6 +293,8 @@ gpgme_wait (gpgme_ctx_t ctx, gpgme_error_t *status, int hang)  	  free (fdt.fds);  	  if (status)  	    *status = gpg_error_from_errno (saved_errno); +	  if (op_err) +	    *op_err = 0;  	  return NULL;  	} @@ -294,6 +304,7 @@ gpgme_wait (gpgme_ctx_t ctx, gpgme_error_t *status, int hang)  	    {  	      gpgme_ctx_t ictx;  	      gpgme_error_t err = 0; +	      gpgme_error_t local_op_err = 0;  	      struct wait_item_s *item;  	      assert (nr); @@ -310,12 +321,12 @@ gpgme_wait (gpgme_ctx_t ctx, gpgme_error_t *status, int hang)  	      UNLOCK (ctx->lock);  	      if (!err) -		err = _gpgme_run_io_cb (&fdt.fds[i], 0); -	      if (err) +		err = _gpgme_run_io_cb (&fdt.fds[i], 0, &local_op_err); +	      if (err || local_op_err)  		{  		  /* An error occured.  Close all fds in this context,  		     and signal it.  */ -		  _gpgme_cancel_with_err (ictx, err); +		  _gpgme_cancel_with_err (ictx, err, local_op_err);  		  /* Break out of the loop, and retry the select()  		     from scratch, because now all fds should be @@ -338,8 +349,10 @@ gpgme_wait (gpgme_ctx_t ctx, gpgme_error_t *status, int hang)  	      break;  	  if (i == actx->fdt.size)  	    { -	      gpgme_error_t err = 0; - +	      struct gpgme_io_event_done_data data; +	      data.err = 0; +	      data.op_err = 0; +	        	      /* FIXME: This does not perform too well.  We have to  		 release the lock because the I/O event handler  		 acquires it to remove the context from the active @@ -349,7 +362,7 @@ gpgme_wait (gpgme_ctx_t ctx, gpgme_error_t *status, int hang)  		 contexts to be released and call the DONE events  		 afterwards.  */  	      UNLOCK (ctx_list_lock); -	      _gpgme_engine_io_event (actx->engine, GPGME_EVENT_DONE, &err); +	      _gpgme_engine_io_event (actx->engine, GPGME_EVENT_DONE, &data);  	      LOCK (ctx_list_lock);  	      goto retry;  	    } @@ -357,7 +370,7 @@ gpgme_wait (gpgme_ctx_t ctx, gpgme_error_t *status, int hang)        UNLOCK (ctx_list_lock);        { -	gpgme_ctx_t dctx = ctx_wait (ctx, status); +	gpgme_ctx_t dctx = ctx_wait (ctx, status, op_err);  	if (dctx)  	  { @@ -369,6 +382,8 @@ gpgme_wait (gpgme_ctx_t ctx, gpgme_error_t *status, int hang)  	    ctx = NULL;  	    if (status)  	      *status = 0; +	    if (op_err) +	      *op_err = 0;  	  }        }      } @@ -376,3 +391,10 @@ gpgme_wait (gpgme_ctx_t ctx, gpgme_error_t *status, int hang)    return ctx;  } + + +gpgme_ctx_t +gpgme_wait (gpgme_ctx_t ctx, gpgme_error_t *status, int hang) +{ +  return gpgme_wait_ext (ctx, status, NULL, hang); +} diff --git a/src/wait-private.c b/src/wait-private.c index 2dee1a93..5d3f267c 100644 --- a/src/wait-private.c +++ b/src/wait-private.c @@ -72,7 +72,8 @@ _gpgme_wait_private_event_cb (void *data, gpgme_event_io_t type,     finished and return its error value.  Otherwise, wait until COND is     satisfied or the operation finished.  */  gpgme_error_t -_gpgme_wait_on_condition (gpgme_ctx_t ctx, volatile int *cond) +_gpgme_wait_on_condition (gpgme_ctx_t ctx, volatile int *cond, +			  gpgme_error_t *op_err_p)  {    gpgme_error_t err = 0;    int hang = 1; @@ -87,8 +88,10 @@ _gpgme_wait_on_condition (gpgme_ctx_t ctx, volatile int *cond)  	  /* An error occured.  Close all fds in this context, and  	     signal it.  */  	  err = gpg_error_from_errno (errno); -          _gpgme_cancel_with_err (ctx, err); +          _gpgme_cancel_with_err (ctx, err, 0); +	  if (op_err_p) +	    *op_err_p = 0;  	  return err;  	} @@ -96,6 +99,8 @@ _gpgme_wait_on_condition (gpgme_ctx_t ctx, volatile int *cond)  	{  	  if (ctx->fdt.fds[i].fd != -1 && ctx->fdt.fds[i].signaled)  	    { +	      gpgme_error_t op_err = 0; +  	      ctx->fdt.fds[i].signaled = 0;  	      assert (nr);  	      nr--; @@ -106,15 +111,33 @@ _gpgme_wait_on_condition (gpgme_ctx_t ctx, volatile int *cond)  	      UNLOCK (ctx->lock);  	      if (!err) -		err = _gpgme_run_io_cb (&ctx->fdt.fds[i], 0); +		err = _gpgme_run_io_cb (&ctx->fdt.fds[i], 0, &op_err);    	      if (err)  		{  		  /* An error occured.  Close all fds in this context,  		     and signal it.  */ -		  _gpgme_cancel_with_err (ctx, err); +		  _gpgme_cancel_with_err (ctx, err, 0); +		  if (op_err_p) +		    *op_err_p = 0;  		  return err;  		} +	      else if (op_err) +		{ +		  /* An operational error occured.  Cancel the current +		     operation but not the session, and signal it.  */ +		  _gpgme_cancel_with_err (ctx, 0, op_err); + +		  /* NOTE: This relies on the operational error being +		     generated after the operation really has +		     completed, for example after no further status +		     line output is generated.  Otherwise the +		     following I/O will spill over into the next +		     operation.  */ +		  if (op_err_p) +		    *op_err_p = op_err; +		  return 0; +		}  	    }  	} @@ -123,7 +146,10 @@ _gpgme_wait_on_condition (gpgme_ctx_t ctx, volatile int *cond)  	  break;        if (i == ctx->fdt.size)  	{ -	  _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_DONE, &err); +	  struct gpgme_io_event_done_data data; +	  data.err = 0; +	  data.op_err = 0; +	  _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_DONE, &data);  	  hang = 0;  	}        if (cond && *cond) @@ -131,14 +157,26 @@ _gpgme_wait_on_condition (gpgme_ctx_t ctx, volatile int *cond)      }    while (hang); +  if (op_err_p) +    *op_err_p = 0;    return 0;  }  /* Wait until the blocking operation in context CTX has finished and -   return the error value.  */ +   return the error value.  This variant can not be used for +   session-based protocols.  */  gpgme_error_t  _gpgme_wait_one (gpgme_ctx_t ctx)  { -  return _gpgme_wait_on_condition (ctx, NULL); +  return _gpgme_wait_on_condition (ctx, NULL, NULL); +} + +/* Wait until the blocking operation in context CTX has finished and +   return the error value.  This is the right variant to use for +   sesion-based protocols.  */ +gpgme_error_t +_gpgme_wait_one_ext (gpgme_ctx_t ctx, gpgme_error_t *op_err) +{ +  return _gpgme_wait_on_condition (ctx, NULL, op_err);  } diff --git a/src/wait-user.c b/src/wait-user.c index 995657fa..63dccfa7 100644 --- a/src/wait-user.c +++ b/src/wait-user.c @@ -41,6 +41,7 @@ gpgme_error_t  _gpgme_user_io_cb_handler (void *data, int fd)  {    gpgme_error_t err = 0; +  gpgme_error_t op_err = 0;    struct tag *tag = (struct tag *) data;    gpgme_ctx_t ctx; @@ -54,9 +55,9 @@ _gpgme_user_io_cb_handler (void *data, int fd)    UNLOCK (ctx->lock);    if (! err) -    err = _gpgme_run_io_cb (&ctx->fdt.fds[tag->idx], 0); -  if (err) -    _gpgme_cancel_with_err (ctx, err); +    err = _gpgme_run_io_cb (&ctx->fdt.fds[tag->idx], 0, &op_err); +  if (err || op_err) +    _gpgme_cancel_with_err (ctx, err, op_err);    else      {        unsigned int i; @@ -64,8 +65,15 @@ _gpgme_user_io_cb_handler (void *data, int fd)        for (i = 0; i < ctx->fdt.size; i++)  	if (ctx->fdt.fds[i].fd != -1)  	  break; +        if (i == ctx->fdt.size) -	_gpgme_engine_io_event (ctx->engine, GPGME_EVENT_DONE, &err); +	{ +	  struct gpgme_io_event_done_data done_data; + +	  done_data.err = 0; +	  done_data.op_err = 0; +	  _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_DONE, &done_data); +	}      }    return 0;  } @@ -180,9 +180,13 @@ _gpgme_remove_io_cb (void *data)     we are called from our own event loops.  So if CHECKED is 1, the     check is skipped.  */  gpgme_error_t -_gpgme_run_io_cb (struct io_select_fd_s *an_fds, int checked) +_gpgme_run_io_cb (struct io_select_fd_s *an_fds, int checked, +		  gpgme_error_t *op_err)  {    struct wait_item_s *item; +  struct io_cb_data iocb_data; +  gpgme_error_t err; +    item = (struct wait_item_s *) an_fds->opaque;    assert (item); @@ -207,5 +211,11 @@ _gpgme_run_io_cb (struct io_select_fd_s *an_fds, int checked)    TRACE2 (DEBUG_CTX, "_gpgme_run_io_cb", item, "handler (%p, %d)",            item->handler_value, an_fds->fd); -  return item->handler (item->handler_value, an_fds->fd); + +  iocb_data.handler_value = item->handler_value; +  iocb_data.op_err = 0; +  err = item->handler (&iocb_data, an_fds->fd); + +  *op_err = iocb_data.op_err; +  return err;  } @@ -75,8 +75,22 @@ void _gpgme_wait_user_remove_io_cb (void *tag);  void _gpgme_wait_user_event_cb (void *data, gpgme_event_io_t type,  				void *type_data); -gpgme_error_t _gpgme_wait_one (gpgme_ctx_t ctx); +gpgme_error_t _gpgme_run_io_cb (struct io_select_fd_s *an_fds, int checked, +				gpgme_error_t *err); -gpgme_error_t _gpgme_run_io_cb (struct io_select_fd_s *an_fds, int checked); + +/* Session based interfaces require to make a distinction between IPC +   errors and operational errors.  To glue this into the old +   interface, I/O handlers (esp. the status handler) are called with a +   struct as the opaque value that contains the handlers opaque value +   but also a field for the operational error to be returned.  */ +struct io_cb_data +{ +  /* If this is the first field, the old internal code will still work.  */ +  void *handler_value; +   +  /* The I/O callback can pass an operational error here.  */ +  gpgme_error_t op_err; +};  #endif	/* WAIT_H */  | 
