diff --git a/doc/gpgme.texi b/doc/gpgme.texi index 45c359d0..b3aa369f 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -187,6 +187,7 @@ Context Attributes * Protocol Selection:: Selecting the protocol used by a context. * Crypto Engine:: Configuring the crypto engine. +* Custom Engine Options:: Adding command line options to an engine. * ASCII Armor:: Requesting @acronym{ASCII} armored output. * Text Mode:: Choosing canonical text mode. * Included Certificates:: Including a number of certificates. @@ -2283,6 +2284,7 @@ started. In fact, these references are accessed through the @menu * Protocol Selection:: Selecting the protocol used by a context. * Crypto Engine:: Configuring the crypto engine. +* Custom Engine Options:: Adding command line options to an engine. * ASCII Armor:: Requesting @acronym{ASCII} armored output. * Text Mode:: Choosing canonical text mode. * Included Certificates:: Including a number of certificates. @@ -2362,6 +2364,29 @@ successful, or an eror code on failure. @end deftypefun +@node Custom Engine Options +@subsection Custom Engine Options +@cindex context, configuring engine +@cindex engine, configuration per context + +Since not all features of all engines may be exposed by @acronym{GPGME}, +additional command line arguments may be needed to allow the wanted +functionality. + +@deftypefun gpgme_error_t gpgme_ctx_set_engine_options (@w{gpgme_ctx_t @var{ctx}}, @w{const char *@var{options}}) +The function @code{gpgme_ctx_set_engine_options} sets command line options for +the configured engine in context @var{ctx} to @var{options}. The options are +passed upon each op call and may be reset by setting @var{options} to +@code{NULL}. This function returns @code{0} on success or an error on failure. +@end deftypefun + +@deftypefun gpgme_error_t gpgme_ctx_get_engine_options (@w{gpgme_ctx_t @var{ctx}}, @w{char ** @var{result}}) +The function @code{gpgme_ctx_get_engine_options} returns the previously set +engine options in @var{result}. This function returns @code{0} on success or +an error on failure. +@end deftypefun + + @c FIXME: Unfortunately, using @acronym here breaks texi2dvi. @node ASCII Armor @subsection @acronym{ASCII} Armor diff --git a/src/engine-assuan.c b/src/engine-assuan.c index 663b2eab..99cd9a6c 100644 --- a/src/engine-assuan.c +++ b/src/engine-assuan.c @@ -759,6 +759,8 @@ struct engine_ops _gpgme_engine_ops_assuan = NULL, /* set_colon_line_handler */ llass_set_locale, NULL, /* set_protocol */ + NULL, /* set_options */ + NULL, /* get_options */ NULL, /* decrypt */ NULL, /* decrypt_verify */ NULL, /* delete */ diff --git a/src/engine-backend.h b/src/engine-backend.h index b3cc412a..1079f5f8 100644 --- a/src/engine-backend.h +++ b/src/engine-backend.h @@ -59,6 +59,8 @@ struct engine_ops void *fnc_value); gpgme_error_t (*set_locale) (void *engine, int category, const char *value); gpgme_error_t (*set_protocol) (void *engine, gpgme_protocol_t protocol); + gpgme_error_t (*set_options) (void *engine, const char *options); + const char *(*get_options) (void *engine); gpgme_error_t (*decrypt) (void *engine, gpgme_data_t ciph, gpgme_data_t plain); gpgme_error_t (*decrypt_verify) (void *engine, gpgme_data_t ciph, diff --git a/src/engine-g13.c b/src/engine-g13.c index a9717eec..6cc91008 100644 --- a/src/engine-g13.c +++ b/src/engine-g13.c @@ -775,6 +775,8 @@ struct engine_ops _gpgme_engine_ops_g13 = NULL, /* set_colon_line_handler */ g13_set_locale, NULL, /* set_protocol */ + NULL, /* set_options */ + NULL, /* get_options */ NULL, /* decrypt */ NULL, /* decrypt_verify */ NULL, /* delete */ diff --git a/src/engine-gpg.c b/src/engine-gpg.c index e14fd8dd..0be970a6 100644 --- a/src/engine-gpg.c +++ b/src/engine-gpg.c @@ -115,6 +115,7 @@ struct engine_gpg char **argv; struct fd_data_map_s *fd_data_map; + char *options; /* gpgme_ctx_set_engine_options() */ /* stuff needed for interactive (command) mode */ struct @@ -404,6 +405,7 @@ gpg_release (void *engine) free (gpg->status.buffer); if (gpg->colon.buffer) free (gpg->colon.buffer); + free (gpg->options); if (gpg->argv) free_argv (gpg->argv); if (gpg->cmd.keyword) @@ -716,6 +718,43 @@ gpg_set_command_handler (void *engine, engine_command_handler_t fnc, } +/* Custom command line options set with gpgme_ctx_set_engine_options() */ +static gpgme_error_t +build_custom_argv (engine_gpg_t gpg, size_t *argc, char ***result) +{ + char *s, *options = gpg->options; + char **argv = NULL; + int total = 0; + + if (!options) + return 0; + + while ((s = strsep (&options, " "))) + { + char **tmp = realloc (argv, (total+2) * sizeof (char *)); + + if (!tmp) + { + free_argv (argv); + return GPG_ERR_ENOMEM; + } + + argv = tmp; + argv[total] = strdup (s); + if (!argv[total++]) + { + free_argv (argv); + return GPG_ERR_ENOMEM; + } + + argv[total] = NULL; + (*argc)++; + } + + *result = argv; + return 0; +} + static gpgme_error_t build_argv (engine_gpg_t gpg, const char *pgmname) { @@ -723,7 +762,7 @@ build_argv (engine_gpg_t gpg, const char *pgmname) struct arg_and_data_s *a; struct fd_data_map_s *fd_data_map; size_t datac=0, argc=0; - char **argv; + char **argv, **custom_argv = NULL, **pp; int need_special = 0; int use_agent = 0; char *p; @@ -780,6 +819,10 @@ build_argv (engine_gpg_t gpg, const char *pgmname) argc++; /* --batch */ argc += 1; /* --no-sk-comments */ + err = build_custom_argv (gpg, &argc, &custom_argv); + if (err) + return err; + argv = calloc (argc + 1, sizeof *argv); if (!argv) return gpg_error_from_syserror (); @@ -801,6 +844,14 @@ build_argv (engine_gpg_t gpg, const char *pgmname) return saved_err; } argc++; + + if (custom_argv) + { + for (pp = custom_argv; pp && *pp; pp++) + argv[argc++] = *pp; + free (custom_argv); + } + if (need_special) { argv[argc] = strdup ("--enable-special-filenames"); @@ -2449,6 +2500,30 @@ gpg_set_pinentry_mode (void *engine, gpgme_pinentry_mode_t mode) return 0; } +static gpgme_error_t +gpg_set_options (void *engine, const char *options) +{ + engine_gpg_t gpg = engine; + + free (gpg->options); + gpg->options = NULL; + if (options) + { + gpg->options = strdup (options); + if (!gpg->options) + return GPG_ERR_ENOMEM; + } + + return 0; +} + +static const char * +gpg_get_options (void *engine) +{ + engine_gpg_t gpg = engine; + + return gpg->options; +} struct engine_ops _gpgme_engine_ops_gpg = @@ -2468,6 +2543,8 @@ struct engine_ops _gpgme_engine_ops_gpg = gpg_set_colon_line_handler, gpg_set_locale, NULL, /* set_protocol */ + gpg_set_options, + gpg_get_options, gpg_decrypt, gpg_decrypt, /* decrypt_verify */ gpg_delete, diff --git a/src/engine-gpgconf.c b/src/engine-gpgconf.c index a2407ac7..1033adbd 100644 --- a/src/engine-gpgconf.c +++ b/src/engine-gpgconf.c @@ -939,6 +939,8 @@ struct engine_ops _gpgme_engine_ops_gpgconf = NULL, /* set_colon_line_handler */ NULL, /* set_locale */ NULL, /* set_protocol */ + NULL, /* set_options */ + NULL, /* get_options */ NULL, /* decrypt */ NULL, /* decrypt_verify */ NULL, /* delete */ diff --git a/src/engine-gpgsm.c b/src/engine-gpgsm.c index ac6c5fc6..1c27898c 100644 --- a/src/engine-gpgsm.c +++ b/src/engine-gpgsm.c @@ -1988,6 +1988,8 @@ struct engine_ops _gpgme_engine_ops_gpgsm = gpgsm_set_colon_line_handler, gpgsm_set_locale, NULL, /* set_protocol */ + NULL, /* set_options */ + NULL, /* get_options */ gpgsm_decrypt, gpgsm_decrypt, gpgsm_delete, /* decrypt_verify */ diff --git a/src/engine-spawn.c b/src/engine-spawn.c index eb4e0385..93850217 100644 --- a/src/engine-spawn.c +++ b/src/engine-spawn.c @@ -445,6 +445,8 @@ struct engine_ops _gpgme_engine_ops_spawn = NULL, /* set_colon_line_handler */ NULL, /* set_locale */ NULL, /* set_protocol */ + NULL, /* set_options */ + NULL, /* get_options */ NULL, /* decrypt */ NULL, /* decrypt_verify */ NULL, /* delete */ diff --git a/src/engine-uiserver.c b/src/engine-uiserver.c index a7184b7a..4bfb8852 100644 --- a/src/engine-uiserver.c +++ b/src/engine-uiserver.c @@ -1316,6 +1316,8 @@ struct engine_ops _gpgme_engine_ops_uiserver = uiserver_set_colon_line_handler, uiserver_set_locale, uiserver_set_protocol, + NULL, /* set_options */ + NULL, /* get_options */ uiserver_decrypt, uiserver_decrypt_verify, NULL, /* delete */ diff --git a/src/engine.c b/src/engine.c index ff015c00..cbd34575 100644 --- a/src/engine.c +++ b/src/engine.c @@ -445,6 +445,37 @@ gpgme_set_engine_info (gpgme_protocol_t proto, return err; } +/* Set custom command line options for the engine associated with a + context. */ +gpgme_error_t +gpgme_ctx_set_engine_options (gpgme_ctx_t ctx, const char *options) +{ + if (!ctx || !ctx->engine) + return gpg_error (GPG_ERR_INV_VALUE); + + if (!ctx->engine->ops->set_options) + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); + + return (*ctx->engine->ops->set_options) (ctx->engine->engine, options); +} + +/* Return previously set custom engine command line options. */ +gpgme_error_t +gpgme_ctx_get_engine_options (gpgme_ctx_t ctx, const char **result) +{ + if (!ctx || !ctx->engine) + return gpg_error (GPG_ERR_INV_VALUE); + + if (!result) + return gpg_error (GPG_ERR_INV_ARG); + + if (!ctx->engine->ops->get_options) + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); + + *result = (*ctx->engine->ops->get_options) (ctx->engine->engine); + return 0; +} + gpgme_error_t _gpgme_engine_new (gpgme_engine_info_t info, engine_t *r_engine) diff --git a/src/gpgme.def b/src/gpgme.def index dc189484..754cb57d 100644 --- a/src/gpgme.def +++ b/src/gpgme.def @@ -217,5 +217,7 @@ EXPORTS gpgme_op_spawn_start @163 gpgme_op_spawn @164 + gpgme_ctx_set_engine_options @165 + gpgme_ctx_get_engine_options @166 ; END diff --git a/src/gpgme.h.in b/src/gpgme.h.in index 15ed8037..ffa58c57 100644 --- a/src/gpgme.h.in +++ b/src/gpgme.h.in @@ -947,6 +947,15 @@ gpgme_error_t gpgme_ctx_set_engine_info (gpgme_ctx_t ctx, const char *file_name, const char *home_dir); +/* Set custom command line options for the engine associated with a + context. */ +gpgme_error_t gpgme_ctx_set_engine_options (gpgme_ctx_t ctx, + const char *options); + +/* Return previously set custom engine command line options. */ +gpgme_error_t gpgme_ctx_get_engine_options (gpgme_ctx_t ctx, + const char **result); + /* Return a statically allocated string with the name of the public key algorithm ALGO, or NULL if that name is not known. */ diff --git a/src/libgpgme.vers b/src/libgpgme.vers index 39663c1c..d7c97c8f 100644 --- a/src/libgpgme.vers +++ b/src/libgpgme.vers @@ -92,6 +92,9 @@ GPGME_1.1 { gpgme_op_spawn_start; gpgme_op_spawn; + + gpgme_ctx_set_engine_options; + gpgme_ctx_get_engine_options; }; diff --git a/src/op-support.c b/src/op-support.c index 2bcb3a35..87a9b8d2 100644 --- a/src/op-support.c +++ b/src/op-support.c @@ -83,9 +83,19 @@ _gpgme_op_reset (gpgme_ctx_t ctx, int type) struct gpgme_io_cbs io_cbs; int no_reset = (type & 256); int reuse_engine = 0; + char *options = NULL; + const char *tmp = NULL; type &= 255; + err = gpgme_ctx_get_engine_options (ctx, &tmp); + if (tmp) + { + options = strdup (tmp); + if (!options) + return GPG_ERR_ENOMEM; + } + _gpgme_release_result (ctx); LOCK (ctx->lock); ctx->canceled = 0; @@ -119,8 +129,22 @@ _gpgme_op_reset (gpgme_ctx_t ctx, int type) err = _gpgme_engine_new (info, &ctx->engine); if (err) return err; + + if (options) + { + err = gpgme_ctx_set_engine_options (ctx, options); + if (err && gpg_err_code (err) != GPG_ERR_NOT_IMPLEMENTED) + { + free (options); + _gpgme_engine_release (ctx->engine); + ctx->engine = NULL; + return err; + } + } } + free (options); + if (!reuse_engine) { err = 0;