From c8e934b2761ded0a7c7fdaaf7f3e2e8af9e3dcaf Mon Sep 17 00:00:00 2001 From: Marcus Brinkmann Date: Mon, 26 Oct 2009 18:52:32 +0000 Subject: [PATCH] 2009-10-26 Marcus Brinkmann * 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 * opassuan/t-command.c: Update to new interface. src/ 2009-10-26 Marcus Brinkmann * 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. --- ChangeLog | 5 + configure.ac | 2 +- src/ChangeLog | 80 +++++++++++++++ src/context.h | 2 +- src/data.c | 6 +- src/engine-assuan.c | 72 +++++++------- src/engine-backend.h | 6 +- src/engine-g13.c | 32 +++--- src/engine-gpg.c | 13 ++- src/engine-gpgsm.c | 8 +- src/engine.c | 20 +++- src/engine.h | 4 +- src/g13.c | 105 +++++++------------- src/gpgme.c | 47 ++++++--- src/gpgme.def | 6 +- src/gpgme.h.in | 92 +++++++++++------- src/keylist.c | 2 +- src/libgpgme.vers | 7 +- src/opassuan.c | 193 +++++++++++++++++++------------------ src/ops.h | 7 +- src/trustlist.c | 2 +- src/wait-global.c | 50 +++++++--- src/wait-private.c | 52 ++++++++-- src/wait-user.c | 16 ++- src/wait.c | 14 ++- src/wait.h | 18 +++- tests/ChangeLog | 4 + tests/opassuan/t-command.c | 16 +-- 28 files changed, 558 insertions(+), 323 deletions(-) diff --git a/ChangeLog b/ChangeLog index fc92fa10..735eb1ac 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-10-26 Marcus Brinkmann + + * configure.ac (NEED_GPG_VERSION_DEFAULT): Bump to 1.4.0 as 1.3.0 + was development versions only. + 2009-10-22 Marcus Brinkmann * configure.ac: Add support for G13. diff --git a/configure.ac b/configure.ac index 44eb5ed5..1d0be30a 100644 --- a/configure.ac +++ b/configure.ac @@ -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 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 + * 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; diff --git a/src/data.c b/src/data.c index 759d328b..408aeab6 100644 --- a/src/data.c +++ b/src/data.c @@ -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 */ diff --git a/src/g13.c b/src/g13.c index b3f5fee8..029a9141 100644 --- a/src/g13.c +++ b/src/g13.c @@ -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,39 +26,95 @@ #include "ops.h" #include "util.h" - -typedef struct +static gpgme_error_t +opassuan_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) { - struct _gpgme_op_assuan_result result; + gpgme_error_t err; -} *op_data_t; + if (!command || !*command) + return gpg_error (GPG_ERR_INV_VALUE); + + /* The flag value 256 is used to suppress an engine reset. This is + required to keep the connection running. */ + err = _gpgme_op_reset (ctx, ((synchronous&255) | 256)); + if (err) + return err; + + return _gpgme_engine_op_assuan_transact (ctx->engine, command, + data_cb, data_cb_value, + inq_cb, inq_cb_value, + status_cb, status_cb_value); +} + + + +/* 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) +{ + return opassuan_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. */ +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 status_cb, + void *status_cb_value, + gpgme_error_t *op_err) +{ + gpgme_error_t err; + + err = opassuan_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_ext (ctx, op_err); + return err; +} -/* 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) +/* 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 { - gpgme_ctx_t ctx = (gpgme_ctx_t)priv; - gpgme_error_t err; - void *hook; - op_data_t opd; + struct engine_ops *ops; + void *engine; +}; - 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; -} +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) @@ -74,85 +130,32 @@ gpgme_op_assuan_result (gpgme_ctx_t ctx) 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; } -static gpgme_error_t -opassuan_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; - op_data_t opd; - - if (!command || !*command) - return gpg_error (GPG_ERR_INV_VALUE); - - /* The flag value 256 is used to suppress an engine reset. This is - required to keep the connection running. */ - err = _gpgme_op_reset (ctx, ((synchronous&255) | 256)); - 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); -} - - - -/* 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) -{ - return opassuan_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. */ 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) + 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; - err = opassuan_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); + /* 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; } - diff --git a/src/ops.h b/src/ops.h index cd3ee4ac..7bc76959 100644 --- a/src/ops.h +++ b/src/ops.h @@ -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; } diff --git a/src/wait.c b/src/wait.c index f5bc2d96..febd5bd9 100644 --- a/src/wait.c +++ b/src/wait.c @@ -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; } diff --git a/src/wait.h b/src/wait.h index eafbb6f6..6ea51e25 100644 --- a/src/wait.h +++ b/src/wait.h @@ -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 */ diff --git a/tests/ChangeLog b/tests/ChangeLog index 0dd8eadb..294f7d84 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,7 @@ +2009-10-26 Marcus Brinkmann + + * opassuan/t-command.c: Update to new interface. + 2009-10-15 Werner Koch * run-verify.c: New. diff --git a/tests/opassuan/t-command.c b/tests/opassuan/t-command.c index 161b8a84..aa5f34ce 100644 --- a/tests/opassuan/t-command.c +++ b/tests/opassuan/t-command.c @@ -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);