core: Add extended versions of the encrypt functions.
authorWerner Koch <wk@gnupg.org>
Tue, 17 Apr 2018 06:33:44 +0000 (08:33 +0200)
committerWerner Koch <wk@gnupg.org>
Tue, 17 Apr 2018 06:45:00 +0000 (08:45 +0200)
* src/gpgme.h.in (gpgme_op_encrypt_ext_start) New.
(gpgme_op_encrypt_ext): New.
(gpgme_op_encrypt_sign_ext_start): New.
(gpgme_op_encrypt_sign_ext): New.
* src/libgpgme.vers, tests/run-encrypt.c: Add them.

* src/encrypt.c (encrypt_start): Add arg recpstring.
(gpgme_op_encrypt): Factor code out to ...
(gpgme_op_encrypt_ext): new function with new arg recpstring.
(gpgme_op_encrypt_start): Factor code out to ...
(gpgme_op_encrypt_ext_start): new function with new arg recpstring.
* src/encrypt-sign.c (encrypt_sign_start): Add arg recpstring.
(gpgme_op_encrypt_sign): Factor code out to ...
(gpgme_op_encrypt_sign_ext): new function with new arg recpstring.
(gpgme_op_encrypt_sign_start): Factor code out to ...
(gpgme_op_encrypt_sign_ext_start): new function with new arg
recpstring.

* src/engine-backend.h (struct engine_ops): Change fields encrypt and
encrypt_sign.
* src/engine.c (_gpgme_engine_op_encrypt): Add arg recpstring and pass
to engine.
(_gpgme_engine_op_encrypt_sign): Ditto.
* src/engine-gpg.c (append_args_from_recipients_string): New.
(gpg_encrypt): Add arg recpstring and call new function as needed.
(gpg_encrypt_sign): Ditto.
* src/engine-gpgsm.c (set_recipients_from_string): New.
(gpgsm_encrypt): Add arg recpstring and call new function as needed.
* src/engine-uiserver.c (set_recipients_from_string): New.
(uiserver_encrypt): Add arg recpstring and call new function as
needed.

* tests/run-encrypt.c (xstrdup): New.
(main): Add option --keystring.

* src/gpgme-json.c (get_keys): Simplify.
(op_encrypt): Modify to make use of the extended encrypt function.

--

This new feature can be used to avoid the need for a key lookup and
thus several extra calls to the backend.

Note that run-test uses a semicolon as delimiter because that make
testing the feature on the command line much easier.

Signed-off-by: Werner Koch <wk@gnupg.org>
15 files changed:
NEWS
doc/gpgme.texi
src/encrypt-sign.c
src/encrypt.c
src/engine-backend.h
src/engine-gpg.c
src/engine-gpgsm.c
src/engine-uiserver.c
src/engine.c
src/engine.h
src/gpgme-json.c
src/gpgme.def
src/gpgme.h.in
src/libgpgme.vers
tests/run-encrypt.c

diff --git a/NEWS b/NEWS
index a8d73a5..51d7923 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -5,11 +5,16 @@ Noteworthy changes in version 1.10.1 (unreleased)
 
  * Interface changes relative to the 1.10.0 release:
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- gpgme_import_result_t       EXTENDED: New field 'skipped_v3_keys'
- cpp: Key::locate                     NEW.
- cpp: Data::toString                  NEW.
+ gpgme_op_encrypt_ext             NEW.
+ gpgme_op_encrypt_ext_start       NEW.
+ gpgme_op_encrypt_sign_ext        NEW.
+ gpgme_op_encrypt_sign_ext_start  NEW.
+ gpgme_import_result_t            EXTENDED: New field 'skipped_v3_keys'.
+ cpp: Key::locate                 NEW.
+ cpp: Data::toString              NEW.
  cpp: ImportResult::numV3KeysSkipped  NEW.
 
+
 Noteworthy changes in version 1.10.0 (2017-12-12)
 -------------------------------------------------
 
index cbb0e64..1df9c46 100644 (file)
@@ -6154,6 +6154,45 @@ pointer, and @code{GPG_ERR_UNUSABLE_PUBKEY} if @var{rset} does not
 contain any valid recipients.
 @end deftypefun
 
+@deftypefun gpgme_error_t gpgme_op_encrypt_ext @
+            (@w{gpgme_ctx_t @var{ctx}}, @
+             @w{gpgme_key_t @var{recp}[]}, @
+             @w{const char *@var{recpstring}}, @
+             @w{gpgme_encrypt_flags_t @var{flags}}, @
+             @w{gpgme_data_t @var{plain}}, @w{gpgme_data_t @var{cipher}})
+
+@since{1.11.0}
+
+This is an extended version of @code{gpgme_op_encrypt} with
+@var{recpstring} as additional parameter.  If @var{recp} is NULL and
+@var{recpstring} is not NULL, the latter is expected to be a linefeed
+delimited string with the set of key specifications.  In contrast to
+@var{recp} the keys are given directly as strings and there is no need
+to first create key objects.  The keys are passed verbatim to the
+backend engine.
+
+@end deftypefun
+
+
+@deftypefun gpgme_error_t gpgme_op_encrypt_ext_start @
+            (@w{gpgme_ctx_t @var{ctx}}, @
+             @w{gpgme_key_t @var{recp}[]}, @
+             @w{const char *@var{recpstring}}, @
+             @w{gpgme_encrypt_flags_t @var{flags}}, @
+             @w{gpgme_data_t @var{plain}}, @w{gpgme_data_t @var{cipher}})
+
+@since{1.11.0}
+
+This is an extended version of @code{gpgme_op_encrypt_start} with
+@var{recpstring} as additional parameter.  If @var{recp} is NULL and
+@var{recpstring} is not NULL, the latter is expected to be a linefeed
+delimited string with the set of key specifications.  In contrast to
+@var{recp} the keys are given directly as strings and there is no need
+to first create key objects.  The keys are passed verbatim to the
+backend engine.
+
+@end deftypefun
+
 @deftp {Data type} {gpgme_encrypt_result_t}
 This is a pointer to a structure used to store the result of a
 @code{gpgme_op_encrypt} operation.  After successfully encrypting
