//====START_GENERATED_PROLOG======================================
//
//
//   COMPONENT_NAME: odole
//
//   CLASSES: none
//
//   ORIGINS: 27
//
//
//   (C) COPYRIGHT International Business Machines Corp. 1995,1996
//   All Rights Reserved
//   Licensed Materials - Property of IBM
//   US Government Users Restricted Rights - Use, duplication or
//   disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
//   	
//   IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
//   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//   PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
//   CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
//   USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
//   OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
//   OR PERFORMANCE OF THIS SOFTWARE.
//
//====END_GENERATED_PROLOG========================================
//
/*-------------------------------------------------------------------+
|                           RegSetup.cpp                             |
| ================================================================== |
|                                                                    |
| Description:  Setup the Windows Registry for OpenDoc...            |
|                                                                    |
| Usage:        RegSetup -p path { -s | -r }                         |
|                                                                    |
|               Where:                                               |
|                   -p path  - Path where OpenDoc was installed      |
|                   -s       - Setup registry entries                |
|                   -r       - Remove registry entires               |
|                                                                    |
| Returns:      (0)    Setup/Remove was successful                   |
|               (-1)   Error:  OpenDoc is already installed          |
|               (-2)   Error:  Unable to remove - not installed      |
|               (-3)   Error:  Unable to remove - not installed      |
|               (-3)   Error:  Register error...                     |
|                                                                    |
| Author:       David Kuettel, Spring 1996                           |
|                                                                    |
+-------------------------------------------------------------------*/
// @(#) 1.9 nt/src/registry/regsetup/RegSetup.cpp, odole, od96nt, odnt9712d 8/14/96 12:16:57 [ 3/21/97 17:21:50 ]

#include <iostream.h>
#include <objbase.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <winbase.h>
#include <windows.h>

#ifndef IBM_WINDREG
#define private public
#include "windreg.h"
#define public private
#endif


/*
 *  Helper functions...
 */
enum EFlag { kNone, kInstall, kRemove };


/*
 *  Function prototypes...
 */
static BOOL AlreadyInstalled ();
static void ParseArgs (int, char **);
static LONG SetSystemEnvironment (LPSTR path);
static LONG ResetSystemEnvironment (LPSTR path);
static LONG SetVariable (HKEY hKey, LPSTR variable, LPSTR value, 
			BOOL expand = TRUE);
static LONG UnsetVariable (HKEY hKey, LPSTR variable, LPSTR value,
			BOOL expand = TRUE);
static void Usage ();

/*
 *  Global flags... (set when parsing command line arguments)
 */
EFlag gFlag        = kNone;
char* gInstallPath = NULL;

/*
 *  Windows registry key for our product...
 */
#define OPENDOC_FOR_WINDOWS	"SOFTWARE\\IBM\\IBM OpenDoc for Windows"
#define OPENDOC_VERSION		"1.0"

/*
 *  Windows system enviroment variables...
 */
#define SYSTEM_ENV "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment"


/*
 *  Error code returned by InstallPath () if OpenDoc has already
 *  been installed...
 */
#define ERROR_ALREADY_INSTALLED   1
#define ERROR_NOT_INSTALLED       2
#define ERROR_COMMAND_FAILED      3


