core: New function gpgme_op_interact, deprecate gpgme_op_edit.
authorWerner Koch <wk@gnupg.org>
Thu, 15 Sep 2016 08:45:04 +0000 (10:45 +0200)
committerWerner Koch <wk@gnupg.org>
Thu, 15 Sep 2016 09:39:43 +0000 (11:39 +0200)
* src/gpgme.h.in (gpgme_interact_cb_t): New.
(GPGME_INTERACT_CARD): New.
(gpgme_op_interact_start, gpgme_op_interact): New.
* src/libgpgme.vers, src/gpgme.def: Add new functions.
* src/edit.c (op_data_t): Rename fnc to fnc_old and change users.  Add
fnc.
(edit_status_handler): Call old or new callback.
(command_handler): Ditto.
(interact_start): New.
(gpgme_op_interact_start, gpgme_op_interact_start): New.
* src/status-table.c (_gpgme_status_to_string): New.

* tests/gpg/t-edit.c (edit_fnc): Rename to interact_fnc and change
type of STATUS.  Use gpgme_io_writen.
(main): s/gpgme_op_edit/gpgme_op_interact/.
--

This change will eventually allow us to remove all those status codes
from gpgme.h.

Signed-off-by: Werner Koch <wk@gnupg.org>
NEWS
doc/gpgme.texi
src/edit.c
src/gpgme.def
src/gpgme.h.in
src/libgpgme.vers
src/status-table.c
src/util.h
tests/gpg/t-edit.c

diff --git a/NEWS b/NEWS
index 6499f5e..5332432 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -9,6 +9,9 @@ Noteworthy changes in version 1.7.0 (unreleased) [C25/A14/R_]
 
  * New global flag "require-gnupg" to set a minimal gnupg version.
 
+ * New function gpgme_op_interact to replace the deprecated functions
+   gpgme_op_edit and gpgme_op_card_edit.
+
  * Interface changes relative to the 1.6.0 release:
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  gpgme_pubkey_algo_string       NEW.
@@ -27,6 +30,15 @@ Noteworthy changes in version 1.7.0 (unreleased) [C25/A14/R_]
  gpgme_op_keysign               NEW.
  gpgme_op_tofu_policy_start     NEW.
  gpgme_op_tofu_policy           NEW.
+ gpgme_op_interact_start        NEW.
+ gpgme_op_interact              NEW.
+ gpgme_interact_cb_t            NEW.
+ gpgme_op_edit_start            DEPRECATED.
+ gpgme_op_edit                  DEPRECATED.
+ gpgme_op_card_edit_start       DEPRECATED.
+ gpgme_op_card_edit             DEPRECATED.
+ gpgme_edit_cb_t                DEPRECATED.
+ gpgme_status_code_t            DEPRECATED.
  gpgme_genkey_result_t          EXTENDED: New fields pubkey and seckey.
  gpgme_signature_t              EXTENDED: New field key.
  gpgme_key_t                    EXTENDED: New field fpr.
@@ -56,6 +68,7 @@ Noteworthy changes in version 1.7.0 (unreleased) [C25/A14/R_]
  GPGME_CREATE_FORCE             NEW.
  GPGME_KEYSIGN_LOCAL            NEW.
  GPGME_KEYSIGN_LFSEP            NEW.
+ GPGME_INTERACT_CARD            NEW.
 
 
 Noteworthy changes in version 1.6.0 (2015-08-26) [C25/A14/R0]
index a4a0814..5971e48 100644 (file)
@@ -15,7 +15,7 @@
 
 @copying
 Copyright @copyright{} 2002, 2003, 2004, 2005, 2006, 2007,
-2008, 2010, 2012, 2013, 2014 g10 Code GmbH.
+2008, 2010, 2012, 2013, 2014, 2016 g10 Code GmbH.
 
 @quotation
 Permission is granted to copy, distribute and/or modify this document
@@ -71,7 +71,7 @@ This is Edition @value{EDITION}, last updated @value{UPDATED}, of
 @center for version @value{VERSION}
 @page
 @vskip 0pt plus 1filll