@@ -6203,6 +6242,44 @@ if @var{ctx}, @var{rset}, @var{plain} or @var{cipher} is not a valid
 pointer.
 @end deftypefun
 
+@deftypefun gpgme_error_t gpgme_op_encrypt_sign_ext @
+            (@w{gpgme_ctx_t @var{ctx}}, @
+             @w{gpgme_key_t @var{recp}[]}, @
+             @w{const char *@var{recpstring}}, @
+             @w{gpgme_encrypt_flags_t @var{flags}}, @
+             @w{gpgme_data_t @var{plain}}, @w{gpgme_data_t @var{cipher}})
+
+@since{1.11.0}
+
+This is an extended version of @code{gpgme_op_encrypt_sign} with
+@var{recpstring} as additional parameter.  If @var{recp} is NULL and
+@var{recpstring} is not NULL, the latter is expected to be a linefeed
+delimited string with the set of key specifications.  In contrast to
+@var{recp} the keys are given directly as strings and there is no need
+to first create the key objects.  The keys are passed verbatim to the
+backend engine.
+
+@end deftypefun
+
+@deftypefun gpgme_error_t gpgme_op_encrypt_sign_ext_start @
+            (@w{gpgme_ctx_t @var{ctx}}, @
+             @w{gpgme_key_t @var{recp}[]}, @
+             @w{const char *@var{recpstring}}, @
+             @w{gpgme_encrypt_flags_t @var{flags}}, @
+             @w{gpgme_data_t @var{plain}}, @w{gpgme_data_t @var{cipher}})
+
+@since{1.11.0}
+
+This is an extended version of @code{gpgme_op_encrypt_sign_start} with
+@var{recpstring} as additional parameter.  If @var{recp} is NULL and
+@var{recpstring} is not NULL, the latter is expected to be a linefeed
+delimited string with the set of key specifications.  In contrast to
+@var{recp} the keys are given directly as strings and there is no need
+to first create the key objects.  The keys are passed verbatim to the
+backend engine.
+
+@end deftypefun
+
 
 @node Miscellaneous
 @section Miscellaneous operations
index af6de63..4db46e2 100644 (file)
@@ -62,6 +62,7 @@ encrypt_sym_status_handler (void *priv, gpgme_status_code_t code, char *args)
 
 static gpgme_error_t
 encrypt_sign_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t recp[],
+                    const char *recpstring,
                    gpgme_encrypt_flags_t flags,
                    gpgme_data_t plain, gpgme_data_t cipher)
 {
@@ -72,7 +73,7 @@ encrypt_sign_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t recp[],
   if (err)
     return err;
 
-  symmetric = !recp || (flags & GPGME_ENCRYPT_SYMMETRIC);
+  symmetric = (!recp && !recpstring) || (flags & GPGME_ENCRYPT_SYMMETRIC);
 
   if (!plain)
     return gpg_error (GPG_ERR_NO_DATA);
@@ -103,43 +104,75 @@ encrypt_sign_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t recp[],
                                     : encrypt_sign_status_handler,
                                    ctx);
 
-  return _gpgme_engine_op_encrypt_sign (ctx->engine, recp, flags, plain,
+  return _gpgme_engine_op_encrypt_sign (ctx->engine, recp, recpstring,
+                                        flags, plain,
                                        cipher, ctx->use_armor,
                                        ctx /* FIXME */);
 }
 
 
-/* Encrypt plaintext PLAIN within CTX for the recipients RECP and
-   store the resulting ciphertext in CIPHER.  Also sign the ciphertext
-   with the signers in CTX.  */
+/* Old version of gpgme_op_encrypt_sign_ext_start w/o RECPSTRING.  */
 gpgme_error_t
 gpgme_op_encrypt_sign_start (gpgme_ctx_t ctx, gpgme_key_t recp[],
                             gpgme_encrypt_flags_t flags,
                             gpgme_data_t plain, gpgme_data_t cipher)
 {
+  return gpgme_op_encrypt_sign_ext_start (ctx, recp, NULL,
+                                          flags, plain, cipher);
+}
+
+
+/* Old version of gpgme_op_encrypt_sign_ext w/o RECPSTRING.  */
+gpgme_error_t
+gpgme_op_encrypt_sign (gpgme_ctx_t ctx, gpgme_key_t recp[],
+                      gpgme_encrypt_flags_t flags,
+                      gpgme_data_t plain, gpgme_data_t cipher)
+{
+  return gpgme_op_encrypt_sign_ext (ctx, recp, NULL, flags, plain, cipher);
+}
+
+
+/* Encrypt plaintext PLAIN within CTX for the recipients RECP and
+ * store the resulting ciphertext in CIPHER.  Also sign the ciphertext
+ * with the signers in CTX.  */
+gpgme_error_t
+gpgme_op_encrypt_sign_ext (gpgme_ctx_t ctx, gpgme_key_t recp[],
+                           const char *recpstring,
+                           gpgme_encrypt_flags_t flags,
+                           gpgme_data_t plain, gpgme_data_t cipher)
+{
   gpgme_error_t err;
 
-  TRACE_BEG3 (DEBUG_CTX, "gpgme_op_encrypt_sign_start", ctx,
+  TRACE_BEG3 (DEBUG_CTX, "gpgme_op_encrypt_sign", ctx,
              "flags=0x%x, plain=%p, cipher=%p", flags, plain, cipher);
 
   if (!ctx)
     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
 
-  if (_gpgme_debug_trace () && recp)
+  if (_gpgme_debug_trace () && (recp || recpstring))
     {
-      int i = 0;
-
-      while (recp[i])
-       {
-         TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i],
-                     (recp[i]->subkeys && recp[i]->subkeys->fpr) ?
-                     recp[i]->subkeys->fpr : "invalid");
-         i++;
-       }
+      if (recp)
+        {
+          int i = 0;
+
+          while (recp[i])
+            {
+              TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i],
+                          (recp[i]->subkeys && recp[i]->subkeys->fpr) ?
+                          recp[i]->subkeys->fpr : "invalid");
+              i++;
+            }
+        }
+      else
+        {
+          TRACE_LOG1 ("recipients = '%s'", recpstring);
+        }
     }
 
