core: New public API gpgme_op_keylist_from_data_start.
authorAndre Heinecke <aheinecke@intevation.de>
Tue, 21 Mar 2017 08:38:11 +0000 (09:38 +0100)
committerWerner Koch <wk@gnupg.org>
Tue, 21 Mar 2017 08:50:23 +0000 (09:50 +0100)
* src/gpgme.h.in: New API gpgme_op_keylist_from_data_start.
* src/libgpgme.vers, src/gpgme.def: Add it.
* src/keylist.c (gpgme_op_keylist_from_data_start): New.
* src/engine-backend.h (engine_ops): Add field 'keylist_data'.  Change
all engines to pass NULL for it.
* src/engine.c (_gpgme_engine_op_keylist_data): New.
* src/engine-gpg.c (gpg_keylist_data): New.
(_gpgme_engine_ops_gpg): Register gpg_keylist_data.

* tests/run-keylist.c (main): New option --from-file.
--

Co-authored-by: Werner Koch <wk@gnupg.org>
GnuPG-bug-id: 2819

17 files changed:
NEWS
doc/gpgme.texi
src/engine-assuan.c
src/engine-backend.h
src/engine-g13.c
src/engine-gpg.c
src/engine-gpgconf.c
src/engine-gpgsm.c
src/engine-spawn.c
src/engine-uiserver.c
src/engine.c
src/engine.h
src/gpgme.def
src/gpgme.h.in
src/keylist.c
src/libgpgme.vers
tests/run-keylist.c

diff --git a/NEWS b/NEWS
index f2ab0bf..cf02fc2 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -11,6 +11,8 @@ Noteworthy changes in version 1.8.1 (unreleased)
  gpgme_op_createsubkey       CHANGED: Meaning of 'expire' parameter.
  GPGME_CREATE_NOEXPIRE       NEW.
  gpgme_subkey_t              EXTENDED: New field is_de_vs.
+ gpgme_op_keylist_from_data_start NEW.
+ gpgme_data_rewind                UN-DEPRECATE.
  cpp: Context::revUid(const Key&, const char*)      NEW.
  cpp: Context::startRevUid(const Key&, const char*) NEW.
  cpp: Context::addUid(const Key&, const char*)      NEW.
@@ -22,7 +24,6 @@ Noteworthy changes in version 1.8.1 (unreleased)
  cpp: Subkey::keyGrip                               NEW.
  cpp: Subkey::isDeVs                                NEW.
  qt: CryptoConfig::stringValueList()                NEW.
- gpgme_data_rewind                                  UN-DEPRECATE.
  py: Context.__init__        EXTENDED: New keyword arg home_dir.
  py: Context.home_dir        NEW.
  py: Context.keylist         EXTENDED: New keyword arg mode.
index 337053f..edcbb98 100644 (file)
@@ -3342,6 +3342,7 @@ This is a linked list with the notation data and policy URLs.
 @cindex key ring, search
 
 @deftypefun gpgme_error_t gpgme_op_keylist_start (@w{gpgme_ctx_t @var{ctx}}, @w{const char *@var{pattern}}, @w{int @var{secret_only}})
+
 The function @code{gpgme_op_keylist_start} initiates a key listing
 operation inside the context @var{ctx}.  It sets everything up so that
 subsequent invocations of @code{gpgme_op_keylist_next} return the keys
@@ -3369,6 +3370,7 @@ are reported by the crypto engine support routines.
 @end deftypefun
 
 @deftypefun gpgme_error_t gpgme_op_keylist_ext_start (@w{gpgme_ctx_t @var{ctx}}, @w{const char *@var{pattern}[]}, @w{int @var{secret_only}}, @w{int @var{reserved}})
+
 The function @code{gpgme_op_keylist_ext_start} initiates an extended
 key listing operation inside the context @var{ctx}.  It sets
 everything up so that subsequent invocations of