-Published by g10 Code GmbH@* HÃ\83¼ttenstr. 61@* 40699 Erkrath, Germany
+Published by g10 Code GmbH@* Hüttenstr. 61@* 40699 Erkrath, Germany
 
 @insertcopying
 @end titlepage
@@ -4301,7 +4301,79 @@ could not be started.
 @subsection Advanced Key Editing
 @cindex key, edit
 
-@deftp {Data type} {gpgme_error_t (*gpgme_edit_cb_t) (@w{void *@var{handle}}, @w{gpgme_status_code_t @var{status}}, @w{const char *@var{args}}, @w{int @var{fd}})}
+@deftp {Data type} {gpgme_error_t (*gpgme_interact_cb_t) @
+   (@w{void *@var{handle}}, @
+    @w{const char *@var{status}}, @
+    @w{const char *@var{args}}, @
+    @w{int @var{fd}})}
+@tindex gpgme_interact_cb_t
+The @code{gpgme_interact_cb_t} type is the type of functions which
+@acronym{GPGME} calls if it a key interact operation is on-going.  The
+status keyword @var{status} and the argument line @var{args} are passed
+through by @acronym{GPGME} from the crypto engine.  The file
+descriptor @var{fd} is -1 for normal status messages.  If @var{status}
+indicates a command rather than a status message, the response to the
+command should be written to @var{fd}.  The @var{handle} is provided
+by the user at start of operation.
+
+The function should return @code{GPG_ERR_FALSE} if it did not handle
+the status code, @code{0} for success, or any other error value.
+@end deftp
+
+@deftypefun gpgme_error_t gpgme_op_interact (@w{gpgme_ctx_t @var{ctx}}, @
+   @w{gpgme_key_t @var{key}}, @
+   @w{unsigned int @var{flags}}, @
+   @w{gpgme_interact_cb_t @var{fnc}}, @
+   @w{void *@var{handle}}, @
+   @w{gpgme_data_t @var{out}})
+The function @code{gpgme_op_interact} processes the key @var{KEY}
+interactively, using the interact callback function @var{FNC} with the
+handle @var{HANDLE}.  The callback is invoked for every status and
+command request from the crypto engine.  The output of the crypto
+engine is written to the data object @var{out}.
+
+Note that the protocol between the callback function and the crypto
+engine is specific to the crypto engine and no further support in
+implementing this protocol correctly is provided by @acronym{GPGME}.
+
+@var{flags} modifies the behaviour of the function; the only defined
+bit value is:
+
+@table @code
+@item GPGME_INTERACT_CARD
+This is used for smartcard based keys and uses gpg’s
+@code{--card-edit} command.
+
+@end table
+
+The function returns @code{0} if the edit operation completes
+successfully, @code{GPG_ERR_INV_VALUE} if @var{ctx} or @var{key} is
+not a valid pointer, and any error returned by the crypto engine or
+the edit callback handler.
+@end deftypefun
+
+
+@deftypefun gpgme_error_t gpgme_op_interact_start (@w{gpgme_ctx_t @var{ctx}}, @
+   @w{gpgme_key_t @var{key}}, @
+   @w{unsigned int @var{flags}}, @
+   @w{gpgme_interact_cb_t @var{fnc}}, @
+   @w{void *@var{handle}}, @
+   @w{gpgme_data_t @var{out}})
+The function @code{gpgme_op_interact_start} initiates a
+@code{gpgme_op_interact} operation.  It can be completed by calling
+@code{gpgme_wait} on the context.  @xref{Waiting For Completion}.
+
+The function returns @code{0} if the operation was started
+successfully, and @code{GPG_ERR_INV_VALUE} if @var{ctx} or @var{key}
+is not a valid pointer.
+@end deftypefun
+
+
+@deftp {Data type} {gpgme_error_t (*gpgme_edit_cb_t) @
+   (@w{void *@var{handle}}, @
+    @w{gpgme_status_code_t @var{status}}, @
+    @w{const char *@var{args}}, @
+    @w{int @var{fd}})}
 @tindex gpgme_edit_cb_t
 The @code{gpgme_edit_cb_t} type is the type of functions which
 @acronym{GPGME} calls if it a key edit operation is on-going.  The
