2002-04-23 Marcus Brinkmann <marcus@g10code.de>
authorMarcus Brinkmann <mb@g10code.com>
Tue, 23 Apr 2002 23:19:02 +0000 (23:19 +0000)
committerMarcus Brinkmann <mb@g10code.com>
Tue, 23 Apr 2002 23:19:02 +0000 (23:19 +0000)
* pinentry/pinentry.h (struct pinentry): New variables lc_ctype
and lc_messages.
* pinentry/pinentry.c (usage): New options --lc-ctype and
--lc-messages.
(pinentry_parse_opts): Likewise.
(option_handler): Likewise.
(struct pinentry pinentry): New initializers for new members.

* curses/pinentry-curses.c (convert_utf8_string): New function.
(struct dialog): New members ok and cancel.
(dialog_create): New variables ERR, DESCRIPTION, ERROR, PROMPT,
OK, and CANCEL.  Initialize them with the localised versions of
the pinentry strings.  If in confirm mode, split up the prompt at
'|' and use the values as button texts.  Use localised strings.
(dialog_switch_pos): Use localised strings.
(dialog_run): Free dialog strings.

* acinclude.m4 (AM_ICONV): New check from gettext.
* configure.ac: Run AM_ICONV if curses pinentry is build.
Don't check for inttypes.h, don't check size of unsigned int or
unsigned long.
(LIBCAP): Move check to interface independent part.

ChangeLog
README
acinclude.m4
configure.ac
curses/Makefile.am
curses/pinentry-curses.c
pinentry/pinentry.c
pinentry/pinentry.h

index d0bdc4e..da65b39 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,28 @@
+2002-04-23  Marcus Brinkmann  <marcus@g10code.de>
+
+       * pinentry/pinentry.h (struct pinentry): New variables lc_ctype
+       and lc_messages.
+       * pinentry/pinentry.c (usage): New options --lc-ctype and
+       --lc-messages.
+       (pinentry_parse_opts): Likewise.
+       (option_handler): Likewise.
+       (struct pinentry pinentry): New initializers for new members.
+
+       * curses/pinentry-curses.c (convert_utf8_string): New function.
+       (struct dialog): New members ok and cancel.
+       (dialog_create): New variables ERR, DESCRIPTION, ERROR, PROMPT,
+       OK, and CANCEL.  Initialize them with the localised versions of
+       the pinentry strings.  If in confirm mode, split up the prompt at
+       '|' and use the values as button texts.  Use localised strings.
+       (dialog_switch_pos): Use localised strings.
+       (dialog_run): Free dialog strings.
+
+       * acinclude.m4 (AM_ICONV): New check from gettext.
+       * configure.ac: Run AM_ICONV if curses pinentry is build.
+       Don't check for inttypes.h, don't check size of unsigned int or
+       unsigned long.
+       (LIBCAP): Move check to interface independent part.
+
 2002-04-21  Steffen Hansen  <steffen@hrhansen.dk>
 
        * Removed X11 dependency and use Qt for grabbing the keyboard.
diff --git a/README b/README
index 0825b8f..125622c 100644 (file)
--- a/README
+++ b/README
@@ -5,17 +5,16 @@ This is a collection of simple PIN or passphrase entry dialogs which
 utilize the Assuan protocol as described by the aegypten project; see
 http://www.gnupg.org/aegypten/ for details.
 
-There are programs for different toolkits available.  For the Curses
-and GTK+ GUIs it is automatically detected which modules can be built,
-but it can also be requested explicitely.  For the Qt GUI it MUST be
-requested explicitely, as an automatic check is not yet implemented.
+There are programs for different toolkits available.  For all GUIs it
+is automatically detected which modules can be built, but it can also
+be requested explicitely.
 
 GUI    OPTION                   DEPENDENCIES
 Curses --enable-pinentry-curses Curses library, for example ncurses
 GTK+   --enable-pinentry-gtk    Gimp Toolkit Library, eg libgtk and libglib
 Qt     --enable-pinentry-qt     Qt, eg libqt-mt
 
-Some of the is taken from Robert Bihlmeyer's Quituple-Agent.  For
-security reasons all internationalization has been removed as the
+Some of the code is taken from Robert Bihlmeyer's Quituple-Agent.  For
+security reasons, all internationalization has been removed.  The
 client is expected to tell the PIN entry the text strings to be
 displayed.