@@ -3399,7 +3401,36 @@ The function returns the error code @code{GPG_ERR_INV_VALUE} if
 are reported by the crypto engine support routines.
 @end deftypefun
 
+@deftypefun gpgme_error_t gpgme_op_keylist_from_data @
+            (@w{gpgme_ctx_t @var{ctx}}, @
+             @w{gpgme_data_t @var{data}}, @
+             @w{int @var{reserved}})
+
+The function @code{gpgme_op_keylist_from_data_start} initiates a key
+listing operation inside the context @var{ctx}.  In contrast to the
+other key listing operation the keys are read from the supplied
+@var{data} and not from the local key database.  The keys are also not
+imported into the local ley database. The function sets everything up
+so that subsequent invocations of @code{gpgme_op_keylist_next} return
+the keys from @var{data}.
+
+The value of @var{reserved} must be @code{0}.
+
+This function requires at least GnuPG version 2.1.14 and currently
+works only with OpenPGP keys.
+
+The context will be busy until either all keys are received (and
+@code{gpgme_op_keylist_next} returns @code{GPG_ERR_EOF}), or
+@code{gpgme_op_keylist_end} is called to finish the operation.
+While the context is busy @var{data} may not be released.
+
+The function returns the error code @code{GPG_ERR_INV_VALUE} if
+@var{ctx} is not a valid pointer, and passes through any errors that
+are reported by the crypto engine support routines.
+@end deftypefun
+
 @deftypefun gpgme_error_t gpgme_op_keylist_next (@w{gpgme_ctx_t @var{ctx}}, @w{gpgme_key_t *@var{r_key}})
+
 The function @code{gpgme_op_keylist_next} returns the next key in the
 list created by a previous @code{gpgme_op_keylist_start} operation in
 the context @var{ctx}.  The key will have one reference for the user.
@@ -3417,6 +3448,7 @@ The function returns the error code @code{GPG_ERR_INV_VALUE} if
 @end deftypefun
 
 @deftypefun gpgme_error_t gpgme_op_keylist_end (@w{gpgme_ctx_t @var{ctx}})
+
 The function @code{gpgme_op_keylist_end} ends a pending key list
 operation in the context @var{ctx}.
 
@@ -3431,7 +3463,7 @@ time during the operation there was not enough memory available.
 
 The following example illustrates how all keys containing a certain
 string (@code{g10code}) can be listed with their key ID and the name
-and e-mail address of the main user ID:
+and email address of the main user ID:
 
 @example
 gpgme_ctx_t ctx;
index 78efb4c..4beb41d 100644 (file)
@@ -787,6 +787,7 @@ struct engine_ops _gpgme_engine_ops_assuan =
     NULL,               /* import */
     NULL,               /* keylist */
     NULL,               /* keylist_ext */
+    NULL,               /* keylist_data */
     NULL,               /* keysign */
     NULL,               /* tofu_policy */
     NULL,               /* sign */
index a8457af..635acb0 100644 (file)
@@ -100,6 +100,7 @@ struct engine_ops
                                int secret_only, int reserved,
                                gpgme_keylist_mode_t mode,
                                int engine_flags);