@@ -4317,6 +4389,9 @@ the status code, @code{0} for success, or any other error value.
 @end deftp
 
 @deftypefun gpgme_error_t gpgme_op_edit (@w{gpgme_ctx_t @var{ctx}}, @w{gpgme_key_t @var{key}}, @w{gpgme_edit_cb_t @var{fnc}}, @w{void *@var{handle}}, @w{gpgme_data_t @var{out}})
+Note: This function is deprecated, please use
+@code{gpgme_op_interact} instead.
+
 The function @code{gpgme_op_edit} processes the key @var{KEY}
 interactively, using the edit callback function @var{FNC} with the
 handle @var{HANDLE}.  The callback is invoked for every status and
@@ -4334,6 +4409,9 @@ by the crypto engine or the edit callback handler.
 @end deftypefun
 
 @deftypefun gpgme_error_t gpgme_op_edit_start (@w{gpgme_ctx_t @var{ctx}}, @w{gpgme_key_t @var{key}}, @w{gpgme_edit_cb_t @var{fnc}}, @w{void *@var{handle}}, @w{gpgme_data_t @var{out}})
+Note: This function is deprecated, please use
+@code{gpgme_op_interact_start} instead.
+
 The function @code{gpgme_op_edit_start} initiates a
 @code{gpgme_op_edit} operation.  It can be completed by calling
 @code{gpgme_wait} on the context.  @xref{Waiting For Completion}.
@@ -4345,11 +4423,17 @@ operation was started successfully, and @code{GPG_ERR_INV_VALUE} if
 
 
 @deftypefun gpgme_error_t gpgme_op_card_edit (@w{gpgme_ctx_t @var{ctx}}, @w{gpgme_key_t @var{key}}, @w{gpgme_edit_cb_t @var{fnc}}, @w{void *@var{handle}}, @w{gpgme_data_t @var{out}})
+Note: This function is deprecated, please use @code{gpgme_op_interact}
+with the flag @code{GPGME_INTERACT_CARD} instead.
+
 The function @code{gpgme_op_card_edit} is analogous to
 @code{gpgme_op_edit}, but should be used to process the smart card corresponding to the key @var{key}.
 @end deftypefun
 
 @deftypefun gpgme_error_t gpgme_op_card_edit_start (@w{gpgme_ctx_t @var{ctx}}, @w{gpgme_key_t @var{key}}, @w{gpgme_edit_cb_t @var{fnc}}, @w{void *@var{handle}}, @w{gpgme_data_t @var{out}})
+Note: This function is deprecated, please use @code{gpgme_op_interact_start}
+with the flag @code{GPGME_INTERACT_CARD} instead.
+
 The function @code{gpgme_op_card_edit_start} initiates a
 @code{gpgme_op_card_edit} operation.  It can be completed by calling
 @code{gpgme_wait} on the context.  @xref{Waiting For Completion}.
index 1be60c4..887af73 100644 (file)
 #include "debug.h"
 #include "context.h"
 #include "ops.h"
+#include "util.h"
+
 
 \f
 typedef struct
 {
   /* The user callback function and its hook value.  */
-  gpgme_edit_cb_t fnc;
+  gpgme_interact_cb_t fnc;
+  gpgme_edit_cb_t fnc_old;
   void *fnc_value;
 } *op_data_t;
 
@@ -58,7 +61,11 @@ edit_status_handler (void *priv, gpgme_status_code_t status, char *args)
   if (err)
     return err;
 
-  return (*opd->fnc) (opd->fnc_value, status, args, -1);
+  if (opd->fnc_old)
+    return (*opd->fnc_old) (opd->fnc_value, status, args, -1);
+
+  return (*opd->fnc) (opd->fnc_value, _gpgme_status_to_string (status),
+                      args, -1);
 }
 
 