-  err = encrypt_sign_start (ctx, 0, recp, flags, plain, cipher);
-  return err;
+  err = encrypt_sign_start (ctx, 1, recp, recpstring, flags, plain, cipher);
+  if (!err)
+    err = _gpgme_wait_one (ctx);
+  return TRACE_ERR (err);
 }
 
 
@@ -147,33 +180,39 @@ gpgme_op_encrypt_sign_start (gpgme_ctx_t ctx, gpgme_key_t recp[],
    store the resulting ciphertext in CIPHER.  Also sign the ciphertext
    with the signers in CTX.  */
 gpgme_error_t
-gpgme_op_encrypt_sign (gpgme_ctx_t ctx, gpgme_key_t recp[],
-                      gpgme_encrypt_flags_t flags,
-                      gpgme_data_t plain, gpgme_data_t cipher)
+gpgme_op_encrypt_sign_ext_start (gpgme_ctx_t ctx, gpgme_key_t recp[],
+                                 const char *recpstring,
+                                 gpgme_encrypt_flags_t flags,
+                                 gpgme_data_t plain, gpgme_data_t cipher)
 {
   gpgme_error_t err;
 
-  TRACE_BEG3 (DEBUG_CTX, "gpgme_op_encrypt_sign", ctx,
+  TRACE_BEG3 (DEBUG_CTX, "gpgme_op_encrypt_sign_start", ctx,
              "flags=0x%x, plain=%p, cipher=%p", flags, plain, cipher);
 
   if (!ctx)
     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
 
-  if (_gpgme_debug_trace () && recp)
+  if (_gpgme_debug_trace () && (recp || recpstring))
     {
-      int i = 0;
-
-      while (recp[i])
-       {
-         TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i],
-                     (recp[i]->subkeys && recp[i]->subkeys->fpr) ?
-                     recp[i]->subkeys->fpr : "invalid");
-         i++;
-       }
+      if (recp)
+        {
+          int i = 0;
+
+          while (recp[i])
+            {
+              TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i],
+                          (recp[i]->subkeys && recp[i]->subkeys->fpr) ?
+                          recp[i]->subkeys->fpr : "invalid");
+              i++;
+            }
+        }
+      else
+        {
+          TRACE_LOG1 ("recipients = '%s'", recpstring);
+        }
     }
 
-  err = encrypt_sign_start (ctx, 1, recp, flags, plain, cipher);
-  if (!err)
-    err = _gpgme_wait_one (ctx);
-  return TRACE_ERR (err);
+  err = encrypt_sign_start (ctx, 0, recp, recpstring, flags, plain, cipher);
+  return err;
 }
index 4023654..2318497 100644 (file)
@@ -214,6 +214,7 @@ _gpgme_op_encrypt_init_result (gpgme_ctx_t ctx)
 
 static gpgme_error_t
 encrypt_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t recp[],
+               const char *recpstring,
               gpgme_encrypt_flags_t flags,
               gpgme_data_t plain, gpgme_data_t cipher)
 {
@@ -228,13 +229,13 @@ encrypt_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t recp[],
   if (err)
     return err;
 
-  symmetric = !recp || (flags & GPGME_ENCRYPT_SYMMETRIC);
+  symmetric = (!recp && !recpstring) || (flags & GPGME_ENCRYPT_SYMMETRIC);
 
   if (!plain)
     return gpg_error (GPG_ERR_NO_DATA);
   if (!cipher)
     return gpg_error (GPG_ERR_INV_VALUE);
-  if (recp && ! *recp)
+  if (recp && !*recp)
     return gpg_error (GPG_ERR_INV_VALUE);
 
   if (symmetric && ctx->passphrase_cb)
@@ -252,72 +253,111 @@ encrypt_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t recp[],
                                    : encrypt_status_handler,
                                    ctx);
 
-  return _gpgme_engine_op_encrypt (ctx->engine, recp, flags, plain, cipher,
-                                  ctx->use_armor);
+  return _gpgme_engine_op_encrypt (ctx->engine, recp, recpstring,
+                                   flags, plain, cipher, ctx->use_armor);
 }
 
 
+/* Old version of gpgme_op_encrypt_ext without RECPSTRING.  */
+gpgme_error_t
+gpgme_op_encrypt (gpgme_ctx_t ctx, gpgme_key_t recp[],
+                 gpgme_encrypt_flags_t flags,
+                 gpgme_data_t plain, gpgme_data_t cipher)
+{
+  return gpgme_op_encrypt_ext (ctx, recp, NULL, flags, plain, cipher);
+}
+
+
+/* Old version of gpgme_op_encrypt_ext_start without RECPSTRING.  */
 gpgme_error_t
 gpgme_op_encrypt_start (gpgme_ctx_t ctx, gpgme_key_t recp[],
                        gpgme_encrypt_flags_t flags,
                        gpgme_data_t plain, gpgme_data_t cipher)
 {
+  return gpgme_op_encrypt_ext_start (ctx, recp, NULL, flags, plain, cipher);
+}
+
+
+/* Encrypt plaintext PLAIN within CTX for the recipients RECP and
+ * store the resulting ciphertext in CIPHER.  RECPSTRING can be used
+ * instead of the RECP array to directly specify recipients as LF
+ * delimited strings; these may be any kind of recipient specification
+ * patterns as supported by the backend.  */
+gpgme_error_t
+gpgme_op_encrypt_ext (gpgme_ctx_t ctx, gpgme_key_t recp[],
+                      const char *recpstring,
+                      gpgme_encrypt_flags_t flags,
+                      gpgme_data_t plain, gpgme_data_t cipher)
+{
   gpgme_error_t err;
 
-  TRACE_BEG3 (DEBUG_CTX, "gpgme_op_encrypt_start", ctx,
+  TRACE_BEG3 (DEBUG_CTX, "gpgme_op_encrypt", ctx,
              "flags=0x%x, plain=%p, cipher=%p", flags, plain, cipher);
 
   if (!ctx)
     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
 
-  if (_gpgme_debug_trace () && recp)
+  if (_gpgme_debug_trace () && (recp || recpstring))
     {
-      int i = 0;
+      if (recp)
+        {
+          int i = 0;
 
-      while (recp[i])
-       {
-         TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i],
+          while (recp[i])
+            {
+              TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i],
                      (recp[i]->subkeys && recp[i]->subkeys->fpr) ?
-                     recp[i]->subkeys->fpr : "invalid");
-         i++;
-       }
+                          recp[i]->subkeys->fpr : "invalid");
+              i++;
+            }
+        }
+      else
+        {
+          TRACE_LOG1 ("recipients = '%s'", recpstring);
+        }
     }
 
