[svn] pinentry - r159 - in trunk: . secmem w32

svn author wk cvs at cvs.gnupg.org
Wed Jun 20 16:29:53 CEST 2007


Author: wk
Date: 2007-06-20 16:29:22 +0200 (Wed, 20 Jun 2007)
New Revision: 159

Added:
   trunk/README.SVN
Removed:
   trunk/README.CVS
Modified:
   trunk/ChangeLog
   trunk/Makefile.am
   trunk/NEWS
   trunk/autogen.sh
   trunk/secmem/secmem.c
   trunk/w32/Makefile.am
   trunk/w32/main.c
Log:
Made W32 version work.  There are still some glitches but it works with
gpg-agent.


Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog	2007-05-10 17:37:07 UTC (rev 158)
+++ trunk/ChangeLog	2007-06-20 14:29:22 UTC (rev 159)
@@ -1,3 +1,25 @@
+2007-06-20  Werner Koch  <wk at g10code.com>
+
+	* w32/main.c (wchar_to_utf8): New.
+	(ok_button_clicked): Use it.
+	(utf8_to_wchar): New.
+	(set_dlg_item_text): New.
+	(dlg_proc): Use new function so that we are able to correctly
+	display all prompts.
+	(main): Load LockSetForegroundWindow.
+	(dlg_proc): Call LockSetForegroundWindow via its fnc ptr.
+	(center_window): New.  Taken from GPGol.
+	(dlg_proc): Call it.
+	(w32_cmd_handler): Revamped the confirm mode.
+
+2007-06-18  Werner Koch  <wk at g10code.com>
+
+	* w32/main.c (dlg_proc): Call LockSetForegroundWindow.
+
+	* Makefile.am (signed-dist, %.sig): Remove.
+
+	* autogen.sh: Modernized.
+
 2007-05-10  Marcus Brinkmann  <marcus at g10code.de>
 
 	* pinentry/pinentry.h (pinentry_color_t): New type.

Modified: trunk/Makefile.am
===================================================================
--- trunk/Makefile.am	2007-05-10 17:37:07 UTC (rev 158)
+++ trunk/Makefile.am	2007-06-20 14:29:22 UTC (rev 159)
@@ -21,7 +21,7 @@
 
 ACLOCAL_AMFLAGS = -I m4
 
-EXTRA_DIST = autogen.sh README.CVS Manifest
+EXTRA_DIST = autogen.sh README.SVN Manifest
 
 if BUILD_PINENTRY_CURSES
 pinentry_curses = curses
@@ -56,11 +56,7 @@
 SUBDIRS = assuan secmem pinentry ${pinentry_curses} \
 	${pinentry_gtk} ${pinentry_gtk_2} ${pinentry_qt} ${pinentry_w32} doc
 
-signed-dist: $(distdir).tar.gz.sig
 
-%.sig: %
-	gpg -sbav -u 0x57548DCD $@ $<
-
 install-exec-local:
 	@list='$(bin_PROGRAMS)'; for p in $$list; do \
 	  echo "  $(SETCAP) cap_ipc_lock+p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \

Modified: trunk/NEWS
===================================================================
--- trunk/NEWS	2007-05-10 17:37:07 UTC (rev 158)
+++ trunk/NEWS	2007-06-20 14:29:22 UTC (rev 159)
@@ -10,7 +10,9 @@
  * New option --colors=FG,BG,SO to set the colors for the curses
    pinentry.
 
+ * Pinentry-w32 does now work.
 
+
 Noteworthy changes in version 0.7.2 (2005-01-27)
 ------------------------------------------------
 

Deleted: trunk/README.CVS

