You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdepim/libkdenetwork/libgpgme-copy/gpgme/w32-util.c

318 lines
7.8 KiB

/* w32-util.c - Utility functions for the W32 API
Copyright (C) 1999 Free Software Foundation, Inc
Copyright (C) 2001 Werner Koch (dd9jn)
Copyright (C) 2001, 2002, 2003, 2004 g10 Code GmbH
This file is part of GPGME.
GPGME is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 of
the License, or (at your option) any later version.
GPGME is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/types.h>
#include <signal.h>
#include <fcntl.h>
#include <windows.h>
#include <shlobj.h>
#include <io.h>
#include "util.h"
#include "sema.h"
#include "debug.h"
DEFINE_STATIC_LOCK (get_path_lock);
#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, type;
char *result = NULL;
if ( !root )
root_key = HKEY_CURRENT_USER;
else if ( !strcmp( root, "HKEY_CLASSES_ROOT" ) )
root_key = HKEY_CLASSES_ROOT;
else if ( !strcmp( root, "HKEY_CURRENT_USER" ) )
root_key = HKEY_CURRENT_USER;
else if ( !strcmp( root, "HKEY_LOCAL_MACHINE" ) )
root_key = HKEY_LOCAL_MACHINE;
else if ( !strcmp( root, "HKEY_USERS" ) )
root_key = HKEY_USERS;
else if ( !strcmp( root, "HKEY_PERFORMANCE_DATA" ) )
root_key = HKEY_PERFORMANCE_DATA;
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 ) )
{
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 ) )
{
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. */
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 );
return result;
}
/* 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;
program = read_w32_registry_string (NULL, "Software\\GNU\\GnuPG", name);
if (program)
{
int i;
DEBUG2 ("found %s in registry: `%s'", name, program);
for (i = 0; program[i]; i++)
{
if (program[i] == '/')
program[i] = '\\';
}
}
return program;
}
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)
{
static char *gpg_program;
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;
#endif
UNLOCK (get_path_lock);
return gpg_program;
}
const char *
_gpgme_get_gpgsm_path (void)
{
static char *gpgsm_program;
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;
#endif
UNLOCK (get_path_lock);
return gpgsm_program;
}
/* Return an integer value from gpgme specific configuration
entries. VALUE receives that value; function returns true if a value
has been configured and false if not. */
int
_gpgme_get_conf_int (const char *key, int *value)
{
char *tmp = read_w32_registry_string (NULL, "Software\\GNU\\gpgme", key);
if (!tmp)
return 0;
*value = atoi (tmp);
free (tmp);
return 1;
}