/*
**	Command & Conquer Red Alert(tm)
**	Copyright 2025 Electronic Arts Inc.
**
**	This program 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 3 of the License, or
**	(at your option) any later version.
**
**	This program 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, see <http://www.gnu.org/licenses/>.
*/

/***********************************************************************************************
 ***              C O N F I D E N T I A L  ---  W E S T W O O D  S T U D I O S               ***
 ***********************************************************************************************
 *                                                                                             *
 *                 Project Name : Command & Conquer/ WW Library                                *
 *                                                                                             *
 *                    File Name : MODEMREG.CPP                                                 *
 *                                                                                             *
 *                   Programmer : Steve Tall                                                   *
 *                                                                                             *
 *                   Start Date : 10/18/96                                                     *
 *                                                                                             *
 *                  Last Update : October 18th 1996 [ST]                                       *
 *                                                                                             *
 *---------------------------------------------------------------------------------------------*
 * Overview:                                                                                   *
 *                                                                                             *
 *   Functions for obtaining modem infommation from the Win95 registry                         *
 *                                                                                             *
 *                                                                                             *
 *---------------------------------------------------------------------------------------------*
 *                                                                                             *
 * Functions:                                                                                  *
 *                                                                                             *
 * Search_Registry_Key -- Search a registry key and all its subkeys for a given value          *
 * MREC::ModemRegistryEntryClass -- Constructor for ModemRegistryEntryClass                    *
 * MREC::~ModemRegistryEntryClass -- Destructor.Free all the memory we allocated for modem info*
 *                                                                                             *
 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */





#include "modemreg.h"
#include <stdio.h>


extern HKEY Get_Registry_Sub_Key (HKEY base_key, char *search_key, BOOL close);




/***********************************************************************************************
 * Search_Registry_Key -- Search a registry key and all its subkeys for a given value          *
 *                                                                                             *
 *                                                                                             *
 *                                                                                             *
 * INPUT:    handle to key to search in                                                        *
 *           name of key to search for                                                         *
 *           value expected in key                                                             *
 *                                                                                             *
 * OUTPUT:   Handle to key containing value. Null if not found.                                *
 *                                                                                             *
 * WARNINGS: This function reenters itself.                                                    *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *    10/18/96 4:01AM ST : Created                                                             *
 *=============================================================================================*/
HKEY Search_Registry_Key (HKEY key_in, char *value_name, char *search_string)
{

	int 	top_key_index = 0;				// Index of topmost key
	int 	retval;								// Result of registry api calls
	HKEY	next_key;							// handle of next key examine
	HKEY	next_search;						// handle of next key to search


	char				*subkey_name = new char [256];			// Area to contain result of key enumeration
	unsigned long	subkey_name_length = 256;					// Length of enumeration result area
	FILETIME			filetime;										// Time key was last touched. Not used.
	unsigned long	value_type;										// Type of data that is contained in a key.
	unsigned char	*key_value = new unsigned char [256];	// Area to return key values into
	unsigned long	key_value_length = 256;						// Length of key value area

	/*
	** Scan through and enumerate all subkeys of this key. Exit the loop when there are
	** no more sub keys to enumerate.
	*/
	do {
		subkey_name_length = 256;			// Has to be set each time through the loop

		/*
		** Get the next key
		*/
		retval = RegEnumKeyEx (key_in, top_key_index++, subkey_name, &subkey_name_length, NULL, NULL, NULL, &filetime);

		if ( retval == ERROR_SUCCESS ){

			/*
			** Get a handle to this key so we can search it.
			*/
			next_key = Get_Registry_Sub_Key (key_in, subkey_name, FALSE);

			if (next_key){

				key_value_length = 256;		// Has to be set each time through the loop

				if ( RegQueryValueEx (next_key, value_name, NULL, &value_type, key_value, &key_value_length) == ERROR_SUCCESS){

					/*
					** If this value is type string then do a compare with the value we are looking for
					*/
					if (value_type == REG_SZ && !strcmp ((char*)key_value, search_string)){
						/*
						** This is our man. Delete our workspace and return the key handle
						*/
						delete [] subkey_name;
						delete [] key_value;
						return (next_key);
					}
				}

				/*
				** We didnt find our search value so search this key for more sub keys by reentering
				** this function with the handle of the subkey.
				*/
				next_search = Search_Registry_Key (next_key, value_name, search_string);
				RegCloseKey (next_key);

				/*
				** If the value was found in a subkey then just return with the key handle.
				*/
				if (next_search){
					delete [] subkey_name;
					delete [] key_value;
					return (next_search);
				}
			}

		}
	} while (retval == ERROR_SUCCESS);

	/*
	** Clean up and exit.
	*/
	delete [] subkey_name;
	delete [] key_value;

	return (0);
}