/*-------------------------------------------------------------------+
|                              main ()                               |
| ================================================================== |
|                                                                    |
| Function:    Add/Remove OpenDoc for Windows registry entries...    |
|                                                                    |
+-------------------------------------------------------------------*/
int main (int argc, char **argv)
{
	LONG result = ERROR_SUCCESS;
	DWORD size;

	/*
	 *  Parse command line arguments...
	 */
	ParseArgs (argc, argv);

	switch (gFlag) {
	/*
	 *  Set the install path and register OpenDoc for Windows...
	 */
	case kInstall:

		/*
		 *  Check to see if OpenDoc has already been installed...
		 */
		if (AlreadyInstalled () == TRUE) {
			result = ERROR_ALREADY_INSTALLED;
			break;
		}

		/*
		 *  Setup the system environment variables....
		 */
		result = SetSystemEnvironment (gInstallPath);
		if (result != ERROR_SUCCESS)
			break;

		/*
		 *  Register the OleWrapper and friends...
		 */
		result = WindowsRegistry::Setup (WindowsRegistry::kInstall,
						 gInstallPath);

		break;

	/*
	 *  Unregister OpenDoc for Windows...
	 */
	case kRemove:

		/*
		 *  Check to see if OpenDoc has already been removed...
		 */
		if (AlreadyInstalled () == FALSE) {
			result = ERROR_NOT_INSTALLED;
			break;
		}

		/*
		 *  Unregister the system environment variables....
		 */

		result = ResetSystemEnvironment (gInstallPath);

		/*
		 *  Remove OleWrapper registry entries...
		 */
		result |= WindowsRegistry::Setup (WindowsRegistry::kRemove,
						  gInstallPath);

		break;

	/*
	 *  Show usage...
	 */
	default:
		Usage ();
		break;
	}

	if (result != ERROR_SUCCESS && result != ERROR_ALREADY_INSTALLED && 
	    result != ERROR_NOT_INSTALLED) {
		result = ERROR_COMMAND_FAILED;
	}

	return result;
}


/*-------------------------------------------------------------------+
|                        AlreadyInstalled ()                         |
| ================================================================== |
|                                                                    |
| Function:    Determines if OpenDoc has already been installed...   |
|                                                                    |
| Algorithm:   o  See if OpenDoc for Windows info is already in the  |
|                 registry.                                          |
|                                                                    |
| Returns:     (TRUE)   Already installed                            |
|              (FALSE)  Not installed                                |
|                                                                    |
+-------------------------------------------------------------------*/
static BOOL AlreadyInstalled ()
{
	HKEY hKey;
	LONG result;

	result = RegOpenKeyEx (HKEY_LOCAL_MACHINE, OPENDOC_FOR_WINDOWS, 
				0, KEY_READ, &hKey);

	return (result == ERROR_SUCCESS) ? TRUE : FALSE;
}


/*-------------------------------------------------------------------+
|                       SetSystemEnvironment ()                      |
| ================================================================== |
|                                                                    |
| Function:    Set Windows system environment variables...           |
|                                                                    |
| Algorithm:   o  ...                                                |
|                                                                    |
| Returns:     ERROR_SUCCESS upon successful completion.  Otherwise  |
|              returns the error code.                               |
|                                                                    |
+-------------------------------------------------------------------*/
static LONG SetSystemEnvironment (LPSTR path)
{
	HKEY hKey = 0;
	LONG result;

	if (path == NULL) return ERROR_INVALID_PARAMETER;

	result = RegOpenKeyEx (HKEY_LOCAL_MACHINE, SYSTEM_ENV, 0, 
				KEY_ALL_ACCESS, &hKey);
	if (result != ERROR_SUCCESS)
		return result;

	do {
		/*
		 *  Set OpenDoc for Windows root directory...
		 */
		result = SetVariable (hKey, "ODBASE", path, FALSE);

		if (result != ERROR_SUCCESS) break;

		/*
		 *  Set "OpenDoc" system variable...
		 */
		result = SetVariable (hKey, "OpenDoc", 
			"%ODBASE%\\bin;%ODBASE%\\dll;%ODBASE%\\samples\\dll");

		/*
		 *  Set "ODCFG" system variable...
		 */
		result = SetVariable (hKey, "ODCFG", "%ODBASE%\\etc");
		if (result != ERROR_SUCCESS) break;

		/*
		 *  Set "SOMIR" system variable...
		 */
		result = SetVariable (hKey, "SOMIR", "%ODCFG%\\opendoc.ir");
		if (result != ERROR_SUCCESS) break;

		/*
		 *  Set "ODLOCALE" system variable...
		 */
		result = SetVariable (hKey, "ODLOCALE", "%ODBASE%\\locale");
		if (result != ERROR_SUCCESS) break;

		/*
		 *  Set "NLSPATH" system variable...
		 */
		result = SetVariable (hKey, "NLSPATH", "%ODLOCALE%\\en_US\\%N");
		if (result != ERROR_SUCCESS) break;

		/*
		 *  System "Path" variable...
		 */
		result = SetVariable (hKey, "Path", "%OpenDoc%");
		if (result != ERROR_SUCCESS) break;

		/*
		 *  Great!  Now propogate the changes to the environment
		 *  variables used in the Program Manager...
		 */
		SendMessage (HWND_BROADCAST, WM_WININICHANGE, 0L, 
				(LPARAM) "Environment");

	} while (0);

	return result;
}


