doc/
authorMarcus Brinkmann <mb@g10code.com>
Sun, 14 Sep 2003 00:02:41 +0000 (00:02 +0000)
committerMarcus Brinkmann <mb@g10code.com>
Sun, 14 Sep 2003 00:02:41 +0000 (00:02 +0000)
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.

12 files changed:
NEWS
doc/ChangeLog
doc/gpgme.texi
gpgme/ChangeLog
gpgme/context.h
gpgme/engine-backend.h
gpgme/engine-gpgsm.c
gpgme/engine.c
gpgme/engine.h
gpgme/gpgme.c
gpgme/op-support.c
gpgme/rungpg.c

diff --git a/NEWS b/NEWS
index 92e049e..f940075 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -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
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 
index dd2c2f0..11cc544 100644 (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.
index 1e00d75..eaa197c 100644 (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
index 0e33c91..acd4251 100644 (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.
index 4dca9ba..64c5276 100644 (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;
 
index e57ffc2..0a59972 100644 (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);
index 4b925f1..270380a 100644 (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)
+         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
            {
@@ -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;
index d974db5..04cefc8 100644 (file)
@@ -158,7 +158,8 @@ gpgme_get_engine_info (gpgme_engine_info_t *info)
 
 \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;
 
@@ -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);
index c6dc09c..563b35b 100644 (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,
index 3143d93..d4f0cf1 100644 (file)
 #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
@@ -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;
 }
 
+\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)
 {
index 68ac39c..e406af9 100644 (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;
 
index 50223c1..d13a9c1 100644 (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;