Made W32 version work. There are still some glitches but it works with
authorWerner Koch <wk@gnupg.org>
Wed, 20 Jun 2007 14:29:22 +0000 (14:29 +0000)
committerWerner Koch <wk@gnupg.org>
Wed, 20 Jun 2007 14:29:22 +0000 (14:29 +0000)
gpg-agent.

ChangeLog
Makefile.am
NEWS
README.SVN [moved from README.CVS with 86% similarity]
autogen.sh
secmem/secmem.c
w32/Makefile.am
w32/main.c

index 5845fe6..c8e65aa 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,25 @@
+2007-06-20  Werner Koch  <wk@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@g10code.com>
+
+       * w32/main.c (dlg_proc): Call LockSetForegroundWindow.
+
+       * Makefile.am (signed-dist, %.sig): Remove.
+
+       * autogen.sh: Modernized.
+
 2007-05-10  Marcus Brinkmann  <marcus@g10code.de>
 
        * pinentry/pinentry.h (pinentry_color_t): New type.
index ff4cbdc..90d7944 100644 (file)
@@ -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,10 +56,6 @@ endif
 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 \
diff --git a/NEWS b/NEWS
index 55af1d8..630feda 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -10,6 +10,8 @@ Noteworthy changes in version 0.7.3
  * 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)
 ------------------------------------------------
similarity index 86%
rename from README.CVS
rename to README.SVN
index ae17923..c642282 100644 (file)
@@ -1,9 +1,11 @@
-If you are building from CVS, run the script
+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.  Then run
+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
 
@@ -40,12 +42,10 @@ 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 CVS and only updated manually
+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.
 
 
-
-
index 8eaf1c2..1976695 100755 (executable)
@@ -28,6 +28,23 @@ check_version () {
     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.
@@ -44,25 +61,22 @@ if test "$1" = "--build-w32"; then
     [ -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 @@ if test "$1" = "--build-w32"; then
     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 @@ then
   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 @@ if test "$DIE" = "yes"; then
     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 @@ $ACLOCAL -I m4 $ACLOCAL_FLAGS
 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\"."
index 5cfddab..796108d 100644 (file)
@@ -281,11 +281,11 @@ void
 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 @@ secmem_init( size_t n )
            if( setuid( uid ) || getuid() != geteuid() )
                log_fatal("failed to drop setuid\n" );
        }
-      #endif
+#endif
     }
     else {
        if( n < DEFAULT_POOLSIZE )
index 6f4312b..6175a4a 100644 (file)
@@ -27,10 +27,11 @@ AM_CPPFLAGS = -I$(top_srcdir)/assuan -I$(top_srcdir)/secmem \
              -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
 
index f539e93..a8cdf62 100644 (file)
 
 #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);
+}
+
+
+
+
+\f
+/* 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 @@ dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
       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 @@ static void
 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 @@ ok_button_clicked (HWND dlg, pinentry_t pe)
 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 @@ main (int argc, char **argv)
       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;