diff --git a/NEWS b/NEWS index 6499f5e4..5332432c 100644 --- 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] diff --git a/doc/gpgme.texi b/doc/gpgme.texi index a4a08143..5971e48c 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -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ü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}. diff --git a/src/edit.c b/src/edit.c index 1be60c46..887af730 100644 --- a/src/edit.c +++ b/src/edit.c @@ -27,12 +27,15 @@ #include "debug.h" #include "context.h" #include "ops.h" +#include "util.h" + 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 @@ -102,6 +114,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; +} + + + + +/* 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, diff --git a/src/gpgme.def b/src/gpgme.def index 7882af62..9815a834 100644 --- a/src/gpgme.def +++ b/src/gpgme.def @@ -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 diff --git a/src/gpgme.h.in b/src/gpgme.h.in index 5ed08903..9c87b7b4 100644 --- a/src/gpgme.h.in +++ b/src/gpgme.h.in @@ -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. */ diff --git a/src/libgpgme.vers b/src/libgpgme.vers index d635b6ba..aec9090d 100644 --- a/src/libgpgme.vers +++ b/src/libgpgme.vers @@ -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; }; diff --git a/src/status-table.c b/src/status-table.c index 1318c8ed..f44a08fb 100644 --- a/src/status-table.c +++ b/src/status-table.c @@ -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"; +} diff --git a/src/util.h b/src/util.h index a59700f6..88e77508 100644 --- a/src/util.h +++ b/src/util.h @@ -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); #ifdef HAVE_W32_SYSTEM diff --git a/tests/gpg/t-edit.c b/tests/gpg/t-edit.c index 8b5f7cb6..7b444fa0 100644 --- a/tests/gpg/t-edit.c +++ b/tests/gpg/t-edit.c @@ -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);