-  err = encrypt_start (ctx, 0, recp, flags, plain, cipher);
+  err = encrypt_start (ctx, 1, recp, recpstring, flags, plain, cipher);
+  if (!err)
+    err = _gpgme_wait_one (ctx);
   return TRACE_ERR (err);
 }
 
 
-/* Encrypt plaintext PLAIN within CTX for the recipients RECP and
-   store the resulting ciphertext in CIPHER.  */
 gpgme_error_t
-gpgme_op_encrypt (gpgme_ctx_t ctx, gpgme_key_t recp[],
-                 gpgme_encrypt_flags_t flags,
-                 gpgme_data_t plain, gpgme_data_t cipher)
+gpgme_op_encrypt_ext_start (gpgme_ctx_t ctx, gpgme_key_t recp[],
+                            const char *recpstring,
+                            gpgme_encrypt_flags_t flags,
+                            gpgme_data_t plain, gpgme_data_t cipher)
 {
   gpgme_error_t err;
 
-  TRACE_BEG3 (DEBUG_CTX, "gpgme_op_encrypt", ctx,
+  TRACE_BEG3 (DEBUG_CTX, "gpgme_op_encrypt_start", ctx,
              "flags=0x%x, plain=%p, cipher=%p", flags, plain, cipher);
 
   if (!ctx)
     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
 
-  if (_gpgme_debug_trace () && recp)
+  if (_gpgme_debug_trace () && (recp || recpstring))
     {
-      int i = 0;
-
-      while (recp[i])
-       {
-         TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i],
-                     (recp[i]->subkeys && recp[i]->subkeys->fpr) ?
-                     recp[i]->subkeys->fpr : "invalid");
-         i++;
-       }
+      if (recp)
+        {
+          int i = 0;
+
+          while (recp[i])
+            {
+              TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i],
+                          (recp[i]->subkeys && recp[i]->subkeys->fpr) ?
+                          recp[i]->subkeys->fpr : "invalid");
+              i++;
+            }
+        }
+      else
+        {
+          TRACE_LOG1 ("recipients = '%s'", recpstring);
+        }
     }
 
-  err = encrypt_start (ctx, 1, recp, flags, plain, cipher);
-  if (!err)
-    err = _gpgme_wait_one (ctx);
+  err = encrypt_start (ctx, 0, recp, recpstring, flags, plain, cipher);
   return TRACE_ERR (err);
 }
index 97cf6a1..f692666 100644 (file)
@@ -72,10 +72,12 @@ struct engine_ops
   gpgme_error_t (*edit) (void *engine, int type, gpgme_key_t key,
                         gpgme_data_t out, gpgme_ctx_t ctx /* FIXME */);
   gpgme_error_t (*encrypt) (void *engine, gpgme_key_t recp[],
+                            const char *recpstring,
                            gpgme_encrypt_flags_t flags,
                            gpgme_data_t plain, gpgme_data_t ciph,
                            int use_armor);
   gpgme_error_t (*encrypt_sign) (void *engine, gpgme_key_t recp[],
+                                 const char *recpstring,
                                 gpgme_encrypt_flags_t flags,
                                 gpgme_data_t plain, gpgme_data_t ciph,
                                 int use_armor, gpgme_ctx_t ctx /* FIXME */);
index a37d1f7..809806c 100644 (file)
@@ -1914,17 +1914,64 @@ append_args_from_recipients (engine_gpg_t gpg, gpgme_key_t recp[])
 }
 
 
+/* Take recipients from the LF delimited STRING and add -r args.  */
+static gpg_error_t
+append_args_from_recipients_string (engine_gpg_t gpg, const char *string)
+{
+  gpg_error_t err = 0;
+  int any = 0;
+  const char *s;
+  int n;
+
+  do
+    {
+      /* Skip leading white space */
+      while (*string == ' ' || *string == '\t')
+        string++;
+      if (!*string)
+        break;
+
+      /* Look for the LF. */
+      s = strchr (string, '\n');
+      if (s)
+        n = s - string;
+      else
+        n = strlen (string);
+      while (n && (string[n-1] == ' ' || string[n-1] == '\t'))
+        n--;
+
+      /* Add arg if it is not empty.  */
+      if (n)
+        {
+          err = add_arg (gpg, "-r");
+          if (!err)
+            err = add_arg_len (gpg, NULL, string, n);
+          if (!err)
+            any = 1;
+        }
+
+      string += n + !!s;
+    }
+  while (!err);
+
+  if (!err && !any)
+    err = gpg_error (GPG_ERR_MISSING_KEY);
+  return err;
+}
+
+
 static gpgme_error_t
