2009-10-26 Marcus Brinkmann <marcus@g10code.de>
authorMarcus Brinkmann <mb@g10code.com>
Mon, 26 Oct 2009 18:52:32 +0000 (18:52 +0000)
committerMarcus Brinkmann <mb@g10code.com>
Mon, 26 Oct 2009 18:52:32 +0000 (18:52 +0000)
* configure.ac (NEED_GPG_VERSION_DEFAULT): Bump to 1.4.0 as 1.3.0
was development versions only.

tests/
2009-10-26  Marcus Brinkmann  <marcus@g10code.de>

* opassuan/t-command.c: Update to new interface.

src/
2009-10-26  Marcus Brinkmann  <marcus@g10code.de>

* 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.

28 files changed:
ChangeLog
configure.ac
src/ChangeLog
src/context.h
src/data.c
src/engine-assuan.c
src/engine-backend.h
src/engine-g13.c
src/engine-gpg.c
src/engine-gpgsm.c
src/engine.c
src/engine.h
src/g13.c
src/gpgme.c
src/gpgme.def
src/gpgme.h.in
src/keylist.c
src/libgpgme.vers
src/opassuan.c
src/ops.h
src/trustlist.c
src/wait-global.c
src/wait-private.c
src/wait-user.c
src/wait.c
src/wait.h
tests/ChangeLog
tests/opassuan/t-command.c

index fc92fa1..735eb1a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2009-10-26  Marcus Brinkmann  <marcus@g10code.de>
+
+       * configure.ac (NEED_GPG_VERSION_DEFAULT): Bump to 1.4.0 as 1.3.0
+       was development versions only.
+
 2009-10-22  Marcus Brinkmann  <marcus@g10code.de>
 
        * configure.ac: Add support for G13.
index 44eb5ed..1d0be30 100644 (file)
@@ -286,7 +286,7 @@ if test "$have_libassuan" = "yes"; then
 fi
 
 # Checks for system services
-NEED_GPG_VERSION_DEFAULT=1.3.0
+NEED_GPG_VERSION_DEFAULT=1.4.0
 NEED_GPGSM_VERSION_DEFAULT=1.9.6
 NEED_GPGCONF_VERSION_DEFAULT=2.0.4
 NEED_G13_VERSION_DEFAULT=2.1.0
index 024c771..f1ac7b4 100644 (file)
@@ -1,5 +1,85 @@
 2009-10-26  Marcus Brinkmann  <marcus@g10code.de>
 
+       * 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.
index e98e7be..6818e7e 100644 (file)
@@ -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;
 
 
index 759d328..408aeab 100644 (file)
@@ -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);
index 07a21fa..92e1e05 100644 (file)
@@ -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
   };
index fa539a3..bb938d0 100644 (file)
@@ -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);
 };
 
 
index f957691..358efc1 100644 (file)
@@ -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,
   };
index dba49a9..6d6ec47 100644 (file)
@@ -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 */
   };
index 1d25190..04f49ed 100644 (file)
@@ -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 */
   };
index b1d815a..6912859 100644 (file)
@@ -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);
+}
index ca746c8..86a3d42 100644 (file)
@@ -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 */
index b3f5fee..029a914 100644 (file)
--- a/src/g13.c
+++ b/src/g13.c
 
 typedef struct
 {
-  struct _gpgme_op_g13_result result;
+  struct _gpgme_op_vfs_mount_result result;
 } *op_data_t;
 
 
 \f
-/* 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;
 }
 
 \f
 /* 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;
 }
index 071b394..52e14d7 100644 (file)
@@ -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);
 
 \f
@@ -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);
 }
 
 
index 5089a27..6d223f4 100644 (file)
@@ -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
 
index 45f5c12..42b9237 100644 (file)
@@ -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);
+
 \f
 /* 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;
 
 \f
 /* 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);
 
 \f
 /* Interface to gpgconf(1).  */
index 55351ee..926b762 100644 (file)
@@ -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;
 
index 7f65d6e..9989c75 100644 (file)
@@ -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;
 };
 
 
index 09f69ee..2db9f6c 100644 (file)
 #include "ops.h"
 #include "util.h"
 
-
-typedef struct
-{
-  struct _gpgme_op_assuan_result result;
-
-} *op_data_t;
-
-
-
-\f
-/* 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;
 }
 
+
+
+\f
+/* 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;
+}
index cd3ee4a..7bc7695 100644 (file)
--- a/src/ops.h
+++ b/src/ops.h
 
 \f
 /* 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);
 
 \f
 /* 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);
 
 \f
 /* From data.c.  */
index e8cdb66..23da08c 100644 (file)
@@ -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)
index ececc1b..77fd47f 100644 (file)
@@ -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);
+}
index 2dee1a9..5d3f267 100644 (file)
@@ -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);
 }
index 995657f..63dccfa 100644 (file)
@@ -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;
 }
index f5bc2d9..febd5bd 100644 (file)
@@ -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;
 }
index eafbb6f..6ea51e2 100644 (file)
@@ -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);
+\f
+/* 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 */
index 0dd8ead..294f7d8 100644 (file)
@@ -1,3 +1,7 @@
+2009-10-26  Marcus Brinkmann  <marcus@g10code.de>
+
+       * opassuan/t-command.c: Update to new interface.
+
 2009-10-15  Werner Koch  <wk@g10code.com>
 
        * run-verify.c: New.
index 161b8a8..aa5f34c 100644 (file)
@@ -101,6 +101,7 @@ int
 main (int argc, char **argv)
 {
   gpgme_error_t err;
+  gpgme_error_t op_err;
   gpgme_ctx_t ctx;
   const char *command;
 
@@ -125,18 +126,9 @@ main (int argc, char **argv)
   err = gpgme_set_protocol (ctx, GPGME_PROTOCOL_ASSUAN);
   fail_if_err (err);
 
-  err = gpgme_op_assuan_transact (ctx, command,
-                                  data_cb, NULL,
-                                  inq_cb, NULL,
-                                  status_cb, NULL);
-  fail_if_err (err);
-  err = gpgme_op_assuan_result (ctx)->err;
-  if (err)
-    fprintf (stderr, "assuan command `%s' failed: %s <%s> (%d)\n", 
-             command, gpg_strerror (err), gpg_strsource (err), err);
-  else
-    fprintf (stderr, "assuan command `%s' succeeded\n", command);
-
+  err = gpgme_op_assuan_transact_ext (ctx, command, data_cb, NULL,
+                                  inq_cb, NULL, status_cb, NULL, &op_err);
+  fail_if_err (err || op_err);
 
   gpgme_release (ctx);