Added: trunk/README.SVN
===================================================================
--- trunk/README.SVN	2007-05-10 17:37:07 UTC (rev 158)
+++ trunk/README.SVN	2007-06-20 14:29:22 UTC (rev 159)
@@ -0,0 +1,51 @@
+If you are building from Subversion, run the script
+
+./autogen.sh
+
+first, to make sure that you have all the necessary maintainer tools
+are installed and to build the actual configuration files.  If you
+have just updated from SVN, you should add the option "--force" to
+autogen.sh so that meta data from SVN is noticed.  Then run
+
+./configure --enable-maintainer-mode
+
+followed by the usual make.
+
+If autogen.sh complains about insufficient versions of the required
+tools, or the tools are not installed, you may use environment
+variables to override the default tool names:
+
+ AUTOMAKE_SUFFIX  is used as a suffix for all tools from the automake
+                  package.  For example 
+                     AUTOMAKE_SUFFIX="-1.7" ./autogen.sh
+                  uses "automake-1.7" and "aclocal-1.7.
+ AUTOMAKE_PREFIX  is used as a prefix for all tools from the automake
+                  page and may be combined with AUTOMAKE_SUFFIX. e.g.:
+                    AUTOMAKE_PREFIX=/usr/foo/bin ./autogen.sh
+                  uses "automake" and "aclocal" in the /usr/foo/bin
+                  directory.
+ AUTOCONF_SUFFIX  is used as a suffix for all tools from the automake
+                  package
+ AUTOCONF_PREFIX  is used as a prefix for all tools from the automake
+                  package
+ GETTEXT_SUFFIX   is used as a suffix for all tools from the gettext
+                  package
+ GETTEXT_PREFIX   is used as a prefix for all tools from the gettext
+                  package
+
+It is also possible to use the variable name AUTOMAKE, AUTOCONF,
+ACLOCAL, AUTOHEADER, GETTEXT and MSGMERGE to directly specify the name
+of the programs to run.  It is however better to use the suffix and
+prefix forms as described above because that does not require
+knowledge about the actual tools used by autgen.sh.
+
+
+Please don't use autopoint, libtoolize or autoreconf unless you are
+the current maintainer and want to update the standard configuration
+files.  All those files should be in the SVN and only updated manually
+if the maintainer decides that newer versions are required.  The
+maintainer should also make sure that the required version of automake
+et al. are properly indicated at the top of configure.ac and take care
+to copy the files and not merely use symlinks.
+
+

Modified: trunk/autogen.sh
===================================================================
--- trunk/autogen.sh	2007-05-10 17:37:07 UTC (rev 158)
+++ trunk/autogen.sh	2007-06-20 14:29:22 UTC (rev 159)
@@ -28,7 +28,24 @@
     return 1
 }
 
+# Allow to override the default tool names
+AUTOCONF=${AUTOCONF_PREFIX}${AUTOCONF:-autoconf}${AUTOCONF_SUFFIX}
+AUTOHEADER=${AUTOCONF_PREFIX}${AUTOHEADER:-autoheader}${AUTOCONF_SUFFIX}
 
+AUTOMAKE=${AUTOMAKE_PREFIX}${AUTOMAKE:-automake}${AUTOMAKE_SUFFIX}
+ACLOCAL=${AUTOMAKE_PREFIX}${ACLOCAL:-aclocal}${AUTOMAKE_SUFFIX}
+
+GETTEXT=${GETTEXT_PREFIX}${GETTEXT:-gettext}${GETTEXT_SUFFIX}
+MSGMERGE=${GETTEXT_PREFIX}${MSGMERGE:-msgmerge}${GETTEXT_SUFFIX}
+
+DIE=no
+FORCE=
+if test x"$1" = x"--force"; then
+  FORCE=" --force"
+  shift
+fi
+
+
 # ***** W32 build script *******
 # Used to cross-compile for Windows.
 if test "$1" = "--build-w32"; then
@@ -44,25 +61,22 @@
     [ -z "$w32root" ] && w32root="$HOME/w32root"
     echo "Using $w32root as standard install directory" >&2
     
