+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.
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
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.
{
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;
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;
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);
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 {
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,
}
+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)
{
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;
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",
/* 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",
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",
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'
{
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
{
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,
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;
NULL, /* conf_save */
llass_set_io_cbs,
llass_io_event,
- llass_cancel
+ llass_cancel,
+ llass_cancel_op
};
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,
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);
};
}
+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)
{
}
-/* 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,
&& line[0] == 'S' && line[1] == ' ')
{
char *rest;
- gpgme_status_code_t r;
rest = strchr (line + 2, ' ');
if (!rest)
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);
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;
NULL, /* conf_save */
g13_set_io_cbs,
g13_io_event,
- g13_cancel
+ g13_cancel,
+ g13_cancel_op,
};
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);
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]);
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]);
NULL, /* conf_save */
gpg_set_io_cbs,
gpg_io_event,
- gpg_cancel
+ gpg_cancel,
+ NULL /* cancel_op */
};
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;
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
NULL, /* conf_save */
gpgsm_set_io_cbs,
gpgsm_io_event,
- gpgsm_cancel
+ gpgsm_cancel,
+ NULL /* cancel_op */
};
#ifdef ENABLE_ASSUAN
&_gpgme_engine_ops_assuan, /* Low-Level Assuan. */
#else
- NULL
+ NULL,
#endif
#ifdef ENABLE_G13
&_gpgme_engine_ops_g13 /* Crypto VFS. */
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,
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);
}
+/* Cancel the session and the pending operation if any. */
gpgme_error_t
_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);
+}
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,
gpgme_error_t _gpgme_engine_cancel (engine_t engine);
+gpgme_error_t _gpgme_engine_cancel_op (engine_t engine);
+
#endif /* ENGINE_H */
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. */
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;
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);
/* 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,
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;
}
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)
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;
}
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
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);
}
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);
}
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);
}
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);
}
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
}
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,
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. */
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,
/* 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). */
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;
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;
};
#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,
void *status_cb_value)
{
gpgme_error_t err;
- void *hook;
- op_data_t opd;
if (!command || !*command)
return gpg_error (GPG_ERR_INV_VALUE);
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)
+ 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,
/* 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;
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;
+}
\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. */
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)
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
/* 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;
ctx_active_list = li->next;
li->status = status;
+ li->op_err = op_err;
/* Add LI to done list. */
li->next = ctx_done_list;
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;
ctx = li->ctx;
if (status)
*status = li->status;
+ if (op_err)
+ *op_err = li->op_err;
/* Remove LI from done list. */
if (li->next)
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;
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
{
UNLOCK (ctx_list_lock);
if (status)
*status = gpg_error_from_errno (saved_errno);
+ if (op_err)
+ *op_err = 0;
return NULL;
}
fdt.size = i;
free (fdt.fds);
if (status)
*status = gpg_error_from_errno (saved_errno);
+ if (op_err)
+ *op_err = 0;
return NULL;
}
{
gpgme_ctx_t ictx;
gpgme_error_t err = 0;
+ gpgme_error_t local_op_err = 0;
struct wait_item_s *item;
assert (nr);
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
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
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;
}
UNLOCK (ctx_list_lock);
{
- gpgme_ctx_t dctx = ctx_wait (ctx, status);
+ gpgme_ctx_t dctx = ctx_wait (ctx, status, op_err);
if (dctx)
{
ctx = NULL;
if (status)
*status = 0;
+ if (op_err)
+ *op_err = 0;
}
}
}
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);
+}
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;
/* 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;
}
{
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--;
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;
+ }
}
}
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)
}
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);
}
_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;
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;
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;
}
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);
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;
}
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 */
+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.
main (int argc, char **argv)
{
gpgme_error_t err;
+ gpgme_error_t op_err;
gpgme_ctx_t ctx;
const char *command;
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);