2003-09-14  Marcus Brinkmann  <marcus@g10code.de>

	* gpgme.texi (Locale): New section.
	(Multi Threading): Set locale in example.

gpgme/
2003-09-14  Marcus Brinkmann  <marcus@g10code.de>

	* context.h (struct gpgme_context): New members lc_ctype and
	lc_messages.
	* gpgme.c: Include <locale.h>.
	(def_lc_lock, def_lc_ctype, def_lc_messages): New static
	variables.
	(gpgme_set_locale): New function.
	* engine.c (_gpgme_engine_new): Add arguments lc_ctype and
	lc_messages.
	* engine.h (_gpgme_engine_new): Likewise.
	* engine-gpgsm.c (gpgsm_new): Likewise.
	* rungpg.c (gpg_new): Likewise.
	* engine-backend.h (struct engine_ops): Likewise to NEW.
	* op-support.c (_gpgme_op_reset): Likewise to invocation of
	_gpgme_engine_new.
This commit is contained in:
Marcus Brinkmann 2003-09-14 00:02:41 +00:00
parent c4ea1235d5
commit 256ef2e87e
12 changed files with 265 additions and 72 deletions

19
NEWS
View File

@ -38,6 +38,24 @@ Noteworthy changes in version 0.4.3 (unreleased)
than an unsigned long (the old class field is preserved for
backwards compatibility).
* A new function gpgme_set_locale() is provided to allow configuring
the locale for the crypto backend. This is necessary for text
terminals so that programs like the pinentry can be started with
the right locale settings for the terminal the application is running
on, in case the terminal has different settings than the system
default (for example, if it is a remote terminal). You are highly
recommended to call the following functions directly after
gpgme_check_version:
#include <locale.h>
setlocale (LC_ALL, "");
gpgme_set_locale (NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL));
gpgme_set_locale (NULL, LC_MESSAGES, setlocale (LC_MESSAGES, NULL));
GPGME can not do this for you, as setlocale is not thread safe, and
there is no alternative.
* Interface changes relative to the 0.4.2 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
gpgme_strerror_t NEW
@ -45,6 +63,7 @@ gpgme_get_key CHANGED: Fails correctly if key ID not unique.
gpgme_key_t EXTENDED: New field can_authenticate.
gpgme_subkey_t EXTENDED: New field can_authenticate.
gpgme_new_signature_t CHANGED: New type for class field.
gpgme_set_locale NEW
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -1,3 +1,8 @@
2003-09-14 Marcus Brinkmann <marcus@g10code.de>
* gpgme.texi (Locale): New section.
(Multi Threading): Set locale in example.
2003-09-13 Marcus Brinkmann <marcus@g10code.de>
* gpgme.texi (Error Strings): Add gpgme_strerror_r.

View File