@@ -90,7 +97,12 @@ command_handler (void *priv, gpgme_status_code_t status, const char *args,
       if (err)
        return err;
 
-      err = (*opd->fnc) (opd->fnc_value, status, args, fd);
+      if (opd->fnc_old)
+        err = (*opd->fnc_old) (opd->fnc_value, status, args, fd);
+      else
+        err = (*opd->fnc) (opd->fnc_value, _gpgme_status_to_string (status),
+                           args, fd);
+
       if (gpg_err_code (err) == GPG_ERR_FALSE)
         err = 0;
       else
@@ -103,6 +115,87 @@ command_handler (void *priv, gpgme_status_code_t status, const char *args,
 
 
 static gpgme_error_t
+interact_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t key,
+                unsigned int flags,
+                gpgme_interact_cb_t fnc, void *fnc_value, gpgme_data_t out)
+{
+  gpgme_error_t err;
+  void *hook;
+  op_data_t opd;
+
+  err = _gpgme_op_reset (ctx, synchronous);
+  if (err)
+    return err;
+
+  if (!fnc || !out)
+    return gpg_error (GPG_ERR_INV_VALUE);
+
+  err = _gpgme_op_data_lookup (ctx, OPDATA_EDIT, &hook, sizeof (*opd), NULL);
+  opd = hook;
+  if (err)
+    return err;
+
+  opd->fnc = fnc;
+  opd->fnc_old = NULL;
+  opd->fnc_value = fnc_value;
+
+  err = _gpgme_engine_set_command_handler (ctx->engine, command_handler,
+                                          ctx, out);
+  if (err)
+    return err;
+
+  _gpgme_engine_set_status_handler (ctx->engine, edit_status_handler, ctx);
+
+  return _gpgme_engine_op_edit (ctx->engine,
+                                (flags & GPGME_INTERACT_CARD)? 1: 0,
+                                key, out, ctx);
+}
+
+
+gpgme_error_t
+gpgme_op_interact_start (gpgme_ctx_t ctx, gpgme_key_t key, unsigned int flags,
+                         gpgme_interact_cb_t fnc, void *fnc_value,
+                         gpgme_data_t out)
+{
+  gpgme_error_t err;
+
+  TRACE_BEG5 (DEBUG_CTX, "gpgme_op_interact_start", ctx,
+             "key=%p flags=0x%x fnc=%p fnc_value=%p, out=%p",
+             key, flags,fnc, fnc_value, out);
+
+  if (!ctx)
+    return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
+
+  err = interact_start (ctx, 0, key, flags, fnc, fnc_value, out);
+  return err;
+}
+
+
+gpgme_error_t
+gpgme_op_interact (gpgme_ctx_t ctx, gpgme_key_t key, unsigned int flags,
+                   gpgme_interact_cb_t fnc, void *fnc_value,
+                   gpgme_data_t out)
+{
+  gpgme_error_t err;
+
+  TRACE_BEG5 (DEBUG_CTX, "gpgme_op_interact", ctx,
+             "key=%p flags=0x%x fnc=%p fnc_value=%p, out=%p",
+             key, flags,fnc, fnc_value, out);
+
+  if (!ctx)
+    return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
+
+  err = interact_start (ctx, 1, key, flags, fnc, fnc_value, out);
+  if (!err)
+    err = _gpgme_wait_one (ctx);
+  return err;
+}
+
+
+
+\f
+/* The deprectated interface.  */
+static gpgme_error_t
 edit_start (gpgme_ctx_t ctx, int synchronous, int type, gpgme_key_t key,
            gpgme_edit_cb_t fnc, void *fnc_value, gpgme_data_t out)
 {
@@ -122,7 +215,8 @@ edit_start (gpgme_ctx_t ctx, int synchronous, int type, gpgme_key_t key,
   if (err)
     return err;
 
-  opd->fnc = fnc;
+  opd->fnc = NULL;
+  opd->fnc_old = fnc;
   opd->fnc_value = fnc_value;
 
   err = _gpgme_engine_set_command_handler (ctx->engine, command_handler,
index 7882af6..9815a83 100644 (file)
@@ -241,6 +241,8 @@ EXPORTS
     gpgme_op_keysign                      @181
     gpgme_op_tofu_policy_start            @182
     gpgme_op_tofu_policy                  @183
+    gpgme_op_interact_start               @184
+    gpgme_op_interact                     @185
 
 ; END
 
index 5ed0890..9c87b7b 100644 (file)
@@ -444,7 +444,9 @@ typedef unsigned int gpgme_export_mode_t;
 #define GPGME_AUDITLOG_HTML      1
 #define GPGME_AUDITLOG_WITH_HELP 128
 
-/* The possible stati for the edit operation.  */
+
+/* The possible stati for gpgme_op_edit.  The use of that function and
+ * these status codes are deprecated in favor of gpgme_op_interact. */
 typedef enum
   {
     GPGME_STATUS_EOF = 0,
@@ -967,8 +969,13 @@ typedef void (*gpgme_progress_cb_t) (void *opaque, const char *what,
 typedef gpgme_error_t (*gpgme_status_cb_t) (void *opaque, const char *keyword,
                                             const char *args);
 
-
 /* Interact with the user about an edit operation.  */
+typedef gpgme_error_t (*gpgme_interact_cb_t) (void *opaque,
+                                              const char *keyword,
+                                              const char *args, int fd);
+
+/* The callback type used by the deprecated functions gpgme_op_card
+ * and gpgme_of_card_edit.  */
 typedef gpgme_error_t (*gpgme_edit_cb_t) (void *opaque,
                                          gpgme_status_code_t status,
                                          const char *args, int fd);
@@ -1217,7 +1224,7 @@ void gpgme_set_io_cbs (gpgme_ctx_t ctx, gpgme_io_cbs_t io_cbs);
 void gpgme_get_io_cbs (gpgme_ctx_t ctx, gpgme_io_cbs_t io_cbs);
 
 /* Wrappers around the internal I/O functions for use with
-   gpgme_passphrase_cb_t and gpgme_edit_cb_t.  */
+   gpgme_passphrase_cb_t and gpgme_interact_cb_t.  */
 @API__SSIZE_T@ gpgme_io_read (int fd, void *buffer, size_t count);
 @API__SSIZE_T@ gpgme_io_write (int fd, const void *buffer, size_t count);
 int     gpgme_io_writen (int fd, const void *buffer, size_t count);
@@ -1949,23 +1956,36 @@ gpgme_error_t gpgme_op_keysign       (gpgme_ctx_t ctx,
  * Key edit interface
  */
 
-/* Edit the key KEY.  Send status and command requests to FNC and
+/* Flags to select the mode of the interact.  */
+#define GPGME_INTERACT_CARD   (1 << 0)  /* Use --card-edit mode. */
+
+
+/* Edit the KEY.  Send status and command requests to FNC and
    output of edit commands to OUT.  */
+gpgme_error_t gpgme_op_interact_start (gpgme_ctx_t ctx,
+                                       gpgme_key_t key,
+                                       unsigned int flags,
+                                       gpgme_interact_cb_t fnc,
+                                       void *fnc_value,
+                                       gpgme_data_t out);
+gpgme_error_t gpgme_op_interact (gpgme_ctx_t ctx, gpgme_key_t key,
+                                 unsigned int flags,
+                                 gpgme_interact_cb_t fnc,
+                                 void *fnc_value,
+                                 gpgme_data_t out);
+
 gpgme_error_t gpgme_op_edit_start (gpgme_ctx_t ctx, gpgme_key_t key,
                                   gpgme_edit_cb_t fnc, void *fnc_value,
-                                  gpgme_data_t out);
+                                  gpgme_data_t out) _GPGME_DEPRECATED;
 gpgme_error_t gpgme_op_edit (gpgme_ctx_t ctx, gpgme_key_t key,
                             gpgme_edit_cb_t fnc, void *fnc_value,
-                            gpgme_data_t out);
-
-/* Edit the card for the key KEY.  Send status and command requests to
-   FNC and output of edit commands to OUT.  */
+                            gpgme_data_t out) _GPGME_DEPRECATED;
 gpgme_error_t gpgme_op_card_edit_start (gpgme_ctx_t ctx, gpgme_key_t key,
                                        gpgme_edit_cb_t fnc, void *fnc_value,
-                                       gpgme_data_t out);
+                                       gpgme_data_t out) _GPGME_DEPRECATED;
 gpgme_error_t gpgme_op_card_edit (gpgme_ctx_t ctx, gpgme_key_t key,
                                  gpgme_edit_cb_t fnc, void *fnc_value,
-                                 gpgme_data_t out);
+                                 gpgme_data_t out) _GPGME_DEPRECATED;
 
 
 /* Set the Tofu policy of KEY to POLCIY.  */
index d635b6b..aec9090 100644 (file)
@@ -115,6 +115,8 @@ GPGME_1.1 {
     gpgme_op_keysign;
     gpgme_op_tofu_policy_start;
     gpgme_op_tofu_policy;
+    gpgme_op_interact_start;
+    gpgme_op_interact;
 };
 
 
index 1318c8e..f44a08f 100644 (file)
@@ -169,3 +169,15 @@ _gpgme_parse_status (const char *name)
               sizeof t, status_cmp);
   return r ? r->code : -1;
 }
+
+
+const char *
+_gpgme_status_to_string (gpgme_status_code_t code)
+{
+  int i;
+
+  for (i=0; i < DIM(status_table); i++)
+    if (status_table[i].code == code)
+      return status_table[i].name;
+  return "status_code_lost";
+}
index a59700f..88e7750 100644 (file)
@@ -185,6 +185,7 @@ gpgme_error_t _gpgme_getenv (const char *name, char **value);
 /* Convert a status string to a status code.  */
 void _gpgme_status_init (void);
 gpgme_status_code_t _gpgme_parse_status (const char *name);
+const char *_gpgme_status_to_string (gpgme_status_code_t code);
 
 \f
 #ifdef HAVE_W32_SYSTEM
index 8b5f7cb..7b444fa 100644 (file)
@@ -55,7 +55,7 @@ flush_data (gpgme_data_t dh)
 
 
 gpgme_error_t
-edit_fnc (void *opaque, gpgme_status_code_t status, const char *args, int fd)
+interact_fnc (void *opaque, const char *status, const char *args, int fd)
 {
   const char *result = NULL;
   gpgme_data_t out = (gpgme_data_t) opaque;
@@ -63,7 +63,7 @@ edit_fnc (void *opaque, gpgme_status_code_t status, const char *args, int fd)
   fputs ("[-- Response --]\n", stdout);
   flush_data (out);
 
-  fprintf (stdout, "[-- Code: %i, %s --]\n", status, args);
+  fprintf (stdout, "[-- Code: %s, %s --]\n", status, args);
 
   if (fd >= 0)
     {
@@ -103,8 +103,8 @@ edit_fnc (void *opaque, gpgme_status_code_t status, const char *args, int fd)
 
   if (result)
     {
-      gpgme_io_write (fd, result, strlen (result));
-      gpgme_io_write (fd, "\n", 1);
+      gpgme_io_writen (fd, result, strlen (result));
+      gpgme_io_writen (fd, "\n", 1);
     }
   return 0;
 }
@@ -141,7 +141,7 @@ main (int argc, char **argv)
   err = gpgme_op_keylist_end (ctx);
   fail_if_err (err);
 
-  err = gpgme_op_edit (ctx, key, edit_fnc, out, out);
+  err = gpgme_op_interact (ctx, key, 0, interact_fnc, out, out);
   fail_if_err (err);
 
   fputs ("[-- Last response --]\n", stdout);