-gpg_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
+gpg_encrypt (void *engine, gpgme_key_t recp[], const char *recpstring,
+             gpgme_encrypt_flags_t flags,
             gpgme_data_t plain, gpgme_data_t ciph, int use_armor)
 {
   engine_gpg_t gpg = engine;
   gpgme_error_t err = 0;
 
-  if (recp)
+  if (recp || recpstring)
     err = add_arg (gpg, "--encrypt");
 
-  if (!err && ((flags & GPGME_ENCRYPT_SYMMETRIC) || !recp))
+  if (!err && ((flags & GPGME_ENCRYPT_SYMMETRIC) || (!recp && !recpstring)))
     err = add_arg (gpg, "--symmetric");
 
   if (!err && use_armor)
@@ -1951,7 +1998,7 @@ gpg_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
       && have_gpg_version (gpg, "2.1.14"))
     err = add_arg (gpg, "--mimemode");
 
-  if (recp)
+  if (recp || recpstring)
     {
       /* If we know that all recipients are valid (full or ultimate trust)
         we can suppress further checks.  */
@@ -1961,7 +2008,9 @@ gpg_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
       if (!err && (flags & GPGME_ENCRYPT_NO_ENCRYPT_TO))
        err = add_arg (gpg, "--no-encrypt-to");
 
-      if (!err)
+      if (!err && !recp && recpstring)
+       err = append_args_from_recipients_string (gpg, recpstring);
+      else if (!err)
        err = append_args_from_recipients (gpg, recp);
     }
 
@@ -1995,6 +2044,7 @@ gpg_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
 
 static gpgme_error_t
 gpg_encrypt_sign (void *engine, gpgme_key_t recp[],
+                  const char *recpstring,
                  gpgme_encrypt_flags_t flags, gpgme_data_t plain,
                  gpgme_data_t ciph, int use_armor,
                  gpgme_ctx_t ctx /* FIXME */)
