* configure.ac (SEPCONSTANTS): New to define DIRSEP_C et al.
authorWerner Koch <wk@gnupg.org>
Fri, 26 Aug 2005 12:38:57 +0000 (12:38 +0000)
committerWerner Koch <wk@gnupg.org>
Fri, 26 Aug 2005 12:38:57 +0000 (12:38 +0000)
* w32-util.c (read_w32_registry_string): Updated from code used by
GnuPG.  This allows for expanding strings and features the
implicit fallback key.
(w32_shgetfolderpath, find_program_at_standard_place): New.
(_gpgme_get_gpg_path, _gpgme_get_gpgsm_path): With no registry
entry, locate the programs at the standard place.
(dlopen, dlsym, dlclose): New, so that we can keep on using what
we are accustomed to.

* debug.c (debug_init): Use PATHSEP_C so that under W32 a
semicolon is used which allows us to create files with drive
letters.

* w32-io.c (_gpgme_io_read, _gpgme_io_write): Print content in
debug mode too.

ChangeLog
NEWS
configure.ac
gpgme/ChangeLog
gpgme/debug.c
gpgme/w32-io.c
gpgme/w32-util.c

index 7a9423e..9018101 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2005-08-26  Werner Koch  <wk@g10code.com>
+
+       * configure.ac (SEPCONSTANTS): New to define DIRSEP_C et al.
+
 2005-08-19  Werner Koch  <wk@g10code.com>
 
        * configure.ac [W32]: Create values for versioninfo.rc and list
diff --git a/NEWS b/NEWS
index d9a04b4..9c7925f 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,10 @@ Noteworthy changes in version 1.1.0 (unreleased)
 
  * "./autogen.sh --build-w32" does now build gpgme.dll.
 
+ * [W32] The environment variable GPGME_DEBUG now uses a semicolon as
+   delimiter.  The standard install directory is used when locating
+   gpg or gpgsm before finally falling back to the hardwired name.
+
  * You can now configure the backend engine file name and home
    directory to be used, as default and per context.
 
index 801a4c4..de35e78 100644 (file)
@@ -458,6 +458,29 @@ fi
 AC_SUBST(BUILD_TIMESTAMP)
 AC_SUBST(BUILD_FILEVERSION)
 
+# Add a few constants to help porting to W32
+AH_VERBATIM([SEPCONSTANTS],
+[
+/* Separators as used in file names and $PATH. Please note that the
+   string version must not contain more than one character because
+   the using code assumes strlen()==1 */
+#ifdef HAVE_DOSISH_SYSTEM
+#define DIRSEP_C '\\\\'
+#define EXTSEP_C '.'
+#define DIRSEP_S "\\\\"
+#define EXTSEP_S "."
+#define PATHSEP_C ';'
+#define PATHSEP_S ";"
+#else
+#define DIRSEP_C '/'
+#define EXTSEP_C '.'
+#define DIRSEP_S "/"
+#define EXTSEP_S "."
+#define PATHSEP_C ':'
+#define PATHSEP_S ":"
+#endif
+])
+
 
 # Substitution used for gpgme-config 
 GPGME_CONFIG_LIBS="-lgpgme"
index 0a50a9f..72a7eab 100644 (file)
@@ -1,3 +1,21 @@
+2005-08-26  Werner Koch  <wk@g10code.com>
+
+       * w32-util.c (read_w32_registry_string): Updated from code used by
+       GnuPG.  This allows for expanding strings and features the
+       implicit fallback key.
+       (w32_shgetfolderpath, find_program_at_standard_place): New.
+       (_gpgme_get_gpg_path, _gpgme_get_gpgsm_path): With no registry
+       entry, locate the programs at the standard place.
+       (dlopen, dlsym, dlclose): New, so that we can keep on using what
+       we are accustomed to.
+
+       * debug.c (debug_init): Use PATHSEP_C so that under W32 a
+       semicolon is used which allows us to create files with drive
+       letters.
+
+       * w32-io.c (_gpgme_io_read, _gpgme_io_write): Print content in
+       debug mode too.
+
 2005-08-19  Werner Koch  <wk@g10code.com>
 
        * gpgme.def: New.