/*-------------------------------------------------------------------+
|                     ResetSystemEnvironment ()                      |
| ================================================================== |
|                                                                    |
| Function:    Reset Windows system environment variables...         |
|                                                                    |
| Algorithm:   o  ...                                                |
|                                                                    |
| Returns:     ERROR_SUCCESS upon successful completion.  Otherwise  |
|              returns the error code.                               |
|                                                                    |
+-------------------------------------------------------------------*/
static LONG ResetSystemEnvironment (LPSTR path)
{
	HKEY hKey = 0;
	LONG result;

	if (path == NULL) return ERROR_INVALID_PARAMETER;

	result = RegOpenKeyEx (HKEY_LOCAL_MACHINE, SYSTEM_ENV, 0, 
				KEY_ALL_ACCESS, &hKey);
	if (result != ERROR_SUCCESS)
		return result;

	/*
	 *  Set OpenDoc for Windows root directory...
	 */
	UnsetVariable (hKey, "ODBASE", path, FALSE);

	/*
	 *  Set "OpenDoc" system variable...
	 */
	UnsetVariable (hKey, "OpenDoc", 
		"%ODBASE%\\bin;%ODBASE%\\dll;%ODBASE%\\odparts\\dll");

	/*
	 *  Set "ODCFG" system variable...
	 */
	UnsetVariable (hKey, "ODCFG", "%ODBASE%\\etc");

	/*
	 *  Set "SOMIR" system variable...
	 */
	UnsetVariable (hKey, "SOMIR", "%ODCFG%\\opendoc.ir");

	/*
	 *  Set "ODLOCALE" system variable...
	 */
	UnsetVariable (hKey, "ODLOCALE", "%ODBASE%\\locale");

	/*
	 *  Set "NLSPATH" system variable...
	 */
	UnsetVariable (hKey, "NLSPATH", "%ODLOCALE%\\en_US\\%N");

	/*
	 *  System "Path" variable...
	 */
	UnsetVariable (hKey, "Path", "%OpenDoc%");

	/*
	 *  Great!  Now propogate the changes to the environment
	 *  variables used in the Program Manager...
	 */
	SendMessage (HWND_BROADCAST, WM_WININICHANGE, 0L, 
			(LPARAM) "Environment");

	return result;
}


/*-------------------------------------------------------------------+
|                          SetVariable ()                            |
| ================================================================== |
|                                                                    |
| Function:    Set a Windows system environment variable...          |
|                                                                    |
| Algorithm:   o  ...                                                |
|                                                                    |
| Returns:     ERROR_SUCCESS upon successful completion.  Otherwise  |
|              returns the error code.                               |
|                                                                    |
+-------------------------------------------------------------------*/
static LONG SetVariable (HKEY hKey, LPSTR variable, LPSTR value, BOOL expand)
{
	LONG result;

	/*
	 *  Update system path...
	 */
	char oldValue [512];
	char newValue [512];
	DWORD size = sizeof (oldValue);

	/*
	 *  Determine if the subkey exists and if so, retrieve it's value...
	 */
	result = WindowsRegistry::QueryValue (hKey, variable, (LPBYTE)
				oldValue, size);

	if (result != ERROR_SUCCESS) {
		/*
		 *  New value...
		 */
		strcpy (newValue, value);

	} else {
		/*
		 *  Append to old value...
		 */
		sprintf (newValue, "%s;%s", oldValue, value);
	}

	/*
	 *  Update variable in registry...
	 */
	result = RegSetValueEx (hKey, variable, 0, 
				(expand) ? REG_EXPAND_SZ : REG_SZ, 
				(const BYTE*) newValue, 
				strlen (newValue) + 1);

	return result;
}