@@ -2002,10 +2052,10 @@ gpg_encrypt_sign (void *engine, gpgme_key_t recp[],
   engine_gpg_t gpg = engine;
   gpgme_error_t err = 0;
 
-  if (recp)
+  if (recp || recpstring)
     err = add_arg (gpg, "--encrypt");
 
-  if (!err && ((flags & GPGME_ENCRYPT_SYMMETRIC) || !recp))
+  if (!err && ((flags & GPGME_ENCRYPT_SYMMETRIC) || (!recp && !recpstring)))
     err = add_arg (gpg, "--symmetric");
 
   if (!err)
@@ -2023,7 +2073,7 @@ gpg_encrypt_sign (void *engine, gpgme_key_t recp[],
       && have_gpg_version (gpg, "2.1.14"))
     err = add_arg (gpg, "--mimemode");
 
-  if (recp)
+  if (recp || recpstring)
     {
       /* If we know that all recipients are valid (full or ultimate trust)
         we can suppress further checks.  */
@@ -2033,7 +2083,9 @@ gpg_encrypt_sign (void *engine, gpgme_key_t recp[],
       if (!err && (flags & GPGME_ENCRYPT_NO_ENCRYPT_TO))
        err = add_arg (gpg, "--no-encrypt-to");
 
-      if (!err)
+      if (!err && !recp && recpstring)
+       err = append_args_from_recipients_string (gpg, recpstring);
+      else if (!err)
        err = append_args_from_recipients (gpg, recp);
     }
 
index b8e44e7..da7e524 100644 (file)
@@ -1327,8 +1327,57 @@ set_recipients (engine_gpgsm_t gpgsm, gpgme_key_t recp[])
 }
 
 
+/* Take recipients from the LF delimited STRING and send RECIPIENT
+ * commands to gpgsm.  */
 static gpgme_error_t
-gpgsm_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
+set_recipients_from_string (engine_gpgsm_t gpgsm, const char *string)
+{
+  gpg_error_t err = 0;
+  char *line = NULL;
+  int no_pubkey = 0;
+  const char *s;
+  int n;
+
+  for (;;)
+    {
+      while (*string == ' ' || *string == '\t')
+        string++;
+      if (!*string)
+        break;
+
+      s = strchr (string, '\n');
+      if (s)
+        n = s - string;
+      else
+        n = strlen (string);
+      while (n && (string[n-1] == ' ' || string[n-1] == '\t'))
+        n--;
+
+      gpgrt_free (line);
+      if (gpgrt_asprintf (&line, "RECIPIENT %.*s", n, string) < 0)
+        {
+          err = gpg_error_from_syserror ();
+          break;
+        }
+      string += n + !!s;
+
+      err = gpgsm_assuan_simple_command (gpgsm, line, gpgsm->status.fnc,
+                                        gpgsm->status.fnc_value);
+
+      /* Fixme: Improve error reporting.  */
+      if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY)
+       no_pubkey++;
+      else if (err)
+        break;
+    }
+  gpgrt_free (line);
+  return err? err : no_pubkey? gpg_error (GPG_ERR_NO_PUBKEY) : 0;
+}
+
+
+static gpgme_error_t
+gpgsm_encrypt (void *engine, gpgme_key_t recp[], const char *recpstring,
+               gpgme_encrypt_flags_t flags,
               gpgme_data_t plain, gpgme_data_t ciph, int use_armor)
 {
   engine_gpgsm_t gpgsm = engine;
@@ -1339,7 +1388,7 @@ gpgsm_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
   if (!recp)
     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
 
-  if (flags & GPGME_ENCRYPT_NO_ENCRYPT_TO)
+  if ((flags & GPGME_ENCRYPT_NO_ENCRYPT_TO))
     {
       err = gpgsm_assuan_simple_command (gpgsm,
                                         "OPTION no-encrypt-to", NULL, NULL);
@@ -1359,7 +1408,10 @@ gpgsm_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
   gpgsm->inline_data = NULL;
 
-  err = set_recipients (gpgsm, recp);
+  if (!recp && recpstring)
+    err = set_recipients_from_string (gpgsm, recpstring);
+  else
+    err = set_recipients (gpgsm, recp);
 
   if (!err)
     err = start (gpgsm, "ENCRYPT");
index fd5ac17..d8f4fce 100644 (file)
@@ -1075,8 +1075,58 @@ set_recipients (engine_uiserver_t uiserver, gpgme_key_t recp[])
 }
 
 
+/* Take recipients from the LF delimited STRING and send RECIPIENT
+ * commands to gpgsm.  */
 static gpgme_error_t
-uiserver_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
+set_recipients_from_string (engine_uiserver_t uiserver, const char *string)
+{
+  gpg_error_t err = 0;
+  char *line = NULL;
+  int no_pubkey = 0;
+  const char *s;
+  int n;
+
+  for (;;)
+    {
+      while (*string == ' ' || *string == '\t')
+        string++;
+      if (!*string)
+        break;
+
+      s = strchr (string, '\n');
+      if (s)
+        n = s - string;
+      else
+        n = strlen (string);
+      while (n && (string[n-1] == ' ' || string[n-1] == '\t'))
+        n--;
+
+      gpgrt_free (line);
+      if (gpgrt_asprintf (&line, "RECIPIENT %.*s", n, string) < 0)
+        {
+          err = gpg_error_from_syserror ();
+          break;
+        }
+      string += n + !!s;
+
+      err = uiserver_assuan_simple_command (uiserver, line,
+                                            uiserver->status.fnc,
+                                            uiserver->status.fnc_value);
+
+      /* Fixme: Improve error reporting.  */
+      if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY)
+       no_pubkey++;
+      else if (err)
+        break;
+    }
+  gpgrt_free (line);
+  return err? err : no_pubkey? gpg_error (GPG_ERR_NO_PUBKEY) : 0;
+}
+
+
+static gpgme_error_t
+uiserver_encrypt (void *engine, gpgme_key_t recp[], const char *recpstring,
+                  gpgme_encrypt_flags_t flags,
                  gpgme_data_t plain, gpgme_data_t ciph, int use_armor)
 {
   engine_uiserver_t uiserver = engine;
@@ -1140,9 +1190,12 @@ uiserver_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
 
   uiserver->inline_data = NULL;
 
-  if (recp)
+  if (recp || recpstring)
     {
-      err = set_recipients (uiserver, recp);
+      if (recp)
+        err = set_recipients (uiserver, recp);
+      else
+        err = set_recipients_from_string (uiserver, recpstring);
       if (err)
        {
          gpgrt_free (cmd);
index e51384f..b716ca2 100644 (file)
@@ -721,6 +721,7 @@ _gpgme_engine_op_edit (engine_t engine, int type, gpgme_key_t key,
 
 gpgme_error_t
 _gpgme_engine_op_encrypt (engine_t engine, gpgme_key_t recp[],
+                          const char *recpstring,
                          gpgme_encrypt_flags_t flags,
                          gpgme_data_t plain, gpgme_data_t ciph, int use_armor)
 {
@@ -730,13 +731,14 @@ _gpgme_engine_op_encrypt (engine_t engine, gpgme_key_t recp[],
   if (!engine->ops->encrypt)
     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
 
-  return (*engine->ops->encrypt) (engine->engine, recp, flags, plain, ciph,
-                                 use_armor);
+  return (*engine->ops->encrypt) (engine->engine, recp, recpstring,
+                                  flags, plain, ciph, use_armor);
 }
 
 
 gpgme_error_t
 _gpgme_engine_op_encrypt_sign (engine_t engine, gpgme_key_t recp[],
+                               const char *recpstring,
                               gpgme_encrypt_flags_t flags,
                               gpgme_data_t plain, gpgme_data_t ciph,
                               int use_armor, gpgme_ctx_t ctx /* FIXME */)
@@ -747,8 +749,8 @@ _gpgme_engine_op_encrypt_sign (engine_t engine, gpgme_key_t recp[],
   if (!engine->ops->encrypt_sign)
     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
 
-  return (*engine->ops->encrypt_sign) (engine->engine, recp, flags,
-                                      plain, ciph, use_armor, ctx);
+  return (*engine->ops->encrypt_sign) (engine->engine, recp, recpstring,
+                                       flags, plain, ciph, use_armor, ctx);
 }
 
 
index 34bf8e9..8b692f2 100644 (file)
@@ -98,11 +98,13 @@ gpgme_error_t _gpgme_engine_op_edit (engine_t engine, int type,
                                     gpgme_ctx_t ctx /* FIXME */);
 gpgme_error_t _gpgme_engine_op_encrypt (engine_t engine,
                                        gpgme_key_t recp[],
+                                        const char *recpstring,
                                        gpgme_encrypt_flags_t flags,
                                        gpgme_data_t plain, gpgme_data_t ciph,
                                        int use_armor);
 gpgme_error_t _gpgme_engine_op_encrypt_sign (engine_t engine,
                                             gpgme_key_t recp[],
+                                             const char *recpstring,
                                             gpgme_encrypt_flags_t flags,
                                             gpgme_data_t plain,
                                             gpgme_data_t ciph,
index b54d9a8..4b1cd5b 100644 (file)
@@ -354,18 +354,19 @@ get_protocol (cjson_t json, gpgme_protocol_t *r_protocol)
 }
 
 
-/* Extract the keys from the KEYS array in the JSON object.  CTX is a
- * GPGME context object.  On success an array with the keys is stored
- * at R_KEYS.  In failure an error code is returned.  */
+/* Extract the keys from the "keys" array in the JSON object.  On
+ * success a string with the keys identifiers is stored at R_KEYS.
+ * The keys in that string are LF delimited.  On failure an error code
+ * is returned.  */
 static gpg_error_t
-get_keys (gpgme_ctx_t ctx, cjson_t json, gpgme_key_t **r_keys)
+get_keys (cjson_t json, char **r_keystring)
 {
-  gpg_error_t err;
   cjson_t j_keys, j_item;
   int i, nkeys;
-  gpgme_key_t *keys;
+  char *p;
+  size_t length;
 
-  *r_keys = NULL;
+  *r_keystring = NULL;
 
   j_keys = cJSON_GetObjectItem (json, "keys");
   if (!j_keys)
@@ -373,8 +374,15 @@ get_keys (gpgme_ctx_t ctx, cjson_t json, gpgme_key_t **r_keys)
   if (!cjson_is_array (j_keys) && !cjson_is_string (j_keys))
     return gpg_error (GPG_ERR_INV_VALUE);
 
+  /* Fixme: We should better use a membuf like thing.  */
+  length = 1; /* For the EOS.  */
   if (cjson_is_string (j_keys))
-    nkeys = 1;
+    {
+      nkeys = 1;
+      length += strlen (j_keys->valuestring);
+      if (strchr (j_keys->valuestring, '\n'))
+        return gpg_error (GPG_ERR_INV_USER_ID);
+    }
   else
     {
       nkeys = cJSON_GetArraySize (j_keys);
@@ -385,43 +393,37 @@ get_keys (gpgme_ctx_t ctx, cjson_t json, gpgme_key_t **r_keys)
           j_item = cJSON_GetArrayItem (j_keys, i);
           if (!j_item || !cjson_is_string (j_item))
             return gpg_error (GPG_ERR_INV_VALUE);
+          if (i)
+            length++; /* Space for delimiter. */
+          length += strlen (j_item->valuestring);
+          if (strchr (j_item->valuestring, '\n'))
+            return gpg_error (GPG_ERR_INV_USER_ID);
         }
     }
 
-  /* Now allocate an array to store the gpgme key objects.  */
-  keys = xcalloc (nkeys + 1, sizeof *keys);
+  p = *r_keystring = xtrymalloc (length);
+  if (!p)
+    return gpg_error_from_syserror ();
 
   if (cjson_is_string (j_keys))
     {
-      err = gpgme_get_key (ctx, j_keys->valuestring, &keys[0], 0);
-      if (err)
-        goto leave;
+      strcpy (p, j_keys->valuestring);
     }
   else
     {
       for (i=0; i < nkeys; i++)
         {
           j_item = cJSON_GetArrayItem (j_keys, i);
-          err = gpgme_get_key (ctx, j_item->valuestring, &keys[i], 0);
-          if (err)
-            goto leave;
+          if (i)
+            *p++ = '\n'; /* Add delimiter.  */
+          p = stpcpy (p, j_item->valuestring);
         }
     }
-  err = 0;
-  *r_keys = keys;
-  keys = NULL;
-
- leave:
-  if (keys)
-    {
-      for (i=0; keys[i]; i++)
-        gpgme_key_unref (keys[i]);
-      xfree (keys);
-    }
-  return err;
+  return 0;
 }
 
 
+
 \f
 /*
  *  GPGME support functions.
@@ -582,11 +584,11 @@ op_encrypt (cjson_t request, cjson_t result)
   gpgme_ctx_t ctx = NULL;
   gpgme_protocol_t protocol;
   int opt_base64;
-  gpgme_key_t *keys = NULL;
+  char *keystring = NULL;
   cjson_t j_input;
   gpgme_data_t input = NULL;
   gpgme_data_t output = NULL;
-  int abool, i;
+  int abool;
   gpgme_encrypt_flags_t encrypt_flags = 0;
 
   if ((err = get_protocol (request, &protocol)))
@@ -622,7 +624,7 @@ op_encrypt (cjson_t request, cjson_t result)
 
 
   /* Get the keys.  */
-  err = get_keys (ctx, request, &keys);
+  err = get_keys (request, &keystring);
   if (err)
     {
       /* Provide a custom error response.  */
@@ -674,7 +676,8 @@ op_encrypt (cjson_t request, cjson_t result)
     }
 
   /* Encrypt.  */
-  err = gpgme_op_encrypt (ctx, keys, encrypt_flags, input, output);
+  err = gpgme_op_encrypt_ext (ctx, NULL, keystring, encrypt_flags,
+                              input, output);
   /* encrypt_result = gpgme_op_encrypt_result (ctx); */
   if (err)
     {
@@ -713,12 +716,7 @@ op_encrypt (cjson_t request, cjson_t result)
     }
 
  leave:
-  if (keys)
-    {
-      for (i=0; keys[i]; i++)
-        gpgme_key_unref (keys[i]);
-      xfree (keys);
-    }
+  xfree (keystring);
   release_context (ctx);
   gpgme_data_release (input);
   return err;
index cad30f6..a01d89a 100644 (file)
@@ -267,5 +267,10 @@ EXPORTS
 
     gpgme_op_conf_dir                    @199
 
+    gpgme_op_encrypt_ext                  @200
+    gpgme_op_encrypt_ext_start            @201
+    gpgme_op_encrypt_sign_ext             @202
+    gpgme_op_encrypt_sign_ext_start       @203
+
 ; END
 
index e319879..8aba5ba 100644 (file)
@@ -1274,10 +1274,22 @@ gpgme_encrypt_flags_t;
    store the resulting ciphertext in CIPHER.  */
 gpgme_error_t gpgme_op_encrypt_start (gpgme_ctx_t ctx, gpgme_key_t recp[],
                                      gpgme_encrypt_flags_t flags,
-                                     gpgme_data_t plain, gpgme_data_t cipher);
+                                     gpgme_data_t plain,
+                                      gpgme_data_t cipher);
 gpgme_error_t gpgme_op_encrypt (gpgme_ctx_t ctx, gpgme_key_t recp[],
                                gpgme_encrypt_flags_t flags,
-                               gpgme_data_t plain, gpgme_data_t cipher);
+                               gpgme_data_t plain,
+                                gpgme_data_t cipher);
+gpgme_error_t gpgme_op_encrypt_ext_start (gpgme_ctx_t ctx, gpgme_key_t recp[],
+                                          const char *recpstring,
+                                          gpgme_encrypt_flags_t flags,
+                                          gpgme_data_t plain,
+                                          gpgme_data_t cipher);
+gpgme_error_t gpgme_op_encrypt_ext (gpgme_ctx_t ctx, gpgme_key_t recp[],
+                                    const char *recpstring,
+                                    gpgme_encrypt_flags_t flags,
+                                    gpgme_data_t plain,
+                                    gpgme_data_t cipher);
 
 /* Encrypt plaintext PLAIN within CTX for the recipients RECP and
    store the resulting ciphertext in CIPHER.  Also sign the ciphertext
@@ -1289,7 +1301,19 @@ gpgme_error_t gpgme_op_encrypt_sign_start (gpgme_ctx_t ctx,
                                           gpgme_data_t cipher);
 gpgme_error_t gpgme_op_encrypt_sign (gpgme_ctx_t ctx, gpgme_key_t recp[],
                                     gpgme_encrypt_flags_t flags,
-                                    gpgme_data_t plain, gpgme_data_t cipher);
+                                    gpgme_data_t plain,
+                                     gpgme_data_t cipher);
+gpgme_error_t gpgme_op_encrypt_sign_ext_start (gpgme_ctx_t ctx,
+                                               gpgme_key_t recp[],
+                                               const char *recpstring,
+                                               gpgme_encrypt_flags_t flags,
+                                               gpgme_data_t plain,
+                                               gpgme_data_t cipher);
+gpgme_error_t gpgme_op_encrypt_sign_ext (gpgme_ctx_t ctx, gpgme_key_t recp[],
+                                         const char *recpstring,
+                                         gpgme_encrypt_flags_t flags,
+                                         gpgme_data_t plain,
+                                         gpgme_data_t cipher);
 
 \f
 /*
index a95befb..b49c86d 100644 (file)
@@ -215,10 +215,15 @@ GPGME_1.0 {
     gpgme_op_edit;
     gpgme_op_edit_start;
     gpgme_op_encrypt;
-    gpgme_op_encrypt_result;
+    gpgme_op_encrypt_start;
+    gpgme_op_encrypt_ext;
+    gpgme_op_encrypt_ext_start;
     gpgme_op_encrypt_sign;
+    gpgme_op_encrypt_sign_ext;
     gpgme_op_encrypt_sign_start;
-    gpgme_op_encrypt_start;
+    gpgme_op_encrypt_sign_ext_start;
+    gpgme_op_encrypt_result;
+
     gpgme_op_export;
     gpgme_op_export_ext;
     gpgme_op_export_ext_start;
index 51e2d60..9408469 100644 (file)
 static int verbose;
 
 
+static char *
+xstrdup (const char *string)
+{
+  char *p = strdup (string);
+  if (!p)
+    {
+      fprintf (stderr, "strdup failed\n");
+      exit (2);
+    }
+  return p;
+}
+
+
 static gpg_error_t
 status_cb (void *opaque, const char *keyword, const char *value)
 {
@@ -88,6 +101,7 @@ show_usage (int ex)
          "  --uiserver         use the UI server\n"
          "  --loopback         use a loopback pinentry\n"
          "  --key NAME         encrypt to key NAME\n"
+         "  --keystring NAMES  encrypt to ';' delimited NAMES\n"
          "  --throw-keyids     use this option\n"
          "  --no-symkey-cache  disable the use of that cache\n"
          "  --wrap             assume input is valid OpenPGP message\n"
@@ -103,7 +117,6 @@ main (int argc, char **argv)
   int last_argc = -1;
   gpgme_error_t err;
   gpgme_ctx_t ctx;
-  const char *key_string = NULL;
   gpgme_protocol_t protocol = GPGME_PROTOCOL_OpenPGP;
   gpgme_data_t in, out;
   gpgme_encrypt_result_t result;
@@ -113,6 +126,7 @@ main (int argc, char **argv)
   char *keyargs[10];
   gpgme_key_t keys[10+1];
   int keycount = 0;
+  char *keystring = NULL;
   int i;
   gpgme_encrypt_flags_t flags = GPGME_ENCRYPT_ALWAYS_TRUST;
   gpgme_off_t offset;
@@ -174,6 +188,17 @@ main (int argc, char **argv)
           keyargs[keycount++] = *argv;
           argc--; argv++;
         }
+      else if (!strcmp (*argv, "--keystring"))
+        {
+          argc--; argv++;
+          if (!argc)
+            show_usage (1);
+          keystring = xstrdup (*argv);
+          for (i=0; keystring[i]; i++)
+            if (keystring[i] == ';')
+              keystring[i] = '\n';
+          argc--; argv++;
+        }
       else if (!strcmp (*argv, "--throw-keyids"))
         {
           flags |= GPGME_ENCRYPT_THROW_KEYIDS;
@@ -207,15 +232,6 @@ main (int argc, char **argv)
   if (argc != 1)
     show_usage (1);
 
-  if (key_string && protocol == GPGME_PROTOCOL_UISERVER)
-    {
-      fprintf (stderr, PGM ": ignoring --key in UI-server mode\n");
-      key_string = NULL;
-    }
-
-  if (!key_string)
-    key_string = "test";
-
   init_gpgme (protocol);
 
   err = gpgme_new (&ctx);
@@ -298,7 +314,8 @@ main (int argc, char **argv)
   err = gpgme_data_new (&out);
   fail_if_err (err);
 
-  err = gpgme_op_encrypt (ctx, keycount ? keys : NULL, flags, in, out);
+  err = gpgme_op_encrypt_ext (ctx, keycount ? keys : NULL, keystring,
+                              flags, in, out);
   result = gpgme_op_encrypt_result (ctx);
   if (result)
     print_result (result);
@@ -318,5 +335,6 @@ main (int argc, char **argv)
   for (i=0; i < keycount; i++)
     gpgme_key_unref (keys[i]);
   gpgme_release (ctx);
+  free (keystring);
   return 0;
 }