diff --git a/NEWS b/NEWS index cc545d31..61997880 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,16 @@ +Noteworthy changes in version 1.1.0 (unreleased) +------------------------------------------------ + + * You can now configure the backend engine file name and home + directory to be used, as default and per context. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +gpgme_set_engine_info NEW +gpgme_ctx_get_engine_info NEW +gpgme_ctx_set_engine_info NEW +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Noteworthy changes in version 1.0.1 (2004-10-22) ------------------------------------------------ diff --git a/gpgme/ChangeLog b/gpgme/ChangeLog index 6b2539d6..647fa19f 100644 --- a/gpgme/ChangeLog +++ b/gpgme/ChangeLog @@ -1,3 +1,57 @@ +2004-12-07 Marcus Brinkmann + + * libgpgme.vers (GPGME_1.1): New version. + * engine-backend.h (struct engine_ops): Add argument FILE_NAME to + member get_version(). Add arguments FILE_NAME and HOME_DIR to + member new(). Change return type of get_file_name and get_version + to char *. + * engine-gpgsm.c (gpgsm_get_version): Change return type to char + pointer. Do not cache result. + (gpgsm_new): Add file_name and home_dir argument, and use them + instead of the defaults, if set. + * rungpg.c (struct engine_gpg): New member file_name. + (gpg_get_version): Change return type to char pointer, and do not + cache result. + (gpg_release): Free gpg->file_name. + (gpg_new): Take new arguments file_name and home_dir. Set the + --homedir argument if HOME_DIR is not NULL. Set gpg->file_name. + (start): Use gpg->file_name instead _gpgme_get_gpg_path, if set. + * engine.h (_gpgme_engine_info_copy, _gpgme_engine_info_release): + New prototypes. + (_gpgme_engine_new): Change first argument to gpgme_engine_info_t + info. + * engine.c: Include . + (gpgme_get_engine_info): Set *INFO within the lock. Move + ENGINE_INFO and ENGINE_INFO_LOCK to .... + (engine_info, engine_info_lock): ... here. New static variables. + (engine_get_version): Add file_name argument to + get_version invocation. Change return type to char pointer. + (gpgme_engine_check_version): Rewritten to free() the return value + of engine_get_version after using it. + (_gpgme_engine_info_release): New function. + (gpgme_get_engine_info): Rewritten. + (_gpgme_engine_info_copy): New function. + (_gpgme_set_engine_info): New function. + (gpgme_set_engine_info): New function. + (_gpgme_engine_new): Change first argument to gpgme_engine_info_t + info, and use that. + * gpgme.h (struct _gpgme_engine_info): Change type of file_name + and version to char * (remove the const). New member home_dir. + (gpgme_set_engine_info, gpgme_ctx_get_engine_info, + gpgme_ctx_set_engine_info): New prototypes. + * context.h (struct gpgme_context): New member engine_info. + * gpgme.c (gpgme_new): Allocate CTX->engine_info. + (gpgme_release): Deallocate CTX->engine_info. + (gpgme_ctx_get_engine_info, gpgme_ctx_set_engine_info): New + functions. + * op-support.c (_gpgme_op_reset): Look for correct engine info and + pass it to _gpgme_engine_new. + * version.c (gpgme_check_version): Adjust to + _gpgme_compare_versions returning an int. + (_gpgme_compare_versions): Return an int value, not a const char + pointer. + * ops.h (_gpgme_compare_versions): Same for prototype. + 2004-10-03 Marcus Brinkmann * verify.c (parse_trust): If no reason is provided, set diff --git a/gpgme/context.h b/gpgme/context.h index 64c5276c..83ee6aa5 100644 --- a/gpgme/context.h +++ b/gpgme/context.h @@ -62,6 +62,9 @@ typedef struct ctx_op_data *ctx_op_data_t; be performed (sequentially). */ struct gpgme_context { + /* The engine info for this context. */ + gpgme_engine_info_t engine_info; + /* The protocol used by this context. */ gpgme_protocol_t protocol; diff --git a/gpgme/engine-backend.h b/gpgme/engine-backend.h index 32fd242e..bf481cf1 100644 --- a/gpgme/engine-backend.h +++ b/gpgme/engine-backend.h @@ -30,10 +30,21 @@ struct engine_ops { /* Static functions. */ - const char *(*get_file_name) (void); - const char *(*get_version) (void); + + /* Return the default file name for the binary of this engine. */ + char *(*get_file_name) (void); + + /* Returns a malloced string containing the version of the engine + with the given binary file name (or the default if FILE_NAME is + NULL. */ + char *(*get_version) (const char *file_name); + + /* Returns a statically allocated string containing the required + version. */ const char *(*get_req_version) (void); + gpgme_error_t (*new) (void **r_engine, + const char *file_name, const char *home_dir, const char *lc_ctype, const char *lc_messages); /* Member functions. */ diff --git a/gpgme/engine-gpgsm.c b/gpgme/engine-gpgsm.c index 0138fdf7..10952be4 100644 --- a/gpgme/engine-gpgsm.c +++ b/gpgme/engine-gpgsm.c @@ -95,18 +95,11 @@ struct engine_gpgsm typedef struct engine_gpgsm *engine_gpgsm_t; -static const char * -gpgsm_get_version (void) +static char * +gpgsm_get_version (const char *file_name) { - static const char *gpgsm_version; - DEFINE_STATIC_LOCK (gpgsm_version_lock); - - LOCK (gpgsm_version_lock); - if (!gpgsm_version) - gpgsm_version = _gpgme_get_program_version (_gpgme_get_gpgsm_path ()); - UNLOCK (gpgsm_version_lock); - - return gpgsm_version; + return _gpgme_get_program_version (file_name ? file_name + : _gpgme_get_gpgsm_path ()); } @@ -319,11 +312,13 @@ gpgsm_release (void *engine) static gpgme_error_t -gpgsm_new (void **engine, const char *lc_ctype, const char *lc_messages) +gpgsm_new (void **engine, const char *file_name, const char *home_dir, + const char *lc_ctype, const char *lc_messages) { gpgme_error_t err = 0; engine_gpgsm_t gpgsm; - char *argv[3]; + char *argv[5]; + int argc; int fds[2]; int child_fds[4]; char *dft_display = NULL; @@ -395,12 +390,19 @@ gpgsm_new (void **engine, const char *lc_ctype, const char *lc_messages) child_fds[2] = gpgsm->message_fd_server; child_fds[3] = -1; - argv[0] = "gpgsm"; - argv[1] = "--server"; - argv[2] = NULL; + argc = 0; + argv[argc++] = "gpgsm"; + if (home_dir) + { + argv[argc++] = "--homedir"; + argv[argc++] = home_dir; + } + argv[argc++] = "--server"; + argv[argc++] = NULL; err = assuan_pipe_connect (&gpgsm->assuan_ctx, - _gpgme_get_gpgsm_path (), argv, child_fds); + file_name ? file_name : _gpgme_get_gpgsm_path (), + argv, child_fds); /* FIXME: Check error. */ /* We need to know the fd used by assuan for reads. We do this by diff --git a/gpgme/engine.c b/gpgme/engine.c index 6128c2f7..f2edc7da 100644 --- a/gpgme/engine.c +++ b/gpgme/engine.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "gpgme.h" #include "util.h" @@ -51,9 +52,14 @@ static struct engine_ops *engine_ops[] = #endif }; + +/* The engine info. */ +static gpgme_engine_info_t engine_info; +DEFINE_STATIC_LOCK (engine_info_lock); + /* Get the file name of the engine for PROTOCOL. */ -static const char * +static char * engine_get_file_name (gpgme_protocol_t proto) { if (proto > DIM (engine_ops)) @@ -66,15 +72,16 @@ engine_get_file_name (gpgme_protocol_t proto) } -/* Get the version number of the engine for PROTOCOL. */ -static const char * -engine_get_version (gpgme_protocol_t proto) +/* Get a malloced string containing the version number of the engine + for PROTOCOL. */ +static char * +engine_get_version (gpgme_protocol_t proto, const char *file_name) { if (proto > DIM (engine_ops)) return NULL; if (engine_ops[proto] && engine_ops[proto]->get_version) - return (*engine_ops[proto]->get_version) (); + return (*engine_ops[proto]->get_version) (file_name); else return NULL; } @@ -98,21 +105,45 @@ engine_get_req_version (gpgme_protocol_t proto) gpgme_error_t gpgme_engine_check_version (gpgme_protocol_t proto) { - return _gpgme_compare_versions (engine_get_version (proto), - engine_get_req_version (proto)) - ? 0 : gpg_error (GPG_ERR_INV_ENGINE); + int result; + char *engine_version = engine_get_version (proto, NULL); + + result = _gpgme_compare_versions (engine_version, + engine_get_req_version (proto)); + if (engine_version) + free (engine_version); + + return result ? 0 : gpg_error (GPG_ERR_INV_ENGINE); +} + + +/* Release the engine info INFO. */ +void +_gpgme_engine_info_release (gpgme_engine_info_t info) +{ + while (info) + { + gpgme_engine_info_t next_info = info->next; + + assert (info->file_name); + free (info->file_name); + if (info->home_dir) + free (info->home_dir); + if (info->version) + free (info->version); + free (info); + info = next_info; + } } /* Get the information about the configured and installed engines. A pointer to the first engine in the statically allocated linked list - is returned in *INFO. If an error occurs, it is returned. */ + is returned in *INFO. If an error occurs, it is returned. The + returned data is valid until the next gpgme_set_engine_info. */ gpgme_error_t gpgme_get_engine_info (gpgme_engine_info_t *info) { - static gpgme_engine_info_t engine_info; - DEFINE_STATIC_LOCK (engine_info_lock); - LOCK (engine_info_lock); if (!engine_info) { @@ -123,70 +154,238 @@ gpgme_get_engine_info (gpgme_engine_info_t *info) for (proto = 0; proto < DIM (proto_list); proto++) { - const char *file_name = engine_get_file_name (proto_list[proto]); + char *file_name = engine_get_file_name (proto_list[proto]); if (!file_name) continue; + file_name = strdup (file_name); + *lastp = malloc (sizeof (*engine_info)); - if (!*lastp) + if (!*lastp || !file_name) { int saved_errno = errno; - while (engine_info) - { - gpgme_engine_info_t next_info = engine_info->next; - free (engine_info); - engine_info = next_info; - } + _gpgme_engine_info_release (engine_info); + engine_info = NULL; + + if (file_name) + free (file_name); + UNLOCK (engine_info_lock); return gpg_error_from_errno (saved_errno); } (*lastp)->protocol = proto_list[proto]; (*lastp)->file_name = file_name; - (*lastp)->version = engine_get_version (proto_list[proto]); + (*lastp)->home_dir = NULL; + (*lastp)->version = engine_get_version (proto_list[proto], NULL); (*lastp)->req_version = engine_get_req_version (proto_list[proto]); (*lastp)->next = NULL; lastp = &(*lastp)->next; } } - UNLOCK (engine_info_lock); + *info = engine_info; + UNLOCK (engine_info_lock); return 0; } + +/* Get a deep copy of the engine info and return it in INFO. */ +gpgme_error_t +_gpgme_engine_info_copy (gpgme_engine_info_t *r_info) +{ + gpgme_error_t err = 0; + gpgme_engine_info_t info; + gpgme_engine_info_t new_info; + gpgme_engine_info_t *lastp; + + LOCK (engine_info_lock); + info = engine_info; + if (!info) + { + /* Make sure it is initialized. */ + UNLOCK (engine_info_lock); + err = gpgme_get_engine_info (&info); + if (err) + return err; + + LOCK (engine_info_lock); + } + + new_info = NULL; + lastp = &new_info; + + while (info) + { + char *file_name; + char *home_dir; + char *version; + + assert (info->file_name); + file_name = strdup (info->file_name); + + if (info->home_dir) + { + home_dir = strdup (info->home_dir); + if (!home_dir) + err = gpg_error_from_errno (errno); + } + else + home_dir = NULL; + + if (info->version) + { + version = strdup (info->version); + if (!version) + err = gpg_error_from_errno (errno); + } + else + version = NULL; + + *lastp = malloc (sizeof (*engine_info)); + if (!*lastp || !file_name || err) + { + int saved_errno = errno; + + _gpgme_engine_info_release (new_info); + + if (file_name) + free (file_name); + if (home_dir) + free (home_dir); + if (version) + free (version); + + UNLOCK (engine_info_lock); + return gpg_error_from_errno (saved_errno); + } + + (*lastp)->protocol = info->protocol; + (*lastp)->file_name = file_name; + (*lastp)->home_dir = home_dir; + (*lastp)->version = version; + (*lastp)->req_version = info->req_version; + (*lastp)->next = NULL; + lastp = &(*lastp)->next; + + info = info->next; + } + + *r_info = new_info; + UNLOCK (engine_info_lock); + return 0; +} + + +/* Set the engine info for the info list INFO, protocol PROTO, to the + file name FILE_NAME and the home directory HOME_DIR. */ +gpgme_error_t +_gpgme_set_engine_info (gpgme_engine_info_t info, gpgme_protocol_t proto, + const char *file_name, const char *home_dir) +{ + char *new_file_name; + char *new_home_dir; + + /* FIXME: Use some PROTO_MAX definition. */ + if (proto > DIM (engine_ops)) + return gpg_error (GPG_ERR_INV_VALUE); + + while (info && info->protocol != proto) + info = info->next; + + if (!info) + return gpg_error (GPG_ERR_INV_ENGINE); + + /* Prepare new members. */ + if (file_name) + new_file_name = strdup (file_name); + else + { + new_file_name = engine_get_file_name (proto); + assert (file_name); + new_file_name = strdup (new_file_name); + } + if (!new_file_name) + return gpg_error_from_errno (errno); + + if (home_dir) + { + new_home_dir = strdup (home_dir); + if (!new_home_dir) + { + free (new_file_name); + return gpg_error_from_errno (errno); + } + } + else + new_home_dir = NULL; + + /* Remove the old members. */ + assert (info->file_name); + free (info->file_name); + if (info->home_dir) + free (info->home_dir); + if (info->version) + free (info->version); + + /* Install the new members. */ + info->file_name = new_file_name; + info->home_dir = new_home_dir; + info->version = engine_get_version (proto, file_name); + + return 0; +} + + +/* Set the default engine info for the protocol PROTO to the file name + FILE_NAME and the home directory HOME_DIR. */ +gpgme_error_t +gpgme_set_engine_info (gpgme_protocol_t proto, + const char *file_name, const char *home_dir) +{ + gpgme_error_t err; + gpgme_engine_info_t info; + + LOCK (engine_info_lock); + info = engine_info; + if (!info) + { + /* Make sure it is initialized. */ + UNLOCK (engine_info_lock); + err = gpgme_get_engine_info (&info); + if (err) + return err; + + LOCK (engine_info_lock); + } + + err = _gpgme_set_engine_info (info, proto, file_name, home_dir); + UNLOCK (engine_info_lock); + return err; +} + gpgme_error_t -_gpgme_engine_new (gpgme_protocol_t proto, engine_t *r_engine, +_gpgme_engine_new (gpgme_engine_info_t info, engine_t *r_engine, const char *lc_ctype, const char *lc_messages) { engine_t engine; - const char *file_name; - const char *version; - - if (proto > DIM (engine_ops)) - return gpg_error (GPG_ERR_INV_VALUE); - - if (!engine_ops[proto]) - return gpg_error (GPG_ERR_INV_ENGINE); - - file_name = engine_get_file_name (proto); - version = engine_get_version (proto); - if (!file_name || !version) + if (!info->file_name || !info->version) return gpg_error (GPG_ERR_INV_ENGINE); engine = calloc (1, sizeof *engine); if (!engine) return gpg_error_from_errno (errno); - engine->ops = engine_ops[proto]; - if (engine_ops[proto]->new) + engine->ops = engine_ops[info->protocol]; + if (engine->ops->new) { - gpgme_error_t err = (*engine_ops[proto]->new) (&engine->engine, - lc_ctype, - lc_messages); + gpgme_error_t err = (*engine->ops->new) (&engine->engine, + info->file_name, info->home_dir, + lc_ctype, lc_messages); if (err) { free (engine); diff --git a/gpgme/engine.h b/gpgme/engine.h index 42cec55c..72659cd3 100644 --- a/gpgme/engine.h +++ b/gpgme/engine.h @@ -35,7 +35,14 @@ typedef gpgme_error_t (*engine_command_handler_t) (void *priv, const char *keyword, int fd); -gpgme_error_t _gpgme_engine_new (gpgme_protocol_t proto, +/* Get a deep copy of the engine info and return it in INFO. */ +gpgme_error_t _gpgme_engine_info_copy (gpgme_engine_info_t *r_info); + +/* Release the engine info INFO. */ +void _gpgme_engine_info_release (gpgme_engine_info_t info); + + +gpgme_error_t _gpgme_engine_new (gpgme_engine_info_t info, engine_t *r_engine, const char *lc_ctype, const char *lc_messages); diff --git a/gpgme/gpgme.c b/gpgme/gpgme.c index de707671..d89a8db2 100644 --- a/gpgme/gpgme.c +++ b/gpgme/gpgme.c @@ -50,6 +50,14 @@ gpgme_new (gpgme_ctx_t *r_ctx) ctx = calloc (1, sizeof *ctx); if (!ctx) return gpg_error_from_errno (errno); + + _gpgme_engine_info_copy (&ctx->engine_info); + if (!ctx->engine_info) + { + free (ctx); + return gpg_error_from_errno (errno); + } + ctx->keylist_mode = GPGME_KEYLIST_MODE_LOCAL; ctx->include_certs = 1; ctx->protocol = GPGME_PROTOCOL_OpenPGP; @@ -62,6 +70,7 @@ gpgme_new (gpgme_ctx_t *r_ctx) if (!ctx->lc_ctype) { UNLOCK (def_lc_lock); + _gpgme_engine_info_release (ctx->engine_info); free (ctx); return gpg_error_from_errno (errno); } @@ -77,6 +86,7 @@ gpgme_new (gpgme_ctx_t *r_ctx) UNLOCK (def_lc_lock); if (ctx->lc_ctype) free (ctx->lc_ctype); + _gpgme_engine_info_release (ctx->engine_info); free (ctx); return gpg_error_from_errno (errno); } @@ -120,6 +130,7 @@ gpgme_release (gpgme_ctx_t ctx) free (ctx->lc_ctype); if (ctx->lc_messages) free (ctx->lc_messages); + _gpgme_engine_info_release (ctx->engine_info); free (ctx); } @@ -389,6 +400,29 @@ gpgme_set_locale (gpgme_ctx_t ctx, int category, const char *value) return 0; } + +/* Get the information about the configured engines. A pointer to the + first engine in the statically allocated linked list is returned. + The returned data is valid until the next gpgme_ctx_set_engine_info. */ +gpgme_engine_info_t +gpgme_ctx_get_engine_info (gpgme_ctx_t ctx) +{ + return ctx->engine_info; +} + + +/* Set the engine info for the context CTX, protocol PROTO, to the + file name FILE_NAME and the home directory HOME_DIR. */ +gpgme_error_t +gpgme_ctx_set_engine_info (gpgme_ctx_t ctx, gpgme_protocol_t proto, + const char *file_name, const char *home_dir) +{ + /* FIXME: Make sure to reset the context if we are running in daemon + mode. */ + return _gpgme_set_engine_info (ctx->engine_info, proto, + file_name, home_dir); +} + const char * gpgme_pubkey_algo_name (gpgme_pubkey_algo_t algo) diff --git a/gpgme/gpgme.h b/gpgme/gpgme.h index ffcfe0e9..3048472d 100644 --- a/gpgme/gpgme.h +++ b/gpgme/gpgme.h @@ -412,13 +412,16 @@ struct _gpgme_engine_info gpgme_protocol_t protocol; /* The file name of the engine binary. */ - const char *file_name; - + char *file_name; + /* The version string of the installed engine. */ - const char *version; + char *version; /* The minimum version required for GPGME. */ const char *req_version; + + /* The home directory used, or NULL if default. */ + char *home_dir; }; typedef struct _gpgme_engine_info *gpgme_engine_info_t; @@ -741,6 +744,19 @@ void gpgme_get_progress_cb (gpgme_ctx_t ctx, gpgme_progress_cb_t *cb, locale if CTX is a null pointer. */ gpgme_error_t gpgme_set_locale (gpgme_ctx_t ctx, int category, const char *value); + +/* Get the information about the configured engines. A pointer to the + first engine in the statically allocated linked list is returned. + The returned data is valid until the next gpgme_ctx_set_engine_info. */ +gpgme_engine_info_t gpgme_ctx_get_engine_info (gpgme_ctx_t ctx); + +/* Set the engine info for the context CTX, protocol PROTO, to the + file name FILE_NAME and the home directory HOME_DIR. */ +gpgme_error_t gpgme_ctx_set_engine_info (gpgme_ctx_t ctx, + gpgme_protocol_t proto, + const char *file_name, + const char *home_dir); + /* Return a statically allocated string with the name of the public key algorithm ALGO, or NULL if that name is not known. */ @@ -1501,9 +1517,18 @@ int gpgme_trust_item_get_int_attr (gpgme_trust_item_t item, _gpgme_attr_t what, /* Check that the library fulfills the version requirement. */ const char *gpgme_check_version (const char *req_version); -/* Retrieve information about the backend engines. */ +/* Get the information about the configured and installed engines. A + pointer to the first engine in the statically allocated linked list + is returned in *INFO. If an error occurs, it is returned. The + returned data is valid until the next gpgme_set_engine_info. */ gpgme_error_t gpgme_get_engine_info (gpgme_engine_info_t *engine_info); +/* Set the default engine info for the protocol PROTO to the file name + FILE_NAME and the home directory HOME_DIR. */ +gpgme_error_t gpgme_set_engine_info (gpgme_protocol_t proto, + const char *file_name, + const char *home_dir); + /* Engine support functions. */ diff --git a/gpgme/libgpgme.vers b/gpgme/libgpgme.vers index 9bef503c..a16d37fa 100644 --- a/gpgme/libgpgme.vers +++ b/gpgme/libgpgme.vers @@ -18,6 +18,15 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA +GPGME_1.1 { + global: + gpgme_set_engine_info; + + gpgme_ctx_get_engine_info; + gpgme_ctx_set_engine_info; +}; + + GPGME_1.0 { global: gpgme_check_version; diff --git a/gpgme/op-support.c b/gpgme/op-support.c index be42e75c..7321af43 100644 --- a/gpgme/op-support.c +++ b/gpgme/op-support.c @@ -66,17 +66,26 @@ gpgme_error_t _gpgme_op_reset (gpgme_ctx_t ctx, int type) { gpgme_error_t err = 0; + gpgme_engine_info_t info; struct gpgme_io_cbs io_cbs; + info = ctx->engine_info; + while (info && info->protocol != ctx->protocol) + info = info->next; + + if (!info) + return gpg_error (GPG_ERR_UNSUPPORTED_PROTOCOL); + _gpgme_release_result (ctx); - /* Create an engine object. */ - if (ctx->engine) + if (ctx->engine) { _gpgme_engine_release (ctx->engine); ctx->engine = NULL; } - err = _gpgme_engine_new (ctx->protocol, &ctx->engine, + + /* Create an engine object. */ + err = _gpgme_engine_new (info, &ctx->engine, ctx->lc_ctype, ctx->lc_messages); if (err) return err; diff --git a/gpgme/ops.h b/gpgme/ops.h index f01cc9a5..79ac7d41 100644 --- a/gpgme/ops.h +++ b/gpgme/ops.h @@ -136,8 +136,10 @@ void _gpgme_op_trustlist_event_cb (void *data, gpgme_event_io_t type, /*-- version.c --*/ -const char *_gpgme_compare_versions (const char *my_version, - const char *req_version); +/* Return true if MY_VERSION is at least REQ_VERSION, and false + otherwise. */ +int _gpgme_compare_versions (const char *my_version, + const char *req_version); char *_gpgme_get_program_version (const char *const path); #endif /* OPS_H */ diff --git a/gpgme/rungpg.c b/gpgme/rungpg.c index ce938c62..3d7d4c82 100644 --- a/gpgme/rungpg.c +++ b/gpgme/rungpg.c @@ -66,6 +66,8 @@ struct fd_data_map_s struct engine_gpg { + char *file_name; + struct arg_and_data_s *arglist; struct arg_and_data_s **argtail; @@ -224,17 +226,11 @@ add_data (engine_gpg_t gpg, gpgme_data_t data, int dup_to, int inbound) } -static const char * -gpg_get_version (void) +static char * +gpg_get_version (const char *file_name) { - static const char *gpg_version; - DEFINE_STATIC_LOCK (gpg_version_lock); - - LOCK (gpg_version_lock); - if (!gpg_version) - gpg_version = _gpgme_get_program_version (_gpgme_get_gpg_path ()); - UNLOCK (gpg_version_lock); - return gpg_version; + return _gpgme_get_program_version (file_name ? file_name + : _gpgme_get_gpg_path ()); } @@ -313,6 +309,9 @@ gpg_release (void *engine) gpg_cancel (engine); + if (gpg->file_name) + free (gpg->file_name); + while (gpg->arglist) { struct arg_and_data_s *next = gpg->arglist->next; @@ -336,7 +335,8 @@ gpg_release (void *engine) static gpgme_error_t -gpg_new (void **engine, const char *lc_ctype, const char *lc_messages) +gpg_new (void **engine, const char *file_name, const char *home_dir, + const char *lc_ctype, const char *lc_messages) { engine_gpg_t gpg; gpgme_error_t rc = 0; @@ -345,6 +345,16 @@ gpg_new (void **engine, const char *lc_ctype, const char *lc_messages) if (!gpg) return gpg_error_from_errno (errno); + if (file_name) + { + gpg->file_name = strdup (file_name); + if (!gpg->file_name) + { + rc = gpg_error_from_errno (errno); + goto leave; + } + } + gpg->argtail = &gpg->arglist; gpg->status.fd[0] = -1; gpg->status.fd[1] = -1; @@ -380,6 +390,16 @@ gpg_new (void **engine, const char *lc_ctype, const char *lc_messages) goto leave; } gpg->status.eof = 0; + + if (home_dir) + { + rc = add_arg (gpg, "--homedir"); + if (!rc) + rc = add_arg (gpg, home_dir); + if (rc) + goto leave; + } + rc = add_arg (gpg, "--status-fd"); if (rc) goto leave; @@ -1043,7 +1063,7 @@ start (engine_gpg_t gpg) if (!gpg) return gpg_error (GPG_ERR_INV_VALUE); - if (! _gpgme_get_gpg_path ()) + if (!gpg->file_name && !_gpgme_get_gpg_path ()) return gpg_error (GPG_ERR_INV_ENGINE); rc = build_argv (gpg); @@ -1101,7 +1121,8 @@ start (engine_gpg_t gpg) fd_parent_list[n].fd = -1; fd_parent_list[n].dup_to = -1; - status = _gpgme_io_spawn (_gpgme_get_gpg_path (), + status = _gpgme_io_spawn (gpg->file_name ? gpg->file_name : + _gpgme_get_gpg_path (), gpg->argv, fd_child_list, fd_parent_list); saved_errno = errno; free (fd_child_list); diff --git a/gpgme/version.c b/gpgme/version.c index e2c4ef81..d4d78643 100644 --- a/gpgme/version.c +++ b/gpgme/version.c @@ -103,7 +103,9 @@ parse_version_string (const char *str, int *major, int *minor, int *micro) } -const char * +/* Return true if MY_VERSION is at least REQ_VERSION, and false + otherwise. */ +int _gpgme_compare_versions (const char *my_version, const char *rq_version) { @@ -112,17 +114,17 @@ _gpgme_compare_versions (const char *my_version, const char *my_plvl, *rq_plvl; if (!rq_version) - return my_version; + return 1; if (!my_version) - return NULL; + return 0; my_plvl = parse_version_string (my_version, &my_major, &my_minor, &my_micro); if (!my_plvl) - return NULL; + return 0; rq_plvl = parse_version_string (rq_version, &rq_major, &rq_minor, &rq_micro); if (!rq_plvl) - return NULL; + return 0; if (my_major > rq_major || (my_major == rq_major && my_minor > rq_minor) @@ -130,9 +132,9 @@ _gpgme_compare_versions (const char *my_version, && my_micro > rq_micro) || (my_major == rq_major && my_minor == rq_minor && my_micro == rq_micro && strcmp (my_plvl, rq_plvl) >= 0)) - return my_version; + return 1; - return NULL; + return 0; } @@ -149,7 +151,7 @@ const char * gpgme_check_version (const char *req_version) { do_subsystem_inits (); - return _gpgme_compare_versions (VERSION, req_version); + return _gpgme_compare_versions (VERSION, req_version) ? VERSION : NULL; }