@ -159,6 +159,7 @@ Context Attributes
* Key Listing Mode:: Selecting key listing mode.
* Passphrase Callback:: Getting the passphrase from the user.
* Progress Meter Callback:: Being informed about the progress.
* Locale:: Setting the locale of a context.
Key Management
@ -492,6 +493,31 @@ features are provided by the installed version of the library.
@end deftypefun
After initializing @acronym{GPGME}, you should set the locale
information to the locale required for your output terminal (only
required if your program runs on a text terminal, rather than in the X
Window environment). Here is an example of a complete initialization:
@example
#include <locale.h>
#include <gpgme.h>
void
init_program (void)
@{
/* Initialize the locale environment. */
setlocale (LC_ALL, "");
gpgme_check_version (NULL);
gpgme_set_locale (NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL));
gpgme_set_locale (NULL, LC_MESSAGES, setlocale (LC_MESSAGES, NULL));
@}
@end example
Note that you are highly recommended to initialize the locale settings
like this. @acronym{GPGME} can not do this for you because it would
not be thread safe.
@node Multi Threading
@section Multi Threading
@cindex thread-safeness
@ -548,7 +574,10 @@ call functions in @acronym{GPGME} could call the following function
before any function in the library:
@example
#include <stdlib.h>
#include <locale.h>
#include <pthread.h>
#include <gpgme.h>
void
initialize_gpgme (void)
@ -559,7 +588,9 @@ initialize_gpgme (void)
pthread_mutex_lock (&gpgme_init_lock);
if (!gpgme_init)
@{
gpgme_check_version ();
gpgme_check_version (NULL);
gpgme_set_locale (NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL));
gpgme_set_locale (NULL, LC_MESSAGES, setlocale (LC_MESSAGES, NULL));
gpgme_init = 1;
@}
pthread_mutex_unlock (&gpgme_init_lock);
@ -950,21 +981,21 @@ error code part of an error value. The error source is left
unspecified and might be anything.
@end deftp
@deftypefun {static __inline__ gpgme_err_code_t} gpgme_err_code (@w{gpgme_error_t @var{err}})
@deftypefun {static inline gpgme_err_code_t} gpgme_err_code (@w{gpgme_error_t @var{err}})
The static inline function @code{gpgme_err_code} returns the
@code{gpgme_err_code_t} component of the error value @var{err}. This
function must be used to extract the error code from an error value in
order to compare it with the @code{GPG_ERR_*} error code macros.
@end deftypefun
@deftypefun {static __inline__ gpgme_err_source_t} gpgme_err_source (@w{gpgme_error_t @var{err}})
@deftypefun {static inline gpgme_err_source_t} gpgme_err_source (@w{gpgme_error_t @var{err}})
The static inline function @code{gpgme_err_source} returns the
@code{gpgme_err_source_t} component of the error value @var{err}. This
function must be used to extract the error source from an error value in
order to compare it with the @code{GPG_ERR_SOURCE_*} error source macros.
@end deftypefun
@deftypefun {static __inline__ gpgme_error_t} gpgme_err_make (@w{gpgme_err_source_t @var{source}}, @w{gpgme_err_code_t @var{code}})
@deftypefun {static inline gpgme_error_t} gpgme_err_make (@w{gpgme_err_source_t @var{source}}, @w{gpgme_err_code_t @var{code}})
The static inline function @code{gpgme_err_make} returns the error
value consisting of the error source @var{source} and the error code
@var{code}.
@ -973,7 +1004,7 @@ This function can be used in callback functions to construct an error
value to return it to the library.
@end deftypefun
@deftypefun {static __inline__ gpgme_error_t} gpgme_error (@w{gpgme_err_code_t @var{code}})
@deftypefun {static inline gpgme_error_t} gpgme_error (@w{gpgme_err_code_t @var{code}})
The static inline function @code{gpgme_error} returns the error value
consisting of the default error source and the error code @var{code}.
@ -1736,6 +1767,7 @@ The function @code{gpgme_release} destroys the context with the handle
* Key Listing Mode:: Selecting key listing mode.
* Passphrase Callback:: Getting the passphrase from the user.
* Progress Meter Callback:: Being informed about the progress.
* Locale:: Setting the locale of a context.
@end menu
@ -2013,6 +2045,43 @@ the corresponding value will not be returned.
@end deftypefun
@node Locale
@subsection Locale
@cindex locale, default
@cindex locale, of a context
A locale setting can be associated with a context. This locale is
passed to the crypto engine, and used for applications like the PIN
entry, which is displayed to the user when entering a passphrase is
required.
The default locale is used to initialize the locale setting of all
contexts created afterwards.
@deftypefun gpgme_error_t gpgme_set_locale (@w{gpgme_ctx_t @var{ctx}}, @w{int @var{category}}, @w{const char *@var{value}})
The function @code{gpgme_set_locale} sets the locale of the context
@var{ctx}, or the default locale if @var{ctx} is a null pointer.
The locale settings that should be changed are specified by
@var{category}. Supported categories are @code{LC_CTYPE},
@code{LC_MESSAGES}, and @code{LC_ALL}, which is a wildcard you can use
if you want to change all the categories at once.
The value to be used for the locale setting is @var{value}, which will
be copied to @acronym{GPGME}'s internal data structures. @var{value}
can be a null pointer, which disables setting the locale, and will
make PIN entry and other applications use their default setting, which
is usually not what you want.
Note that the settings are only used if the application runs on a text
terminal, and that the settings should fit the configuration of the
output terminal. Normally, it is sufficient to initialize the default
value at startup.
The function returns an error if not enough memory is available.
@end deftypefun
@node Key Management
@section Key Management
@cindex key management

