From 88f2c1c0d16eee6bb36a901623ea65ac69499f03 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 19 May 2016 17:01:07 +0200 Subject: [PATCH] api: Add new function gpgme_set_ctx_flag. * src/gpgme.h.in (gpgme_set_ctx_flag): New prototype. * src/gpgme.c (gpgme_set_ctx_flag): New. * src/gpgme.def, src/libgpgme.vers: Add new function. * src/context.h (struct gpgme_context): Add FULL_STATUS. * src/decrypt.c (_gpgme_decrypt_status_handler): Do not call the status callback if FULL_STATUS is set. * src/genkey.c (genkey_status_handler): Ditto. * src/passphrase.c (_gpgme_passphrase_status_handler): Ditto. * src/sign.c (_gpgme_sign_status_handler): Ditto. * src/engine-backend.h (struct engine_ops): Add SET_STATUS_CB and add adjust all definitions of that variable. * src/engine.c (_gpgme_engine_set_status_cb): New. * src/op-support.c (_gpgme_op_reset): Call this function. * src/engine-gpg.c (struct engine_gpg): Add fields MON_CB and MON_CB_VALUE. (gpg_set_status_cb): New. (_gpgme_engine_ops_gpg): Register that function. (read_status): Call the monitor callback. * src/engine-gpgsm.c (struct engine_gpgsm): Add fields MON_CB and MON_CB_VALUE. (_gpgme_engine_ops_gpgsm): Register that function. (gpgsm_assuan_simple_command): Change first arg to be an engine context and adjust call callers. Call the monitor callback. * src/engine-uiserver.c (struct engine_uiserver): Add fields MON_CB and MON_CB_VALUE. (_gpgme_engine_ops_uiserver): Register that function. (uiserver_assuan_simple_command): Change first arg to be an engine context and adjust call callers. Call the monitor callback. * tests/run-verify.c (status_cb): New. (print_result): Print algo names. (main): Add option --status. -- This new feature is mainly intended for bug tracking. Having access to the raw status lines might also be useful for applications, though. Signed-off-by: Werner Koch --- NEWS | 1 + doc/gpgme.texi | 21 ++++++++++++++ src/context.h | 4 +++ src/decrypt.c | 2 +- src/engine-assuan.c | 1 + src/engine-backend.h | 1 + src/engine-g13.c | 1 + src/engine-gpg.c | 39 ++++++++++++++++++++------ src/engine-gpgconf.c | 1 + src/engine-gpgsm.c | 65 +++++++++++++++++++++++++++---------------- src/engine-spawn.c | 1 + src/engine-uiserver.c | 43 ++++++++++++++++++++++------ src/engine.c | 15 ++++++++++ src/engine.h | 2 ++ src/genkey.c | 2 +- src/gpgme.c | 24 ++++++++++++++++ src/gpgme.def | 1 + src/gpgme.h.in | 6 +++- src/libgpgme.vers | 1 + src/op-support.c | 6 ++++ src/passphrase.c | 11 ++++---- src/sign.c | 2 +- tests/run-verify.c | 29 +++++++++++++++++-- 23 files changed, 225 insertions(+), 54 deletions(-) diff --git a/NEWS b/NEWS index cfff559e..119866e1 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,7 @@ Noteworthy changes in version 1.7.0 (unreleased) [C25/A14/R_] * Interface changes relative to the 1.6.0 release: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ gpgme_pubkey_algo_string NEW. + gpgme_set_ctx_flag NEW. GPGME_PK_EDDSA NEW. diff --git a/doc/gpgme.texi b/doc/gpgme.texi index db94617b..4d7a8746 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -2736,6 +2736,27 @@ or @var{ctx} is not a valid pointer, @code{NULL} is returned in both variables. @end deftypefun +@deftypefun {gpgme_error_t} gpgme_set_ctx_flag @ + (@w{gpgme_ctx_t @var{ctx}}, @ + @w{const char *@var{name}}, @ + @w{const char *@var{value}}) + +Some minor properties of the context can be controlled with flags set +by this function. The properties are identified by the following +values for @var{name}: + +@table @code +@item "full-status" +Using a @var{value} of "1" the status callback set by +gpgme_set_status_cb returns all status lines with the exception of +PROGRESS lines. With the default of "0" the status callback is only +called in certain situations. + +@end table + +This function returns @code{0} on success. +@end deftypefun + @node Locale @subsection Locale diff --git a/src/context.h b/src/context.h index 757d9b42..078f0cbd 100644 --- a/src/context.h +++ b/src/context.h @@ -101,6 +101,10 @@ struct gpgme_context /* True if offline mode should be used. */ unsigned int offline : 1; + /* True if a status callback shall be called for nearly all status + * lines. */ + unsigned int full_status : 1; + /* Flags for keylist mode. */ gpgme_keylist_mode_t keylist_mode; diff --git a/src/decrypt.c b/src/decrypt.c index 4db68a10..51e42920 100644 --- a/src/decrypt.c +++ b/src/decrypt.c @@ -303,7 +303,7 @@ _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code, break; case GPGME_STATUS_INQUIRE_MAXLEN: - if (ctx->status_cb) + if (ctx->status_cb && !ctx->full_status) { err = ctx->status_cb (ctx->status_cb_value, "INQUIRE_MAXLEN", args); if (err) diff --git a/src/engine-assuan.c b/src/engine-assuan.c index 99024675..a3960067 100644 --- a/src/engine-assuan.c +++ b/src/engine-assuan.c @@ -752,6 +752,7 @@ struct engine_ops _gpgme_engine_ops_assuan = /* Member functions. */ llass_release, NULL, /* reset */ + NULL, /* set_status_cb */ NULL, /* set_status_handler */ NULL, /* set_command_handler */ NULL, /* set_colon_line_handler */ diff --git a/src/engine-backend.h b/src/engine-backend.h index 4f4519c0..ea7db144 100644 --- a/src/engine-backend.h +++ b/src/engine-backend.h @@ -49,6 +49,7 @@ struct engine_ops /* Member functions. */ void (*release) (void *engine); gpgme_error_t (*reset) (void *engine); + void (*set_status_cb) (void *engine, gpgme_status_cb_t cb, void *cb_value); void (*set_status_handler) (void *engine, engine_status_handler_t fnc, void *fnc_value); gpgme_error_t (*set_command_handler) (void *engine, diff --git a/src/engine-g13.c b/src/engine-g13.c index 4a7b75c5..8f24f4c2 100644 --- a/src/engine-g13.c +++ b/src/engine-g13.c @@ -768,6 +768,7 @@ struct engine_ops _gpgme_engine_ops_g13 = #else NULL, /* reset */ #endif + NULL, /* set_status_cb */ NULL, /* set_status_handler */ NULL, /* set_command_handler */ NULL, /* set_colon_line_handler */ diff --git a/src/engine-gpg.c b/src/engine-gpg.c index 9efced25..e507c683 100644 --- a/src/engine-gpg.c +++ b/src/engine-gpg.c @@ -95,6 +95,8 @@ struct engine_gpg int eof; engine_status_handler_t fnc; void *fnc_value; + gpgme_status_cb_t mon_cb; + void *mon_cb_value; void *tag; } status; @@ -609,6 +611,17 @@ gpg_set_locale (void *engine, int category, const char *value) return 0; } +/* This sets a status callback for monitoring status lines before they + * are passed to a caller set handler. */ +static void +gpg_set_status_cb (void *engine, gpgme_status_cb_t cb, void *cb_value) +{ + engine_gpg_t gpg = engine; + + gpg->status.mon_cb = cb; + gpg->status.mon_cb_value = cb_value; +} + /* Note, that the status_handler is allowed to modifiy the args value. */ @@ -1019,6 +1032,7 @@ read_status (engine_gpg_t gpg) size_t bufsize = gpg->status.bufsize; char *buffer = gpg->status.buffer; size_t readpos = gpg->status.readpos; + gpgme_error_t err; assert (buffer); if (bufsize - readpos < 256) @@ -1037,15 +1051,15 @@ read_status (engine_gpg_t gpg) if (!nread) { + err = 0; gpg->status.eof = 1; + if (gpg->status.mon_cb) + err = gpg->status.mon_cb (gpg->status.mon_cb_value, + GPGME_STATUS_EOF, ""); if (gpg->status.fnc) - { - gpgme_error_t err; - err = gpg->status.fnc (gpg->status.fnc_value, GPGME_STATUS_EOF, ""); - if (err) - return err; - } - return 0; + err = gpg->status.fnc (gpg->status.fnc_value, GPGME_STATUS_EOF, ""); + + return err; } while (nread > 0) @@ -1071,6 +1085,15 @@ read_status (engine_gpg_t gpg) *rest++ = 0; r = _gpgme_parse_status (buffer + 9); + if (gpg->status.mon_cb && r != GPGME_STATUS_PROGRESS) + { + /* Note that we call the monitor even if we do + * not know the status code (r < 0). */ + err = gpg->status.mon_cb (gpg->status.mon_cb_value, + buffer + 9, rest); + if (err) + return err; + } if (r >= 0) { if (gpg->cmd.used @@ -1099,7 +1122,6 @@ read_status (engine_gpg_t gpg) } else if (gpg->status.fnc) { - gpgme_error_t err; err = gpg->status.fnc (gpg->status.fnc_value, r, rest); if (err) @@ -2470,6 +2492,7 @@ struct engine_ops _gpgme_engine_ops_gpg = /* Member functions. */ gpg_release, NULL, /* reset */ + gpg_set_status_cb, gpg_set_status_handler, gpg_set_command_handler, gpg_set_colon_line_handler, diff --git a/src/engine-gpgconf.c b/src/engine-gpgconf.c index a2407ac7..bcc95225 100644 --- a/src/engine-gpgconf.c +++ b/src/engine-gpgconf.c @@ -934,6 +934,7 @@ struct engine_ops _gpgme_engine_ops_gpgconf = /* Member functions. */ gpgconf_release, NULL, /* reset */ + NULL, /* set_status_cb */ NULL, /* set_status_handler */ NULL, /* set_command_handler */ NULL, /* set_colon_line_handler */ diff --git a/src/engine-gpgsm.c b/src/engine-gpgsm.c index 476e9ef3..3aa9f0bf 100644 --- a/src/engine-gpgsm.c +++ b/src/engine-gpgsm.c @@ -88,6 +88,8 @@ struct engine_gpgsm { engine_status_handler_t fnc; void *fnc_value; + gpgme_status_cb_t mon_cb; + void *mon_cb_value; } status; struct @@ -558,10 +560,11 @@ gpgsm_set_locale (void *engine, int category, const char *value) static gpgme_error_t -gpgsm_assuan_simple_command (assuan_context_t ctx, char *cmd, +gpgsm_assuan_simple_command (engine_gpgsm_t gpgsm, char *cmd, engine_status_handler_t status_fnc, void *status_fnc_value) { + assuan_context_t ctx = gpgsm->assuan_ctx; gpg_error_t err, cb_err; char *line; size_t linelen; @@ -610,8 +613,15 @@ gpgsm_assuan_simple_command (assuan_context_t ctx, char *cmd, *(rest++) = 0; r = _gpgme_parse_status (line + 2); + if (gpgsm->status.mon_cb && r != GPGME_STATUS_PROGRESS) + { + /* Note that we call the monitor even if we do + * not know the status code (r < 0). */ + cb_err = gpgsm->status.mon_cb (gpgsm->status.mon_cb_value, + line + 2, rest); + } - if (r >= 0 && status_fnc) + if (r >= 0 && status_fnc && !cb_err) cb_err = status_fnc (status_fnc_value, r, rest); } } @@ -726,7 +736,7 @@ gpgsm_set_fd (engine_gpgsm_t gpgsm, fd_type_t fd_type, const char *opt) which, iocb_data->server_fd_str); #endif - err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, line, NULL, NULL); + err = gpgsm_assuan_simple_command (gpgsm, line, NULL, NULL); #if USE_DESCRIPTOR_PASSING leave_set_fd: @@ -1075,8 +1085,7 @@ gpgsm_reset (void *engine) need to reset the list of signers. Note that RESET does not reset OPTION commands. */ return (gpgsm->assuan_ctx - ? gpgsm_assuan_simple_command (gpgsm->assuan_ctx, "RESET", - NULL, NULL) + ? gpgsm_assuan_simple_command (gpgsm, "RESET", NULL, NULL) : 0); } #endif @@ -1180,7 +1189,6 @@ static gpgme_error_t set_recipients (engine_gpgsm_t gpgsm, gpgme_key_t recp[]) { gpgme_error_t err = 0; - assuan_context_t ctx = gpgsm->assuan_ctx; char *line; int linelen; int invalid_recipients = 0; @@ -1218,7 +1226,7 @@ set_recipients (engine_gpgsm_t gpgsm, gpgme_key_t recp[]) } strcpy (&line[10], fpr); - err = gpgsm_assuan_simple_command (ctx, line, gpgsm->status.fnc, + err = gpgsm_assuan_simple_command (gpgsm, line, gpgsm->status.fnc, gpgsm->status.fnc_value); /* FIXME: This requires more work. */ if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY) @@ -1249,7 +1257,7 @@ gpgsm_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags, if (flags & GPGME_ENCRYPT_NO_ENCRYPT_TO) { - err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, + err = gpgsm_assuan_simple_command (gpgsm, "OPTION no-encrypt-to", NULL, NULL); if (err) return err; @@ -1472,8 +1480,7 @@ gpgsm_import (void *engine, gpgme_data_t keydata, gpgme_key_t *keyarray) /* Fist check whether the engine already features the --re-import option. */ err = gpgsm_assuan_simple_command - (gpgsm->assuan_ctx, - "GETINFO cmd_has_option IMPORT re-import", NULL, NULL); + (gpgsm, "GETINFO cmd_has_option IMPORT re-import", NULL, NULL); if (err) return gpg_error (GPG_ERR_NOT_SUPPORTED); @@ -1575,13 +1582,12 @@ gpgsm_keylist (void *engine, const char *pattern, int secret_only, available and thus there is no need for gpgsm to ask the agent whether a secret key exists for the public key. */ if (secret_only || (mode & GPGME_KEYLIST_MODE_WITH_SECRET)) - gpgsm_assuan_simple_command (gpgsm->assuan_ctx, "GETINFO agent-check", - NULL, NULL); + gpgsm_assuan_simple_command (gpgsm, "GETINFO agent-check", NULL, NULL); /* Always send list-mode option because RESET does not reset it. */ if (asprintf (&line, "OPTION list-mode=%d", (list_mode & 3)) < 0) return gpg_error_from_syserror (); - err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, line, NULL, NULL); + err = gpgsm_assuan_simple_command (gpgsm, line, NULL, NULL); free (line); if (err) return err; @@ -1591,24 +1597,24 @@ gpgsm_keylist (void *engine, const char *pattern, int secret_only, /* Use the validation mode if requested. We don't check for an error yet because this is a pretty fresh gpgsm features. */ - gpgsm_assuan_simple_command (gpgsm->assuan_ctx, + gpgsm_assuan_simple_command (gpgsm, (mode & GPGME_KEYLIST_MODE_VALIDATE)? "OPTION with-validation=1": "OPTION with-validation=0" , NULL, NULL); /* Include the ephemeral keys if requested. We don't check for an error yet because this is a pretty fresh gpgsm features. */ - gpgsm_assuan_simple_command (gpgsm->assuan_ctx, + gpgsm_assuan_simple_command (gpgsm, (mode & GPGME_KEYLIST_MODE_EPHEMERAL)? "OPTION with-ephemeral-keys=1": "OPTION with-ephemeral-keys=0" , NULL, NULL); - gpgsm_assuan_simple_command (gpgsm->assuan_ctx, + gpgsm_assuan_simple_command (gpgsm, (mode & GPGME_KEYLIST_MODE_WITH_SECRET)? "OPTION with-secret=1": "OPTION with-secret=0" , NULL, NULL); - gpgsm_assuan_simple_command (gpgsm->assuan_ctx, + gpgsm_assuan_simple_command (gpgsm, (engine_flags & GPGME_ENGINE_FLAG_OFFLINE)? "OPTION offline=1": "OPTION offline=0" , @@ -1665,7 +1671,7 @@ gpgsm_keylist_ext (void *engine, const char *pattern[], int secret_only, /* Always send list-mode option because RESET does not reset it. */ if (asprintf (&line, "OPTION list-mode=%d", (list_mode & 3)) < 0) return gpg_error_from_syserror (); - err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, line, NULL, NULL); + err = gpgsm_assuan_simple_command (gpgsm, line, NULL, NULL); free (line); if (err) return err; @@ -1673,17 +1679,17 @@ gpgsm_keylist_ext (void *engine, const char *pattern[], int secret_only, /* Always send key validation because RESET does not reset it. */ /* Use the validation mode if required. We don't check for an error yet because this is a pretty fresh gpgsm features. */ - gpgsm_assuan_simple_command (gpgsm->assuan_ctx, + gpgsm_assuan_simple_command (gpgsm, (mode & GPGME_KEYLIST_MODE_VALIDATE)? "OPTION with-validation=1": "OPTION with-validation=0" , NULL, NULL); - gpgsm_assuan_simple_command (gpgsm->assuan_ctx, + gpgsm_assuan_simple_command (gpgsm, (mode & GPGME_KEYLIST_MODE_WITH_SECRET)? "OPTION with-secret=1": "OPTION with-secret=0" , NULL, NULL); - gpgsm_assuan_simple_command (gpgsm->assuan_ctx, + gpgsm_assuan_simple_command (gpgsm, (engine_flags & GPGME_ENGINE_FLAG_OFFLINE)? "OPTION offline=1": "OPTION offline=0" , @@ -1797,8 +1803,7 @@ gpgsm_sign (void *engine, gpgme_data_t in, gpgme_data_t out, if (asprintf (&assuan_cmd, "OPTION include-certs %i", include_certs) < 0) return gpg_error_from_syserror (); - err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, assuan_cmd, - NULL, NULL); + err = gpgsm_assuan_simple_command (gpgsm, assuan_cmd, NULL, NULL); free (assuan_cmd); if (err) return err; @@ -1812,7 +1817,7 @@ gpgsm_sign (void *engine, gpgme_data_t in, gpgme_data_t out, char buf[100]; strcpy (stpcpy (buf, "SIGNER "), s); - err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, buf, + err = gpgsm_assuan_simple_command (gpgsm, buf, gpgsm->status.fnc, gpgsm->status.fnc_value); } @@ -1913,6 +1918,17 @@ gpgsm_getauditlog (void *engine, gpgme_data_t output, unsigned int flags) } +/* This sets a status callback for monitoring status lines before they + * are passed to a caller set handler. */ +static void +gpgsm_set_status_cb (void *engine, gpgme_status_cb_t cb, void *cb_value) +{ + engine_gpgsm_t gpgsm = engine; + + gpgsm->status.mon_cb = cb; + gpgsm->status.mon_cb_value = cb_value; +} + static void gpgsm_set_status_handler (void *engine, engine_status_handler_t fnc, @@ -2001,6 +2017,7 @@ struct engine_ops _gpgme_engine_ops_gpgsm = #else NULL, /* reset */ #endif + gpgsm_set_status_cb, gpgsm_set_status_handler, NULL, /* set_command_handler */ gpgsm_set_colon_line_handler, diff --git a/src/engine-spawn.c b/src/engine-spawn.c index eb4e0385..3674efb2 100644 --- a/src/engine-spawn.c +++ b/src/engine-spawn.c @@ -440,6 +440,7 @@ struct engine_ops _gpgme_engine_ops_spawn = /* Member functions. */ engspawn_release, NULL, /* reset */ + NULL, /* set_status_cb */ NULL, /* set_status_handler */ NULL, /* set_command_handler */ NULL, /* set_colon_line_handler */ diff --git a/src/engine-uiserver.c b/src/engine-uiserver.c index e4fd47c3..d05ade61 100644 --- a/src/engine-uiserver.c +++ b/src/engine-uiserver.c @@ -90,6 +90,8 @@ struct engine_uiserver { engine_status_handler_t fnc; void *fnc_value; + gpgme_status_cb_t mon_cb; + void *mon_cb_value; } status; struct @@ -451,10 +453,11 @@ uiserver_set_protocol (void *engine, gpgme_protocol_t protocol) static gpgme_error_t -uiserver_assuan_simple_command (assuan_context_t ctx, char *cmd, - engine_status_handler_t status_fnc, - void *status_fnc_value) +uiserver_assuan_simple_command (engine_uiserver_t uiserver, char *cmd, + engine_status_handler_t status_fnc, + void *status_fnc_value) { + assuan_context_t ctx = uiserver->assuan_ctx; gpg_error_t err; char *line; size_t linelen; @@ -493,8 +496,17 @@ uiserver_assuan_simple_command (assuan_context_t ctx, char *cmd, *(rest++) = 0; r = _gpgme_parse_status (line + 2); + if (uiserver->status.mon_cb && r != GPGME_STATUS_PROGRESS) + { + /* Note that we call the monitor even if we do + * not know the status code (r < 0). */ + err = uiserver->status.mon_cb (uiserver->status.mon_cb_value, + line + 2, rest); + } - if (r >= 0 && status_fnc) + if (err) + ; + else if (r >= 0 && status_fnc) err = status_fnc (status_fnc_value, r, rest); else err = gpg_error (GPG_ERR_GENERAL); @@ -576,7 +588,7 @@ uiserver_set_fd (engine_uiserver_t uiserver, fd_type_t fd_type, const char *opt) else snprintf (line, COMMANDLINELEN, "%s FD", which); - err = uiserver_assuan_simple_command (uiserver->assuan_ctx, line, NULL, NULL); + err = uiserver_assuan_simple_command (uiserver, line, NULL, NULL); leave_set_fd: if (err) @@ -915,7 +927,7 @@ uiserver_reset (void *engine) /* We must send a reset because we need to reset the list of signers. Note that RESET does not reset OPTION commands. */ - return uiserver_assuan_simple_command (uiserver->assuan_ctx, "RESET", NULL, NULL); + return uiserver_assuan_simple_command (uiserver, "RESET", NULL, NULL); } @@ -984,7 +996,6 @@ static gpgme_error_t set_recipients (engine_uiserver_t uiserver, gpgme_key_t recp[]) { gpgme_error_t err = 0; - assuan_context_t ctx = uiserver->assuan_ctx; char *line; int linelen; int invalid_recipients = 0; @@ -1023,7 +1034,8 @@ set_recipients (engine_uiserver_t uiserver, gpgme_key_t recp[]) /* FIXME: need to do proper escaping */ strcpy (&line[10], uid); - err = uiserver_assuan_simple_command (ctx, line, uiserver->status.fnc, + err = uiserver_assuan_simple_command (uiserver, line, + uiserver->status.fnc, uiserver->status.fnc_value); /* FIXME: This might requires more work. */ if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY) @@ -1160,7 +1172,7 @@ uiserver_sign (void *engine, gpgme_data_t in, gpgme_data_t out, char buf[100]; strcpy (stpcpy (buf, "SENDER --info "), s); - err = uiserver_assuan_simple_command (uiserver->assuan_ctx, buf, + err = uiserver_assuan_simple_command (uiserver, buf, uiserver->status.fnc, uiserver->status.fnc_value); } @@ -1252,6 +1264,18 @@ uiserver_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text, } +/* This sets a status callback for monitoring status lines before they + * are passed to a caller set handler. */ +static void +uiserver_set_status_cb (void *engine, gpgme_status_cb_t cb, void *cb_value) +{ + engine_uiserver_t uiserver = engine; + + uiserver->status.mon_cb = cb; + uiserver->status.mon_cb_value = cb_value; +} + + static void uiserver_set_status_handler (void *engine, engine_status_handler_t fnc, void *fnc_value) @@ -1309,6 +1333,7 @@ struct engine_ops _gpgme_engine_ops_uiserver = /* Member functions. */ uiserver_release, uiserver_reset, + uiserver_set_status_cb, uiserver_set_status_handler, NULL, /* set_command_handler */ uiserver_set_colon_line_handler, diff --git a/src/engine.c b/src/engine.c index 8e84da95..c9449db1 100644 --- a/src/engine.c +++ b/src/engine.c @@ -503,6 +503,21 @@ _gpgme_engine_release (engine_t engine) } +/* Set a status callback which is used to monitor the status values + * before they are passed to a handler set with + * _gpgme_engine_set_status_handler. */ +void +_gpgme_engine_set_status_cb (engine_t engine, + gpgme_status_cb_t cb, void *cb_value) +{ + if (!engine) + return; + + if (engine->ops->set_status_cb) + (*engine->ops->set_status_cb) (engine->engine, cb, cb_value); +} + + void _gpgme_engine_set_status_handler (engine_t engine, engine_status_handler_t fnc, void *fnc_value) diff --git a/src/engine.h b/src/engine.h index 56fcc420..238a21c0 100644 --- a/src/engine.h +++ b/src/engine.h @@ -62,6 +62,8 @@ gpgme_error_t _gpgme_engine_set_locale (engine_t engine, int category, gpgme_error_t _gpgme_engine_set_protocol (engine_t engine, gpgme_protocol_t protocol); void _gpgme_engine_release (engine_t engine); +void _gpgme_engine_set_status_cb (engine_t engine, + gpgme_status_cb_t cb, void *cb_value); void _gpgme_engine_set_status_handler (engine_t engine, engine_status_handler_t fnc, void *fnc_value); diff --git a/src/genkey.c b/src/genkey.c index 3afd3b41..34cc5af4 100644 --- a/src/genkey.c +++ b/src/genkey.c @@ -134,7 +134,7 @@ genkey_status_handler (void *priv, gpgme_status_code_t code, char *args) break; case GPGME_STATUS_INQUIRE_MAXLEN: - if (ctx->status_cb) + if (ctx->status_cb && !ctx->full_status) { err = ctx->status_cb (ctx->status_cb_value, "INQUIRE_MAXLEN", args); if (err) diff --git a/src/gpgme.c b/src/gpgme.c index 0b42ea19..3289be9d 100644 --- a/src/gpgme.c +++ b/src/gpgme.c @@ -82,6 +82,30 @@ gpgme_set_global_flag (const char *name, const char *value) } +/* Set the flag NAME for CTX to VALUE. The supported flags are: + * + * - full-status :: With a value of "1" the status callback set by + * gpgme_set_status_cb returns all status lines + * except for PROGRESS lines. With the default of + * "0" the status callback is only called in certain + * situations. + */ +gpgme_error_t +gpgme_set_ctx_flag (gpgme_ctx_t ctx, const char *name, const char *value) +{ + if (!ctx || !name || !value) + return gpg_error (GPG_ERR_INV_VALUE); + else if (!strcmp (name, "full-status")) + { + ctx->full_status = *value? !!atoi (value) : 0; + } + else + return gpg_error (GPG_ERR_UNKNOWN_NAME); + + return 0; +} + + /* Create a new context as an environment for GPGME crypto operations. */ diff --git a/src/gpgme.def b/src/gpgme.def index 3b56aaad..dfdb6c66 100644 --- a/src/gpgme.def +++ b/src/gpgme.def @@ -225,5 +225,6 @@ EXPORTS gpgme_get_status_cb @168 gpgme_pubkey_algo_string @169 + gpgme_set_ctx_flag @170 ; END diff --git a/src/gpgme.h.in b/src/gpgme.h.in index 7a58dedd..5f7896de 100644 --- a/src/gpgme.h.in +++ b/src/gpgme.h.in @@ -911,6 +911,10 @@ gpgme_error_t gpgme_new (gpgme_ctx_t *ctx); /* Release the context CTX. */ void gpgme_release (gpgme_ctx_t ctx); +/* Set the flag NAME for CTX to VALUE. */ +gpgme_error_t gpgme_set_ctx_flag (gpgme_ctx_t ctx, + const char *name, const char *value); + /* Set the protocol to be used by CTX to PROTO. */ gpgme_error_t gpgme_set_protocol (gpgme_ctx_t ctx, gpgme_protocol_t proto); @@ -993,7 +997,7 @@ void gpgme_get_progress_cb (gpgme_ctx_t ctx, gpgme_progress_cb_t *cb, void **hook_value); /* Set the status callback function in CTX to CB. HOOK_VALUE is - passed as first argument to thes status callback function. */ + passed as first argument to the status callback function. */ void gpgme_set_status_cb (gpgme_ctx_t c, gpgme_status_cb_t cb, void *hook_value); diff --git a/src/libgpgme.vers b/src/libgpgme.vers index c677190f..873cb190 100644 --- a/src/libgpgme.vers +++ b/src/libgpgme.vers @@ -100,6 +100,7 @@ GPGME_1.1 { gpgme_get_status_cb; gpgme_pubkey_algo_string; + gpgme_set_ctx_flag; }; diff --git a/src/op-support.c b/src/op-support.c index 4e388a41..a74405ef 100644 --- a/src/op-support.c +++ b/src/op-support.c @@ -148,6 +148,12 @@ _gpgme_op_reset (gpgme_ctx_t ctx, int type) err = 0; } + if (!err && ctx->status_cb && ctx->full_status) + { + _gpgme_engine_set_status_cb (ctx->engine, + ctx->status_cb, ctx->status_cb_value); + } + if (err) { _gpgme_engine_release (ctx->engine); diff --git a/src/passphrase.c b/src/passphrase.c index c88e57d2..74d235cb 100644 --- a/src/passphrase.c +++ b/src/passphrase.c @@ -118,9 +118,8 @@ _gpgme_passphrase_status_handler (void *priv, gpgme_status_code_t code, case GPGME_STATUS_ERROR: /* We abuse this status handler to forward ERROR status codes to - the caller. This should better be done in a generic handler, - but for now this is sufficient. */ - if (ctx->status_cb) + the caller. */ + if (ctx->status_cb && !ctx->full_status) { err = ctx->status_cb (ctx->status_cb_value, "ERROR", args); if (err) @@ -130,9 +129,8 @@ _gpgme_passphrase_status_handler (void *priv, gpgme_status_code_t code, case GPGME_STATUS_FAILURE: /* We abuse this status handler to forward FAILURE status codes - to the caller. This should better be done in a generic - handler, but for now this is sufficient. */ - if (ctx->status_cb) + to the caller. */ + if (ctx->status_cb && !ctx->full_status) { err = ctx->status_cb (ctx->status_cb_value, "FAILURE", args); if (err) @@ -173,6 +171,7 @@ _gpgme_passphrase_command_handler (void *priv, gpgme_status_code_t code, if (processed) *processed = 1; + /* Fake a status line to to convey the MAXLEN info. */ if (ctx->status_cb && opd->maxlen) err = ctx->status_cb (ctx->status_cb_value, "INQUIRE_MAXLEN", opd->maxlen); diff --git a/src/sign.c b/src/sign.c index d8650a94..bfd9ad18 100644 --- a/src/sign.c +++ b/src/sign.c @@ -369,7 +369,7 @@ _gpgme_sign_status_handler (void *priv, gpgme_status_code_t code, char *args) break; case GPGME_STATUS_INQUIRE_MAXLEN: - if (ctx->status_cb) + if (ctx->status_cb && !ctx->full_status) err = ctx->status_cb (ctx->status_cb_value, "INQUIRE_MAXLEN", args); break; diff --git a/tests/run-verify.c b/tests/run-verify.c index b49ea2ab..b7be3203 100644 --- a/tests/run-verify.c +++ b/tests/run-verify.c @@ -36,6 +36,15 @@ static int verbose; +static gpg_error_t +status_cb (void *opaque, const char *keyword, const char *value) +{ + (void)opaque; + fprintf (stderr, "status_cb: %s %s\n", keyword, value); + return 0; +} + + static void print_summary (gpgme_sigsum_t summary) { @@ -102,8 +111,10 @@ print_result (gpgme_verify_result_t result) printf (" validity ..: "); print_validity (sig->validity); putchar ('\n'); printf (" val.reason : %s\n", gpgme_strerror (sig->status)); - printf (" pubkey algo: %d\n", sig->pubkey_algo); - printf (" digest algo: %d\n", sig->hash_algo); + printf (" pubkey algo: %d (%s)\n", sig->pubkey_algo, + nonnull(gpgme_pubkey_algo_name (sig->pubkey_algo))); + printf (" digest algo: %d (%s)\n", sig->hash_algo, + nonnull(gpgme_hash_algo_name (sig->hash_algo))); printf (" pka address: %s\n", nonnull (sig->pka_address)); printf (" pka trust .: %s\n", sig->pka_trust == 0? "n/a" : @@ -126,6 +137,7 @@ show_usage (int ex) fputs ("usage: " PGM " [options] [DETACHEDSIGFILE] FILE\n\n" "Options:\n" " --verbose run in verbose mode\n" + " --status print status lines from the backend\n" " --openpgp use the OpenPGP protocol (default)\n" " --cms use the CMS protocol\n" , stderr); @@ -145,6 +157,7 @@ main (int argc, char **argv) FILE *fp_msg = NULL; gpgme_data_t msg = NULL; gpgme_verify_result_t result; + int print_status = 0; if (argc) { argc--; argv++; } @@ -164,6 +177,11 @@ main (int argc, char **argv) verbose = 1; argc--; argv++; } + else if (!strcmp (*argv, "--status")) + { + print_status = 1; + argc--; argv++; + } else if (!strcmp (*argv, "--openpgp")) { protocol = GPGME_PROTOCOL_OpenPGP; @@ -207,6 +225,11 @@ main (int argc, char **argv) err = gpgme_new (&ctx); fail_if_err (err); gpgme_set_protocol (ctx, protocol); + if (print_status) + { + gpgme_set_status_cb (ctx, status_cb, NULL); + gpgme_set_ctx_flag (ctx, "full-status", "1"); + } err = gpgme_data_new_from_stream (&sig, fp_sig); if (err) @@ -232,7 +255,7 @@ main (int argc, char **argv) print_result (result); if (err) { - fprintf (stderr, PGM ": signing failed: %s\n", gpgme_strerror (err)); + fprintf (stderr, PGM ": verify failed: %s\n", gpgme_strerror (err)); exit (1); }