-    # See whether we have the Debian cross compiler package or the
-    # old mingw32/cpd system
-    if i586-mingw32msvc-gcc --version >/dev/null 2>&1 ; then
-        host=i586-mingw32msvc
-        crossbindir=/usr/$host/bin
-    else
-       host=i386--mingw32
-       if ! mingw32 --version >/dev/null; then
-          echo "We need at least version 0.3 of MingW32/CPD" >&2
-          exit 1
-       fi
-       crossbindir=`mingw32 --install-dir`/bin
-       # Old autoconf version required us to setup the environment
-       # with the proper tool names.
-       CC=`mingw32 --get-path gcc`
-       CPP=`mingw32 --get-path cpp`
-       AR=`mingw32 --get-path ar`
-       RANLIB=`mingw32 --get-path ranlib`
-       export CC CPP AR RANLIB 
+
+    # Locate the cross compiler
+    crossbindir=
+    for host in i586-mingw32msvc i386-mingw32msvc mingw32; do
+        if ${host}-gcc --version >/dev/null 2>&1 ; then
+            crossbindir=/usr/${host}/bin
+            conf_CC="CC=${host}-gcc"
+            break;
+        fi
+    done
+    if [ -z "$crossbindir" ]; then
+        echo "Cross compiler kit not installed" >&2
+        echo "Under Debian GNU/Linux, you may install it using" >&2
+        echo "  apt-get install mingw32 mingw32-runtime mingw32-binutils" >&2 
+        echo "Stop." >&2
+        exit 1
     fi
    
     if [ -f "$tsdir/config.log" ]; then
@@ -73,16 +87,12 @@
     fi
 
     ./configure --enable-maintainer-mode --prefix=${w32root} \
-                --host=i586-mingw32msvc --build=${build} \
+                --host=${host} --build=${build} \
                 --disable-pinentry-gtk \
                 --disable-pinentry-gtk2 \
                 --disable-pinentry-qt 
 
     rc=$?
-    # Ugly hack to overcome a gettext problem.  Someone should look into
-    # gettext to figure out why the po directory is not ignored as it used
-    # to be.
-    [ $rc = 0 ] && touch $tsdir/po/all
     exit $rc
 fi
 # ***** end W32 build script *******
@@ -116,19 +126,6 @@
   exit 1
 fi
 
-# Allow to override the default tool names
-AUTOCONF=${AUTOCONF_PREFIX}${AUTOCONF:-autoconf}${AUTOCONF_SUFFIX}
-AUTOHEADER=${AUTOCONF_PREFIX}${AUTOHEADER:-autoheader}${AUTOCONF_SUFFIX}
-
-AUTOMAKE=${AUTOMAKE_PREFIX}${AUTOMAKE:-automake}${AUTOMAKE_SUFFIX}
-ACLOCAL=${AUTOMAKE_PREFIX}${ACLOCAL:-aclocal}${AUTOMAKE_SUFFIX}
-
-#GETTEXT=${GETTEXT_PREFIX}${GETTEXT:-gettext}${GETTEXT_SUFFIX}
-#MSGMERGE=${GETTEXT_PREFIX}${MSGMERGE:-msgmerge}${GETTEXT_SUFFIX}
-
-DIE=no
-
-
 if check_version $AUTOCONF $autoconf_vers_num $autoconf_vers ; then
     check_version $AUTOHEADER $autoconf_vers_num $autoconf_vers autoconf
 fi
@@ -143,7 +140,7 @@
     cat <<EOF
 
 Note that you may use alternative versions of the tools by setting 
-the corresponding environment variables; see README.CVS for details.
+the corresponding environment variables; see README.SVN for details.
                    
 EOF
     exit 1
@@ -154,8 +151,8 @@
 echo "Running autoheader..."
 $AUTOHEADER
 echo "Running automake --gnu ..."
-$AUTOMAKE --gnu;
-echo "Running autoconf..."
-$AUTOCONF
+$AUTOMAKE --gnu
+echo "Running autoconf${FORCE}..."
+$AUTOCONF${FORCE}
 
 echo "You may now run \"./configure --enable-maintainer-mode && make\"."