index 32b669f..1212a08 100644 (file)
@@ -130,6 +130,80 @@ AC_DEFUN([IU_LIB_CURSES], [
   AC_SUBST(LIBCURSES)])dnl
 dnl additional configure macros
 
+#
+# From /usr/share/aclocal/iconv.m4.
+#
+#serial AM2
+
+dnl From Bruno Haible.
+
+AC_DEFUN([AM_ICONV],
+[
+  dnl Some systems have iconv in libc, some have it in libiconv (OSF/1 and
+  dnl those with the standalone portable GNU libiconv installed).
+
+  AC_ARG_WITH([libiconv-prefix],
+[  --with-libiconv-prefix=DIR  search for libiconv in DIR/include and DIR/lib], [
+    for dir in `echo "$withval" | tr : ' '`; do
+      if test -d $dir/include; then CPPFLAGS="$CPPFLAGS -I$dir/include"; fi
+      if test -d $dir/lib; then LDFLAGS="$LDFLAGS -L$dir/lib"; fi
+    done
+   ])
+
+  AC_CACHE_CHECK(for iconv, am_cv_func_iconv, [
+    am_cv_func_iconv="no, consider installing GNU libiconv"
+    am_cv_lib_iconv=no
+    AC_TRY_LINK([#include <stdlib.h>
+#include <iconv.h>],
+      [iconv_t cd = iconv_open("","");
+       iconv(cd,NULL,NULL,NULL,NULL);
+       iconv_close(cd);],
+      am_cv_func_iconv=yes)
+    if test "$am_cv_func_iconv" != yes; then
+      am_save_LIBS="$LIBS"
+      LIBS="$LIBS -liconv"
+      AC_TRY_LINK([#include <stdlib.h>
+#include <iconv.h>],
+        [iconv_t cd = iconv_open("","");
+         iconv(cd,NULL,NULL,NULL,NULL);
+         iconv_close(cd);],
+        am_cv_lib_iconv=yes
+        am_cv_func_iconv=yes)
+      LIBS="$am_save_LIBS"
+    fi
+  ])
+  if test "$am_cv_func_iconv" = yes; then
+    AC_DEFINE(HAVE_ICONV, 1, [Define if you have the iconv() function.])
+    AC_MSG_CHECKING([for iconv declaration])
+    AC_CACHE_VAL(am_cv_proto_iconv, [
+      AC_TRY_COMPILE([
+#include <stdlib.h>
+#include <iconv.h>
+extern
+#ifdef __cplusplus
+"C"
+#endif
+#if defined(__STDC__) || defined(__cplusplus)
+size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);
+#else
+size_t iconv();
+#endif
+], [], am_cv_proto_iconv_arg1="", am_cv_proto_iconv_arg1="const")
+      am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"])
+    am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'`
+    AC_MSG_RESULT([$]{ac_t:-
+         }[$]am_cv_proto_iconv)
+    AC_DEFINE_UNQUOTED(ICONV_CONST, $am_cv_proto_iconv_arg1,
+      [Define as const if the declaration of iconv() needs const.])
+  fi
+  LIBICONV=
+  if test "$am_cv_lib_iconv" = yes; then
+    LIBICONV="-liconv"
+  fi
+  AC_SUBST(LIBICONV)
+])
+
+
 dnl
 dnl GNUPG_CHECK_TYPEDEF(TYPE, HAVE_NAME)
 dnl Check whether a typedef exists and create a #define $2 if it exists
index 8195cf6..366c69f 100644 (file)
@@ -62,6 +62,12 @@ dnl Checks for libsecmem.
 GNUPG_CHECK_TYPEDEF(byte, HAVE_BYTE_TYPEDEF)
 GNUPG_CHECK_TYPEDEF(ulong, HAVE_ULONG_TYPEDEF)
 
+AC_PATH_PROG(SETCAP, setcap, :, "$PATH:/sbin:/usr/sbin")
+AC_CHECK_LIB(cap, cap_set_proc, [
+  AC_DEFINE(USE_CAPABILITIES,1,[The capabilities support library is installed])
+  LIBCAP=-lcap
+])
+AC_SUBST(LIBCAP)
 
 dnl
 dnl Check for curses pinentry program.
@@ -89,6 +95,10 @@ else
 fi
 AM_CONDITIONAL(BUILD_PINENTRY_CURSES, test "$pinentry_curses" = "yes")
 
+if test "$pinentry_curses" = "yes"; then
+dnl Additional checks for Curses pinentry.
+AM_ICONV
+fi
 
 dnl
 dnl Check for GTK+ pinentry program.
@@ -131,22 +141,10 @@ if test "$pinentry_gtk" != "no"; then
 fi
 AM_CONDITIONAL(BUILD_PINENTRY_GTK, test "$pinentry_gtk" = "yes")
 
-if test "$pinentry_gtk" = "yes"; then
+dnl if test "$pinentry_gtk" = "yes"; then
 dnl Additional checks for GTK+ pinentry.
-AC_PATH_PROG(SETCAP, setcap, :, "$PATH:/sbin:/usr/sbin")
-AC_CHECK_LIB(cap, cap_set_proc, [
-  AC_DEFINE(USE_CAPABILITIES,1,[The capabilities support library is installed])
-  LIBCAP=-lcap
-])
-AC_SUBST(LIBCAP)
-
-AC_CHECK_HEADERS(inttypes.h, , need_inttypes=yes)
-if test x$need_inttypes = xyes; then
-  AC_CHECK_SIZEOF(unsigned int, 4)
-  AC_CHECK_SIZEOF(unsigned long, 4)
-fi
 dnl End of additional checks for GTK+ pinentry.
-fi
+dnl fi
 
 
 dnl
index d9a847d..1d3a6eb 100644 (file)
@@ -23,6 +23,6 @@ bin_PROGRAMS = pinentry-curses
 
 AM_CPPFLAGS = -I$(top_srcdir)/pinentry
 LDADD = ../pinentry/libpinentry.a ../assuan/libassuan.a ../secmem/libsecmem.a \
-       $(LIBCAP) $(LIBCURSES)
+       $(LIBCAP) $(LIBCURSES) $(LIBICONV)
 
 pinentry_curses_SOURCES = pinentry-curses.c
index 26fb00b..b3a933e 100644 (file)
 #include <fcntl.h>
 #include <unistd.h>
 #include <stdlib.h>
+#include <locale.h>
+#include <iconv.h>
+#include <langinfo.h>
+#include <limits.h>
+#include <string.h>
 #include <errno.h>
 
 #include "pinentry.h"
@@ -61,15 +66,67 @@ struct dialog
 
   int ok_y;
   int ok_x;
+  char *ok;
   int cancel_y;
   int cancel_x;
+  char *cancel;
 };
 typedef struct dialog *dialog_t;
 
 \f
+char *
+convert_utf8_string (char *lc_ctype, char *text)
+{
+  char *old_ctype;
+  char *target_encoding;
+  iconv_t cd;
+  char *input = text;
+  size_t input_len = strlen (text) + 1;
+  char *output;
+  size_t output_len;
+  char *output_buf;
+  size_t processed;
+
+  /* If no locale setting could be determined, simply copy the
+     string.  */
+  if (!lc_ctype)
+    return strdup (text);
+
+  old_ctype = strdup (setlocale (LC_CTYPE, NULL));
+  if (!old_ctype)
+    return NULL;
+  setlocale (LC_CTYPE, lc_ctype);
+  target_encoding = nl_langinfo (CODESET);
+  setlocale (LC_CTYPE, old_ctype);
+  free (old_ctype);
+
+  /* This is overkill, but simplifies the iconv invocation greatly.  */
+  output_len = input_len * MB_LEN_MAX;
+  output_buf = output = malloc (output_len);
+  if (!output)
+    return NULL;
+
+  cd = iconv_open (target_encoding, "UTF-8");
+  if (cd == (iconv_t) -1)
+    {
+      free (output);
+      return NULL;
+    }
+  processed = iconv (cd, &input, &input_len, &output, &output_len);
+  iconv_close (cd);
+  if (processed == (size_t) -1 || input_len)
+    {
+      free (output_buf);
+      return NULL;
+    }
+  return output_buf;
+}
+
+
 static int
 dialog_create (pinentry_t pinentry, dialog_t dialog)
 {
+  int err = 0;
   int size_y;
   int size_x;
   int y;
@@ -77,14 +134,82 @@ dialog_create (pinentry_t pinentry, dialog_t dialog)
   int ypos;
   int xpos;
   int description_x = 0;
+  char *description = NULL;
+  char *error = NULL;
+  char *prompt = NULL;
+  char *ok = NULL;
+  char *cancel = NULL;
 
+  if (pinentry->description)
+    {
+      description = convert_utf8_string (pinentry->lc_ctype,
+                                        pinentry->description);
+      if (!description)
+       {
+         err = 1;
+         goto out;
+       }
+    }
+  if (pinentry->error)
+    {
+      error = convert_utf8_string (pinentry->lc_ctype,
+                                  pinentry->error);
+      if (!error)
+       {
+         err = 1;
+         goto out;
+       }
+    }
+  if (pinentry->prompt)
+    {
+      if (pinentry->pin)
+       {
+         prompt = convert_utf8_string (pinentry->lc_ctype,
+                                       pinentry->prompt);
+         if (!prompt)
+           {
+             err = 1;
+             goto out;
+           }
+       }
+      else
+       {
+         char *prompt_copy = strdup (pinentry->prompt);
+         char *split;
+
+         if (!prompt_copy)
+           {
+             err = 1;
+             goto out;
+           }
+         split = strchr (prompt_copy, '|');
+         if (split)
+           {
+             *(split++) = '\0';
+             ok = prompt_copy;
+             cancel = split;
+           }
+       }
+    }
+  dialog->ok = convert_utf8_string (pinentry->lc_ctype,
+                                   ok ? ok : STRING_OK);
+  dialog->cancel = convert_utf8_string (pinentry->lc_ctype,
+                                       cancel ? cancel : STRING_CANCEL);
+  /* Release ok & cancel.  */
+  if (ok)
+    free (ok);
+  if (!dialog->ok || !dialog->cancel)
+    {
+      err = 1;
+      goto out;
+    }
   getmaxyx (stdscr, size_y, size_x);
 
   /* Check if all required lines fit on the screen.  */
   y = 1;               /* Top frame.  */
-  if (pinentry->description)
+  if (description)
     {
-      char *p = pinentry->description;
+      char *p = description;
       int desc_x = 0;
 
       while (*p)
@@ -106,18 +231,21 @@ dialog_create (pinentry_t pinentry, dialog_t dialog)
       
   if (pinentry->pin)
     {
-      if (pinentry->error)
+      if (error)
        y += 2;         /* Error message.  */
       y += 2;          /* Pin entry field.  */
     }
   y += 2;              /* OK/Cancel and bottom frame.  */
   
   if (y > size_y)
-    return 1;
+    {
+      err = 1;
+      goto out;
+    }
 
   /* Check if all required columns fit on the screen.  */
   x = 0;
-  if (pinentry->description)
+  if (description)
     {
       int new_x = description_x;
       if (new_x > size_x - 4)
@@ -130,9 +258,9 @@ dialog_create (pinentry_t pinentry, dialog_t dialog)
 #define MIN_PINENTRY_LENGTH 40
       int new_x;
 
-      if (pinentry->error)
+      if (error)
        {
-         new_x = strlen (pinentry->error);
+         new_x = strlen (error);
          if (new_x > size_x - 4)
            new_x = size_x - 4;
          if (new_x > x)
@@ -140,25 +268,28 @@ dialog_create (pinentry_t pinentry, dialog_t dialog)
        }
 
       new_x = MIN_PINENTRY_LENGTH;
-      if (pinentry->prompt)
-       new_x += strlen (pinentry->prompt) + 1; /* One space after prompt.  */
+      if (prompt)
+       new_x += strlen (prompt) + 1;   /* One space after prompt.  */
       if (new_x > size_x - 4)
        new_x = size_x - 4;
       if (new_x > x)
        x = new_x;
     }
-  /* We position the Buttons after the first and second third of the
-     width.  Account for rounding when calculating the necessary*/
-  if (x < 2 * (sizeof (STRING_OK) - 1))
-    x = 2 * (sizeof (STRING_OK) - 1);
-  if (x < 2 * (sizeof (STRING_CANCEL) - 1))
-    x = 2 * (sizeof (STRING_CANCEL) - 1);
+  /* We position the buttons after the first and second third of the
+     width.  Account for rounding.  */
+  if (x < 2 * (sizeof (dialog->ok) - 1))
+    x = 2 * (sizeof (dialog->ok) - 1);
+  if (x < 2 * (sizeof (dialog->cancel) - 1))
+    x = 2 * (sizeof (dialog->cancel) - 1);
 
   /* Add the frame.  */
   x += 4;
 
   if (x > size_x)
-    return 1;
+    {
+      err = 1;
+      goto out;
+    }
 
   dialog->pos = DIALOG_POS_NONE;
   dialog->pin = pinentry->pin;
@@ -180,9 +311,9 @@ dialog_create (pinentry_t pinentry, dialog_t dialog)
   move (ypos + y - 1, xpos + x - 1);
   addch (ACS_LRCORNER);
   ypos++;
-  if (pinentry->description)
+  if (description)
     {
-      char *p = pinentry->description;
+      char *p = description;
       int i = 0;
 
       while (*p)
@@ -194,7 +325,7 @@ dialog_create (pinentry_t pinentry, dialog_t dialog)
            if (i < x - 4)
              {
                i++;
-               addch (*(p++));
+               addch ((unsigned char) *(p++));
              }
          if (*p == '\n')
            p++;
@@ -209,10 +340,10 @@ dialog_create (pinentry_t pinentry, dialog_t dialog)
     {
       int i;
 
-      if (pinentry->error)
+      if (error)
        {
-         char *p = pinentry->error;
-         i = strlen (pinentry->error);
+         char *p = error;
+         i = strlen (error);
          move (ypos, xpos);
          addch (ACS_VLINE);
          addch (' ');
@@ -223,7 +354,7 @@ dialog_create (pinentry_t pinentry, dialog_t dialog)
          else
            standout ();
          while (i-- > 0)
-           addch (*(p++));
+           addch ((unsigned char) *(p++));
          if (has_colors () && COLOR_PAIRS >= 1)
            attroff (COLOR_PAIR(1) | A_BOLD);
          else
@@ -241,16 +372,16 @@ dialog_create (pinentry_t pinentry, dialog_t dialog)
       dialog->pin_y = ypos;
       dialog->pin_x = xpos + 2;
       dialog->pin_size = x - 4;
-      if (pinentry->prompt)
+      if (prompt)
        {
-         char *p = pinentry->prompt;
-         i = strlen (pinentry->prompt);
+         char *p = prompt;
+         i = strlen (prompt);
          if (i > x - 4 - MIN_PINENTRY_LENGTH)
            i = x - 4 - MIN_PINENTRY_LENGTH;
          dialog->pin_x += i + 1;
          dialog->pin_size -= i + 1;
          while (i-- > 0)
-           addch (*(p++));
+           addch ((unsigned char) *(p++));
          addch (' ');
        }
       for (i = 0; i < dialog->pin_size; i++)
@@ -264,15 +395,23 @@ dialog_create (pinentry_t pinentry, dialog_t dialog)
   addch (ACS_VLINE);
   dialog->ok_y = ypos;
   /* Calculating the left edge of the left button, rounding down.  */
-  dialog->ok_x = xpos + 2 + ((x - 4) / 2 - (sizeof (STRING_OK) - 1)) / 2;
+  dialog->ok_x = xpos + 2 + ((x - 4) / 2 - (sizeof (dialog->ok) - 1)) / 2;
   move (dialog->ok_y, dialog->ok_x);
-  addstr (STRING_OK);
+  addstr (dialog->ok);
   dialog->cancel_y = ypos;
   /* Calculating the left edge of the right button, rounding up.  */
-  dialog->cancel_x = xpos + x - 2 - ((x - 4) / 2 + (sizeof (STRING_CANCEL) - 1)) / 2;
+  dialog->cancel_x = xpos + x - 2 - ((x - 4) / 2 + (sizeof (dialog->cancel) - 1)) / 2;
   move (dialog->cancel_y, dialog->cancel_x);
-  addstr (STRING_CANCEL);
-  return 0;
+  addstr (dialog->cancel);
+
+ out:
+  if (description)
+    free (description);
+  if (error)
+    free (error);
+  if (prompt)
+    free (prompt);
+  return err;
 }
 
 \f
@@ -303,11 +442,11 @@ dialog_switch_pos (dialog_t diag, dialog_pos_t new_pos)
        {
        case DIALOG_POS_OK:
          move (diag->ok_y, diag->ok_x);
-         addstr (STRING_OK);
+         addstr (diag->ok);
          break;
        case DIALOG_POS_CANCEL:
          move (diag->cancel_y, diag->cancel_x);
-         addstr (STRING_CANCEL);
+         addstr (diag->cancel);
          break;
        default:
          break;
@@ -322,14 +461,14 @@ dialog_switch_pos (dialog_t diag, dialog_pos_t new_pos)
        case DIALOG_POS_OK:
          move (diag->ok_y, diag->ok_x);
          standout ();
-         addstr (STRING_OK);
+         addstr (diag->ok);
          standend ();
          set_cursor_state (0);
          break;
        case DIALOG_POS_CANCEL:
          move (diag->cancel_y, diag->cancel_x);
          standout ();
-         addstr (STRING_CANCEL);
+         addstr (diag->cancel);
          standend ();
          set_cursor_state (0);
          break;
@@ -544,6 +683,9 @@ dialog_run (pinentry_t pinentry, const char *tty_name, const char *tty_type)
     fclose (ttyfi);
   if (ttyfo)
     fclose (ttyfo);
+  /* XXX Factor out into dialog_release or something.  */
+  free (diag.ok);
+  free (diag.cancel);
   return diag.pin ? (done < 0 ? -1 : diag.pin_len) : (done < 0 ? 0 : 1);
 }
 
index 62a2a1a..5553b2e 100644 (file)
@@ -43,6 +43,8 @@ struct pinentry pinentry =
     0,         /* Display.  */
     0,         /* TTY name.  */
     0,         /* TTY type.  */
+    0,         /* TTY LC_CTYPE.  */
+    0,         /* TTY LC_MESSAGES.  */
     0,         /* Debug mode.  */
     0,         /* Enhanced mode.  */
     1,         /* Global grab.  */
@@ -96,6 +98,8 @@ Ask securely for a secret and print it to stdout.\n\
       --display DISPLAY Set the X display\n\
       --ttyname PATH    Set the tty terminal node name\n\
       --ttytype NAME    Set the tty terminal type\n\
+      --lc-ctype        Set the tty LC_CTYPE value\n\
+      --lc-messages     Set the tty LC_MESSAGES value\n\
   -e, --enhanced        Ask for timeout and insurance, too\n\
   -g, --no-global-grab  Grab keyboard only while window is focused\n\
   -d, --debug           Turn on debugging output\n\
@@ -118,6 +122,8 @@ pinentry_parse_opts (int argc, char *argv[])
      { "display", required_argument, 0, 'D' },
      { "ttyname", required_argument, 0, 'T' },
      { "ttytype", required_argument, 0, 'N' },
+     { "lc-ctype", required_argument, 0, 'C' },
+     { "lc-messages", required_argument, 0, 'M' },
      { "enhanced", no_argument, &pinentry.enhanced, 1 },
      { "no-global-grab", no_argument, &pinentry.grab, 0 },
      { "help", no_argument, &opt_help, 1 },
@@ -158,6 +164,24 @@ pinentry_parse_opts (int argc, char *argv[])
              exit (EXIT_FAILURE);
            }
          break;
+       case 'C':
+         pinentry.lc_ctype = strdup (optarg);
+         if (!pinentry.lc_ctype)
+           {
+             /* XXX Program name.  */
+             fprintf (stderr, "pinentry: %s\n", strerror (errno));
+             exit (EXIT_FAILURE);
+           }
+         break;
+       case 'M':
+         pinentry.lc_messages = strdup (optarg);
+         if (!pinentry.lc_messages)
+           {
+             /* XXX Program name.  */
+             fprintf (stderr, "pinentry: %s\n", strerror (errno));
+             exit (EXIT_FAILURE);
+           }
+         break;
         default:
           /* XXX Should never happen.  */
         }
@@ -212,6 +236,22 @@ option_handler (ASSUAN_CONTEXT ctx, const char *key, const char *value)
       if (!pinentry.ttytype)
        return ASSUAN_Out_Of_Core;
     }
+  else if (!strcmp (key, "lc-ctype"))
+    {
+      if (pinentry.lc_ctype)
+       free (pinentry.lc_ctype);
+      pinentry.lc_ctype = strdup (value);
+      if (!pinentry.lc_ctype)
+       return ASSUAN_Out_Of_Core;
+    }
+  else if (!strcmp (key, "lc-messages"))
+    {
+      if (pinentry.lc_messages)
+       free (pinentry.lc_messages);
+      pinentry.lc_messages = strdup (value);
+      if (!pinentry.lc_messages)
+       return ASSUAN_Out_Of_Core;
+    }
   else
     return ASSUAN_Invalid_Option;
   return 0;
index ae3a08e..c41656d 100644 (file)
@@ -37,6 +37,10 @@ struct pinentry
   char *ttyname;
   /* The type of the terminal.  */
   char *ttytype;
+  /* The LC_CTYPE value for the terminal.  */
+  char *lc_ctype;
+  /* The LC_MESSAGES value for the terminal.  */
+  char *lc_messages;
 
   /* True if debug mode is requested.  */
   int debug;