/*-------------------------------------------------------------------+
|                         UnsetVariable ()                           |
| ================================================================== |
|                                                                    |
| Function:    Reset a Windows system environment variable...        |
|                                                                    |
| Algorithm:   o  ...                                                |
|                                                                    |
| Returns:     ERROR_SUCCESS upon successful completion.  Otherwise  |
|              returns the error code.                               |
|                                                                    |
+-------------------------------------------------------------------*/
static LONG UnsetVariable (HKEY hKey, LPSTR variable, LPSTR value, BOOL expand)
{
	LONG result;

	/*
	 *  Update system path...
	 */
	char oldValue [512];
	char newValue [512];
	DWORD size = sizeof (oldValue);

	/*
	 *  Determine if the subkey exists and if so, retrieve it's value...
	 */
	result = WindowsRegistry::QueryValue (hKey, variable, (LPBYTE)
				oldValue, size);

	/*
	 *  Special case:  key does not exist and we are trying to delete it...
	 */
	if (result != ERROR_SUCCESS)
		return result;

	/*
	 *  If the old value matches our value we can delete the key...
	 */
	if (strcmp (oldValue, value) == 0)
		return RegDeleteValue (hKey, variable);

	/*
	 *  Extract value from oldValue...  Make sure we remove the 
	 *  semicolon's too...
	 */
	char pattern [512];
	sprintf (pattern, ";%s", value);

	char *match;
	
	if ((match = strstr (oldValue, pattern)) != NULL) {
		*match = '\0';
		match += strlen (pattern);
	} else if ((match = strstr (oldValue, value)) != NULL) {
		*match = '\0';
		match += strlen (value);
	} else {
		return ERROR_SUCCESS;		// Nothing to remove
	}

	strcpy (newValue, oldValue);
	strcat (newValue, match);

	/*
	 *  Update variable...
	 */
	result = RegSetValueEx (hKey, variable, 0, 
				(expand) ? REG_EXPAND_SZ : REG_SZ, 
				(const BYTE*) newValue, 
				strlen (newValue) + 1);

	return result;
}


/*---------------------------------------------------------------------+
|                            ParseArgs ()                              |
| ==================================================================== |
|                                                                      |
| Function:  Parse the command line arguments & initialize global      |
|            variables.                                                |
|                                                                      |
| Updates:   gFlag         - Setup/Remove indicator                    |
|            gInstallPath  - OpenDoc for Windows install path          |
|                                                                      |
+---------------------------------------------------------------------*/
void ParseArgs (int argc, char **argv)
{
	for (int i=1; i<argc; i++) {

		if (argv [i] == NULL) break;

		/*
		 *  Path flag...
		 */
		if (!strcmp (argv [i], "-p")) {
			if ((i+1) == argc || argv [i+1] == NULL)
				Usage ();

			gInstallPath = argv [++i];
		}
		/*
		 *  Install flag...
		 */
		else if (!strcmp (argv [i], "-s")) {
			gFlag = kInstall;
		}
		/*
		 *  Uninstall flag...
		 */
		else if (!strcmp (argv [i], "-r")) {
			gFlag = kRemove;
		}
		/*
		 *  Usage flags...
		 */
		else if (!strcmp (argv [i], "-?")) {
			Usage ();
		} 
		else if (!strcmp (argv [i], "-h")) {
			Usage ();
                }
        }

	/*
	 *  Check for invalid usage...
	 */
	if (gInstallPath == NULL || gFlag == kNone)
		Usage ();
}


/*---------------------------------------------------------------------+
|                              Usage ()                                |
| ==================================================================== |
|                                                                      |
| Function:  Print usage statement...                                  |
|                                                                      |
+---------------------------------------------------------------------*/
void Usage ()
{
	cerr << endl
	     << "Usage: RegSetup -p path { -s | -r }" << endl << endl
	     << "where: -p path   OpenDoc install path" << endl
	     << "       -s        Setup registry entries" << endl
	     << "       -r        Remove registry entries" << endl
	     << endl << endl;

	exit (1);
}
