diff --git a/ChangeLog b/ChangeLog index 7a9423ea..90181013 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2005-08-26 Werner Koch + + * configure.ac (SEPCONSTANTS): New to define DIRSEP_C et al. + 2005-08-19 Werner Koch * configure.ac [W32]: Create values for versioninfo.rc and list diff --git a/NEWS b/NEWS index d9a04b47..9c7925f9 100644 --- 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. diff --git a/configure.ac b/configure.ac index 801a4c43..de35e787 100644 --- a/configure.ac +++ b/configure.ac @@ -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" diff --git a/gpgme/ChangeLog b/gpgme/ChangeLog index 0a50a9fd..72a7eab7 100644 --- a/gpgme/ChangeLog +++ b/gpgme/ChangeLog @@ -1,3 +1,21 @@ +2005-08-26 Werner Koch + + * 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 * gpgme.def: New. diff --git a/gpgme/debug.c b/gpgme/debug.c index 34a794d6..c51f05ac 100644 --- a/gpgme/debug.c +++ b/gpgme/debug.c @@ -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) diff --git a/gpgme/w32-io.c b/gpgme/w32-io.c index 431acbe9..94f0a06a 100644 --- a/gpgme/w32-io.c +++ b/gpgme/w32-io.c @@ -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; diff --git a/gpgme/w32-util.c b/gpgme/w32-util.c index e4fac8e2..fa1a6d7a 100644 --- a/gpgme/w32-util.c +++ b/gpgme/w32-util.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include "util.h" @@ -41,62 +42,187 @@ 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) - goto leave; - if (RegQueryValueEx (key_handle, name, 0, NULL, result, &n1)) + if ( RegQueryValueEx( key_handle, name, 0, NULL, NULL, &nbytes ) ) { - free (result); - result = NULL; + 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, &type, result, &n1 ) ) + { + 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;