index 34a794d..c51f05a 100644 (file)
@@ -101,7 +101,7 @@ debug_init (void)
       if (e)
        {
          debug_level = atoi (e);
-         s1 = strchr (e, ':');
+         s1 = strchr (e, PATHSEP_C);
          if (s1)
            {
 #ifndef HAVE_DOSISH_SYSTEM
@@ -112,7 +112,7 @@ debug_init (void)
                  FILE *fp;
 
                  s1++;
-                 if (!(s2 = strchr (s1, ':')))
+                 if (!(s2 = strchr (s1, PATHSEP_C)))
                    s2 = s1 + strlen (s1);
                  p = malloc (s2 - s1 + 1);
                  if (p)
index 431acbe..94f0a06 100644 (file)
@@ -395,12 +395,11 @@ _gpgme_io_read ( int fd, void *buffer, size_t count )
     UNLOCK (c->mutex);
 
     DEBUG2 ("fd %d: got %d bytes\n", fd, nread );
+    if (nread > 0)
+      _gpgme_debug (2, "fd %d: got `%.*s'\n", fd, nread, buffer);
 
     return nread;
 }
-
-
-
 /*
  * The writer does use a simple buffering strategy so that we are
  * informed about write errors as soon as possible (i.e. with the the
@@ -600,6 +599,7 @@ _gpgme_io_write ( int fd, const void *buffer, size_t count )
     struct writer_context_s *c = find_writer (fd,1);
 
     DEBUG2 ("fd %d: about to write %d bytes\n", fd, (int)count );
+    _gpgme_debug (2, "fd %d: write `%.*s'\n", fd, (int) count, buffer);
     if ( !c ) {
         DEBUG0 ( "no writer thread\n");
         return -1;
index e4fac8e..fa1a6d7 100644 (file)
@@ -33,6 +33,7 @@
 #include <signal.h>
 #include <fcntl.h>
 #include <windows.h>
+#include <shlobj.h>
 #include <io.h>
 
 #include "util.h"
 
 DEFINE_STATIC_LOCK (get_path_lock);
 
-/* Return a string from the Win32 Registry or NULL in case of error.
-  Caller must release the return value.  A NULL for root is an alias
-  for HKEY_CURRENT_USER.  */
+
+#define RTLD_LAZY 0
+
+static __inline__ void *
+dlopen (const char * name, int flag)
+{
+  void * hd = LoadLibrary (name);
+  return hd;
+}
+
+static __inline__ void *
+dlsym (void * hd, const char * sym)
+{
+  if (hd && sym)
+    {
+      void * fnc = GetProcAddress (hd, sym);
+      if (!fnc)
+        return NULL;
+      return fnc;
+    }
+  return NULL;
+}
+
+static __inline__ int
+dlclose (void * hd)
+{
+  if (hd)
+    {
+      FreeLibrary (hd);
+      return 0;
+    }
+  return -1;
+}  
+
+
+/* Return a string from the W32 Registry or NULL in case of error.
+   Caller must release the return value.  A NULL for root is an alias
+   for HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE in turn. */
 static char *
 read_w32_registry_string (const char *root, const char *dir, const char *name)
 {
   HKEY root_key, key_handle;
-  DWORD n1, nbytes;
+  DWORD n1, nbytes, type;
   char *result = NULL;
-
-#ifdef HAVE_W32_SYSTEM
-#warning Check that this code matches the one used by gnupg
-#endif
-
-  if (!root)
+       
+  if ( !root )
     root_key = HKEY_CURRENT_USER;
-  else if (!strcmp (root, "HKEY_CLASSES_ROOT"))
+  else if ( !strcmp( root, "HKEY_CLASSES_ROOT" ) )
     root_key = HKEY_CLASSES_ROOT;
-  else if (!strcmp (root, "HKEY_CURRENT_USER"))
+  else if ( !strcmp( root, "HKEY_CURRENT_USER" ) )
     root_key = HKEY_CURRENT_USER;
-  else if (!strcmp (root, "HKEY_LOCAL_MACHINE"))
+  else if ( !strcmp( root, "HKEY_LOCAL_MACHINE" ) )
     root_key = HKEY_LOCAL_MACHINE;
-  else if (!strcmp (root, "HKEY_USERS"))
+  else if ( !strcmp( root, "HKEY_USERS" ) )
     root_key = HKEY_USERS;
-  else if (!strcmp (root, "HKEY_PERFORMANCE_DATA"))
+  else if ( !strcmp( root, "HKEY_PERFORMANCE_DATA" ) )
     root_key = HKEY_PERFORMANCE_DATA;
-  else if (!strcmp (root, "HKEY_CURRENT_CONFIG"))
+  else if ( !strcmp( root, "HKEY_CURRENT_CONFIG" ) )
     root_key = HKEY_CURRENT_CONFIG;
   else
     return NULL;
-
-  if (RegOpenKeyEx (root_key, dir, 0, KEY_READ, &key_handle))
-    return NULL;       /* No need for a RegClose, so return directly.  */
+       
+  if ( RegOpenKeyEx ( root_key, dir, 0, KEY_READ, &key_handle ) )
+    {
+      if (root)
+        return NULL; /* no need for a RegClose, so return direct */
+      /* It seems to be common practise to fall back to HKLM. */
+      if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) )
+        return NULL; /* still no need for a RegClose, so return direct */
+    }
 
   nbytes = 1;
-  if (RegQueryValueEx (key_handle, name, 0, NULL, NULL, &nbytes))
-    goto leave;
-  n1 = nbytes + 1;
-  result = malloc (n1);
-  if (!result)
+  if ( RegQueryValueEx( key_handle, name, 0, NULL, NULL, &nbytes ) )
+    {
+      if (root)
+        goto leave;
+      /* Try to fallback to HKLM also vor a missing value.  */
+      RegCloseKey (key_handle);
+      if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) )
+        return NULL; /* Nope.  */
+      if (RegQueryValueEx ( key_handle, name, 0, NULL, NULL, &nbytes))
+        goto leave;
+    }
+  result = malloc ( (n1=nbytes+1) );
+  if ( !result )
     goto leave;
