* configure.ac (SEPCONSTANTS): New to define DIRSEP_C et al.

* 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.
This commit is contained in:
Werner Koch 2005-08-26 12:38:57 +00:00
parent 01baed5b70
commit 82a0c97250
7 changed files with 238 additions and 36 deletions

View File

@ -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> 2005-08-19 Werner Koch <wk@g10code.com>
* configure.ac [W32]: Create values for versioninfo.rc and list * configure.ac [W32]: Create values for versioninfo.rc and list

4
NEWS
View File

@ -3,6 +3,10 @@ Noteworthy changes in version 1.1.0 (unreleased)
* "./autogen.sh --build-w32" does now build gpgme.dll. * "./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 * You can now configure the backend engine file name and home
directory to be used, as default and per context. directory to be used, as default and per context.

View File

@ -458,6 +458,29 @@ fi
AC_SUBST(BUILD_TIMESTAMP) AC_SUBST(BUILD_TIMESTAMP)
AC_SUBST(BUILD_FILEVERSION) 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 # Substitution used for gpgme-config
GPGME_CONFIG_LIBS="-lgpgme" GPGME_CONFIG_LIBS="-lgpgme"

View 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> 2005-08-19 Werner Koch <wk@g10code.com>
* gpgme.def: New. * gpgme.def: New.

View File

@ -101,7 +101,7 @@ debug_init (void)
if (e) if (e)
{ {
debug_level = atoi (e); debug_level = atoi (e);
s1 = strchr (e, ':'); s1 = strchr (e, PATHSEP_C);
if (s1) if (s1)
{ {
#ifndef HAVE_DOSISH_SYSTEM #ifndef HAVE_DOSISH_SYSTEM
@ -112,7 +112,7 @@ debug_init (void)
FILE *fp; FILE *fp;
s1++; s1++;
if (!(s2 = strchr (s1, ':'))) if (!(s2 = strchr (s1, PATHSEP_C)))
s2 = s1 + strlen (s1); s2 = s1 + strlen (s1);
p = malloc (s2 - s1 + 1); p = malloc (s2 - s1 + 1);
if (p) if (p)

View File

@ -395,12 +395,11 @@ _gpgme_io_read ( int fd, void *buffer, size_t count )
UNLOCK (c->mutex); UNLOCK (c->mutex);
DEBUG2 ("fd %d: got %d bytes\n", fd, nread ); 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; return nread;
} }
/* /*
* The writer does use a simple buffering strategy so that we are * 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 * 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); struct writer_context_s *c = find_writer (fd,1);
DEBUG2 ("fd %d: about to write %d bytes\n", fd, (int)count ); 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 ) { if ( !c ) {
DEBUG0 ( "no writer thread\n"); DEBUG0 ( "no writer thread\n");
return -1; return -1;

View File

@ -33,6 +33,7 @@
#include <signal.h> #include <signal.h>
#include <fcntl.h> #include <fcntl.h>
#include <windows.h> #include <windows.h>
#include <shlobj.h>
#include <io.h> #include <io.h>
#include "util.h" #include "util.h"
@ -41,62 +42,187 @@
DEFINE_STATIC_LOCK (get_path_lock); 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 #define RTLD_LAZY 0
for HKEY_CURRENT_USER. */
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 * static char *
read_w32_registry_string (const char *root, const char *dir, const char *name) read_w32_registry_string (const char *root, const char *dir, const char *name)
{ {
HKEY root_key, key_handle; HKEY root_key, key_handle;
DWORD n1, nbytes; DWORD n1, nbytes, type;
char *result = NULL; char *result = NULL;
#ifdef HAVE_W32_SYSTEM if ( !root )
#warning Check that this code matches the one used by gnupg
#endif
if (!root)
root_key = HKEY_CURRENT_USER; root_key = HKEY_CURRENT_USER;
else if (!strcmp (root, "HKEY_CLASSES_ROOT")) else if ( !strcmp( root, "HKEY_CLASSES_ROOT" ) )
root_key = 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; root_key = HKEY_CURRENT_USER;
else if (!strcmp (root, "HKEY_LOCAL_MACHINE")) else if ( !strcmp( root, "HKEY_LOCAL_MACHINE" ) )
root_key = HKEY_LOCAL_MACHINE; root_key = HKEY_LOCAL_MACHINE;
else if (!strcmp (root, "HKEY_USERS")) else if ( !strcmp( root, "HKEY_USERS" ) )
root_key = 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; root_key = HKEY_PERFORMANCE_DATA;
else if (!strcmp (root, "HKEY_CURRENT_CONFIG")) else if ( !strcmp( root, "HKEY_CURRENT_CONFIG" ) )
root_key = HKEY_CURRENT_CONFIG; root_key = HKEY_CURRENT_CONFIG;
else else
return NULL; return NULL;
if (RegOpenKeyEx (root_key, dir, 0, KEY_READ, &key_handle)) if ( RegOpenKeyEx ( root_key, dir, 0, KEY_READ, &key_handle ) )
return NULL; /* No need for a RegClose, so return directly. */ {
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; nbytes = 1;
if (RegQueryValueEx (key_handle, name, 0, NULL, NULL, &nbytes)) if ( RegQueryValueEx( key_handle, name, 0, NULL, NULL, &nbytes ) )
goto leave;
n1 = nbytes + 1;
result = malloc (n1);
if (!result)
goto leave;
if (RegQueryValueEx (key_handle, name, 0, NULL, result, &n1))
{ {
free (result); if (root)
result = NULL; 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, &type, result, &n1 ) )
{
free(result); result = NULL;
goto leave; 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: leave:
RegCloseKey (key_handle); RegCloseKey( key_handle );
return result; 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) find_program_in_registry (const char *name)
{ {
char *program = NULL; 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 * const char *
_gpgme_get_gpg_path (void) _gpgme_get_gpg_path (void)
{ {
@ -125,6 +274,8 @@ _gpgme_get_gpg_path (void)
LOCK (get_path_lock); LOCK (get_path_lock);
if (!gpg_program) if (!gpg_program)
gpg_program = find_program_in_registry ("gpgProgram"); gpg_program = find_program_in_registry ("gpgProgram");
if (!gpg_program)
gpg_program = find_program_at_standard_place ("GNU\\GnuPG\\gpg.exe");
#ifdef GPG_PATH #ifdef GPG_PATH
if (!gpg_program) if (!gpg_program)
gpg_program = GPG_PATH; gpg_program = GPG_PATH;
@ -141,6 +292,8 @@ _gpgme_get_gpgsm_path (void)
LOCK (get_path_lock); LOCK (get_path_lock);
if (!gpgsm_program) if (!gpgsm_program)
gpgsm_program = find_program_in_registry ("gpgsmProgram"); gpgsm_program = find_program_in_registry ("gpgsmProgram");
if (!gpgsm_program)
gpgsm_program = find_program_at_standard_place ("GNU\\GnuPG\\gpgsm.exe");
#ifdef GPGSM_PATH #ifdef GPGSM_PATH
if (!gpgsm_program) if (!gpgsm_program)
gpgsm_program = GPGSM_PATH; gpgsm_program = GPGSM_PATH;