/***********************************************************************************************
 * MREC::ModemRegistryEntryClass -- Constructor for ModemRegistryEntryClass                    *
 *                                                                                             *
 *  This function does all the work in the class. All the registry searching is done here      *
 *                                                                                             *
 * INPUT:    Modem number                                                                      *
 *                                                                                             *
 * OUTPUT:   Nothing                                                                           *
 *                                                                                             *
 * WARNINGS: None                                                                              *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *    10/18/96 4:12AM ST : Created                                                             *
 *=============================================================================================*/
ModemRegistryEntryClass::ModemRegistryEntryClass (int modem_number)
{
	HKEY				key;
	unsigned char	return_buf[256];
	DWORD				retbuf_size = sizeof(return_buf);

	int				pnp = 0;					//Not a plug n pray modem

	/*
	** Initialise all the info we expect from the registry to NULL.
	** Any entries we cant find will just stay NULL.
	*/
	ModemName = NULL;
	ModemDeviceName = NULL;
	ErrorCorrectionEnable = NULL;
	ErrorCorrectionDisable = NULL;
	CompressionEnable = NULL;
	CompressionDisable = NULL;
	HardwareFlowControl = NULL;
	NoFlowControl = NULL;


	/*
	** Modem info is stored under
	** HKEY_LOCAL_MACHINE / System / CurrentControlSet / Services / Class / Modem / nnnn
	** where nnnn is a four digit modem number.
	*/

	key = Get_Registry_Sub_Key (HKEY_LOCAL_MACHINE, "System", FALSE);
	if (!key) return;

	key = Get_Registry_Sub_Key (key, "CurrentControlSet", TRUE);
	if (!key) return;

	key = Get_Registry_Sub_Key (key, "Services", TRUE);
	if (!key) return;

	key = Get_Registry_Sub_Key (key, "Class", TRUE);
	if (!key) return;

	key = Get_Registry_Sub_Key (key, "Modem", TRUE);
	if (!key) return;

	char which_modem[5];
	sprintf (which_modem, "%04d", modem_number);

	/*
	** Get a handle to the modem key if it exists. Then extract the info we need.
	*/
	key = Get_Registry_Sub_Key (key, which_modem, TRUE);
	if (!key) return;


	/*
	** Get the name of the modem. This is what will be displayed in the modem list presented
	** to the user.
	*/
	if (RegQueryValueEx(key, "Model", NULL, NULL, return_buf, &retbuf_size) != ERROR_SUCCESS){
		RegCloseKey (key);
		return;
	}
	ModemName = new char [retbuf_size];
	memcpy (ModemName, return_buf, retbuf_size);

	/*
	** Find out what COM port the modem is attached to. If this info isnt here, then its a
	** Plug n Pray modem. Set the flag so we know to do the pnp search later.
	*/
	retbuf_size = sizeof (return_buf);
	if (RegQueryValueEx(key, "AttachedTo", NULL, NULL, return_buf, &retbuf_size) != ERROR_SUCCESS){
		/*
		** Must be a plug n pray modem. Set the flag. We will look for the port later.
		*/
		pnp = 1;
		ModemDeviceName = new char [strlen (ModemName)+1];
		strcpy (ModemDeviceName, ModemName);
	}else{
		ModemDeviceName = new char [retbuf_size];
		memcpy (ModemDeviceName, return_buf, retbuf_size);
	}


	/*
	** The list of modem 'AT' commands is stored in the 'Settings'  key.
	*/
	key = Get_Registry_Sub_Key (key, "Settings", TRUE);
	if (!key) return;


	/*
	** Extract the control strings for error control.
	*/
	retbuf_size = sizeof (return_buf);
	if (RegQueryValueEx(key, "ErrorControl_On", NULL, NULL, return_buf, &retbuf_size) == ERROR_SUCCESS){
		ErrorCorrectionEnable = new char [retbuf_size];
		memcpy (ErrorCorrectionEnable, return_buf, retbuf_size);
	}

	retbuf_size = sizeof (return_buf);
	if (RegQueryValueEx(key, "ErrorControl_Off", NULL, NULL, return_buf, &retbuf_size) == ERROR_SUCCESS){
		ErrorCorrectionDisable = new char [retbuf_size];
		memcpy (ErrorCorrectionDisable, return_buf, retbuf_size);
	}

	/*
	** Extract the control strings for data compression.
	*/
	retbuf_size = sizeof (return_buf);
	if (RegQueryValueEx(key, "Compression_On", NULL, NULL, return_buf, &retbuf_size) == ERROR_SUCCESS){
		CompressionEnable = new char [retbuf_size];
		memcpy (CompressionEnable, return_buf, retbuf_size);
	}

	retbuf_size = sizeof (return_buf);
	if (RegQueryValueEx(key, "Compression_Off", NULL, NULL, return_buf, &retbuf_size) == ERROR_SUCCESS){
		CompressionDisable = new char [retbuf_size];
		memcpy (CompressionDisable, return_buf, retbuf_size);
	}

	/*
	** Extract the control strings for hardware flow control.
	*/
	retbuf_size = sizeof (return_buf);
	if (RegQueryValueEx(key, "FlowControl_Hard", NULL, NULL, return_buf, &retbuf_size) == ERROR_SUCCESS){
		HardwareFlowControl = new char [retbuf_size];
		memcpy (HardwareFlowControl, return_buf, retbuf_size);
	}

	/*
	** Extract the control strings for no flow control.
	*/
	retbuf_size = sizeof (return_buf);
	if (RegQueryValueEx(key, "FlowControl_Off", NULL, NULL, return_buf, &retbuf_size) == ERROR_SUCCESS){
		NoFlowControl = new char [retbuf_size];
		memcpy (NoFlowControl, return_buf, retbuf_size);
	}



	RegCloseKey (key);



	/*
	** If this is a plug n pray modem then we need to search for the COM port it is
	** attached to.
	*/
	if (pnp){

		/*
		** The driver name in the HKEY_LOCAL_MACHINE / Enum section will be Modem\nnnn where nnnn
	  	** is a four digit modem number.
		*/
		char search_string [256] = {"Modem\\"};
		strcat (search_string, which_modem);

		/*
		** Search through all the registry entries under HKEY_LOCAL_MACHINE / Enum
		*/
		key = Get_Registry_Sub_Key (HKEY_LOCAL_MACHINE, "Enum", FALSE);
		if (!key) return;

		HKEY newkey = Search_Registry_Key ( key, "Driver", search_string );

		if (newkey){
			retbuf_size = sizeof (return_buf);

			/*
			** Extract the PORTNAME value. This is the name of the port to use to communicate
			** with the modem.
			*/
			retbuf_size = sizeof (return_buf);
			if (RegQueryValueEx(newkey, "PORTNAME", NULL, NULL, return_buf, &retbuf_size) == ERROR_SUCCESS){

				if (ModemDeviceName) delete [] ModemDeviceName;

				ModemDeviceName = new char [retbuf_size];
				memcpy (ModemDeviceName, return_buf, retbuf_size);
			}
		}
		RegCloseKey (key);
	}

}








/***********************************************************************************************
 * MREC::~ModemRegistryEntryClass -- Destructor.Free all the memory we allocated for modem info*
 *                                                                                             *
 *                                                                                             *
 *                                                                                             *
 * INPUT:    Nothing                                                                           *
 *                                                                                             *
 * OUTPUT:   Nothing                                                                           *
 *                                                                                             *
 * WARNINGS: None                                                                              *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *    10/18/96 11:39AM ST : Created                                                              *
 *=============================================================================================*/
ModemRegistryEntryClass::~ModemRegistryEntryClass (void)
{
	if (ModemName) delete [] ModemName;
	if (ModemDeviceName) delete [] ModemDeviceName;

	if (ErrorCorrectionEnable) delete [] ErrorCorrectionEnable;
	if (ErrorCorrectionDisable) delete [] ErrorCorrectionDisable;

	if (CompressionEnable) delete [] CompressionEnable;
	if (CompressionDisable) delete [] CompressionDisable;

	if (HardwareFlowControl) delete [] HardwareFlowControl;
	if (NoFlowControl) delete [] NoFlowControl;
}