Modified: trunk/secmem/secmem.c
===================================================================
--- trunk/secmem/secmem.c	2007-05-10 17:37:07 UTC (rev 158)
+++ trunk/secmem/secmem.c	2007-06-20 14:29:22 UTC (rev 159)
@@ -281,11 +281,11 @@
 secmem_init( size_t n )
 {
     if( !n ) {
-      #ifdef USE_CAPABILITIES
+#ifdef USE_CAPABILITIES
 	/* drop all capabilities */
 	cap_set_proc( cap_from_text("all-eip") );
 
-      #elif !defined(HAVE_DOSISH_SYSTEM)
+#elif !defined(HAVE_DOSISH_SYSTEM)
 	uid_t uid;
 
 	disable_secmem=1;
@@ -294,7 +294,7 @@
 	    if( setuid( uid ) || getuid() != geteuid() )
 		log_fatal("failed to drop setuid\n" );
 	}
-      #endif
+#endif
     }
     else {
 	if( n < DEFAULT_POOLSIZE )

Modified: trunk/w32/Makefile.am
===================================================================
--- trunk/w32/Makefile.am	2007-05-10 17:37:07 UTC (rev 158)
+++ trunk/w32/Makefile.am	2007-06-20 14:29:22 UTC (rev 159)
@@ -27,10 +27,11 @@
 	      -I$(top_srcdir)/pinentry
 
 
-
 pinentry_w32_SOURCES = main.c pinentry-w32.rc resource.h
 
-pinentry_w32_LDFLAGS = -mwindows -mconsole
+# If you want to test pinnetry on the console, you should add
+# -mconsole to the ldflags.
+pinentry_w32_LDFLAGS = -mwindows
 pinentry_w32_LDADD = pinentry-w32.o \
 	../pinentry/libpinentry.a ../assuan/libassuan.a ../secmem/libsecmem.a
 

Modified: trunk/w32/main.c
===================================================================
--- trunk/w32/main.c	2007-05-10 17:37:07 UTC (rev 158)
+++ trunk/w32/main.c	2007-06-20 14:29:22 UTC (rev 159)
@@ -29,22 +29,157 @@
 
 #define PGMNAME "pinentry-w32"
 
+#ifndef LSFW_LOCK
+# define LSFW_LOCK 1
+# define LSFW_UNLOCK 2
+#endif
 
+
+/* This function pointer gets initialized in main.  */
+static WINUSERAPI BOOL WINAPI (*lock_set_foreground_window)(UINT);
+
+
 static int w32_cmd_handler (pinentry_t pe);
 static void ok_button_clicked (HWND dlg, pinentry_t pe);
 
 
-/* We use gloabl variables for the state, becuase there should never
+/* We use gloabl variables for the state, because there should never
    ever be a second instance.  */
 static HWND dialog_handle;
-static int passphrase_ok = 0;
+static int confirm_mode;
+static int passphrase_ok;
+static int confirm_yes;
 
-
 /* Connect this module to the pinnetry framework.  */
 pinentry_cmd_handler_t pinentry_cmd_handler = w32_cmd_handler;
 
 
 
+
+
+/* Convert a wchar to UTF8.  Caller needs to release the string.
+   Returns NULL on error. */
+static char *
+wchar_to_utf8 (const wchar_t *string, size_t len, int secure)
+{
+  int n;
+  char *result;
+
+  /* Note, that CP_UTF8 is not defined in Windows versions earlier
+     than NT.  */
+  n = WideCharToMultiByte (CP_UTF8, 0, string, len, NULL, 0, NULL, NULL);
+  if (n < 0)
+    return NULL;
+
+  result = secure? secmem_malloc (n+1) : malloc (n+1);
+  if (!result)
+    return NULL;
+  n = WideCharToMultiByte (CP_UTF8, 0, string, len, result, n, NULL, NULL);
+  if (n < 0)
+    {
+      if (secure)
+        secmem_free (result);
+      else
+        free (result);
+      return NULL;
+    }
+  return result;
+}
+
+
+/* Convert a UTF8 string to wchar.  Returns NULL on error. Caller
+   needs to free the returned value.  */
+wchar_t *
+utf8_to_wchar (const char *string)
+{
+  int n;
+  wchar_t *result;
+  size_t len = strlen (string);
+
+  n = MultiByteToWideChar (CP_UTF8, 0, string, len, NULL, 0);
+  if (n < 0)
+    return NULL;
+
+  result = calloc ((n+1), sizeof *result);
+  if (!result)
+    return NULL;
+  n = MultiByteToWideChar (CP_UTF8, 0, string, len, result, n);
+  if (n < 0)
+    {
+      free (result);
+      return NULL;
+    }
+  result[n] = 0;
+  return result;
+}
+
+
+/* Center the window CHILDWND with the desktop as its parent
+   window.  STYLE is passed as second arg to SetWindowPos.*/
+void
+center_window (HWND childwnd, HWND style) 
+{     
+  HWND parwnd;
+  RECT rchild, rparent;    
+  HDC hdc;
+  int wchild, hchild, wparent, hparent;
+  int wscreen, hscreen, xnew, ynew;
+  int flags = SWP_NOSIZE | SWP_NOZORDER;
+  
+  parwnd = GetDesktopWindow ();
+  GetWindowRect (childwnd, &rchild);     
+  wchild = rchild.right - rchild.left;     
+  hchild = rchild.bottom - rchild.top;
+  
+  GetWindowRect (parwnd, &rparent);     
+  wparent = rparent.right - rparent.left;     
+  hparent = rparent.bottom - rparent.top;      
+  
+  hdc = GetDC (childwnd);     
+  wscreen = GetDeviceCaps (hdc, HORZRES);     
+  hscreen = GetDeviceCaps (hdc, VERTRES);     
+  ReleaseDC (childwnd, hdc);      
+  xnew = rparent.left + ((wparent - wchild) / 2);     
+  if (xnew < 0)
+    xnew = 0;
+  else if ((xnew+wchild) > wscreen) 
+    xnew = wscreen - wchild;
+  ynew = rparent.top  + ((hparent - hchild) / 2);
+  if (ynew < 0)
+    ynew = 0;
+  else if ((ynew+hchild) > hscreen)
+    ynew = hscreen - hchild;
+  if (style == HWND_TOPMOST || style == HWND_NOTOPMOST)
+    flags = SWP_NOMOVE | SWP_NOSIZE;
+  SetWindowPos (childwnd, style? style : NULL, xnew, ynew, 0, 0, flags);
+}
+
+
+
+
+
+/* Call SetDlgItemTextW with an UTF8 string.  */
+static void
+set_dlg_item_text (HWND dlg, int item, const char *string)
+{
+  if (!string || !*string)
+    SetDlgItemText (dlg, item, "");
+  else
+    {
+      wchar_t *wbuf;
+      
+      wbuf = utf8_to_wchar (string);
+      if (!wbuf)
+        SetDlgItemText (dlg, item, "[out of core]");
+      else
+        {
+          SetDlgItemTextW (dlg, item, wbuf);
+          free (wbuf);
+        }
+    }
+}
+
+
 /* Dialog processing loop.  */
 static BOOL CALLBACK
 dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
@@ -57,24 +192,40 @@
       pe = (pinentry_t)lparam;
       if (!pe)
         abort ();
-      SetDlgItemText (dlg, IDC_PINENT_PROMPT, pe->prompt);
-      SetDlgItemText (dlg, IDC_PINENT_DESC, pe->description);
-      SetDlgItemText (dlg, IDC_PINENT_TEXT, "");
+      set_dlg_item_text (dlg, IDC_PINENT_PROMPT, pe->prompt);
+      set_dlg_item_text (dlg, IDC_PINENT_DESC, pe->description);
+      set_dlg_item_text (dlg, IDC_PINENT_TEXT, "");
       if (pe->ok)
-        SetDlgItemText (dlg, IDOK, pe->ok);
+        set_dlg_item_text (dlg, IDOK, pe->ok);
       if (pe->cancel)
-        SetDlgItemText (dlg, IDCANCEL, pe->cancel);
+        set_dlg_item_text (dlg, IDCANCEL, pe->cancel);
       if (pe->error)
-        SetDlgItemText (dlg, IDC_PINENT_ERR, pe->error);
+        set_dlg_item_text (dlg, IDC_PINENT_ERR, pe->error);
+
+      if (confirm_mode)
+        {
+          EnableWindow (GetDlgItem (dlg, IDC_PINENT_TEXT), FALSE);
+          SetWindowPos (GetDlgItem (dlg, IDC_PINENT_TEXT), NULL, 0, 0, 0, 0,
+                        (SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_HIDEWINDOW));
+        }
+
       dialog_handle = dlg;
-      SetForegroundWindow (dlg);
+      center_window (dlg, HWND_TOP);
+      /* Fixme: There are two problems: A race condition between the
+         two calls and more important that SetForegroundWindow will
+         fail if a Menu is somewhere open.  */
+      if (SetForegroundWindow (dlg) && lock_set_foreground_window)
+        lock_set_foreground_window (LSFW_LOCK);
       break;
 
     case WM_COMMAND:
       switch (LOWORD (wparam))
 	{
 	case IDOK:
-          ok_button_clicked (dlg, pe);
+          if (confirm_mode)
+            confirm_yes = 1;
+          else
+            ok_button_clicked (dlg, pe);
 	  EndDialog (dlg, TRUE);
 	  break;
 
@@ -95,27 +246,27 @@
 ok_button_clicked (HWND dlg, pinentry_t pe)
 {
   char *s_utf8;
-  char *s_buffer;
-  size_t s_buffer_size = 256;
+  wchar_t *w_buffer;
+  size_t w_buffer_size = 255;
+  unsigned int nchar;
   
   pe->locale_err = 1;
-  s_buffer = secmem_malloc (s_buffer_size + 1);
-  if (!s_buffer)
+  w_buffer = secmem_malloc ((w_buffer_size + 1) * sizeof *w_buffer);
+  if (!w_buffer)
     return;
 
-  pe->result = GetDlgItemText (dlg, IDC_PINENT_TEXT, s_buffer, s_buffer_size);
-/*   s_utf8 = pinentry_local_to_utf8 (pe->lc_ctype, s_buffer, 1); */
-/*   secmem_free (s_buffer); */
-  s_utf8 = s_buffer;   /* FIXME */
+  nchar = GetDlgItemTextW (dlg, IDC_PINENT_TEXT, w_buffer, w_buffer_size);
+  s_utf8 = wchar_to_utf8 (w_buffer, nchar, 1);
+  secmem_free (w_buffer);
   if (s_utf8)
     {
       passphrase_ok = 1;
       pinentry_setbufferlen (pe, strlen (s_utf8) + 1);
       if (pe->pin)
         strcpy (pe->pin, s_utf8);
-/*       secmem_free (s_utf8); */
+      secmem_free (s_utf8);
       pe->locale_err = 0;
-      pe->result = strlen (pe->pin);
+      pe->result = pe->pin? strlen (pe->pin) : 0;
     }
 }
 
@@ -123,37 +274,31 @@
 static int
 w32_cmd_handler (pinentry_t pe)
 {
-  int want_pass = !!pe->pin;
+  confirm_mode = !pe->pin;
 
-  passphrase_ok = 0;
+  passphrase_ok = confirm_yes = 0;
 
-  if (want_pass)
-    {
-      DialogBoxParam (NULL, (LPCTSTR) IDD_PINENT,
-                      GetDesktopWindow (), dlg_proc, (LPARAM)pe);
-      ShowWindow (dialog_handle, SW_SHOWNORMAL);
-      return pe->result;
-    }
-  else /* Confirmation mode.  */
-    {
-      int ret;
-
-      if (pe->error)
-        ret = MessageBox (NULL, pe->error, "Error", MB_YESNO | MB_ICONERROR);
-      else
-        ret = MessageBox (NULL, pe->description?pe->description:"",
-                          "Information", MB_YESNO | MB_ICONINFORMATION);
-      if (ret == IDYES)
-        return 1;
-      else
-        return 0;
-    }
+  DialogBoxParam (NULL, (LPCTSTR) IDD_PINENT,
+                  GetDesktopWindow (), dlg_proc, (LPARAM)pe);
+  ShowWindow (dialog_handle, SW_SHOWNORMAL);
+  if (lock_set_foreground_window)
+    lock_set_foreground_window (LSFW_UNLOCK);
+  DestroyWindow (dialog_handle);
+  dialog_handle = NULL;
+  if (confirm_mode)
+    return confirm_yes;
+  else if (passphrase_ok && pe->pin)
+    return strlen (pe->pin);
+  else
+    return -1;
 }
 
 
 int
 main (int argc, char **argv)
 {
+  void *handle;
+
   pinentry_init (PGMNAME);
 
   /* Consumes all arguments.  */
@@ -163,6 +308,19 @@
       exit (EXIT_SUCCESS);
     }
 
+  /* We need to load a functuion because that one is only available
+     since W2000 but not in older NTs.  */
+  handle = LoadLibrary ("user32.dll");
+  if (handle)
+    {
+      void *foo;
+      foo = GetProcAddress (handle, "LockSetForegroundWindow");
+      if (foo)
+        lock_set_foreground_window = foo;
+      else
+        CloseHandle (handle);
+    }
+
   if (pinentry_loop ())
     return 1;
 




More information about the Gnupg-commits mailing list