View File

@ -1,3 +1,20 @@
2003-09-14 Marcus Brinkmann <marcus@g10code.de>
* context.h (struct gpgme_context): New members lc_ctype and
lc_messages.
* gpgme.c: Include <locale.h>.
(def_lc_lock, def_lc_ctype, def_lc_messages): New static
variables.
(gpgme_set_locale): New function.
* engine.c (_gpgme_engine_new): Add arguments lc_ctype and
lc_messages.
* engine.h (_gpgme_engine_new): Likewise.
* engine-gpgsm.c (gpgsm_new): Likewise.
* rungpg.c (gpg_new): Likewise.
* engine-backend.h (struct engine_ops): Likewise to NEW.
* op-support.c (_gpgme_op_reset): Likewise to invocation of
_gpgme_engine_new.
2003-09-13 Marcus Brinkmann <marcus@g10code.de>
* gpgme.h (gpgme_strerror_r): New prototype.

View File

@ -87,6 +87,10 @@ struct gpgme_context
unsigned int signers_size;
gpgme_key_t *signers;
/* The locale for the pinentry. */
char *lc_ctype;
char *lc_messages;
/* The operation data hooked into the context. */
ctx_op_data_t op_data;

View File

@ -33,7 +33,8 @@ struct engine_ops
const char *(*get_file_name) (void);
const char *(*get_version) (void);
const char *(*get_req_version) (void);
gpgme_error_t (*new) (void **r_engine);
gpgme_error_t (*new) (void **r_engine,
const char *lc_ctype, const char *lc_messages);
/* Member functions. */
void (*release) (void *engine);

View File

