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
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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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.
* 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
@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
before any function in the library:
@example
+#include <stdlib.h>
+#include <locale.h>
#include <pthread.h>
+#include <gpgme.h>
void
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);
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}.
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}.
* 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
@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
+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.
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;
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);
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;
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;
}
}
- 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)
+ 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);
+ 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 (lc_messages)
{
- if (asprintf (&optstr, "OPTION lc-messages=%s", dft_lc) < 0)
+ if (asprintf (&optstr, "OPTION lc-messages=%s", lc_messages) < 0)
err = gpg_error_from_errno (errno);
else
{
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;
\f
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;
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);
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,
#include <string.h>
#include <assert.h>
#include <errno.h>
+#include <locale.h>
#include "util.h"
#include "context.h"
#include "ops.h"
#include "wait.h"
+\f
+/* The default locale. */
+DEFINE_STATIC_LOCK (def_lc_lock);
+static char *def_lc_ctype;
+static char *def_lc_messages;
+
+\f
/* Create a new context as an environment for GPGME crypto
operations. */
gpgme_error_t
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;
}
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);
}
*io_cbs = ctx->io_cbs;
}
+\f
+/* 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;
+}
+\f
const char *
gpgme_pubkey_algo_name (gpgme_pubkey_algo_t algo)
{
_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;
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;