diff --git a/src/context.h b/src/context.h index e9214368..745ffa89 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_VFS_MOUNT, - OPDATA_PASSWD + OPDATA_PASSWD, OPDATA_EXPORT } ctx_op_data_id_t; diff --git a/src/export.c b/src/export.c index 81a23b04..8930aa68 100644 --- a/src/export.c +++ b/src/export.c @@ -1,6 +1,6 @@ /* export.c - Export a key. Copyright (C) 2000 Werner Koch (dd9jn) - Copyright (C) 2001, 2002, 2003, 2004, 2010 g10 Code GmbH + Copyright (C) 2001-2004, 2010, 2014 g10 Code GmbH This file is part of GPGME. @@ -31,9 +31,82 @@ #include "ops.h" +/* Local operation data. */ +typedef struct +{ + gpg_error_t err; /* Error encountred during the export. */ +} *op_data_t; + + +static void +release_op_data (void *hook) +{ + op_data_t opd = (op_data_t) hook; + + (void)opd; /* Nothing to release here. */ +} + + +/* Parse an error status line. Return the error location and the + error code. The function may modify ARGS. */ +static char * +parse_error (char *args, gpg_error_t *r_err) +{ + char *where = strchr (args, ' '); + char *which; + + if (where) + { + *where = '\0'; + which = where + 1; + + where = strchr (which, ' '); + if (where) + *where = '\0'; + + where = args; + } + else + { + *r_err = trace_gpg_error (GPG_ERR_INV_ENGINE); + return NULL; + } + + *r_err = atoi (which); + + return where; +} + + static gpgme_error_t export_status_handler (void *priv, gpgme_status_code_t code, char *args) { + gpgme_ctx_t ctx = (gpgme_ctx_t) priv; + gpgme_error_t err; + void *hook; + op_data_t opd; + const char *loc; + + err = _gpgme_op_data_lookup (ctx, OPDATA_EXPORT, &hook, -1, NULL); + opd = hook; + if (err) + return err; + + switch (code) + { + case GPGME_STATUS_ERROR: + loc = parse_error (args, &err); + if (!loc) + return err; + else if (opd->err) + ; /* We only want to report the first error. */ + else if (!strcmp (loc, "keyserver_send")) + opd->err = err; + break; + + default: + break; + } return 0; } @@ -43,6 +116,8 @@ export_start (gpgme_ctx_t ctx, int synchronous, const char *pattern, gpgme_export_mode_t mode, gpgme_data_t keydata) { gpgme_error_t err; + void *hook; + op_data_t opd; if ((mode & ~(GPGME_EXPORT_MODE_EXTERN |GPGME_EXPORT_MODE_MINIMAL))) @@ -64,6 +139,12 @@ export_start (gpgme_ctx_t ctx, int synchronous, const char *pattern, if (err) return err; + err = _gpgme_op_data_lookup (ctx, OPDATA_EXPORT, &hook, + sizeof (*opd), release_op_data); + opd = hook; + if (err) + return err; + _gpgme_engine_set_status_handler (ctx->engine, export_status_handler, ctx); return _gpgme_engine_op_export (ctx->engine, pattern, mode, keydata, @@ -114,6 +195,8 @@ export_ext_start (gpgme_ctx_t ctx, int synchronous, const char *pattern[], gpgme_export_mode_t mode, gpgme_data_t keydata) { gpgme_error_t err; + void *hook; + op_data_t opd; if ((mode & ~(GPGME_EXPORT_MODE_EXTERN |GPGME_EXPORT_MODE_MINIMAL))) @@ -134,6 +217,12 @@ export_ext_start (gpgme_ctx_t ctx, int synchronous, const char *pattern[], if (err) return err; + err = _gpgme_op_data_lookup (ctx, OPDATA_EXPORT, &hook, + sizeof (*opd), release_op_data); + opd = hook; + if (err) + return err; + _gpgme_engine_set_status_handler (ctx->engine, export_status_handler, ctx); return _gpgme_engine_op_export_ext (ctx->engine, pattern, mode, keydata, @@ -196,7 +285,24 @@ gpgme_op_export_ext (gpgme_ctx_t ctx, const char *pattern[], err = export_ext_start (ctx, 1, pattern, mode, keydata); if (!err) - err = _gpgme_wait_one (ctx); + { + err = _gpgme_wait_one (ctx); + if (!err) + { + /* For this synchronous operation we check for operational + errors and return them. For asynchronous operations + there is currently no way to do this - we need to add a + gpgme_op_export_result function to fix that. */ + void *hook; + op_data_t opd; + + err = _gpgme_op_data_lookup (ctx, OPDATA_EXPORT, &hook, -1, NULL); + opd = hook; + if (!err) + err = opd->err; + } + } + return TRACE_ERR (err); } @@ -319,7 +425,24 @@ gpgme_op_export_keys (gpgme_ctx_t ctx, err = export_keys_start (ctx, 1, keys, mode, keydata); if (!err) - err = _gpgme_wait_one (ctx); + { + err = _gpgme_wait_one (ctx); + if (!err) + { + /* For this synchronous operation we check for operational + errors and return them. For asynchronous operations + there is currently no way to do this - we need to add a + gpgme_op_export_result function to fix that. */ + void *hook; + op_data_t opd; + + err = _gpgme_op_data_lookup (ctx, OPDATA_EXPORT, &hook, -1, NULL); + opd = hook; + if (!err) + err = opd->err; + } + } + return TRACE_ERR (err); }