w32: Avoid conflict with Mingw-w64 version 4.0.4-1
[gpgme.git] / src / w32-util.c
index daf3bd2..a27955b 100644 (file)
@@ -85,7 +85,10 @@ static HMODULE my_hmodule;
    binaries.  The are set only once by gpgme_set_global_flag.  */
 static char *default_gpg_name;
 static char *default_gpgconf_name;
-
+/* If this variable is not NULL the value is assumed to be the
+   installation directory.  The variable may only be set once by
+   gpgme_set_global_flag and accessed by _gpgme_get_inst_dir.  */
+static char *override_inst_dir;
 
 #ifdef HAVE_ALLOW_SET_FOREGROUND_WINDOW
 
@@ -347,6 +350,9 @@ _gpgme_get_inst_dir (void)
 {
   static char *inst_dir;
 
+  if (override_inst_dir)
+    return override_inst_dir;
+
   LOCK (get_path_lock);
   if (!inst_dir)
     {
@@ -398,47 +404,18 @@ find_program_in_dir (const char *dir, const char *name)
 
 
 static char *
-find_program_in_inst_dir (const char *inst_dir, const char *name)
-{
-  char *result;
-  char *dir;
-
-  /* If an installation directory has been passed, this overrides a
-     location given by the registry.  The idea here is that we prefer
-     a program installed alongside with gpgme.  We don't want the
-     registry to override this to have a better isolation of an gpgme
-     aware applications for other effects.  Note that the "Install
-     Directory" registry item has been used for ages in Gpg4win and
-     earlier GnuPG windows installers.  It is technically not anymore
-     required.  */
-  if (inst_dir)
-    {
-      result = find_program_in_dir (inst_dir, name);
-      if (result)
-        return result;
-    }
-
-  dir = read_w32_registry_string ("HKEY_LOCAL_MACHINE",
-                                 "Software\\GNU\\GnuPG",
-                                 "Install Directory");
-  if (dir)
-    {
-      result = find_program_in_dir (dir, name);
-      free (dir);
-      return result;
-    }
-  return NULL;
-}
-
-
-static char *
 find_program_at_standard_place (const char *name)
 {
   char path[MAX_PATH];
   char *result = NULL;
 
-  /* See http://wiki.tcl.tk/17492 for details on compatibility.  */
-  if (SHGetSpecialFolderPathA (NULL, path, CSIDL_PROGRAM_FILES, 0))
+  /* See http://wiki.tcl.tk/17492 for details on compatibility.
+
+     We First try the generic place and then fallback to the x86
+     (i.e. 32 bit) place.  This will prefer a 64 bit of the program
+     over a 32 bit version on 64 bit Windows if installed.  */
+  if (SHGetSpecialFolderPathA (NULL, path, CSIDL_PROGRAM_FILES, 0)
+      || SHGetSpecialFolderPathA (NULL, path, CSIDL_PROGRAM_FILESX86, 0))
     {
       result = malloc (strlen (path) + 1 + strlen (name) + 1);
       if (result)
@@ -490,30 +467,73 @@ _gpgme_set_default_gpgconf_name (const char *name)
 }
 
 
+/* Set the override installation directory.  This function may only be
+   called by gpgme_set_global_flag.  Returns 0 on success.  */
+int
+_gpgme_set_override_inst_dir (const char *dir)
+{
+  if (!override_inst_dir)
+    {
+      override_inst_dir = malloc (strlen (dir) + 1);
+      if (override_inst_dir)
+        {
+          strcpy (override_inst_dir, dir);
+          replace_slashes (override_inst_dir);
+          /* Remove a trailing slash.  */
+          if (*override_inst_dir
+              && override_inst_dir[strlen (override_inst_dir)-1] == '\\')
+            override_inst_dir[strlen (override_inst_dir)-1] = 0;
+        }
+    }
+  return !override_inst_dir;
+}
+
+
 /* Return the full file name of the GPG binary.  This function is used
-   if gpgconf was not found and thus it can be assumed that gpg2 is
+   iff gpgconf was not found and thus it can be assumed that gpg2 is
    not installed.  This function is only called by get_gpgconf_item
    and may not be called concurrently. */
 char *
 _gpgme_get_gpg_path (void)
 {
-  char *gpg;
-  const char *inst_dir, *name;
+  char *gpg = NULL;
+  const char *name, *inst_dir;
 
+  name = default_gpg_name? get_basename (default_gpg_name) : "gpg.exe";
+
+  /* 1. Try to find gpg.exe in the installation directory of gpgme.  */
   inst_dir = _gpgme_get_inst_dir ();
-  gpg = find_program_in_inst_dir
-    (inst_dir,
-     default_gpg_name? get_basename (default_gpg_name) : "gpg.exe");
+  if (inst_dir)
+    {
+      gpg = find_program_in_dir (inst_dir, name);
+    }
+
+  /* 2. Try to find gpg.exe using that ancient registry key.  */
+  if (!gpg)
+    {
+      char *dir;
+
+      dir = read_w32_registry_string ("HKEY_LOCAL_MACHINE",
+                                      "Software\\GNU\\GnuPG",
+                                      "Install Directory");
+      if (dir)
+        {
+          gpg = find_program_in_dir (dir, name);
+          free (dir);
+        }
+    }
+
+  /* 3. Try to find gpg.exe below CSIDL_PROGRAM_FILES.  */
   if (!gpg)
     {
-      name = (default_gpg_name? default_gpg_name
-              /* */           : "GNU\\GnuPG\\gpg.exe");
+      name = default_gpg_name? default_gpg_name : "GNU\\GnuPG\\gpg.exe";
       gpg = find_program_at_standard_place (name);
-      if (!gpg)
-        _gpgme_debug (DEBUG_ENGINE, "_gpgme_get_gpg_path: '%s' not found",
-                      name);
     }
 
+  /* 4. Print a debug message if not found.  */
+  if (!gpg)
+    _gpgme_debug (DEBUG_ENGINE, "_gpgme_get_gpg_path: '%s' not found", name);
+
   return gpg;
 }
 
@@ -523,22 +543,52 @@ _gpgme_get_gpg_path (void)
 char *
 _gpgme_get_gpgconf_path (void)
 {
-  char *gpgconf;
+  char *gpgconf = NULL;
   const char *inst_dir, *name;
 
+  name = default_gpgconf_name? get_basename(default_gpgconf_name):"gpgconf.exe";
+
+  /* 1. Try to find gpgconf.exe in the installation directory of gpgme.  */
   inst_dir = _gpgme_get_inst_dir ();
-  gpgconf = find_program_in_inst_dir
-    (inst_dir,
-     default_gpgconf_name? get_basename (default_gpgconf_name) : "gpgconf.exe");
+  if (inst_dir)
+    {
+      gpgconf = find_program_in_dir (inst_dir, name);
+    }
+
+  /* 2. Try to find gpgconf.exe from GnuPG >= 2.1 below CSIDL_PROGRAM_FILES. */
   if (!gpgconf)
     {
-      name = (default_gpgconf_name? default_gpgconf_name
-              /* */               : "GNU\\GnuPG\\gpgconf.exe");
-      gpgconf = find_program_at_standard_place (name);
-      if (!gpgconf)
-        _gpgme_debug (DEBUG_ENGINE, "_gpgme_get_gpgconf_path: '%s' not found",
-                      name);
+      const char *name2 = (default_gpgconf_name ? default_gpgconf_name
+                           /**/                 : "GnuPG\\bin\\gpgconf.exe");
+      gpgconf = find_program_at_standard_place (name2);
     }
+
+  /* 3. Try to find gpgconf.exe using that ancient registry key.  This
+        should eventually be removed.  */
+  if (!gpgconf)
+    {
+      char *dir;
+
+      dir = read_w32_registry_string ("HKEY_LOCAL_MACHINE",
+                                      "Software\\GNU\\GnuPG",
+                                      "Install Directory");
+      if (dir)
+        {
+          gpgconf = find_program_in_dir (dir, name);
+          free (dir);
+        }
+    }
+
+  /* 4. Try to find gpgconf.exe from Gpg4win below CSIDL_PROGRAM_FILES.  */
+  if (!gpgconf)
+    {
+      gpgconf = find_program_at_standard_place ("GNU\\GnuPG\\gpgconf.exe");
+    }
+
+  /* 5. Print a debug message if not found.  */
+  if (!gpgconf)
+    _gpgme_debug (DEBUG_ENGINE, "_gpgme_get_gpgconf_path: '%s' not found",name);
+
   return gpgconf;
 }
 
@@ -552,10 +602,7 @@ _gpgme_get_w32spawn_path (void)
   inst_dir = _gpgme_get_inst_dir ();
   LOCK (get_path_lock);
   if (!w32spawn_program)
-    w32spawn_program = find_program_in_inst_dir (inst_dir,"gpgme-w32spawn.exe");
-  if (!w32spawn_program)
-    w32spawn_program
-      = find_program_at_standard_place ("GNU\\GnuPG\\gpgme-w32spawn.exe");
+    w32spawn_program = find_program_in_dir (inst_dir, "gpgme-w32spawn.exe");
   UNLOCK (get_path_lock);
   return w32spawn_program;
 }
@@ -600,7 +647,7 @@ static const char letters[] =
    does not exist at the time of the call to mkstemp.  TMPL is
    overwritten with the result.  */
 static int
-mkstemp (char *tmpl)
+my_mkstemp (char *tmpl)
 {
   int len;
   char *XXXXXX;
@@ -708,7 +755,7 @@ _gpgme_mkstemp (int *fd, char **name)
   if (!tmpname)
     return -1;
   strcpy (stpcpy (tmpname, tmp), "\\gpgme-XXXXXX");
-  *fd = mkstemp (tmpname);
+  *fd = my_mkstemp (tmpname);
   if (fd < 0)
     {
       free (tmpname);