+  gpgme_error_t (*keylist_data) (void *engine, gpgme_data_t data);
   gpgme_error_t (*keysign) (void *engine,
                             gpgme_key_t key, const char *userid,
                             unsigned long expires, unsigned int flags,
index bb06d35..593177c 100644 (file)
@@ -802,6 +802,7 @@ struct engine_ops _gpgme_engine_ops_g13 =
     NULL,               /* import */
     NULL,               /* keylist */
     NULL,               /* keylist_ext */
+    NULL,               /* keylist_data */
     NULL,               /* keysign */
     NULL,               /* tofu_policy */
     NULL,               /* sign */
index 59cf405..4b87a8a 100644 (file)
@@ -2731,6 +2731,38 @@ gpg_keylist_ext (void *engine, const char *pattern[], int secret_only,
 
 
 static gpgme_error_t
+gpg_keylist_data (void *engine, gpgme_data_t data)
+{
+  engine_gpg_t gpg = engine;
+  gpgme_error_t err;
+
+  if (!have_gpg_version (gpg, "2.1.14"))
+    return gpg_error (GPG_ERR_NOT_SUPPORTED);
+
+  err = add_arg (gpg, "--with-colons");
+  if (!err)
+    err = add_arg (gpg, "--with-fingerprint");
+  if (!err)
+    err = add_arg (gpg, "--import-options");
+  if (!err)
+    err = add_arg (gpg, "import-show");
+  if (!err)
+    err = add_arg (gpg, "--dry-run");
+  if (!err)
+    err = add_arg (gpg, "--import");
+  if (!err)
+    err = add_arg (gpg, "--");
+  if (!err)
+    err = add_data (gpg, data, -1, 0);
+
+  if (!err)
+    err = start (gpg);
+
+  return err;
+}
+
+
+static gpgme_error_t
 gpg_keysign (void *engine, gpgme_key_t key, const char *userid,
              unsigned long expire, unsigned int flags,
              gpgme_ctx_t ctx)
@@ -3013,6 +3045,7 @@ struct engine_ops _gpgme_engine_ops_gpg =
     gpg_import,
     gpg_keylist,
     gpg_keylist_ext,
+    gpg_keylist_data,
     gpg_keysign,
     gpg_tofu_policy,    /* tofu_policy */
     gpg_sign,
index 3e46310..4891977 100644 (file)
@@ -1244,6 +1244,7 @@ struct engine_ops _gpgme_engine_ops_gpgconf =
     NULL,              /* import */
     NULL,              /* keylist */
     NULL,              /* keylist_ext */
+    NULL,               /* keylist_data */
     NULL,               /* keysign */
     NULL,               /* tofu_policy */
     NULL,              /* sign */
index d5d2901..7652363 100644 (file)
@@ -2106,6 +2106,7 @@ struct engine_ops _gpgme_engine_ops_gpgsm =
     gpgsm_import,
     gpgsm_keylist,
     gpgsm_keylist_ext,
+    NULL,               /* keylist_data */
     NULL,               /* keysign */
     NULL,               /* tofu_policy */
     gpgsm_sign,
index 1cd4421..fa406d4 100644 (file)
@@ -460,6 +460,7 @@ struct engine_ops _gpgme_engine_ops_spawn =
     NULL,              /* import */
     NULL,              /* keylist */
     NULL,              /* keylist_ext */
+    NULL,               /* keylist_data */
     NULL,               /* keysign */
     NULL,               /* tofu_policy */
     NULL,              /* sign */
index ff5227e..12efd27 100644 (file)
@@ -1394,6 +1394,7 @@ struct engine_ops _gpgme_engine_ops_uiserver =
     NULL,              /* import */
     NULL,              /* keylist */
     NULL,              /* keylist_ext */
+    NULL,               /* keylist_data */
     NULL,               /* keysign */
     NULL,               /* tofu_policy */
     uiserver_sign,
index 75d9ff7..a918a50 100644 (file)
@@ -876,6 +876,19 @@ _gpgme_engine_op_keylist_ext (engine_t engine, const char *pattern[],
 
 
 gpgme_error_t
+_gpgme_engine_op_keylist_data (engine_t engine, gpgme_data_t data)
+{
+  if (!engine)
+    return gpg_error (GPG_ERR_INV_VALUE);
+
+  if (!engine->ops->keylist_data)
+    return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+
+  return (*engine->ops->keylist_data) (engine->engine, data);
+}
+
+
+gpgme_error_t
 _gpgme_engine_op_sign (engine_t engine, gpgme_data_t in, gpgme_data_t out,
                       gpgme_sig_mode_t mode, int use_armor,
                       int use_textmode, int include_certs,
index 29d2f25..f456812 100644 (file)
@@ -148,6 +148,8 @@ gpgme_error_t _gpgme_engine_op_keylist_ext (engine_t engine,
                                            int reserved,
                                            gpgme_keylist_mode_t mode,
                                            int engine_flags);
+gpgme_error_t _gpgme_engine_op_keylist_data (engine_t engine,
+                                            gpgme_data_t data);
 gpgme_error_t _gpgme_engine_op_sign (engine_t engine, gpgme_data_t in,
                                     gpgme_data_t out, gpgme_sig_mode_t mode,
                                     int use_armor, int use_textmode,
index 0d3ce74..ddd57d3 100644 (file)
@@ -177,8 +177,8 @@ EXPORTS
     gpgme_io_read                         @136
     gpgme_io_write                        @137
 
-    gpgme_result_ref                     @138
-    gpgme_result_unref                   @139
+    gpgme_result_ref                      @138
+    gpgme_result_unref                    @139
 
     gpgme_op_import_keys                  @140
     gpgme_op_import_keys_start            @141
@@ -253,5 +253,8 @@ EXPORTS
     gpgme_op_query_swdb_result            @190
 
     gpgme_get_ctx_flag                    @191
+
+    gpgme_op_keylist_from_data_start      @192
+
 ; END
 
index b660cb5..2cf096b 100644 (file)
@@ -1817,20 +1817,31 @@ typedef struct _gpgme_op_keylist_result *gpgme_keylist_result_t;
 gpgme_keylist_result_t gpgme_op_keylist_result (gpgme_ctx_t ctx);
 
 /* Start a keylist operation within CTX, searching for keys which
  match PATTERN.  If SECRET_ONLY is true, only secret keys are
  returned.  */
* match PATTERN.  If SECRET_ONLY is true, only secret keys are
* returned.  */
 gpgme_error_t gpgme_op_keylist_start (gpgme_ctx_t ctx, const char *pattern,
                                      int secret_only);
 gpgme_error_t gpgme_op_keylist_ext_start (gpgme_ctx_t ctx,
                                          const char *pattern[],
                                          int secret_only, int reserved);
 
+/* List the keys contained in DATA.  */
+gpgme_error_t gpgme_op_keylist_from_data_start (gpgme_ctx_t ctx,
+                                                gpgme_data_t data,
+                                                int reserved);
+
 /* Return the next key from the keylist in R_KEY.  */
 gpgme_error_t gpgme_op_keylist_next (gpgme_ctx_t ctx, gpgme_key_t *r_key);
 
 /* Terminate a pending keylist operation within CTX.  */
 gpgme_error_t gpgme_op_keylist_end (gpgme_ctx_t ctx);
 
+
+\f
+/*
+ * Protecting keys
+ */
+
 /* Change the passphrase for KEY.  FLAGS is reserved for future use
    and must be passed as 0.  */
 gpgme_error_t gpgme_op_passwd_start (gpgme_ctx_t ctx, gpgme_key_t key,
index de9bbb2..c88a7ca 100644 (file)
@@ -1142,6 +1142,42 @@ gpgme_op_keylist_ext_start (gpgme_ctx_t ctx, const char *pattern[],
 }
 
 
+/* Start a keylist operation within CTX to show keys contained
+ * in DATA.  */
+gpgme_error_t
+gpgme_op_keylist_from_data_start (gpgme_ctx_t ctx, gpgme_data_t data,
+                                  int reserved)
+{
+  gpgme_error_t err;
+  void *hook;
+  op_data_t opd;
+
+  TRACE_BEG (DEBUG_CTX, "gpgme_op_keylist_from_data_start", ctx);
+
+  if (!ctx || !data || reserved)
+    return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
+
+  err = _gpgme_op_reset (ctx, 2);
+  if (err)
+    return TRACE_ERR (err);
+
+  err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook,
+                               sizeof (*opd), release_op_data);
+  opd = hook;
+  if (err)
+    return TRACE_ERR (err);
+
+  _gpgme_engine_set_status_handler (ctx->engine, keylist_status_handler, ctx);
+  err = _gpgme_engine_set_colon_line_handler (ctx->engine,
+                                              keylist_colon_handler, ctx);
+  if (err)
+    return TRACE_ERR (err);
+
+  err = _gpgme_engine_op_keylist_data (ctx->engine, data);
+  return TRACE_ERR (err);
+}
+
+
 /* Return the next key from the keylist in R_KEY.  */
 gpgme_error_t
 gpgme_op_keylist_next (gpgme_ctx_t ctx, gpgme_key_t *r_key)
index a55cd10..9344a75 100644 (file)
@@ -223,6 +223,7 @@ GPGME_1.0 {
     gpgme_op_import_start;
     gpgme_op_keylist_end;
     gpgme_op_keylist_ext_start;
+    gpgme_op_keylist_from_data_start;
     gpgme_op_keylist_next;
     gpgme_op_keylist_result;
     gpgme_op_keylist_start;
index fd9c7c2..aab4bb6 100644 (file)
@@ -41,7 +41,7 @@ static int verbose;
 static int
 show_usage (int ex)
 {
-  fputs ("usage: " PGM " [options] [USERID]\n\n"
+  fputs ("usage: " PGM " [options] [USERID_or_FILE]\n\n"
          "Options:\n"
          "  --verbose        run in verbose mode\n"
          "  --openpgp        use the OpenPGP protocol (default)\n"
@@ -56,6 +56,7 @@ show_usage (int ex)
          "  --validate       use GPGME_KEYLIST_MODE_VALIDATE\n"
          "  --import         import all keys\n"
          "  --offline        use offline mode\n"
+         "  --from-file      list all keys in the given file\n"
          "  --require-gnupg  required at least the given GnuPG version\n"
          , stderr);
   exit (ex);
@@ -98,6 +99,9 @@ main (int argc, char **argv)
   gpgme_protocol_t protocol = GPGME_PROTOCOL_OpenPGP;
   int only_secret = 0;
   int offline = 0;
+  int from_file = 0;
+  gpgme_data_t data = NULL;
+
 
   if (argc)
     { argc--; argv++; }
@@ -177,6 +181,11 @@ main (int argc, char **argv)
           offline = 1;
           argc--; argv++;
         }
+      else if (!strcmp (*argv, "--from-file"))
+        {
+          from_file = 1;
+          argc--; argv++;
+        }
       else if (!strcmp (*argv, "--require-gnupg"))
         {
           argc--; argv++;
@@ -191,6 +200,8 @@ main (int argc, char **argv)
 
   if (argc > 1)
     show_usage (1);
+  else if (from_file && !argc)
+    show_usage (1);
 
   init_gpgme (protocol);
 
@@ -202,7 +213,15 @@ main (int argc, char **argv)
 
   gpgme_set_offline (ctx, offline);
 
-  err = gpgme_op_keylist_start (ctx, argc? argv[0]:NULL, only_secret);
+  if (from_file)
+    {
+      err = gpgme_data_new_from_file (&data, *argv, 1);
+      fail_if_err (err);
+
+      err = gpgme_op_keylist_from_data_start (ctx, data, 0);
+    }
+  else
+    err = gpgme_op_keylist_start (ctx, argc? argv[0]:NULL, only_secret);
   fail_if_err (err);
 
   while (!(err = gpgme_op_keylist_next (ctx, &key)))
@@ -322,6 +341,7 @@ main (int argc, char **argv)
   err = gpgme_op_keylist_end (ctx);
   fail_if_err (err);
   keyarray[keyidx] = NULL;
+  gpgme_data_release (data);
 
   result = gpgme_op_keylist_result (ctx);
   if (result->truncated)