-  if (RegQueryValueEx (key_handle, name, 0, NULL, result, &n1))
+  if ( RegQueryValueEx ( key_handle, name, 0, &type, result, &n1 ) )
     {
-      free (result);
-      result = NULL;
+      free(result); result = NULL;
       goto leave;
     }
-  result[nbytes] = 0;  /* Make sure it is really a string.  */
+  result[nbytes] = 0; /* Make sure it is really a string.  */
+  if (type == REG_EXPAND_SZ && strchr (result, '%')) 
+    {
+      char *tmp;
+        
+      n1 += 1000;
+      tmp = malloc (n1+1);
+      if (!tmp)
+        goto leave;
+      nbytes = ExpandEnvironmentStrings (result, tmp, n1);
+      if (nbytes && nbytes > n1)
+        {
+          free (tmp);
+          n1 = nbytes;
+          tmp = malloc (n1 + 1);
+          if (!tmp)
+            goto leave;
+          nbytes = ExpandEnvironmentStrings (result, tmp, n1);
+          if (nbytes && nbytes > n1) {
+            free (tmp); /* Oops - truncated, better don't expand at all. */
+            goto leave;
+          }
+          tmp[nbytes] = 0;
+          free (result);
+          result = tmp;
+        }
+      else if (nbytes)  /* Okay, reduce the length. */
+        {
+          tmp[nbytes] = 0;
+          free (result);
+          result = malloc (strlen (tmp)+1);
+          if (!result)
+            result = tmp;
+          else 
+            {
+              strcpy (result, tmp);
+              free (tmp);
+            }
+        }
+      else  /* Error - don't expand. */
+        {
+          free (tmp);
+        }
+    }
 
  leave:
-  RegCloseKey (key_handle);
+  RegCloseKey( key_handle );
   return result;
 }
 
 
-static const char *
+/* This is a helper function to load and run a Windows function from
+   either of one DLLs. */
+static HRESULT
+w32_shgetfolderpath (HWND a, int b, HANDLE c, DWORD d, LPSTR e)
+{
+  static int initialized;
+  static HRESULT (WINAPI * func)(HWND,int,HANDLE,DWORD,LPSTR);
+
+  if (!initialized)
+    {
+      static char *dllnames[] = { "shell32.dll", "shfolder.dll", NULL };
+      void *handle;
+      int i;
+
+      initialized = 1;
+
+      for (i=0, handle = NULL; !handle && dllnames[i]; i++)
+        {
+          handle = dlopen (dllnames[i], RTLD_LAZY);
+          if (handle)
+            {
+              func = dlsym (handle, "SHGetFolderPathA");
+              if (!func)
+                {
+                  dlclose (handle);
+                  handle = NULL;
+                }
+            }
+        }
+    }
+
+  if (func)
+    return func (a,b,c,d,e);
+  else
+    return -1;
+}
+
+
+static char *
 find_program_in_registry (const char *name)
 {
   char *program = NULL;
@@ -117,6 +243,29 @@ find_program_in_registry (const char *name)
 }
 
 
+static char *
+find_program_at_standard_place (const char *name)
+{
+  char path[MAX_PATH];
+  char *result = NULL;
+      
+  if (w32_shgetfolderpath (NULL, CSIDL_PROGRAM_FILES, NULL, 0, path) >= 0) 
+    {
+      result = malloc (strlen (path) + 1 + strlen (name) + 1);
+      if (result)
+        {
+          strcpy (stpcpy (stpcpy (result, path), "\\"), name);
+          if (access (result, F_OK))
+            {
+              free (result);
+              result = NULL;
+            }
+        }
+    }
+  return result;
+}
+
+
 const char *
 _gpgme_get_gpg_path (void)
 {
@@ -125,6 +274,8 @@ _gpgme_get_gpg_path (void)
   LOCK (get_path_lock);
   if (!gpg_program)
     gpg_program = find_program_in_registry ("gpgProgram");
+  if (!gpg_program)
+    gpg_program = find_program_at_standard_place ("GNU\\GnuPG\\gpg.exe");
 #ifdef GPG_PATH
   if (!gpg_program)
     gpg_program = GPG_PATH;
@@ -141,6 +292,8 @@ _gpgme_get_gpgsm_path (void)
   LOCK (get_path_lock);
   if (!gpgsm_program)
     gpgsm_program = find_program_in_registry ("gpgsmProgram");
+  if (!gpgsm_program)
+    gpgsm_program = find_program_at_standard_place ("GNU\\GnuPG\\gpgsm.exe");
 #ifdef GPGSM_PATH
   if (!gpgsm_program)
     gpgsm_program = GPGSM_PATH;