diff options
Diffstat (limited to '')
-rw-r--r-- | complus/gpgcom.c | 543 |
1 files changed, 543 insertions, 0 deletions
diff --git a/complus/gpgcom.c b/complus/gpgcom.c new file mode 100644 index 00000000..acea9829 --- /dev/null +++ b/complus/gpgcom.c @@ -0,0 +1,543 @@ +/* gpgcom.c - COM+ component to access GnuPG + * Copyright (C) 2001 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 General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU 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 + */ + + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <assert.h> +#include <time.h> +#include <windows.h> + +#include <ole2.h> + +#include "argparse.h" + +#include "main.h" +#include "igpgme.h" + +static void register_server (void); +static void unregister_server (void); +static void enter_complus (void); + + +enum cmd_and_opt_values { aNull = 0, + oQuiet = 'q', + oVerbose = 'v', + + oNoVerbose = 500, + oOptions, + oDebug, + oDebugAll, + oNoGreeting, + oNoOptions, + oHomedir, + oGPGBinary, + oRegServer, + oUnregServer, + oEmbedding, +aTest }; + + +static ARGPARSE_OPTS opts[] = { + + { 301, NULL, 0, N_("@Options:\n ") }, + + { oVerbose, "verbose", 0, N_("verbose") }, + { oQuiet, "quiet", 0, N_("be somewhat more quiet") }, + { oOptions, "options" , 2, N_("read options from file")}, + { oDebug, "debug" ,4|16, N_("set debugging flags")}, + { oDebugAll, "debug-all" ,0, N_("enable full debugging")}, + { oGPGBinary, "gpg-program", 2 , "" }, + { oRegServer, "RegServer" , 0, "" }, + { oUnregServer, "UnregServer" , 0, "" }, + { oEmbedding, "Embedding" , 0, "" }, +{0} }; + + + + +static const char * +my_strusage( int level ) +{ + const char *p; + switch( level ) { + case 11: p = "gpgcom"; + break; + case 13: p = VERSION; break; + /*case 17: p = PRINTABLE_OS_NAME; break;*/ + case 19: p = + _("Please report bugs to <[email protected]>.\n"); + break; + case 1: + case 40: p = + _("Usage: gpgcom [options] (-h for help)"); + break; + case 41: p = + _("Syntax: gpgcom [options]\n" + "GnuPG COM+ component\n"); + break; + + default: p = NULL; + } + return p; +} + + +int +main (int argc, char **argv ) +{ + ARGPARSE_ARGS pargs; + int orig_argc; + char **orig_argv; + FILE *configfp = NULL; + char *configname = NULL; + unsigned configlineno; + int parse_debug = 0; + int default_config =1; + int greeting = 0; + int nogreeting = 0; + int action = 0; + + set_strusage( my_strusage ); + /*log_set_name ("gpa"); not yet implemented in logging.c */ + + opt.homedir = getenv("GNUPGHOME"); + if( !opt.homedir || !*opt.homedir ) { + #ifdef HAVE_DRIVE_LETTERS + opt.homedir = "c:/gnupg"; + #else + opt.homedir = "~/.gnupg"; + #endif + } + + /* check whether we have a config file on the commandline */ + orig_argc = argc; + orig_argv = argv; + pargs.argc = &argc; + pargs.argv = &argv; + pargs.flags= 1|(1<<6); /* do not remove the args, ignore version */ + while( arg_parse( &pargs, opts) ) { + if( pargs.r_opt == oDebug || pargs.r_opt == oDebugAll ) + parse_debug++; + else if( pargs.r_opt == oOptions ) { + /* yes there is one, so we do not try the default one, but + * read the option file when it is encountered at the commandline + */ + default_config = 0; + } + else if( pargs.r_opt == oNoOptions ) + default_config = 0; /* --no-options */ + else if( pargs.r_opt == oHomedir ) + opt.homedir = pargs.r.ret_str; + } + + if( default_config ) + configname = make_filename(opt.homedir, "gpgme.conf", NULL ); + + + argc = orig_argc; + argv = orig_argv; + pargs.argc = &argc; + pargs.argv = &argv; + pargs.flags= 1 | (1<<5); /* do not remove the args, allow one dash */ + next_pass: + if( configname ) { + configlineno = 0; + configfp = fopen( configname, "r" ); + if( !configfp ) { + if( default_config ) { + if( parse_debug ) + log_info(_("NOTE: no default option file `%s'\n"), + configname ); + } + else { + log_error(_("option file `%s': %s\n"), + configname, strerror(errno) ); + exit(2); + } + free(configname); configname = NULL; + } + if( parse_debug && configname ) + log_info(_("reading options from `%s'\n"), configname ); + default_config = 0; + } + + while( optfile_parse( configfp, configname, &configlineno, + &pargs, opts) ) { + switch( pargs.r_opt ) { + case oQuiet: opt.quiet = 1; break; + case oVerbose: opt.verbose++; break; + + case oDebug: opt.debug |= pargs.r.ret_ulong; break; + case oDebugAll: opt.debug = ~0; break; + + case oOptions: + /* config files may not be nested (silently ignore them) */ + if( !configfp ) { + free(configname); + configname = xstrdup(pargs.r.ret_str); + goto next_pass; + } + break; + case oNoGreeting: nogreeting = 1; break; + case oNoVerbose: opt.verbose = 0; break; + case oNoOptions: break; /* no-options */ + case oHomedir: opt.homedir = pargs.r.ret_str; break; + case oGPGBinary: break; + + case oRegServer: action = 1; break; + case oUnregServer: action = 2; break; + case oEmbedding: action = 3; break; + + default : pargs.err = configfp? 1:2; break; + } + } + if( configfp ) { + fclose( configfp ); + configfp = NULL; + free(configname); configname = NULL; + goto next_pass; + } + free( configname ); configname = NULL; + if( log_get_errorcount(0) ) + exit(2); + if( nogreeting ) + greeting = 0; + + if( greeting ) { + fprintf(stderr, "%s %s; %s\n", + strusage(11), strusage(13), strusage(14) ); + fprintf(stderr, "%s\n", strusage(15) ); + } + #ifdef IS_DEVELOPMENT_VERSION + log_info("NOTE: this is a development version!\n"); + #endif + + if ( action == 1 ) + register_server (); + else if (action == 2 ) + unregister_server (); + else if (action == 3 ) + enter_complus (); + else { + fprintf (stderr, "This is a COM+ component with no user interface.\n" + "gpgme --help will give you a list of options\n" ); + exit (1); + } + + return 0; +} + + +static void +register_progid ( const char *name ) +{ + HKEY hk = 0; + char buf[500]; + + /* Create a ProgID entry to point to the ClassID */ + sprintf (buf, "%.400s", name); + if (RegCreateKeyA (HKEY_CLASSES_ROOT, buf, &hk)) { + fprintf (stderr,"RegCreateKey(`%s') failed\n", buf); + exit (1); + } + sprintf (buf, "g10 Code's GnuPG made easy COMponent" ); + if (RegSetValueExA (hk, 0, 0, REG_SZ, buf, 0)) { + fprintf (stderr,"RegSetValueEx(`%s') failed\n", buf); + exit (1); + } + if (RegCloseKey (hk)) { + fprintf (stderr,"RegCloseKey() failed\n"); + exit (1); + } + sprintf (buf, "%.400s\\CLSID", name); + if (RegCreateKeyA (HKEY_CLASSES_ROOT, buf, &hk)) { + fprintf (stderr,"RegCreateKey(`%s') failed\n", buf); + exit (1); + } + sprintf (buf, "%.100s", debugstr_guid (&CLSID_Gpgme) ); + if (RegSetValueExA (hk, 0, 0, REG_SZ, buf, strlen (buf))) { + fprintf (stderr,"RegSetValueEx(`%s') failed\n", buf); + exit (1); + } + if (RegCloseKey (hk)) { + fprintf (stderr,"RegCloseKey() failed\n"); + exit (1); + } + hk = 0; +} + + +static void +register_typelib (void) +{ + ITypeLib *pTypeLib; + HRESULT hr; + char name[500]; + wchar_t *wname; + size_t n; + + if ( !GetModuleFileNameA (0, name, sizeof (name)-10) ) { + fprintf (stderr,"GetModuleFileName() failed: %d\n", + (int)GetLastError()); + exit (1); + } + n = mbstowcs (NULL, name, strlen(name)+1); + wname = xmalloc ((n+1)*sizeof *wname); + mbstowcs (wname, name, strlen (name)+1); + + hr = CoInitializeEx (NULL, COINIT_APARTMENTTHREADED); + if (hr) + fprintf (stderr, "CoInitializeEx() failed: hr=%lu\n", hr); + + hr = LoadTypeLibEx (wname, REGKIND_REGISTER, &pTypeLib); + if (hr) + fprintf (stderr, "LoadTypeLibEx() failed: hr=%lx\n", hr); + + ITypeLib_Release (pTypeLib); + CoUninitialize (); + free (wname); +} + +static void +unregister_typelib (void) +{ + UnRegisterTypeLib (&TLBID_Gpgcom, 1, 0, LANG_NEUTRAL, SYS_WIN32); +} + +static void +register_server () +{ + HKEY hk = 0; + char buf[500]; + + + register_typelib (); + + /* Create a key for the CLSID */ + sprintf (buf, "CLSID\\%.100s", debugstr_guid (&CLSID_Gpgme) ); + if (RegCreateKeyA (HKEY_CLASSES_ROOT, buf, &hk)) { + fprintf (stderr,"RegCreateKey(`%s') failed\n", buf); + exit (1); + } + /* Store our class name as default value */ + strcpy (buf, "Gpgme"); + if (RegSetValueExA (hk, 0, 0, REG_SZ, buf, strlen (buf))) { + fprintf (stderr,"RegSetValueEx(`%s') failed\n", buf); + exit (1); + } + + /* Set the application ID */ + sprintf (buf, "%.100s", debugstr_guid (&APPID_Gpgcom) ); + if (RegSetValueExA (hk, "AppID", 0, REG_SZ, buf, strlen (buf))) { + fprintf (stderr,"RegSetValueEx(`%s') failed\n", buf); + exit (1); + } + if (RegCloseKey (hk)) { + fprintf (stderr,"RegCloseKey() failed\n"); + exit (1); + } + hk = 0; + + /* Create the LocalServer32 subkey under the CLSID key */ + sprintf (buf, "CLSID\\%.100s\\LocalServer32", + debugstr_guid (&CLSID_Gpgme) ); + if (RegCreateKeyA (HKEY_CLASSES_ROOT, buf, &hk)) { + fprintf (stderr,"RegCreateKey(`%s') failed\n", buf); + exit (1); + } + /* retrieve the module name and add it under the key */ + if ( !GetModuleFileNameA (0, buf, sizeof (buf)-10) ) { + fprintf (stderr,"GetModuleFileName() failed\n"); + exit (1); + } + if (RegSetValueExA (hk, 0, 0, REG_SZ, buf, strlen (buf))) { + fprintf (stderr,"RegSetValueEx(`%s') failed\n", buf); + exit (1); + } + if (RegCloseKey (hk)) { + fprintf (stderr,"RegCloseKey() failed\n"); + exit (1); + } + hk = 0; + + /* Create the ProgID subkey under the CLSID key */ + sprintf (buf, "CLSID\\%.100s\\ProgID", + debugstr_guid (&CLSID_Gpgme) ); + if (RegCreateKeyA (HKEY_CLASSES_ROOT, buf, &hk)) { + fprintf (stderr,"RegCreateKey(`%s') failed\n", buf); + exit (1); + } + if (RegSetValueExA (hk, 0, 0, REG_SZ, "Gpgcom.Gpgme.1", 0)) { + fprintf (stderr,"RegSetValueEx(`%s') failed\n", buf); + exit (1); + } + if (RegCloseKey (hk)) { + fprintf (stderr,"RegCloseKey() failed\n"); + exit (1); + } + hk = 0; + /* Create the VersionIndependentProgID subkey under the CLSID key */ + sprintf (buf, "CLSID\\%.100s\\VersionIndependentProgID", + debugstr_guid (&CLSID_Gpgme) ); + if (RegCreateKeyA (HKEY_CLASSES_ROOT, buf, &hk)) { + fprintf (stderr,"RegCreateKey(`%s') failed\n", buf); + exit (1); + } + if (RegSetValueExA (hk, 0, 0, REG_SZ, "Gpgcom.Gpgme", 0)) { + fprintf (stderr,"RegSetValueEx(`%s') failed\n", buf); + exit (1); + } + if (RegCloseKey (hk)) { + fprintf (stderr,"RegCloseKey() failed\n"); + exit (1); + } + hk = 0; + + + /* Create a key to store AppID info */ + sprintf (buf, "AppID\\%.100s", debugstr_guid (&APPID_Gpgcom) ); + if (RegCreateKeyA (HKEY_CLASSES_ROOT, buf, &hk)) { + fprintf (stderr,"RegCreateKey(`%s') failed\n", buf); + exit (1); + } + /* Store the name as default value */ + strcpy (buf, "Gpgcom"); + if (RegSetValueExA (hk, 0, 0, REG_SZ, buf, strlen (buf))) { + fprintf (stderr,"RegSetValueEx(`%s') failed\n", buf); + exit (1); + } + if (RegCloseKey (hk)) { + fprintf (stderr,"RegCloseKey() failed\n"); + exit (1); + } + hk = 0; + + register_progid ("Gpgcom.Gpgme"); + register_progid ("Gpgcom.Gpgme.1"); + + /* Create a convenience cross reference to the AppID */ + sprintf (buf, "AppID\\gpgcom.exe"); + if (RegCreateKeyA (HKEY_CLASSES_ROOT, buf, &hk)) { + fprintf (stderr,"RegCreateKey(`%s') failed\n", buf); + exit (1); + } + sprintf (buf, "%.100s", debugstr_guid (&APPID_Gpgcom) ); + if (RegSetValueExA (hk, "AppID", 0, REG_SZ, buf, strlen (buf))) { + fprintf (stderr,"RegSetValueEx(`%s') failed\n", buf); + exit (1); + } + if (RegCloseKey (hk)) { + fprintf (stderr,"RegCloseKey() failed\n"); + exit (1); + } + hk = 0; + + fprintf (stderr,"*** Component registered\n"); +} + +static void +unregister_server () +{ + char buf[500]; + + unregister_typelib (); + sprintf (buf, "CLSID\\%.100s\\LocalServer32", + debugstr_guid (&CLSID_Gpgme) ); + if (RegDeleteKey (HKEY_CLASSES_ROOT, buf)) + fprintf (stderr,"RegDeleteKey(`%s') failed\n", buf); + + sprintf (buf, "CLSID\\%.100s\\ProgID", debugstr_guid (&CLSID_Gpgme) ); + if (RegDeleteKey (HKEY_CLASSES_ROOT, buf)) + fprintf (stderr,"RegDeleteKey(`%s') failed\n", buf); + + sprintf (buf, "CLSID\\%.100s", debugstr_guid (&CLSID_Gpgme) ); + if (RegDeleteKey (HKEY_CLASSES_ROOT, buf)) + fprintf (stderr,"RegDeleteKey(`%s') failed\n", buf); + + sprintf (buf, "Gpgcom.Gpgme.1\\CLSID"); + if (RegDeleteKey (HKEY_CLASSES_ROOT, buf)) + fprintf (stderr,"RegDeleteKey(`%s') failed\n", buf); + sprintf (buf, "Gpgcom.Gpgme.1"); + if (RegDeleteKey (HKEY_CLASSES_ROOT, buf)) + fprintf (stderr,"RegDeleteKey(`%s') failed\n", buf); + + sprintf (buf, "Gpgcom.Gpgme\\CLSID"); + if (RegDeleteKey (HKEY_CLASSES_ROOT, buf)) + fprintf (stderr,"RegDeleteKey(`%s') failed\n", buf); + sprintf (buf, "Gpgcom.Gpgme"); + if (RegDeleteKey (HKEY_CLASSES_ROOT, buf)) + fprintf (stderr,"RegDeleteKey(`%s') failed\n", buf); + + + sprintf (buf, "AppID\\%.100s", debugstr_guid (&APPID_Gpgcom) ); + if (RegDeleteKey (HKEY_CLASSES_ROOT, buf)) + fprintf (stderr,"RegDeleteKey(`%s') failed\n", buf); + + sprintf (buf, "AppID\\gpgcom.exe" ); + if (RegDeleteKey (HKEY_CLASSES_ROOT, buf)) + fprintf (stderr,"RegDeleteKey(`%s') failed\n", buf); + + fprintf (stderr,"*** component unregistered\n"); +} + + +static void +enter_complus () +{ + HANDLE running; + DWORD reg; + IClassFactory *factory; + CLSID clsid; + HRESULT hr; + + fprintf (stderr,"*** enter enter_complus()\n"); + CoInitializeEx (NULL, COINIT_MULTITHREADED); + running = CreateEvent (NULL, FALSE, FALSE, NULL ); + fprintf (stderr,"*** CoInitialize() done; event=%lx\n", (unsigned long)running ); + + factory = igpgme_factory_new ( &clsid ); + fprintf (stderr,"*** igpgme_factory_new() done; got=%p\n", factory ); + hr = CoRegisterClassObject (&clsid, (IUnknown*)factory, + CLSCTX_LOCAL_SERVER, + REGCLS_SUSPENDED|REGCLS_MULTIPLEUSE, ® ); + if (hr) { + fprintf (stderr, "CoRegisterClassObject() failed: hr=%lx\n", hr); + exit (1); + } + hr = CoResumeClassObjects (); + if (hr) + fprintf (stderr, "CoRegisterClassObject() failed: hr=%lx\n", hr); + fprintf (stderr,"*** class object registered; waiting\n" ); + + WaitForSingleObject ( running, INFINITE ); + fprintf (stderr,"*** shutting down\n" ); + CloseHandle (running); + CoRevokeClassObject ( reg ); + fprintf (stderr,"*** class object revoked\n" ); + igpgme_factory_release (factory); + fprintf (stderr,"*** factory released\n" ); + CoUninitialize (); + fprintf (stderr,"*** leave enter_complus()\n" ); +} + |