@ -294,7 +294,7 @@ gpgsm_release (void *engine)
static gpgme_error_t
gpgsm_new (void **engine)
gpgsm_new (void **engine, const char *lc_ctype, const char *lc_messages)
{
gpgme_error_t err = 0;
engine_gpgsm_t gpgsm;
@ -304,8 +304,6 @@ gpgsm_new (void **engine)
char *dft_display = NULL;
char dft_ttyname[64];
char *dft_ttytype = NULL;
char *old_lc = NULL;
char *dft_lc = NULL;
char *optstr;
int fdlist[5];
int nfds;
@ -470,52 +468,25 @@ gpgsm_new (void **engine)
}
}
old_lc = setlocale (LC_CTYPE, NULL);
if (old_lc)
{
old_lc = strdup (old_lc);
if (!old_lc)
{
err = gpg_error_from_errno (errno);
goto leave;
}
}
dft_lc = setlocale (LC_CTYPE, "");
if (dft_lc)
if (lc_ctype)
{
if (asprintf (&optstr, "OPTION lc-ctype=%s", dft_lc) < 0)
err = gpg_error_from_errno (errno);
else
{
err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL,
NULL, NULL, NULL, NULL);
free (optstr);
if (err)
err = map_assuan_error (err);
}
}
if (old_lc)
{
setlocale (LC_CTYPE, old_lc);
free (old_lc);
}
if (err)
goto leave;
old_lc = setlocale (LC_MESSAGES, NULL);
if (old_lc)
{
old_lc = strdup (old_lc);
if (!old_lc)
{
err = gpg_error_from_errno (errno);
goto leave;
}
}
dft_lc = setlocale (LC_MESSAGES, "");
if (dft_lc)
{
if (asprintf (&optstr, "OPTION lc-messages=%s", dft_lc) < 0)
if (asprintf (&optstr, "OPTION lc-ctype=%s", lc_ctype) < 0)
err = gpg_error_from_errno (errno);
else
{
err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL,
NULL, NULL, NULL, NULL);
free (optstr);
if (err)
err = map_assuan_error (err);
}
}
if (err)
goto leave;
if (lc_messages)
{
if (asprintf (&optstr, "OPTION lc-messages=%s", lc_messages) < 0)
err = gpg_error_from_errno (errno);
else
{
@ -526,24 +497,19 @@ gpgsm_new (void **engine)
err = map_assuan_error (err);
}
}
if (old_lc)
{
setlocale (LC_MESSAGES, old_lc);
free (old_lc);
}
if (err)
goto leave;
}
if (!err &&
(_gpgme_io_set_close_notify (gpgsm->status_cb.fd,
close_notify_handler, gpgsm)
|| _gpgme_io_set_close_notify (gpgsm->input_cb.fd,
close_notify_handler, gpgsm)
|| _gpgme_io_set_close_notify (gpgsm->output_cb.fd,
if (!err
&& (_gpgme_io_set_close_notify (gpgsm->status_cb.fd,
close_notify_handler, gpgsm)
|| _gpgme_io_set_close_notify (gpgsm->message_cb.fd,
close_notify_handler, gpgsm)))
|| _gpgme_io_set_close_notify (gpgsm->input_cb.fd,
close_notify_handler, gpgsm)
|| _gpgme_io_set_close_notify (gpgsm->output_cb.fd,
close_notify_handler, gpgsm)
|| _gpgme_io_set_close_notify (gpgsm->message_cb.fd,
close_notify_handler, gpgsm)))
{
err = gpg_error (GPG_ERR_GENERAL);
goto leave;

View File

@ -158,7 +158,8 @@ gpgme_get_engine_info (gpgme_engine_info_t *info)
gpgme_error_t
_gpgme_engine_new (gpgme_protocol_t proto, engine_t *r_engine)
_gpgme_engine_new (gpgme_protocol_t proto, engine_t *r_engine,
const char *lc_ctype, const char *lc_messages)
{
engine_t engine;
@ -183,7 +184,9 @@ _gpgme_engine_new (gpgme_protocol_t proto, engine_t *r_engine)
engine->ops = engine_ops[proto];
if (engine_ops[proto]->new)
{
gpgme_error_t err = (*engine_ops[proto]->new) (&engine->engine);
gpgme_error_t err = (*engine_ops[proto]->new) (&engine->engine,
lc_ctype,
lc_messages);
if (err)
{
free (engine);

View File

@ -36,7 +36,9 @@ typedef gpgme_error_t (*engine_command_handler_t) (void *priv,
int fd);
gpgme_error_t _gpgme_engine_new (gpgme_protocol_t proto,
engine_t *r_engine);
engine_t *r_engine,
const char *lc_ctype,
const char *lc_messages);
void _gpgme_engine_release (engine_t engine);
void _gpgme_engine_set_status_handler (engine_t engine,
engine_status_handler_t fnc,

View File

@ -26,12 +26,20 @@
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <locale.h>
#include "util.h"
#include "context.h"
#include "ops.h"
#include "wait.h"
/* The default locale. */
DEFINE_STATIC_LOCK (def_lc_lock);
static char *def_lc_ctype;
static char *def_lc_messages;
/* Create a new context as an environment for GPGME crypto
operations. */
gpgme_error_t
@ -46,6 +54,37 @@ gpgme_new (gpgme_ctx_t *r_ctx)
ctx->include_certs = 1;
ctx->protocol = GPGME_PROTOCOL_OpenPGP;
_gpgme_fd_table_init (&ctx->fdt);
LOCK (def_lc_lock);
if (def_lc_ctype)
{
ctx->lc_ctype = strdup (def_lc_ctype);
if (!ctx->lc_ctype)
{
UNLOCK (def_lc_lock);
free (ctx);
return gpg_error_from_errno (errno);
}
}
else
def_lc_ctype = NULL;
if (def_lc_messages)
{
ctx->lc_messages = strdup (def_lc_messages);
if (!ctx->lc_messages)
{
UNLOCK (def_lc_lock);
if (ctx->lc_ctype)
free (ctx->lc_ctype);
free (ctx);
return gpg_error_from_errno (errno);
}
}
else
def_lc_messages = NULL;
UNLOCK (def_lc_lock);
*r_ctx = ctx;
return 0;
}
@ -61,6 +100,10 @@ gpgme_release (gpgme_ctx_t ctx)
gpgme_signers_clear (ctx);
if (ctx->signers)
free (ctx->signers);
if (ctx->lc_ctype)
free (ctx->lc_ctype);
if (ctx->lc_messages)
free (ctx->lc_messages);
free (ctx);
}
@ -267,7 +310,70 @@ gpgme_get_io_cbs (gpgme_ctx_t ctx, gpgme_io_cbs_t io_cbs)
*io_cbs = ctx->io_cbs;
}
/* This function sets the locale for the context CTX, or the default
locale if CTX is a null pointer. */
gpgme_error_t
gpgme_set_locale (gpgme_ctx_t ctx, int category, const char *value)
{
int failed = 0;
char *new_lc_ctype;
char *new_lc_messages;
#define PREPARE_ONE_LOCALE(lcat, ucat) \
if (!failed && value \
&& (category == LC_ALL || category == LC_ ## ucat)) \
{ \
new_lc_ ## lcat = strdup (value); \
if (!new_lc_ ## lcat) \
failed = 1; \
} \
else \
new_lc_ ## lcat = NULL;
PREPARE_ONE_LOCALE (ctype, CTYPE);
PREPARE_ONE_LOCALE (messages, MESSAGES);
if (failed)
{
int saved_errno = errno;
if (new_lc_ctype)
free (new_lc_ctype);
if (new_lc_messages)
free (new_lc_messages);
return gpg_error_from_errno (saved_errno);
}
#define SET_ONE_LOCALE(lcat, ucat) \
if (category == LC_ALL || category == LC_ ## ucat) \
{ \
if (ctx) \
{ \
if (ctx->lc_ ## lcat) \
free (ctx->lc_ ## lcat); \
ctx->lc_ ## lcat = new_lc_ ## lcat; \
} \
else \
{ \
if (def_lc_ ## lcat) \
free (def_lc_ ## lcat); \
def_lc_ ## lcat = new_lc_ ## lcat; \
} \
}
if (!ctx)
LOCK (def_lc_lock);
SET_ONE_LOCALE (ctype, CTYPE);
SET_ONE_LOCALE (messages, MESSAGES);
if (!ctx)
UNLOCK (def_lc_lock);
return 0;
}
const char *
gpgme_pubkey_algo_name (gpgme_pubkey_algo_t algo)
{

View File

@ -76,7 +76,8 @@ _gpgme_op_reset (gpgme_ctx_t ctx, int type)
_gpgme_engine_release (ctx->engine);
ctx->engine = NULL;
}
err = _gpgme_engine_new (ctx->protocol, &ctx->engine);
err = _gpgme_engine_new (ctx->protocol, &ctx->engine,
ctx->lc_ctype, ctx->lc_messages);
if (err)
return err;

View File

@ -325,7 +325,7 @@ gpg_release (void *engine)
static gpgme_error_t
gpg_new (void **engine)
gpg_new (void **engine, const char *lc_ctype, const char *lc_messages)
{
engine_gpg_t gpg;
gpgme_error_t rc = 0;