NT4/private/unimodem/tapisp/mcxapi.c
2020-09-30 17:12:29 +02:00

592 lines
18 KiB
C

/*
mcxapi.c
MCX - Modem Configuration Extensions API
Chris Caputo - January 1994
*/
#include "unimdm.h"
#include "mcxp.h"
char szSettings[] = "Settings";
char szSettingsInit[] = "Settings\\Init";
char szPrefix[] = "Prefix";
char szTerminator[] = "Terminator";
#define MAX_REG_COMMAND_LEN 30 // BUGBUG - verify this with each change to the inf file
//****************************************************************************
// BOOL CreateSettingsInitEntry(MODEMINFORMATION *)
//
// Function: Creates a Settings\Init section in the registry, ala:
// Settings\Init\0 = "AT ... <cr>"
// Settings\Init\1 = "AT ... <cr>"
// ...
//
// Returns: TRUE on success
// FALSE on failure (note: leaves SettingsInit key in registry, if created. Not harmful)
//
// Note: Trusted function - don't need to verify hPort...
//****************************************************************************
BOOL CreateSettingsInitEntry(MODEMINFORMATION *pModemInfo)
{
DWORD dwOptions = pModemInfo->mi_dwPreferredModemOptions;
DWORD dwCaps = pModemInfo->mi_dwModemOptionsCap;
CHAR *pszTemp;
CHAR *pszPrefix;
CHAR *pszTerminator;
CHAR *pszCommand;
DWORD dwResult;
HKEY hSettingsInitKey;
HKEY hSettingsKey;
DWORD dwType;
DWORD dwSize;
DWORD dwCounter = CMD_INDEX_START;
BOOL fRet = FALSE;
static char szCallSetupFailTimer[] = "CallSetupFailTimer";
static char szInactivityTimeout[] = "InactivityTimeout";
static char szSpeakerVolume[] = "SpeakerVolume";
static char szSpeakerMode[] = "SpeakerMode";
static char szFlowControl[] = "FlowControl";
static char szErrorControl[] = "ErrorControl";
static char szCompression[] = "Compression";
static char szModulation[] = "Modulation";
static char szCCITT[] = "_CCITT";
static char szBell[] = "_Bell";
static char szCCITT_V23[] = "_CCITT_V23";
static char szSpeedNegotiation[] = "SpeedNegotiation";
static char szLow[] = "_Low";
static char szMed[] = "_Med";
static char szHigh[] = "_High";
static char szSpkrModeDial[] = "_Dial";
static char szSetup[] = "_Setup";
static char szForced[] = "_Forced";
static char szCellular[] = "_Cellular";
static char szHard[] = "_Hard";
static char szSoft[] = "_Soft";
static char szOff[] = "_Off";
static char szOn[] = "_On";
pszTemp = (LPSTR)LocalAlloc(LPTR,
HAYES_COMMAND_LENGTH + 1 + // pszTemp
HAYES_COMMAND_LENGTH + 1 + // pszPrefix
HAYES_COMMAND_LENGTH + 1 + // pszTerminator
MAX_REG_COMMAND_LEN); // pszCommand
if (!pszTemp)
{
DPRINTF("out of memory.");
LocalFree(pszTemp);
return fRet;
}
pszPrefix = pszTemp + HAYES_COMMAND_LENGTH + 1;
pszTerminator = pszPrefix + HAYES_COMMAND_LENGTH + 1;
pszCommand = pszTerminator + HAYES_COMMAND_LENGTH + 1;
// deleted existing szSettingsInit key tree
//
dwResult = RegDeleteKeyA(pModemInfo->mi_hKeyModem, szSettingsInit);
// create new szSettingsInit key
//
// BUGBUG: JosephJ 7/3/96: We want to change this post 4.0 to not write to
// the registry -- keep this stuff in memory. I tried RegCreateKeyEx(REG_VOLATILE),
// but couldn't get measurable performance difference so I left things the way they
// are now.
if (RegCreateKeyA(pModemInfo->mi_hKeyModem, szSettingsInit, &hSettingsInitKey)
!= ERROR_SUCCESS)
{
DPRINTF("RegCreateKey failed.");
LocalFree(pszTemp);
return fRet;
}
// get Settings key
//
if (RegOpenKeyA(pModemInfo->mi_hKeyModem, szSettings, &hSettingsKey)
!= ERROR_SUCCESS)
{
DPRINTFA1("RegOpenKey failed when opening %s.", szSettings);
RegCloseKey(hSettingsInitKey);
LocalFree(pszTemp);
return fRet;
}
// read in prefix and terminator
//
dwSize = HAYES_COMMAND_LENGTH;
if (RegQueryValueExA(hSettingsKey, szPrefix, NULL, &dwType, (VOID *)pszTemp, &dwSize)
!= ERROR_SUCCESS)
{
DPRINTFA1("RegQueryValueEx failed when opening %s.", szPrefix);
goto Failure;
}
if (dwType != REG_SZ)
{
DPRINTFA1("'%s' wasn't REG_SZ.", szPrefix);
goto Failure;
}
ExpandMacros(pszTemp, pszPrefix, NULL, NULL, 0);
dwSize = HAYES_COMMAND_LENGTH;
if (RegQueryValueExA(hSettingsKey, szTerminator, NULL, &dwType, (VOID *)pszTemp, &dwSize)
!= ERROR_SUCCESS)
{
DPRINTFA1("RegQueryValueEx failed when opening %s.", szTerminator);
goto Failure;
}
if (dwType != REG_SZ)
{
DPRINTFA1("'%s' wasn't REG_SZ.", szTerminator);
goto Failure;
}
ExpandMacros(pszTemp, pszTerminator, NULL, NULL, 0);
ASSERT (lstrlenA(pszPrefix) + lstrlenA(pszTerminator) <= HAYES_COMMAND_LENGTH);
// set temp length to 0 and initialize first command string for use in CreateCommand()
//
lstrcpyA(pszTemp, pszPrefix);
// CallSetupFailTimer
//
if (pModemInfo->mi_dwCallSetupFailTimerCap)
{
if (!CreateCommand(pModemInfo->mi_hKeyModem, hSettingsKey, hSettingsInitKey, szCallSetupFailTimer,
pModemInfo->mi_dwCallSetupFailTimerSetting, pszPrefix, pszTerminator,
&dwCounter, pszTemp))
{
goto Failure;
}
}
// InactivityTimeout
//
if (pModemInfo->mi_dwInactivityTimeoutCap)
{
DWORD dwInactivityTimeout;
// Convert from seconds to the units used on the modem, rounding up if not an exact division.
//
dwInactivityTimeout = pModemInfo->mi_dwInactivityTimeoutSetting / pModemInfo->mi_dwInactivityScale +
(pModemInfo->mi_dwInactivityTimeoutSetting % pModemInfo->mi_dwInactivityScale ? 1 : 0);
if (!CreateCommand(pModemInfo->mi_hKeyModem, hSettingsKey, hSettingsInitKey, szInactivityTimeout,
dwInactivityTimeout, pszPrefix, pszTerminator,
&dwCounter, pszTemp))
{
goto Failure;
}
}
// BUGBUG - these could be optimized with a lookup-table
// SpeakerVolume
if (pModemInfo->mi_dwSpeakerVolumeCap)
{
lstrcpyA(pszCommand, szSpeakerVolume);
switch (pModemInfo->mi_dwSpeakerVolumeSetting)
{
case MDMVOL_LOW:
lstrcatA(pszCommand, szLow);
break;
case MDMVOL_MEDIUM:
lstrcatA(pszCommand, szMed);
break;
case MDMVOL_HIGH:
lstrcatA(pszCommand, szHigh);
break;
default:
DPRINTF("invalid SpeakerVolume.");
}
if (!CreateCommand(pModemInfo->mi_hKeyModem, hSettingsKey, hSettingsInitKey, pszCommand, 0,
pszPrefix, pszTerminator, &dwCounter, pszTemp))
{
goto Failure;
}
}
// SpeakerMode
//
if (pModemInfo->mi_dwSpeakerModeCap)
{
lstrcpyA(pszCommand, szSpeakerMode);
switch (pModemInfo->mi_dwSpeakerModeSetting)
{
case MDMSPKR_OFF:
lstrcatA(pszCommand, szOff);
break;
case MDMSPKR_DIAL:
lstrcatA(pszCommand, szSpkrModeDial);
break;
case MDMSPKR_ON:
lstrcatA(pszCommand, szOn);
break;
case MDMSPKR_CALLSETUP:
lstrcatA(pszCommand, szSetup);
break;
default:
DPRINTF("invalid SpeakerMode.");
}
if (!CreateCommand(pModemInfo->mi_hKeyModem, hSettingsKey, hSettingsInitKey, pszCommand, 0,
pszPrefix, pszTerminator, &dwCounter, pszTemp))
{
goto Failure;
}
}
// PreferredModemOptions
// NOTE: ERRORCONTROL MUST BE DONE BEFORE COMPRESSION BECAUSE OF ZYXEL MODEMS
// NOTE: THEY HAVE A SINGLE SET OF COMMANDS FOR BOTH EC AND COMP, AND WE CAN
// NOTE: ONLY DO THINGS IF WE HAVE THIS ORDER. UGLY BUT TRUE.
// - ErrorControl (On,Off,Forced)
//
if (dwCaps & MDM_ERROR_CONTROL)
{
lstrcpyA(pszCommand, szErrorControl);
switch (dwOptions & (MDM_ERROR_CONTROL | MDM_FORCED_EC | MDM_CELLULAR))
{
case MDM_ERROR_CONTROL:
lstrcatA(pszCommand, szOn);
break;
case MDM_ERROR_CONTROL | MDM_FORCED_EC:
lstrcatA(pszCommand, szForced);
break;
case MDM_ERROR_CONTROL | MDM_CELLULAR:
lstrcatA(pszCommand, szCellular);
break;
case MDM_ERROR_CONTROL | MDM_FORCED_EC | MDM_CELLULAR:
lstrcatA(pszCommand, szCellular);
lstrcatA(pszCommand, szForced);
break;
default: // no error control
lstrcatA(pszCommand, szOff);
break;
}
if (!CreateCommand(pModemInfo->mi_hKeyModem, hSettingsKey, hSettingsInitKey, pszCommand, 0,
pszPrefix, pszTerminator, &dwCounter, pszTemp))
{
goto Failure;
}
}
// - Compression (On,Off)
//
if (dwCaps & MDM_COMPRESSION)
{
lstrcpyA(pszCommand, szCompression);
lstrcatA(pszCommand, (dwOptions & MDM_COMPRESSION ? szOn : szOff));
if (!CreateCommand(pModemInfo->mi_hKeyModem, hSettingsKey, hSettingsInitKey, pszCommand, 0,
pszPrefix, pszTerminator, &dwCounter, pszTemp))
{
goto Failure;
}
}
// - FlowControl
//
if (dwCaps & (MDM_FLOWCONTROL_HARD | MDM_FLOWCONTROL_SOFT))
{
lstrcpyA(pszCommand, szFlowControl);
switch (dwOptions & (MDM_FLOWCONTROL_HARD | MDM_FLOWCONTROL_SOFT))
{
case MDM_FLOWCONTROL_HARD:
lstrcatA(pszCommand, szHard);
break;
case MDM_FLOWCONTROL_SOFT:
lstrcatA(pszCommand, szSoft);
break;
case MDM_FLOWCONTROL_HARD | MDM_FLOWCONTROL_SOFT:
if (dwCaps & MDM_FLOWCONTROL_HARD)
{
lstrcatA(pszCommand, szHard);
}
else
{
lstrcatA(pszCommand, szSoft);
}
break;
default:
lstrcatA(pszCommand, szOff);
}
if (!CreateCommand(pModemInfo->mi_hKeyModem, hSettingsKey, hSettingsInitKey, pszCommand, 0,
pszPrefix, pszTerminator, &dwCounter, pszTemp))
{
goto Failure;
}
}
// - CCITT Override
//
if (dwCaps & MDM_CCITT_OVERRIDE)
{
lstrcpyA(pszCommand, szModulation);
if (dwOptions & MDM_CCITT_OVERRIDE)
{
// use szCCITT or V.23
if (dwCaps & MDM_V23_OVERRIDE && dwOptions & MDM_V23_OVERRIDE)
{
lstrcatA(pszCommand, szCCITT_V23);
}
else
{
lstrcatA(pszCommand, szCCITT);
}
}
else
{
lstrcatA(pszCommand, szBell);
}
if (!CreateCommand(pModemInfo->mi_hKeyModem, hSettingsKey, hSettingsInitKey, pszCommand, 0,
pszPrefix, pszTerminator, &dwCounter, pszTemp))
{
goto Failure;
}
}
// - SpeedAdjust
//
if (dwCaps & MDM_SPEED_ADJUST)
{
lstrcpyA(pszCommand, szSpeedNegotiation);
lstrcatA(pszCommand, (dwOptions & MDM_SPEED_ADJUST ? szOn : szOff));
if (!CreateCommand(pModemInfo->mi_hKeyModem, hSettingsKey, hSettingsInitKey, pszCommand, 0L,
pszPrefix, pszTerminator, &dwCounter, pszTemp))
{
goto Failure;
}
}
// - Blind Dial
//
if (dwCaps & MDM_BLIND_DIAL)
{
lstrcpyA(pszCommand, (dwOptions & MDM_BLIND_DIAL ? szBlindOn : szBlindOff));
if (!CreateCommand(pModemInfo->mi_hKeyModem, hSettingsKey, hSettingsInitKey, pszCommand, 0,
pszPrefix, pszTerminator, &dwCounter, pszTemp))
{
goto Failure;
}
}
// finish the current command line by passing in a NULL command name
if (!CreateCommand(pModemInfo->mi_hKeyModem, hSettingsKey, hSettingsInitKey, NULL, 0,
pszPrefix, pszTerminator, &dwCounter, pszTemp))
{
goto Failure;
}
// Success
fRet = TRUE;
Failure:
// close keys
RegCloseKey(hSettingsInitKey);
RegCloseKey(hSettingsKey);
LocalFree(pszTemp);
return fRet;
}
//****************************************************************************
// BOOL CreateCommand(HKEY hKeyModem, HKEY hSettings, HKEY hInit,
// LPSTR pszRegName, DWORD dwNumber, LPSTR pszPrefix,
// LPSTR pszTerminator, LPDWORD pdwCounter,
// LPSTR pszString)
//
// Function: Creates a command string
//
// Returns: TRUE on success, FALSE otherwise
//
// Note: if pszRegName is NULL then it is the last command
//****************************************************************************
BOOL CreateCommand(HKEY hKeyModem,
HKEY hSettings,
HKEY hInit,
LPSTR pszRegName,
DWORD dwNumber,
LPSTR pszPrefix,
LPSTR pszTerminator,
LPDWORD pdwCounter,
LPSTR pszString)
{
CHAR pszCommand[HAYES_COMMAND_LENGTH + 1];
CHAR pszCommandExpanded[HAYES_COMMAND_LENGTH + 1];
CHAR pszNumber[MAXUINTSTRLENGTH];
DWORD dwCommandLength;
DWORD dwSize;
DWORD dwType;
struct _ModemMacro ModemMacro;
static char szUserInit[] = "UserInit";
static char szNumberMacro[] = "<#>";
// do we really have a command to add?
//
if (pszRegName)
{
// read in command text (ie. SpeakerMode_Off = "M0")
//
dwSize = HAYES_COMMAND_LENGTH;
if (RegQueryValueExA(hSettings, pszRegName, NULL, &dwType, (VOID *)pszCommand, &dwSize)
!= ERROR_SUCCESS)
{
DPRINTFA1("RegQueryValueEx failed when opening %s. Continuing...", pszRegName);
// LOGPRINTF((hLogFile,GET_MESSAGE_PTR(MsgWrnFailedToQueryValue), pszRegName));
return TRUE; // we will not consider this fatal
}
if (dwType != REG_SZ)
{
DPRINTFA1("'%s' wasn't REG_SZ.", pszRegName);
return FALSE;
}
// expand macros pszCommandExpanded <= pszCommand
//
lstrcpyA(ModemMacro.MacroName, szNumberMacro);
wsprintfA(pszNumber, "%d", dwNumber);
lstrcpyA(ModemMacro.MacroValue, pszNumber);
dwCommandLength = dwSize;
if (!ExpandMacros(pszCommand, pszCommandExpanded, &dwCommandLength, &ModemMacro, 1))
{
DPRINTF("ExpandMacro Error. State <- Unknown");
return FALSE;
}
// check string + new command + terminator, flush if too big and start a new one.
// will new command fit on existing string? If not, flush it and start new one.
//
if (lstrlenA(pszString) + lstrlenA(pszCommandExpanded) + lstrlenA(pszTerminator)
> HAYES_COMMAND_LENGTH)
{
lstrcatA(pszString, pszTerminator);
wsprintfA(pszNumber, "%d", *pdwCounter);
*pdwCounter = *pdwCounter + 1;
if (RegSetValueExA(hInit, pszNumber, 0, REG_SZ, (VOID *)pszString, lstrlenA(pszString) + 1)
!= ERROR_SUCCESS)
{
DPRINTFA2("RegSetValueEx failed when writing '%s=%s'.", pszNumber, pszString);
return FALSE;
}
lstrcpyA(pszString, pszPrefix);
}
lstrcatA(pszString, pszCommandExpanded);
}
else
{
// finish off the current string
//
lstrcatA(pszString, pszTerminator);
wsprintfA(pszNumber, "%d", *pdwCounter);
*pdwCounter = *pdwCounter + 1;
if (RegSetValueExA(hInit, pszNumber, 0, REG_SZ, (VOID *)pszString, lstrlenA(pszString) + 1)
!= ERROR_SUCCESS)
{
DPRINTFA2("RegSetValueEx failed when writing '%s=%s'.", pszNumber, pszString);
return FALSE;
}
// now write the UserInit string, if there is one...
// get the UserInit string length (including null), don't ExpandMacros on it
//
if (RegQueryValueExA(hKeyModem, szUserInit, NULL, &dwType, NULL, &dwSize)
!= ERROR_SUCCESS)
{
DPRINTFA1("RegQueryValueEx failed when opening %s (this can be okay).", szUserInit);
return TRUE; // it is okay to not have a UserInit
}
else
{
LPSTR pszUserInit;
if (dwType != REG_SZ)
{
DPRINTFA1("'%s' wasn't REG_SZ.", szUserInit);
return FALSE; // this is not okay
}
// check for 0 length string
// BUGBUG this could be folded into the above if. CPC 12/14/94
//
if (dwSize == 1)
{
DPRINTFA1("ignoring zero length %s entry.", szUserInit);
return TRUE;
}
// we allow the size of this string to be larger than 40 chars, because the user
// should have enough knowledge about what the modem can do, if they are using this
// allocate enough for if we need to add a prefix and terminator
//
if (!(pszUserInit = (LPSTR)LocalAlloc(LPTR,
dwSize +
lstrlenA(pszPrefix) +
lstrlenA(pszTerminator) +
1)))
{
DPRINTF("unable to allocate memory for building the UserInit string.");
return FALSE;
}
if (RegQueryValueExA(hKeyModem, szUserInit, NULL, &dwType, (VOID *)pszUserInit, &dwSize)
!= ERROR_SUCCESS)
{
DPRINTFA1("RegQueryValueEx failed when opening %s.", szUserInit);
LocalFree(pszUserInit);
return FALSE; // it is not okay at this point
}
// check for prefix
//
if (strncmpi(pszUserInit, pszPrefix, lstrlenA(pszPrefix)))
{
// prepend a prefix string
lstrcpyA(pszUserInit, pszPrefix);
// reload string; it's easier than shifting...
if (RegQueryValueExA(hKeyModem, szUserInit, NULL, &dwType, (VOID *)(pszUserInit+lstrlenA(pszPrefix)), &dwSize)
!= ERROR_SUCCESS)
{
DPRINTFA1("RegQueryValueEx failed when opening %s.", szUserInit);
LocalFree(pszUserInit);
return FALSE; // it is not okay at this point
}
}
// check for terminator
//
if (strncmpi(pszUserInit+lstrlenA(pszUserInit)-lstrlenA(pszTerminator),
pszTerminator, lstrlenA(pszTerminator)))
{
// append a terminator
//
lstrcatA(pszUserInit, pszTerminator);
}
// we have one, so add it to the init strings
//
wsprintfA(pszNumber, "%d", *pdwCounter);
*pdwCounter = *pdwCounter + 1;
if (RegSetValueExA(hInit, pszNumber, 0, REG_SZ, (VOID *)pszUserInit, lstrlenA(pszUserInit) + 1)
!= ERROR_SUCCESS)
{
DPRINTFA2("RegSetValueEx failed when writing '%s=%s'.", pszNumber, pszUserInit);
LocalFree(pszUserInit);
return FALSE;
}
// free pszUserInit
//
LocalFree(pszUserInit);
}
}
return TRUE;
}