Return an error for some export key operations.
authorWerner Koch <wk@gnupg.org>
Mon, 8 Dec 2014 10:19:16 +0000 (11:19 +0100)
committerWerner Koch <wk@gnupg.org>
Mon, 8 Dec 2014 10:19:16 +0000 (11:19 +0100)
* src/context.h (OPDATA_EXPORT): New.
* src/export.c (op_data_t): New.
(release_op_data): New.
(parse_error): New.
(export_status_handler): New.
(export_start, export_ext_start): Prepare op_data.
(gpgme_op_export_ext, gpgme_op_export_keys): Return an error from the
status handler.
--

To support an error return also for the async functions we need to
extend the API.  Until we have done that this new features helps at
least in some cases; in particular for --send-keys.

src/context.h
src/export.c

index e921436..745ffa8 100644 (file)
@@ -38,7 +38,7 @@ typedef enum
     OPDATA_DECRYPT, OPDATA_SIGN, OPDATA_ENCRYPT, OPDATA_PASSPHRASE,
     OPDATA_IMPORT, OPDATA_GENKEY, OPDATA_KEYLIST, OPDATA_EDIT,
     OPDATA_VERIFY, OPDATA_TRUSTLIST, OPDATA_ASSUAN, OPDATA_VFS_MOUNT,
-    OPDATA_PASSWD
+    OPDATA_PASSWD, OPDATA_EXPORT
   } ctx_op_data_id_t;
 
 
index 81a23b0..8930aa6 100644 (file)
@@ -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.
 
 #include "ops.h"
 
 \f
+/* 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);
 }