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.
1582 lines
51 KiB
1582 lines
51 KiB
/*****************************************************************************
|
|
** Microsoft RAS Device INF Library wrapper **
|
|
** Copyright (C) 1992-93 Microsft Corporation. All rights reserved. **
|
|
** **
|
|
** File Name : msxwrap.c **
|
|
** **
|
|
** Revision History : **
|
|
** July 23, 1992 David Kays Created **
|
|
** Feb 22, 1993 Perryh Hannah Changed static routines to global to **
|
|
** ease degugging. **
|
|
** **
|
|
** Description : **
|
|
** RAS Device INF File Library wrapper above RASFILE Library for **
|
|
** modem/X.25/switch DLL (RASMXS). **
|
|
*****************************************************************************/
|
|
|
|
#define _CTYPE_DISABLE_MACROS
|
|
#include <stddef.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <windef.h>
|
|
#include <winnt.h>
|
|
#include <wtypes.h>
|
|
#include "rasfile.h"
|
|
#include "rasman.h" // RASMAN_DEVICEINFO, RAS_PARAMS struct, etc.
|
|
#include "raserror.h" // SUCCESS & ERROR_BUFFER_TOO_SMALL
|
|
#include "rasmxs.h" // Public rasmxs DLL error messages
|
|
#include "mxsint.h" // Internal rasmxs DLL error messages
|
|
#include "wrapint.h"
|
|
#include "mxswrap.h"
|
|
|
|
// local
|
|
BOOL rasDevGroupFunc( LPTSTR );
|
|
BOOL rasDevIsDecimalMacro ( LPTSTR );
|
|
void rasDevGetMacroValue ( LPTSTR *, DWORD *, LPTSTR );
|
|
void rasDevGetDecimalMacroValue ( LPTSTR *, DWORD *, LPTSTR );
|
|
BOOL rasDevExpandMacros( LPTSTR, LPTSTR, DWORD *, BYTE,
|
|
MACROXLATIONTABLE *);
|
|
BOOL rasDevLookupMacro( LPTSTR, LPTSTR *, MACROXLATIONTABLE *);
|
|
DWORD rasDevMacroInsert( MACRO *, WORD, MACROXLATIONTABLE *);
|
|
void rasDevExtractKey ( LPTSTR , LPTSTR );
|
|
void rasDevExtractValue ( LPTSTR , LPTSTR, DWORD, HRASFILE );
|
|
void rasDevSortParams( LPTSTR *, DWORD );
|
|
void rasDevCheckParams( LPTSTR *, DWORD *);
|
|
void rasDevCheckMacros( LPTSTR *, LPTSTR *, DWORD *);
|
|
BYTE ctox( char );
|
|
void GetMem(DWORD dSize, BYTE **ppMem);
|
|
|
|
/*
|
|
* RasDevEnumDevices :
|
|
* Returns in pBuffer an array of RASMAN_DEVICE structures which contain
|
|
* all the devices in the INF file (i.e. all header names).
|
|
*
|
|
* Arguments :
|
|
* lpszFileName (IN) - File path name of device file
|
|
* pNumEntries (OUT) - Number of devices found in the INF file
|
|
* pBuffer (OUT) - Buffer to contain the RASMAN_DEVICE structures
|
|
* pwSize (INOUT) - Size of pBuffer, this parameter filled with
|
|
* the needed size of pBuffer if too small
|
|
*
|
|
* Return Value :
|
|
* ERROR_BUFFER_TOO_SMALL if pBuffer not big enough to hold all of the
|
|
* RASMAN_DEVICE structs, SUCCESS otherwise.
|
|
*/
|
|
DWORD APIENTRY
|
|
RasDevEnumDevices( PTCH lpszFileName, DWORD *pNumEntries,
|
|
BYTE *pBuffer, DWORD *pdwSize )
|
|
{
|
|
HRASFILE hFile;
|
|
RASMAN_DEVICE DeviceName;
|
|
DWORD dwCurSize;
|
|
|
|
if ( (hFile = RasfileLoad(lpszFileName,RFM_ENUMSECTIONS,NULL,NULL)) == -1 )
|
|
return ERROR_FILE_COULD_NOT_BE_OPENED;
|
|
|
|
*pNumEntries = 0;
|
|
if ( ! RasfileFindFirstLine(hFile,RFL_SECTION,RFS_FILE) ) {
|
|
*pBuffer = '\0';
|
|
*pdwSize = 0;
|
|
RasfileClose(hFile);
|
|
return SUCCESS;
|
|
}
|
|
|
|
// copy RASMAN_DEVICE structs
|
|
dwCurSize = 0;
|
|
do {
|
|
// get the section name
|
|
RasfileGetSectionName(hFile,(LPTSTR) &DeviceName);
|
|
// ignore the Modem Responses section
|
|
if ( ! _stricmp(RESPONSES_SECTION_NAME,(LPTSTR) &DeviceName) )
|
|
continue;
|
|
|
|
dwCurSize += sizeof(RASMAN_DEVICE);
|
|
// if current size exceeds the size of the buffer then just
|
|
// continue counting the size needed
|
|
if ( dwCurSize > *pdwSize )
|
|
continue;
|
|
|
|
strcpy(pBuffer,(LPTSTR) &DeviceName);
|
|
pBuffer += sizeof(RASMAN_DEVICE);
|
|
(*pNumEntries)++;
|
|
} while ( RasfileFindNextLine(hFile,RFL_SECTION,RFS_FILE) );
|
|
|
|
RasfileClose(hFile);
|
|
if ( dwCurSize > *pdwSize ) {
|
|
*pdwSize = dwCurSize;
|
|
return ERROR_BUFFER_TOO_SMALL;
|
|
}
|
|
else
|
|
*pdwSize = dwCurSize;
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* RasDevOpen :
|
|
* Open an INF file for use by the device DLL.
|
|
*
|
|
* Arguments :
|
|
* lpszFileName (IN) - File path name of device file
|
|
* lpszSectionName (IN) - Section of device file to be loaded (by Rasfile)
|
|
* hFile (OUT) - File handle obtained from RasfileLoad()
|
|
*
|
|
* Return Value :
|
|
* ERROR_FILE_COULD_NOT_BE_OPENED if the file could not be found or opened.
|
|
* ERROR_DEVICENAME_NOT_FOUND if the section name was not found in the
|
|
* INF file.
|
|
* ERROR_DEVICENAME_TOO_LONG if the section name is too long.
|
|
* SUCCESS otherwise.
|
|
*/
|
|
DWORD APIENTRY
|
|
RasDevOpen( PTCH lpszFileName, PTCH lpszSectionName, HRASFILE *hFile )
|
|
{
|
|
HRASFILE hRasfile;
|
|
|
|
if ( strlen(lpszSectionName) > MAX_DEVICE_NAME )
|
|
return ERROR_DEVICENAME_TOO_LONG;
|
|
|
|
// send RasfileLoad() the rasDevGroupFunc() to identify command lines
|
|
// as group headers
|
|
if ( (hRasfile = RasfileLoad(lpszFileName,RFM_READONLY,
|
|
lpszSectionName,rasDevGroupFunc)) == -1 )
|
|
return ERROR_FILE_COULD_NOT_BE_OPENED;
|
|
|
|
// if there is no section header loaded then the device name is invalid
|
|
if ( ! RasfileFindFirstLine(hRasfile,RFL_SECTION,RFS_FILE) ) {
|
|
RasfileClose(hRasfile);
|
|
return ERROR_DEVICENAME_NOT_FOUND;
|
|
}
|
|
|
|
// check if this section has an ALIAS
|
|
// current Rasfile line is the section header
|
|
if ( RasfileFindNextKeyLine(hRasfile,"ALIAS",RFS_SECTION) ) {
|
|
// TCHAR szSection[MAX_DEVICE_NAME + 1];
|
|
TCHAR *pszSection = NULL;
|
|
|
|
pszSection = malloc(RAS_MAXLINEBUFLEN);
|
|
if(NULL == pszSection)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
ZeroMemory(pszSection, RAS_MAXLINEBUFLEN);
|
|
|
|
RasfileGetKeyValueFields(hRasfile,NULL,pszSection);
|
|
RasfileClose(hRasfile);
|
|
if ( (hRasfile = RasfileLoad(lpszFileName,RFM_READONLY,
|
|
pszSection,rasDevGroupFunc)) == -1 )
|
|
{
|
|
free(pszSection);
|
|
return ERROR_FILE_COULD_NOT_BE_OPENED;
|
|
}
|
|
|
|
free(pszSection);
|
|
|
|
if ( ! RasfileFindFirstLine(hRasfile,RFL_SECTION,RFS_FILE) ) {
|
|
RasfileClose(hRasfile);
|
|
return ERROR_DEVICENAME_NOT_FOUND;
|
|
}
|
|
}
|
|
|
|
// set the Rasfile current line to the first keyvalue line
|
|
RasfileFindFirstLine(hRasfile,RFL_KEYVALUE,RFS_SECTION);
|
|
|
|
*hFile = hRasfile;
|
|
return SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* RasDevClose :
|
|
* Close an INF file used by the device DLL.
|
|
*
|
|
* Arguments :
|
|
* hFile (IN) - the Rasfile handle of the file to close
|
|
*
|
|
* Return Value :
|
|
* ERROR_INVALID_HANDLE if hFile is invalid, SUCCESS otherwise.
|
|
*/
|
|
void APIENTRY
|
|
RasDevClose( HRASFILE hFile )
|
|
{
|
|
RasfileClose(hFile);
|
|
}
|
|
|
|
/*
|
|
* RasDevGetParams :
|
|
* Returns in pBuffer a RASMAN_DEVICEINFO structure which contains all of the
|
|
* keyword=value pairs between the top of the section loaded and the
|
|
* first command.
|
|
*
|
|
* Assumptions:
|
|
* All strings read from INF files are zero terminated.
|
|
*
|
|
* Arguments :
|
|
* hFile (IN) - the Rasfile handle of the opened INF file
|
|
* pBuffer (OUT) - the buffer to hold the RASMAN_DEVICEINFO structure
|
|
* pdSize (INOUT) - the size of pBuffer, this is filled in with the needed
|
|
* buffer size to hold the RASMAN_DEVICEINFO struct if
|
|
* pBuffer is too small
|
|
*
|
|
* Return Value :
|
|
* ERROR_BUFFER_TOO_SMALL if pBuffer is too small to contain the
|
|
* RASMAN_DEVICEINFO structure, SUCCESS otherwise.
|
|
*/
|
|
DWORD APIENTRY
|
|
RasDevGetParams( HRASFILE hFile, BYTE *pBuffer, DWORD *pdSize )
|
|
{
|
|
RASMAN_DEVICEINFO *pDeviceInfo;
|
|
DWORD dParams, dCurrentSize, i, dValueLen;
|
|
LPTSTR *alpszLines, *alpszLinesSave, *lppszLine, *alpszMallocedLines;
|
|
BOOL bBufferTooSmall = FALSE;
|
|
TCHAR szString[RAS_MAXLINEBUFLEN];
|
|
|
|
if ( ! RasfileFindFirstLine(hFile,RFL_KEYVALUE,RFS_SECTION) ) {
|
|
|
|
if (*pdSize >= sizeof(DWORD)) {
|
|
*((DWORD *)pBuffer) = 0;
|
|
*pdSize = sizeof(DWORD);
|
|
return SUCCESS;
|
|
}
|
|
else {
|
|
*pdSize = sizeof(DWORD);
|
|
return ERROR_BUFFER_TOO_SMALL;
|
|
}
|
|
}
|
|
|
|
// count the number of keyvalue lines between the top of section and
|
|
// the first command, and the number of bytes to hold all of the lines
|
|
dParams = 0;
|
|
do {
|
|
if ( RasfileGetLineType(hFile) & RFL_GROUP )
|
|
break;
|
|
dParams++;
|
|
} while ( RasfileFindNextLine(hFile,RFL_KEYVALUE,RFS_SECTION) );
|
|
|
|
RasfileFindFirstLine(hFile,RFL_KEYVALUE,RFS_SECTION);
|
|
|
|
// malloc enough for two times as many lines as currently exist
|
|
lppszLine = malloc(2 * dParams * sizeof(LPTSTR));
|
|
alpszMallocedLines = malloc(dParams * sizeof(LPTSTR));
|
|
|
|
if( (NULL == lppszLine)
|
|
|| (NULL == alpszMallocedLines))
|
|
{
|
|
DWORD retcode = GetLastError();
|
|
|
|
if(NULL != lppszLine)
|
|
{
|
|
free(lppszLine);
|
|
}
|
|
|
|
if(NULL != alpszMallocedLines)
|
|
{
|
|
free(alpszMallocedLines);
|
|
}
|
|
|
|
return retcode;
|
|
}
|
|
|
|
alpszLines =lppszLine;
|
|
// record all Rasfile keyvalue lines until a group header or end of
|
|
// section is found
|
|
do {
|
|
if ( RasfileGetLineType(hFile) & RFL_GROUP )
|
|
break;
|
|
*lppszLine++ = (LPTSTR)RasfileGetLine(hFile);
|
|
} while ( RasfileFindNextLine(hFile,RFL_KEYVALUE,RFS_SECTION) );
|
|
|
|
// sort the lines by key
|
|
rasDevSortParams( alpszLines, dParams );
|
|
// check for duplicate keys and remove any that are found
|
|
rasDevCheckParams( alpszLines, &dParams );
|
|
// insert missing _ON or _OFF macros into the list
|
|
rasDevCheckMacros( alpszLines, alpszMallocedLines, &dParams );
|
|
|
|
// check if given buffer is large enough
|
|
dCurrentSize = sizeof(RASMAN_DEVICEINFO)
|
|
+ ((dParams - 1) * sizeof(RAS_PARAMS));
|
|
if ( (NULL == pBuffer)
|
|
|| (dCurrentSize > *pdSize )) {
|
|
*pdSize = dCurrentSize;
|
|
lppszLine = alpszMallocedLines;
|
|
while ( *lppszLine != NULL )
|
|
free(*lppszLine++);
|
|
free(alpszMallocedLines);
|
|
free(alpszLines);
|
|
return ERROR_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
// fill in pBuffer with RASMAN_DEVICEINFO struct
|
|
pDeviceInfo = (RASMAN_DEVICEINFO *) pBuffer;
|
|
pDeviceInfo->DI_NumOfParams = (WORD) dParams;
|
|
|
|
for ( i = 0, alpszLinesSave = alpszLines; i < dParams; i++, alpszLines++) {
|
|
RAS_PARAMS *pParam;
|
|
pParam = &(pDeviceInfo->DI_Params[i]);
|
|
|
|
if (!bBufferTooSmall) {
|
|
// set the Type and Attributes field
|
|
pParam->P_Type = String;
|
|
if ( strcspn(*alpszLines,LMS) < strcspn(*alpszLines,"=") )
|
|
pParam->P_Attributes = 0;
|
|
else
|
|
pParam->P_Attributes = ATTRIB_VARIABLE;
|
|
|
|
// get the key
|
|
rasDevExtractKey(*alpszLines,pParam->P_Key);
|
|
|
|
// if there are continuation lines for this keyword=value pair,
|
|
// then set Rasfile line to the proper line
|
|
if ( strcspn(*alpszLines,"\\") < strlen(*alpszLines) ) {
|
|
TCHAR szFullKey[MAX_PARAM_KEY_SIZE];
|
|
|
|
if ( ! pParam->P_Attributes ) {
|
|
strcpy(szFullKey,LMS);
|
|
strcat(szFullKey,pParam->P_Key);
|
|
strcat(szFullKey,RMS);
|
|
}
|
|
else
|
|
strcpy(szFullKey,pParam->P_Key);
|
|
|
|
// find the last occurence of this key
|
|
RasfileFindFirstLine(hFile,RFL_KEYVALUE,RFS_SECTION);
|
|
while ( RasfileFindNextKeyLine(hFile,szFullKey,RFS_SECTION) )
|
|
;
|
|
}
|
|
}
|
|
|
|
// get the value string
|
|
rasDevExtractValue(*alpszLines,
|
|
szString,
|
|
sizeof(szString),
|
|
hFile);
|
|
|
|
dValueLen = strlen(szString);
|
|
pParam->P_Value.String.Length = dValueLen;
|
|
pParam->P_Value.String.Data = malloc(dValueLen + 1);
|
|
if(NULL != pParam->P_Value.String.Data)
|
|
{
|
|
strcpy(pParam->P_Value.String.Data, szString);
|
|
}
|
|
}
|
|
|
|
// free up all mallocs
|
|
lppszLine = alpszMallocedLines;
|
|
while ( *lppszLine != NULL )
|
|
free(*lppszLine++);
|
|
free(alpszMallocedLines);
|
|
free(alpszLinesSave);
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* RasDevGetCommand :
|
|
* Returns the next command line of the given type and advances
|
|
* the Rasfile file pointer to the first line following this command
|
|
* line.
|
|
*
|
|
* Arguments :
|
|
* hFile (IN) - the Rasfile file handle for the INF file
|
|
* pszCmdTypeSuffix (IN) - the type of command line to search for :
|
|
* GENERIC, INIT, DIAL, or LISTEN.
|
|
* pMacroXlations (IN) - the Macro Translation table used to expand
|
|
* all macros in the command line
|
|
* lpsCommand (OUT) - buffer to hold the value string of the found
|
|
* command line
|
|
* pdwCmdLen (OUT) - length of output string with expanded macros
|
|
*
|
|
* Return Value :
|
|
* ERROR_END_OF_SECTION if no command lines of the given type could
|
|
* be found.
|
|
* ERROR_MACRO_NOT_DEFINED if no entry in the given Macro Translation table
|
|
* for a macro found in the command line could be found.
|
|
* SUCCESS otherwise.
|
|
*/
|
|
DWORD APIENTRY
|
|
RasDevGetCommand( HRASFILE hFile, PTCH pszCmdTypeSuffix,
|
|
MACROXLATIONTABLE *pMacroXlations, PTCH lpsCommand,
|
|
DWORD *pdwCmdLen )
|
|
{
|
|
TCHAR szLineKey[MAX_PARAM_KEY_SIZE], sCommand[MAX_PARAM_KEY_SIZE];
|
|
TCHAR szValue[RAS_MAXLINEBUFLEN];
|
|
TCHAR sCommandValue[2*MAX_CMD_BUF_LEN];// WARNING : if we ever
|
|
// get a command line > this
|
|
// size msxwrap could bomb!
|
|
|
|
LPTSTR lpszLine;
|
|
|
|
if ( ! (RasfileGetLineType(hFile) & RFL_GROUP) ) {
|
|
if ( ! RasfileFindNextLine(hFile,RFL_GROUP,RFS_SECTION) )
|
|
return ERROR_END_OF_SECTION;
|
|
}
|
|
else if ( RasfileGetLineMark(hFile) == EOS_COOKIE ) {
|
|
RasfilePutLineMark(hFile,0);
|
|
return ERROR_END_OF_SECTION;
|
|
}
|
|
|
|
strncpy(sCommand,"command",MAX_PARAM_KEY_SIZE-1);
|
|
strncat(sCommand,pszCmdTypeSuffix,MAX_PARAM_KEY_SIZE-sizeof("command")-1);
|
|
|
|
for ( ;; ) {
|
|
|
|
lpszLine = (LPTSTR) RasfileGetLine(hFile);
|
|
|
|
if(NULL == lpszLine)
|
|
{
|
|
break;
|
|
}
|
|
|
|
rasDevExtractKey(lpszLine,szLineKey);
|
|
if ( ! _stricmp(sCommand,szLineKey) ) {
|
|
// get the value string
|
|
lpszLine = (LPTSTR) RasfileGetLine(hFile);
|
|
if(!lpszLine)
|
|
return ERROR_END_OF_SECTION;
|
|
rasDevExtractValue((LPTSTR)lpszLine,szValue,
|
|
RAS_MAXLINEBUFLEN,hFile);
|
|
// expand all macros in the value string
|
|
if ( ! rasDevExpandMacros(szValue, sCommandValue, pdwCmdLen,
|
|
EXPAND_ALL, pMacroXlations) )
|
|
return ERROR_MACRO_NOT_DEFINED;
|
|
if ( *pdwCmdLen > MAX_CMD_BUF_LEN )
|
|
return ERROR_CMD_TOO_LONG;
|
|
else
|
|
memcpy(lpsCommand, sCommandValue, *pdwCmdLen);
|
|
break;
|
|
}
|
|
if ( ! RasfileFindNextLine(hFile,RFL_GROUP,RFS_SECTION) )
|
|
return ERROR_END_OF_SECTION;
|
|
}
|
|
|
|
// advance to the first response following the command or
|
|
// to the next command line; if no such line exists mark the
|
|
// current line as the end of the section
|
|
if ( ! RasfileFindNextLine(hFile,RFL_ANYACTIVE,RFS_SECTION) )
|
|
RasfilePutLineMark(hFile,EOS_COOKIE);
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* RasDevResetCommand :
|
|
* Moves the Rasfile file pointer to the first command of any type
|
|
* in the loaded section.
|
|
*
|
|
* Arguments :
|
|
* hFile (IN) - the Rasfile handle to the loaded file
|
|
*
|
|
* Return Value :
|
|
* ERROR_NO_COMMAND_FOUND if no command line could be found,
|
|
* SUCCESS otherwise.
|
|
*/
|
|
DWORD APIENTRY
|
|
RasDevResetCommand( HRASFILE hFile )
|
|
{
|
|
if ( ! RasfileFindFirstLine(hFile,RFL_GROUP,RFS_SECTION) )
|
|
return ERROR_NO_COMMAND_FOUND;
|
|
else
|
|
return SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* RasDevCheckResponse :
|
|
* Returns the keyword found in the line whose value string matches
|
|
* the string in lpszReceived. Any macros other than fixed macros
|
|
* which are found in the received string have their values copied
|
|
* into the Macro Translation table.
|
|
* All lines in a Command-Response Set are checked.
|
|
*
|
|
* Arguments :
|
|
* hFile (IN) - the Rasfile handle to the loaded file
|
|
* lpszReceived (IN) - the string received from the modem or X25 net
|
|
* dReceivedLength (IN) - length of the received string
|
|
* pMacroXlations (INOUT) - the Macro Translation table
|
|
* lpszResponse (OUT) - buffer to copy the found keyword into
|
|
*
|
|
* Return Value :
|
|
* ERROR_PARTIAL_RESPONSE if a line is matched up to the APPEND_MACRO.
|
|
* ERROR_MACRO_NOT_DEFINED if a value for "carrierbaud", "connectbaud",
|
|
* or "diagnotics" is found in the received string, but could
|
|
* not be found in the given Macro Translation table.
|
|
* ERROR_UNRECOGNIZED_RESPONSE if no matching reponse could be
|
|
* found.
|
|
* ERROR_NO_REPSONSES if when called, the Rasfile current line is a
|
|
* command, section header, or is invalid.
|
|
* SUCCESS otherwise.
|
|
*/
|
|
DWORD APIENTRY
|
|
RasDevCheckResponse( HRASFILE hFile, PTCH lpsReceived, DWORD dReceivedLength,
|
|
MACROXLATIONTABLE *pMacroXlations, PTCH lpszResponse )
|
|
{
|
|
LPTSTR lpszValue, lpsRec, lpszResponseLine;
|
|
TCHAR szValueString[RAS_MAXLINEBUFLEN], szValue[RAS_MAXLINEBUFLEN];
|
|
MACRO aszMacros[10];
|
|
DWORD dwRC, dRecLength, dwValueLen;
|
|
WORD wMacros;
|
|
BYTE bMatch;
|
|
|
|
// find the nearest previous COMMAND line (Modem section) or
|
|
// the section header (Modem Responses section)
|
|
|
|
if ( RasfileGetLineMark(hFile) != EOS_COOKIE ) {
|
|
RasfileFindPrevLine(hFile,RFL_ANYHEADER,RFS_SECTION);
|
|
// set Rasfile line to the first keyvalue line in the response set
|
|
RasfileFindNextLine(hFile,RFL_KEYVALUE,RFS_SECTION);
|
|
}
|
|
|
|
// else this line is a COMMAND line and the last line of the section
|
|
// and ERROR_NO_RESPONSES will be returned
|
|
|
|
if ( RasfileGetLine(hFile) == NULL ||
|
|
RasfileGetLineType(hFile) & RFL_ANYHEADER )
|
|
return ERROR_NO_RESPONSES;
|
|
|
|
for ( ;; ) {
|
|
lpszResponseLine = (LPTSTR)RasfileGetLine(hFile);
|
|
|
|
if(NULL == lpszResponseLine)
|
|
{
|
|
return ERROR_NO_RESPONSES;
|
|
}
|
|
|
|
rasDevExtractValue(lpszResponseLine,szValueString,
|
|
RAS_MAXLINEBUFLEN,hFile);
|
|
|
|
// expand <cr> and <lf> macros only
|
|
//*** Warning: this could expand line beyond array size!
|
|
|
|
if ( ! rasDevExpandMacros(szValueString, szValue, &dwValueLen,
|
|
EXPAND_FIXED_ONLY, NULL) )
|
|
return ERROR_MACRO_NOT_DEFINED;
|
|
|
|
lpsRec = lpsReceived;
|
|
dRecLength = dReceivedLength;
|
|
bMatch = 0;
|
|
wMacros = 0;
|
|
|
|
for ( lpszValue = szValue; *lpszValue != '\0' && dRecLength > 0; ) {
|
|
|
|
// check for a macro
|
|
if ( *lpszValue == LMSCH ) {
|
|
|
|
// check for <<
|
|
if (*(lpszValue + 1) == LMSCH) {
|
|
if (*lpsRec == LMSCH) {
|
|
lpszValue +=2;
|
|
lpsRec++;
|
|
dRecLength--;
|
|
}
|
|
else
|
|
break; // fond a mismatch
|
|
}
|
|
|
|
// check for <append> macro and simply advance past it
|
|
else if ( ! _strnicmp(lpszValue,APPEND_MACRO,
|
|
strlen(APPEND_MACRO)) )
|
|
lpszValue += strlen(APPEND_MACRO);
|
|
|
|
// check for <ignore> macro
|
|
else if ( ! _strnicmp(lpszValue,IGNORE_MACRO,
|
|
strlen(IGNORE_MACRO)) ) {
|
|
bMatch = FULL_MATCH;
|
|
break;
|
|
}
|
|
|
|
// check for <match> macro
|
|
else if ( ! _strnicmp(lpszValue,MATCH_MACRO,
|
|
strlen(MATCH_MACRO)) ) {
|
|
TCHAR szSubString[RAS_MAXLINEBUFLEN];
|
|
memset(szSubString,0,RAS_MAXLINEBUFLEN);
|
|
// advance value string to first char in match string
|
|
lpszValue += strcspn(lpszValue,"\"") + 1;
|
|
// extract match string
|
|
strncpy(szSubString,lpszValue,strcspn(lpszValue,"\""));
|
|
if ( RasDevSubStr(lpsRec,
|
|
dRecLength,
|
|
szSubString,
|
|
strlen(szSubString)) != NULL ) {
|
|
rasDevExtractKey(lpszResponseLine,lpszResponse);
|
|
return SUCCESS;
|
|
}
|
|
else
|
|
break; // value string does not match
|
|
}
|
|
|
|
// check for hex macro
|
|
else if ( (lpszValue[1] == 'h' || lpszValue[1] == 'H') &&
|
|
isxdigit(lpszValue[2]) && isxdigit(lpszValue[3]) &&
|
|
lpszValue[4] == RMSCH ) {
|
|
char c;
|
|
c = (char) (ctox(lpszValue[2]) * 0x10 + ctox(lpszValue[3]));
|
|
if ( c == *lpsRec++ ) {
|
|
lpszValue += 5; // '<', 'h', two hex digits, and '>'
|
|
dRecLength--;
|
|
continue;
|
|
}
|
|
else // does not match
|
|
break;
|
|
}
|
|
|
|
// check for wildcard character
|
|
else if ( ! _strnicmp(lpszValue,WILDCARD_MACRO,
|
|
strlen(WILDCARD_MACRO)) ) {
|
|
lpszValue += strlen(WILDCARD_MACRO);
|
|
lpsRec++; // advance Receive string one character
|
|
dRecLength--;
|
|
}
|
|
|
|
else { // get macro name and value
|
|
memset(aszMacros[wMacros].MacroName,0,MAX_PARAM_KEY_SIZE);
|
|
|
|
// copy macro name
|
|
strncpy(aszMacros[wMacros].MacroName, lpszValue + 1,
|
|
strcspn(lpszValue,RMS) - 1);
|
|
|
|
// advance the value string over the macro
|
|
lpszValue += strcspn(lpszValue,RMS) + 1 /* past RMS */;
|
|
|
|
// get macro value
|
|
if (rasDevIsDecimalMacro(aszMacros[wMacros].MacroName))
|
|
rasDevGetDecimalMacroValue(&lpsRec, &dRecLength,
|
|
aszMacros[wMacros++].MacroValue);
|
|
else
|
|
rasDevGetMacroValue(&lpsRec, &dRecLength,
|
|
aszMacros[wMacros++].MacroValue);
|
|
}
|
|
}
|
|
|
|
else if ( *lpszValue == *lpsRec ) {
|
|
if (*lpszValue == RMSCH && *(lpszValue + 1) == RMSCH)
|
|
lpszValue++;
|
|
lpszValue++;
|
|
lpsRec++;
|
|
dRecLength--;
|
|
continue;
|
|
}
|
|
else // found a mismatch
|
|
break;
|
|
} // for
|
|
|
|
|
|
// If we already have a match break out pf outer loop now
|
|
|
|
if (bMatch != 0)
|
|
break;
|
|
|
|
// full match. When there is trailing line noise dRecLength will not
|
|
// be zero, so check for full match aganist length of expected
|
|
// response. Also make sure expected response is not empty.
|
|
|
|
if ( *lpszValue == '\0' && lpszValue != szValue) {
|
|
bMatch |= FULL_MATCH;
|
|
break;
|
|
}
|
|
// partial match
|
|
else if ( dRecLength == 0 &&
|
|
! _strnicmp(lpszValue,APPEND_MACRO,strlen(APPEND_MACRO)) ) {
|
|
bMatch |= PARTIAL_MATCH;
|
|
break;
|
|
}
|
|
|
|
if ( ! RasfileFindNextLine(hFile,RFL_KEYVALUE,RFS_SECTION) )
|
|
return ERROR_UNRECOGNIZED_RESPONSE;
|
|
if ( RasfileGetLineType(hFile) & RFL_GROUP )
|
|
return ERROR_UNRECOGNIZED_RESPONSE;
|
|
} // for
|
|
|
|
// sanity check
|
|
if ( ! (bMatch & (FULL_MATCH | PARTIAL_MATCH)) )
|
|
return ERROR_UNRECOGNIZED_RESPONSE;
|
|
|
|
// only get this far if a full or partial match was made
|
|
|
|
// insert any macro values found in the received string
|
|
// into the macro translation table
|
|
if ((dwRC = rasDevMacroInsert(aszMacros,wMacros,pMacroXlations)) != SUCCESS)
|
|
return(dwRC);
|
|
|
|
// finally, copy the keyword string into lpszResponse string
|
|
rasDevExtractKey(lpszResponseLine,lpszResponse);
|
|
return ( bMatch & FULL_MATCH ) ? SUCCESS : ERROR_PARTIAL_RESPONSE;
|
|
}
|
|
|
|
/*
|
|
* RasDevResponseExpected :
|
|
* Checks the INF for presence of reponses to the current command.
|
|
* If the key work "NoResponse" is found on the current line the
|
|
* function returns FALSE. Otherwise modems always expect responses.
|
|
*
|
|
* Arguments :
|
|
* hFile (IN) - Rasfile file handle for the INF file.
|
|
* eDevType (IN) - The type of the device. (Modem, PAD, or Switch)
|
|
*
|
|
* Return Value :
|
|
* FALSE if the current Rasfile line points to a command line or the
|
|
* current line starts with "NoResponse", TRUE otherwise. Except
|
|
* modems always return TRUE unless "NoResponse" key word is found.
|
|
* (See code.)
|
|
*/
|
|
BOOL APIENTRY
|
|
RasDevResponseExpected( HRASFILE hFile, DEVICETYPE eDevType )
|
|
{
|
|
TCHAR szLine[RAS_MAXLINEBUFLEN];
|
|
|
|
szLine[0] = TEXT('\0');
|
|
|
|
RasfileGetLineText( hFile, szLine );
|
|
if ( _strnicmp(szLine, MXS_NORESPONSE, strlen(MXS_NORESPONSE)) == 0 )
|
|
return( FALSE );
|
|
|
|
if (eDevType == DT_MODEM)
|
|
return( TRUE );
|
|
|
|
if ( RasfileGetLineType(hFile) & RFL_ANYHEADER )
|
|
return( FALSE );
|
|
else
|
|
return( TRUE );
|
|
}
|
|
|
|
/*
|
|
* RasDevEchoExpected :
|
|
* Checks the current line of the INF file for the keyword NoEcho.
|
|
* If found the function returns FALSE. Otherwise, it returns TRUE.
|
|
*
|
|
* Arguments :
|
|
* hFile (IN) - Rasfile file handle for the INF file.
|
|
*
|
|
* Return Value :
|
|
* FALSE if the current line is "NoEcho", else TRUE.
|
|
*/
|
|
BOOL APIENTRY
|
|
RasDevEchoExpected( HRASFILE hFile )
|
|
{
|
|
TCHAR szLine[RAS_MAXLINEBUFLEN];
|
|
|
|
szLine[0] = TEXT('\0');
|
|
|
|
RasfileGetLineText( hFile, szLine );
|
|
return( ! (_strnicmp(szLine, MXS_NOECHO, strlen(MXS_NOECHO)) == 0) );
|
|
}
|
|
|
|
/*
|
|
* RasDevIdFistCommand :
|
|
* Determines the type of the first command in the section.
|
|
*
|
|
* Arguments :
|
|
* hFile (IN) - Rasfile file handle for the INF file.
|
|
*
|
|
* Assumptions :
|
|
* RasDevGetParams has been called previously, that is, the current
|
|
* line is the first command.
|
|
*
|
|
* Return Value :
|
|
* FALSE if current line is not a command, otherwise TRUE.
|
|
*/
|
|
CMDTYPE APIENTRY
|
|
RasDevIdFirstCommand( HRASFILE hFile )
|
|
{
|
|
//TCHAR szKey[MAX_PARAM_KEY_SIZE + 1];
|
|
|
|
TCHAR *pszKey = NULL;
|
|
CMDTYPE Type = CT_UNKNOWN;
|
|
|
|
pszKey = malloc(RAS_MAXLINEBUFLEN);
|
|
|
|
if(NULL == pszKey)
|
|
{
|
|
return CT_UNKNOWN;
|
|
}
|
|
|
|
ZeroMemory(pszKey, RAS_MAXLINEBUFLEN);
|
|
|
|
// Find the first command
|
|
|
|
do
|
|
{
|
|
|
|
if ( ! RasfileFindFirstLine(hFile,RFL_GROUP,RFS_SECTION))
|
|
{
|
|
break;
|
|
}
|
|
|
|
if ( ! RasfileGetKeyValueFields(hFile, pszKey, NULL))
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (_stricmp(MXS_GENERIC_COMMAND, pszKey) == 0)
|
|
{
|
|
Type = CT_GENERIC;
|
|
break;
|
|
}
|
|
|
|
else if (_stricmp(MXS_DIAL_COMMAND, pszKey) == 0)
|
|
{
|
|
Type = CT_DIAL;
|
|
break;
|
|
}
|
|
|
|
else if (_stricmp(MXS_INIT_COMMAND, pszKey) == 0)
|
|
{
|
|
Type = CT_INIT;
|
|
break;
|
|
}
|
|
|
|
else if (_stricmp(MXS_LISTEN_COMMAND, pszKey) == 0)
|
|
{
|
|
Type = CT_LISTEN;
|
|
break;
|
|
}
|
|
}
|
|
while(FALSE);
|
|
|
|
free(pszKey);
|
|
|
|
return Type;
|
|
}
|
|
|
|
/*
|
|
* RasDevSubStr :
|
|
* Finds a substring and returns a pointer to it. This function works like
|
|
* the C runtime function strstr, but works in strings that contain zeros.
|
|
*
|
|
* Arguments :
|
|
* psStr (IN) - the string to be searched for a substring
|
|
* dwStrLen (IN) - length of the string to be searched
|
|
* psSubStr (IN) - the substring to search for
|
|
* dwSubStrLen (IN) - length of the substring
|
|
*
|
|
* Return Value :
|
|
* A pointer to the beginning of the substring, or NULL if the substring
|
|
* was not found.
|
|
*/
|
|
LPTSTR APIENTRY
|
|
RasDevSubStr( LPTSTR psStr,
|
|
DWORD dwStrLen,
|
|
LPTSTR psSubStr,
|
|
DWORD dwSubStrLen )
|
|
{
|
|
LPTSTR ps;
|
|
|
|
|
|
if (dwSubStrLen > dwStrLen)
|
|
return NULL;
|
|
|
|
for (ps = psStr; ps <= psStr + dwStrLen - dwSubStrLen; ps++)
|
|
|
|
if (memcmp(ps, psSubStr, dwSubStrLen) == 0)
|
|
return ps;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
** Rasfile Wrapper internal routines **
|
|
****************************************************************************/
|
|
|
|
/*
|
|
* rasDevGroupFunc :
|
|
* The PFBISGROUP function passed to RasfileLoad().
|
|
*
|
|
* Arguments :
|
|
* lpszLine (IN) - a Rasfile line
|
|
*
|
|
* Return Value :
|
|
* TRUE if the line is a command line, FALSE otherwise.
|
|
*/
|
|
BOOL rasDevGroupFunc( LPTSTR lpszLine )
|
|
{
|
|
TCHAR szKey[MAX_PARAM_KEY_SIZE], *lpszKey;
|
|
|
|
if ( strcspn(lpszLine,"=") == strlen(lpszLine) )
|
|
return FALSE;
|
|
|
|
while ( *lpszLine == ' ' || *lpszLine == '\t' )
|
|
lpszLine++;
|
|
|
|
lpszKey = szKey;
|
|
while ( *lpszLine != ' ' && *lpszLine != '\t' && *lpszLine != '=' )
|
|
*lpszKey++ = *lpszLine++;
|
|
*lpszKey = '\0';
|
|
|
|
if ( ! _stricmp(szKey,"COMMAND") || ! _stricmp(szKey,"COMMAND_INIT") ||
|
|
! _stricmp(szKey,"COMMAND_DIAL") || ! _stricmp(szKey,"COMMAND_LISTEN") )
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* rasDevIsDecimalMacro :
|
|
* Indicates whether or not a given macro must have only ascii
|
|
* decimal digits for its value.
|
|
*
|
|
* Arguments:
|
|
* lpszMacroName (IN) - macro name
|
|
*
|
|
* Return Value:
|
|
* TRUE if only digits are legal in the macro value; otherwise FALSE.
|
|
*
|
|
* Remarks:
|
|
* Called by API RasDevCheckResponse().
|
|
*/
|
|
BOOL rasDevIsDecimalMacro ( LPTSTR lpszMacroName )
|
|
{
|
|
if (_stricmp(lpszMacroName, MXS_CONNECTBPS_KEY) == 0 ||
|
|
_stricmp(lpszMacroName, MXS_CARRIERBPS_KEY) == 0)
|
|
return(TRUE);
|
|
else
|
|
return(FALSE);
|
|
}
|
|
|
|
/*
|
|
* rasDevGetMacroValue :
|
|
* Extracts a macro value from string *lppszReceived and copies it
|
|
* to string lpszMacro. Also updates the string pointer of
|
|
* lppszValue and lppszReceived, and updates dRecLength.
|
|
*
|
|
* Arguments :
|
|
* lppszReceived (INOUT) - received string (from a modem)
|
|
* dRecLength (INOUT) - remaining length of the received string
|
|
* lpszMacro (OUT) - buffer to receive the macro value
|
|
*
|
|
* Return Value :
|
|
* None.
|
|
*
|
|
* Remarks :
|
|
* Called by API RasDevCheckResponse().
|
|
*/
|
|
void rasDevGetMacroValue ( LPTSTR *lppszReceived, DWORD *dRecLength,
|
|
LPTSTR lpszMacroValue )
|
|
{
|
|
while ( **lppszReceived != CR && **lppszReceived != '\0' ) {
|
|
*lpszMacroValue++ = *(*lppszReceived)++;
|
|
(*dRecLength)--;
|
|
}
|
|
*lpszMacroValue = '\0'; // Null terminate the Macro value string
|
|
}
|
|
|
|
/*
|
|
* rasDevGetDecimalMacroValue :
|
|
* Extracts a macro value from string *lppszReceived and copies it
|
|
* to string lpszMacro. Also updates the string pointer of
|
|
* lppszReceived, and updates dRecLength.
|
|
* This functions only extracts characters which are ascii decimal
|
|
* digits.
|
|
*
|
|
* Arguments :
|
|
* lppszReceived (INOUT) - received string (from a modem)
|
|
* dRecLength (INOUT) - remaining length of the received string
|
|
* lpszMacro (OUT) - buffer to receive the macro value
|
|
*
|
|
* Return Value :
|
|
* None.
|
|
*
|
|
* Remarks :
|
|
* Called by API RasDevCheckResponse().
|
|
*/
|
|
void rasDevGetDecimalMacroValue ( LPTSTR *lppszReceived,
|
|
DWORD *dRecLength,
|
|
LPTSTR lpszMacroValue )
|
|
{
|
|
TCHAR szBuffer[16], *pBuf = szBuffer;
|
|
WORD wcRightHandDigits = 0;
|
|
BOOL bDpFound = FALSE;
|
|
ULONG lBps;
|
|
|
|
|
|
while ( isdigit(**lppszReceived) || **lppszReceived == '.' ) {
|
|
|
|
if (isdigit(**lppszReceived)) {
|
|
*pBuf++ = *(*lppszReceived)++;
|
|
(*dRecLength)--;
|
|
if (bDpFound)
|
|
wcRightHandDigits++;
|
|
}
|
|
else if (!bDpFound && **lppszReceived == '.') {
|
|
(*lppszReceived)++;
|
|
(*dRecLength)--;
|
|
bDpFound = TRUE;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
*pBuf = '\0'; // Null terminate the Macro value string
|
|
|
|
lBps = atol(szBuffer);
|
|
|
|
switch(wcRightHandDigits)
|
|
{
|
|
case 0: case 3:
|
|
break;
|
|
case 1:
|
|
lBps *= 100;
|
|
break;
|
|
case 2:
|
|
lBps *= 10;
|
|
break;
|
|
}
|
|
|
|
_ltoa(lBps, lpszMacroValue, 10);
|
|
}
|
|
|
|
/*
|
|
* rasDevExpandMacros :
|
|
* Takes the string lpszLine, and copies it to lpszVal, using
|
|
* Macro Translation table pMacroXlations to expand macros.
|
|
* <cr>, <lf>, and <hxx> macros are always expanded directly.
|
|
* If bFlag == EXPAND_ALL << and >> are converted to < and >.
|
|
* (A single > which is not at the end of a macro is simply copied.
|
|
* An error could be raised here for such a >, but it is left to
|
|
* be caught later when the device chokes on the unexpected >.
|
|
* This has the advantage that a > where a >> should be will work.)
|
|
*
|
|
* Assumptions:
|
|
* Expanded macros may contain zeros, therefore output command string
|
|
* may contain zeros.
|
|
*
|
|
* Arguments :
|
|
* lpszLine (IN) - a value string from a Rasfile keyword=value line
|
|
* lpsVal (OUT) - buffer to copied to with expanded macros
|
|
* pdwValLen (OUT) - length of output string with expanded macros
|
|
* bFlag (IN) - EXPAND_FIXED_ONLY if only the fixed macros <cr>
|
|
* and <lf> macros are to be expanded, and
|
|
* EXPAND_ALL if all macros should be expanded
|
|
* pMacroXlations (IN) - the Macro Translation table
|
|
*
|
|
* Return Value :
|
|
* FALSE if a needed macro translation could not be found in the
|
|
* pMacroXlations table, TRUE otherwise.
|
|
*
|
|
* Remarks :
|
|
* Called by APIs RasDevGetCommand() and RasDevCheckResponse().
|
|
*/
|
|
BOOL rasDevExpandMacros( LPTSTR lpszLine,
|
|
LPTSTR lpsVal,
|
|
DWORD *pdwValLen,
|
|
BYTE bFlag,
|
|
MACROXLATIONTABLE *pMacroXlations )
|
|
{
|
|
TCHAR szMacro[RAS_MAXLINEBUFLEN];
|
|
LPTSTR lpsValue;
|
|
|
|
|
|
lpsValue = lpsVal;
|
|
|
|
for ( ; *lpszLine != '\0'; ) {
|
|
// check for RMSCH
|
|
// if EXPAND_ALL convert double RMSCH to single RMSCH, and
|
|
// simply copy single RMSCH.
|
|
if ((bFlag & EXPAND_ALL) && *lpszLine == RMSCH) {
|
|
*lpsValue++ = *lpszLine++;
|
|
if (*lpszLine == RMSCH)
|
|
lpszLine++;
|
|
}
|
|
// check for a macro or double LMSCH
|
|
else if ( *lpszLine == LMSCH ) {
|
|
if ((bFlag & EXPAND_ALL) && *(lpszLine + 1) == LMSCH) {
|
|
*lpsValue++ = *lpszLine;
|
|
lpszLine += 2;
|
|
}
|
|
else if ( ! _strnicmp(lpszLine,CR_MACRO,4) ) {
|
|
*lpsValue++ = CR;
|
|
lpszLine += 4;
|
|
}
|
|
else if ( ! _strnicmp(lpszLine,LF_MACRO,4) ) {
|
|
*lpsValue++ = LF;
|
|
lpszLine += 4;
|
|
}
|
|
else if ( ! _strnicmp(lpszLine,APPEND_MACRO,8) &&
|
|
(bFlag & EXPAND_ALL) )
|
|
lpszLine += 8;
|
|
|
|
// Hex macro stuff
|
|
//
|
|
else if ((lpszLine[1] == 'h' || lpszLine[1] == 'H') &&
|
|
isxdigit(lpszLine[2]) && isxdigit(lpszLine[3]) &&
|
|
(lpszLine[4] == RMSCH) &&
|
|
( bFlag & EXPAND_ALL )) {
|
|
char c;
|
|
c = (char) (ctox(lpszLine[2]) * 0x10 + ctox(lpszLine[3]));
|
|
lpszLine += 5; // '<', 'h', two hex digits, and '>'
|
|
|
|
*lpsValue++ = c;
|
|
}
|
|
else if ( bFlag & EXPAND_ALL ) {
|
|
LPTSTR lpszStr;
|
|
char buf[256];
|
|
|
|
for ( lpszLine++, lpszStr = szMacro; *lpszLine != RMSCH; )
|
|
*lpszStr++ = *lpszLine++;
|
|
lpszLine++; // advance past RMSCH
|
|
*lpszStr = '\0'; // Null terminate szMacro string
|
|
|
|
if ( ! rasDevLookupMacro(szMacro,&lpsValue,pMacroXlations) )
|
|
return FALSE;
|
|
}
|
|
else {
|
|
// just copy the macro if EXPAND_ALL is not set
|
|
while ( *lpszLine != RMSCH )
|
|
*lpsValue++ = *lpszLine++;
|
|
*lpsValue++ = *lpszLine++;
|
|
}
|
|
}
|
|
else
|
|
*lpsValue++ = *lpszLine++;
|
|
} // for
|
|
|
|
*lpsValue = '\0';
|
|
*pdwValLen = (DWORD) (lpsValue - lpsVal);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* rasDevLookupMacro :
|
|
* Lookup macro lpszMacro in the given Macro Translation table, and
|
|
* return it's value in *lppszExpanded if found.
|
|
*
|
|
* Arguments :
|
|
* lpszMacro (IN) - the macro whose value is sought
|
|
* lppszExpanded (OUT) - double pointer to increment and copy the
|
|
* macro's value to
|
|
* pMacroXlations (IN) - the Macro Translation table
|
|
*
|
|
* Return Value :
|
|
* FALSE if the macro could not be found in the given Macro Translation
|
|
* table, TRUE otherwise.
|
|
*
|
|
* Remarks :
|
|
* Called by internal function rasDevExpandMacros().
|
|
*/
|
|
BOOL rasDevLookupMacro( LPTSTR lpszMacro, LPTSTR *lppszExpanded,
|
|
MACROXLATIONTABLE *pMacroXlations )
|
|
{
|
|
WORD i;
|
|
LPTSTR lpszMacroValue;
|
|
|
|
for ( i = 0; i < pMacroXlations->MXT_NumOfEntries; i++ ) {
|
|
if ( ! _stricmp(pMacroXlations->MXT_Entry[i].E_MacroName, lpszMacro) ) {
|
|
lpszMacroValue =
|
|
pMacroXlations->MXT_Entry[i].E_Param->P_Value.String.Data;
|
|
|
|
while (*lpszMacroValue != 0) {
|
|
**lppszExpanded = *lpszMacroValue; // copy macro char by char
|
|
|
|
if ((*lpszMacroValue == LMSCH && *(lpszMacroValue+1) == LMSCH)
|
|
|| (*lpszMacroValue == RMSCH && *(lpszMacroValue+1) == RMSCH))
|
|
lpszMacroValue++; // skip one of double angle brackets
|
|
|
|
lpszMacroValue++;
|
|
(*lppszExpanded)++;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* rasDevMacroInsert :
|
|
* Updates the value of macro lpszMacro with new value lpszNewValue
|
|
* in the given Macro Translation table.
|
|
*
|
|
* Arguments :
|
|
* aszMacros (IN) - array of macro name and value pairs
|
|
* wMacros (IN) - number of elements of aszMacros array
|
|
* pMacroXlations (INOUT) - the Macro Translation table
|
|
*
|
|
* Return Value : SUCCESS
|
|
* ERROR_MACRO_NOT_DEFINED
|
|
*
|
|
* Remarks :
|
|
* Called by API RasDevCheckResponse().
|
|
*/
|
|
DWORD rasDevMacroInsert( MACRO *aszMacros, WORD wMacros,
|
|
MACROXLATIONTABLE *pMacroXlations )
|
|
{
|
|
int iMacros;
|
|
WORD iXlations;
|
|
DWORD dwRC;
|
|
|
|
for ( iMacros = (int)(wMacros - 1); iMacros >= 0; iMacros-- ) {
|
|
|
|
for ( iXlations = 0; iXlations < pMacroXlations->MXT_NumOfEntries;
|
|
iXlations++ ) {
|
|
|
|
if ( ! _stricmp(pMacroXlations->MXT_Entry[iXlations].E_MacroName,
|
|
aszMacros[iMacros].MacroName) ) {
|
|
|
|
dwRC = UpdateParamString(pMacroXlations->MXT_Entry[iXlations].E_Param,
|
|
aszMacros[iMacros].MacroValue,
|
|
strlen(aszMacros[iMacros].MacroValue));
|
|
if (dwRC != SUCCESS)
|
|
return dwRC;
|
|
|
|
break;
|
|
}
|
|
}
|
|
if ( iXlations == pMacroXlations->MXT_NumOfEntries )
|
|
return ERROR_MACRO_NOT_DEFINED;
|
|
}
|
|
return SUCCESS;
|
|
}
|
|
|
|
|
|
/*
|
|
* rasDevExtractKey :
|
|
* Extracts the keyvalue from a Rasfile line.
|
|
*
|
|
* Arguments :
|
|
* lpszString (IN) - Rasfile line pointer.
|
|
* lpszKey (OUT) - buffer to hold the keyvalue
|
|
*
|
|
* Return Value :
|
|
* None.
|
|
*
|
|
* Remarks :
|
|
* Called by APIs RasDevGetParams(), RasDevGetCommand(), and
|
|
* RasDevCheckResponse(), and internal functions rasDevCheckParams()
|
|
* and rasDevCheckMacros().
|
|
*/
|
|
void rasDevExtractKey ( LPTSTR lpszString, LPTSTR lpszKey )
|
|
{
|
|
// skip to beginning of keyword (skip '<' if present)
|
|
while ( *lpszString == ' ' || *lpszString == '\t' ||
|
|
*lpszString == LMSCH )
|
|
lpszString++;
|
|
|
|
while ( *lpszString != RMSCH && *lpszString != '=' &&
|
|
*lpszString != ' ' && *lpszString != '\t' )
|
|
*lpszKey++ = *lpszString++;
|
|
*lpszKey = '\0'; // Null terminate keyword string
|
|
}
|
|
|
|
/*
|
|
* rasDevExtractValue :
|
|
* Extracts the value string for a keyword=value string which
|
|
* begins on Rasfile line lpszString. This function recongizes a
|
|
* backslash \ as a line continuation character and a double
|
|
* backslash \\ as a backslash character.
|
|
*
|
|
* Assumptions: lpszValue output buffer is ALWAYS large enough.
|
|
*
|
|
* Arguments :
|
|
* lpszString (IN) - Rasfile line where the keyword=value string begins
|
|
* lpszValue (OUT) - buffer to hold the value string
|
|
* dSize (IN) - size of the lpszValue buffer
|
|
* hFile (IN) - Rasfile handle, the current line must be the line
|
|
* which lpszString points to
|
|
*
|
|
* Return Value :
|
|
* None.
|
|
*
|
|
* Remarks :
|
|
* Called by APIs RasDevGetParams(), RasDevGetCommand(), and
|
|
* RasDevCheckResponse().
|
|
*/
|
|
void rasDevExtractValue ( LPTSTR lpszString, LPTSTR lpszValue,
|
|
DWORD dSize, HRASFILE hFile )
|
|
{
|
|
LPTSTR lpszInputStr;
|
|
BOOL bLineContinues;
|
|
|
|
|
|
// skip to beginning of value string
|
|
for ( lpszString += strcspn(lpszString,"=") + 1;
|
|
*lpszString == ' ' || *lpszString == '\t'; lpszString++ )
|
|
;
|
|
|
|
// check for continuation lines
|
|
if ( strcspn(lpszString,"\\") == strlen(lpszString) )
|
|
strcpy(lpszValue,lpszString); // copy value string
|
|
|
|
else {
|
|
memset(lpszValue,0,dSize);
|
|
lpszInputStr = lpszString;
|
|
|
|
for (;;) {
|
|
// copy the current line
|
|
bLineContinues = FALSE;
|
|
|
|
while (*lpszInputStr != '\0') {
|
|
if (*lpszInputStr == '\\')
|
|
if (*(lpszInputStr + 1) == '\\') {
|
|
*lpszValue++ = *lpszInputStr; // copy one backslash
|
|
lpszInputStr += 2;
|
|
}
|
|
else {
|
|
bLineContinues = TRUE;
|
|
break;
|
|
}
|
|
|
|
else
|
|
*lpszValue++ = *lpszInputStr++;
|
|
}
|
|
|
|
if ( ! bLineContinues)
|
|
break;
|
|
|
|
// get the next line
|
|
if ( ! RasfileFindNextLine(hFile,RFL_ANYACTIVE,RFS_SECTION) )
|
|
break;
|
|
lpszInputStr = (LPTSTR)RasfileGetLine(hFile);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
/*
|
|
* rasDevSortParams :
|
|
* Sorts an array of Rasfile lines by keyvalue.
|
|
*
|
|
* Arguments :
|
|
* alpszLines (INOUT) - the array of line pointers
|
|
* dParams (IN) - number of elements in the array
|
|
*
|
|
* Return Value :
|
|
* None.
|
|
*
|
|
* Remarks :
|
|
* Called by API RasDevGetParams().
|
|
*/
|
|
void rasDevSortParams( LPTSTR *alpszLines, DWORD dParams )
|
|
{
|
|
TCHAR szKey1[MAX_PARAM_KEY_SIZE], szKey2[MAX_PARAM_KEY_SIZE];
|
|
LPTSTR lpszTemp;
|
|
DWORD i,j;
|
|
BOOL changed;
|
|
|
|
// If there is nothing to sort, don't try
|
|
if (dParams < 2)
|
|
return;
|
|
|
|
/* Bubble sort - it's stable */
|
|
for ( i = dParams - 1; i > 0; i-- ) {
|
|
changed = FALSE;
|
|
for ( j = 0; j < i; j++ ) {
|
|
rasDevExtractKey(alpszLines[j],szKey1);
|
|
rasDevExtractKey(alpszLines[j+1],szKey2);
|
|
// sort by keyvalue
|
|
if ( _stricmp(szKey1,szKey2) > 0 ) {
|
|
lpszTemp = alpszLines[j];
|
|
alpszLines[j] = alpszLines[j+1];
|
|
alpszLines[j+1] = lpszTemp;
|
|
changed = TRUE;
|
|
}
|
|
}
|
|
if ( ! changed )
|
|
return;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* rasDevCheckParams :
|
|
* Removes duplicate lines from the alpszLines array of lines.
|
|
* Duplicates lines are those whose keyvalue is identical. The
|
|
* line with the lesser index is removed.
|
|
*
|
|
* Arguments :
|
|
* alpszLines (INOUT) - the array of line pointers
|
|
* pdTotalParams (INOUT) - number of array entries, this is updated
|
|
* if duplicates are removed
|
|
*
|
|
* Return Value :
|
|
* None.
|
|
*
|
|
* Remarks :
|
|
* Called by API RasDevGetParams().
|
|
*/
|
|
void rasDevCheckParams( LPTSTR *alpszLines, DWORD *pdTotalParams )
|
|
{
|
|
TCHAR szKey1[MAX_PARAM_KEY_SIZE], szKey2[MAX_PARAM_KEY_SIZE];
|
|
DWORD dParams, i;
|
|
|
|
dParams = *pdTotalParams;
|
|
for ( i = 1; i < *pdTotalParams ; i++ ) {
|
|
rasDevExtractKey(alpszLines[i-1],szKey1);
|
|
rasDevExtractKey(alpszLines[i],szKey2);
|
|
if ( _stricmp(szKey1,szKey2) == 0 ) {
|
|
memcpy(&(alpszLines[i-1]),&(alpszLines[i]),
|
|
(*pdTotalParams - i) * sizeof(LPTSTR *));
|
|
(*pdTotalParams)--;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* rasDevCheckMacros :
|
|
* Checks the array of lines for missing _ON or _OFF macros
|
|
* in binary macro pairs and inserts any such missing macro
|
|
* into the array of lines.
|
|
*
|
|
* Arguments :
|
|
* alpszLines (INOUT) - array of lines
|
|
* alpszMallocedLines (OUT) - array of newly malloced lines for
|
|
* this routine
|
|
* pdTotalParams (INOUT) - total number of elements in alpszLines
|
|
* array, this is updated if new entries are
|
|
* added
|
|
*
|
|
* Return Value :
|
|
* None.
|
|
*
|
|
* Remarks :
|
|
* Called by API RasDevGetParams().
|
|
*/
|
|
void rasDevCheckMacros( LPTSTR *alpszLines, LPTSTR *alpszMallocedLines,
|
|
DWORD *pdTotalParams )
|
|
{
|
|
TCHAR szKey1[MAX_PARAM_KEY_SIZE], szKey2[MAX_PARAM_KEY_SIZE];
|
|
DWORD i, j;
|
|
BYTE bMissing;
|
|
|
|
if(alpszLines == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// insert missing _ON and _OFF macros
|
|
for ( i = 0; i < *pdTotalParams; i++ ) {
|
|
if ( strcspn(alpszLines[i],LMS) > strcspn(alpszLines[i],"=") )
|
|
continue; // not a macro
|
|
|
|
bMissing = NONE;
|
|
rasDevExtractKey(alpszLines[i],szKey1);
|
|
|
|
// if current key is an _OFF macro, check for a missing _ON
|
|
if ( strstr(szKey1,"_OFF") != NULL || strstr(szKey1,"_off") != NULL ) {
|
|
if ( i+1 == *pdTotalParams ) // looking at last parameter
|
|
bMissing = ON;
|
|
// get next key
|
|
else {
|
|
rasDevExtractKey(alpszLines[i+1],szKey2);
|
|
if (_strnicmp(szKey1,szKey2,strlen(szKey1) - strlen("OFF")) != 0)
|
|
bMissing = ON;
|
|
}
|
|
}
|
|
|
|
// if current key is an _ON macro, check for a missing _OFF
|
|
if ( strstr(szKey1,"_ON") != NULL || strstr(szKey1,"_on") != NULL ) {
|
|
if ( i == 0 ) // looking at first parameter
|
|
bMissing = OFF;
|
|
// get previous key
|
|
else {
|
|
rasDevExtractKey(alpszLines[i-1],szKey2);
|
|
if (_strnicmp(szKey1,szKey2,strlen(szKey1) - strlen("ON")) != 0)
|
|
bMissing = OFF;
|
|
}
|
|
}
|
|
|
|
if ( bMissing != NONE ) {
|
|
// shift everything over one position
|
|
for ( j = *pdTotalParams - 1;
|
|
j >= i + ((bMissing == ON) ? 1 : 0); j-- )
|
|
alpszLines[j+1] = alpszLines[j];
|
|
|
|
// point j to the new empty array entry
|
|
j = (bMissing == OFF) ? i : i + 1;
|
|
|
|
alpszLines[j] = malloc(sizeof(TCHAR) * RAS_MAXLINEBUFLEN);
|
|
|
|
if(NULL == alpszLines[j])
|
|
{
|
|
*alpszMallocedLines = NULL;
|
|
return;
|
|
}
|
|
|
|
*alpszMallocedLines++ = alpszLines[j];
|
|
|
|
memset(alpszLines[j],0,sizeof(TCHAR) * RAS_MAXLINEBUFLEN);
|
|
strcpy(alpszLines[j],LMS);
|
|
if ( bMissing == ON )
|
|
strncat(alpszLines[j],szKey1,
|
|
strlen(szKey1) - strlen(OFF_STR));
|
|
else // bMissing == OFF
|
|
strncat(alpszLines[j],szKey1,
|
|
strlen(szKey1) - strlen(ON_STR));
|
|
strcat(alpszLines[j], bMissing == ON ? ON_STR : OFF_STR );
|
|
strcat(alpszLines[j], RMS);
|
|
strcat(alpszLines[j], "=");
|
|
|
|
(*pdTotalParams)++;
|
|
i++; // increment i to compensate for the new entry
|
|
}
|
|
|
|
} // for
|
|
|
|
// Null terminate the Malloced Lines array
|
|
*alpszMallocedLines = NULL;
|
|
}
|
|
|
|
/*
|
|
* ctox :
|
|
* Convert char hex digit to decimal number.
|
|
*/
|
|
BYTE ctox( char ch )
|
|
{
|
|
if ( isdigit(ch) )
|
|
return ch - '0';
|
|
else
|
|
return (tolower(ch) - 'a') + 10;
|
|
}
|
|
|
|
//* UpdateParamString ------------------------------------------------------
|
|
//
|
|
// Function: This function copys a new string into a PARAM.P_Value
|
|
// allocating new memory of the new string is longer than
|
|
// the old. The copied string is then zero terminated.
|
|
//
|
|
// NOTE: This function frees and allocates memory and is not
|
|
// suitable for copying into an existing buffer. Use with
|
|
// InfoTable and other RAS_PARAMS with 'unpacked' strings.
|
|
//
|
|
// Arguments:
|
|
// pParam OUT Pointer to Param to update
|
|
// psStr IN Input string
|
|
// dwStrLen IN Length of input string
|
|
//
|
|
// Returns: SUCCESS
|
|
// ERROR_ALLOCATING_MEMORY
|
|
//*
|
|
|
|
DWORD
|
|
UpdateParamString(RAS_PARAMS *pParam, TCHAR *psStr, DWORD dwStrLen)
|
|
{
|
|
|
|
if (dwStrLen > pParam->P_Value.String.Length)
|
|
{
|
|
free(pParam->P_Value.String.Data);
|
|
|
|
GetMem(dwStrLen + 1, &(pParam->P_Value.String.Data));
|
|
if (pParam->P_Value.String.Data == NULL)
|
|
return(ERROR_ALLOCATING_MEMORY);
|
|
}
|
|
pParam->P_Value.String.Length = dwStrLen;
|
|
|
|
memcpy(pParam->P_Value.String.Data, psStr, dwStrLen);
|
|
pParam->P_Value.String.Data[dwStrLen] = '\0'; //Zero Terminate
|
|
|
|
return(SUCCESS);
|
|
}
|
|
|
|
//* GetMem -----------------------------------------------------------------
|
|
//
|
|
// Function: Allocates memory. If the memory allocation fails the output
|
|
// parameter will be NULL.
|
|
//
|
|
// Returns: Nothing.
|
|
//
|
|
//*
|
|
|
|
void
|
|
GetMem(DWORD dSize, BYTE **ppMem)
|
|
{
|
|
|
|
*ppMem = (BYTE *) calloc(dSize, 1);
|
|
}
|