Source code of Windows XP (NT5)
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.

1534 lines
49 KiB

  1. /*****************************************************************************
  2. ** Microsoft RAS Device INF Library wrapper **
  3. ** Copyright (C) 1992-93 Microsft Corporation. All rights reserved. **
  4. ** **
  5. ** File Name : msxwrap.c **
  6. ** **
  7. ** Revision History : **
  8. ** July 23, 1992 David Kays Created **
  9. ** Feb 22, 1993 Perryh Hannah Changed static routines to global to **
  10. ** ease degugging. **
  11. ** **
  12. ** Description : **
  13. ** RAS Device INF File Library wrapper above RASFILE Library for **
  14. ** modem/X.25/switch DLL (RASMXS). **
  15. *****************************************************************************/
  16. #define _CTYPE_DISABLE_MACROS
  17. #include <stddef.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <ctype.h>
  21. #include <windef.h>
  22. #include <winnt.h>
  23. #include "rasfile.h"
  24. #include "rasman.h" // RASMAN_DEVICEINFO, RAS_PARAMS struct, etc.
  25. #include "raserror.h" // SUCCESS & ERROR_BUFFER_TOO_SMALL
  26. #include "rasmxs.h" // Public rasmxs DLL error messages
  27. #include "mxsint.h" // Internal rasmxs DLL error messages
  28. #include "wrapint.h"
  29. #include "mxswrap.h"
  30. // local
  31. BOOL rasDevGroupFunc( LPTSTR );
  32. BOOL rasDevIsDecimalMacro ( LPTSTR );
  33. void rasDevGetMacroValue ( LPTSTR *, DWORD *, LPTSTR );
  34. void rasDevGetDecimalMacroValue ( LPTSTR *, DWORD *, LPTSTR );
  35. BOOL rasDevExpandMacros( LPTSTR, LPTSTR, DWORD *, BYTE,
  36. MACROXLATIONTABLE *);
  37. BOOL rasDevLookupMacro( LPTSTR, LPTSTR *, MACROXLATIONTABLE *);
  38. DWORD rasDevMacroInsert( MACRO *, WORD, MACROXLATIONTABLE *);
  39. void rasDevExtractKey ( LPTSTR , LPTSTR );
  40. void rasDevExtractValue ( LPTSTR , LPTSTR, DWORD, HRASFILE );
  41. void rasDevSortParams( LPTSTR *, DWORD );
  42. void rasDevCheckParams( LPTSTR *, DWORD *);
  43. void rasDevCheckMacros( LPTSTR *, LPTSTR *, DWORD *);
  44. BYTE ctox( char );
  45. void GetMem(DWORD dSize, BYTE **ppMem);
  46. /*
  47. * RasDevEnumDevices :
  48. * Returns in pBuffer an array of RASMAN_DEVICE structures which contain
  49. * all the devices in the INF file (i.e. all header names).
  50. *
  51. * Arguments :
  52. * lpszFileName (IN) - File path name of device file
  53. * pNumEntries (OUT) - Number of devices found in the INF file
  54. * pBuffer (OUT) - Buffer to contain the RASMAN_DEVICE structures
  55. * pwSize (INOUT) - Size of pBuffer, this parameter filled with
  56. * the needed size of pBuffer if too small
  57. *
  58. * Return Value :
  59. * ERROR_BUFFER_TOO_SMALL if pBuffer not big enough to hold all of the
  60. * RASMAN_DEVICE structs, SUCCESS otherwise.
  61. */
  62. DWORD APIENTRY
  63. RasDevEnumDevices( PTCH lpszFileName, DWORD *pNumEntries,
  64. BYTE *pBuffer, DWORD *pdwSize )
  65. {
  66. HRASFILE hFile;
  67. RASMAN_DEVICE DeviceName;
  68. DWORD dwCurSize;
  69. if ( (hFile = RasfileLoad(lpszFileName,RFM_ENUMSECTIONS,NULL,NULL)) == -1 )
  70. return ERROR_FILE_COULD_NOT_BE_OPENED;
  71. *pNumEntries = 0;
  72. if ( ! RasfileFindFirstLine(hFile,RFL_SECTION,RFS_FILE) ) {
  73. *pBuffer = '\0';
  74. *pdwSize = 0;
  75. RasfileClose(hFile);
  76. return SUCCESS;
  77. }
  78. // copy RASMAN_DEVICE structs
  79. dwCurSize = 0;
  80. do {
  81. // get the section name
  82. RasfileGetSectionName(hFile,(LPTSTR) &DeviceName);
  83. // ignore the Modem Responses section
  84. if ( ! _stricmp(RESPONSES_SECTION_NAME,(LPTSTR) &DeviceName) )
  85. continue;
  86. dwCurSize += sizeof(RASMAN_DEVICE);
  87. // if current size exceeds the size of the buffer then just
  88. // continue counting the size needed
  89. if ( dwCurSize > *pdwSize )
  90. continue;
  91. strcpy(pBuffer,(LPTSTR) &DeviceName);
  92. pBuffer += sizeof(RASMAN_DEVICE);
  93. (*pNumEntries)++;
  94. } while ( RasfileFindNextLine(hFile,RFL_SECTION,RFS_FILE) );
  95. RasfileClose(hFile);
  96. if ( dwCurSize > *pdwSize ) {
  97. *pdwSize = dwCurSize;
  98. return ERROR_BUFFER_TOO_SMALL;
  99. }
  100. else
  101. *pdwSize = dwCurSize;
  102. return SUCCESS;
  103. }
  104. /*
  105. * RasDevOpen :
  106. * Open an INF file for use by the device DLL.
  107. *
  108. * Arguments :
  109. * lpszFileName (IN) - File path name of device file
  110. * lpszSectionName (IN) - Section of device file to be loaded (by Rasfile)
  111. * hFile (OUT) - File handle obtained from RasfileLoad()
  112. *
  113. * Return Value :
  114. * ERROR_FILE_COULD_NOT_BE_OPENED if the file could not be found or opened.
  115. * ERROR_DEVICENAME_NOT_FOUND if the section name was not found in the
  116. * INF file.
  117. * ERROR_DEVICENAME_TOO_LONG if the section name is too long.
  118. * SUCCESS otherwise.
  119. */
  120. DWORD APIENTRY
  121. RasDevOpen( PTCH lpszFileName, PTCH lpszSectionName, HRASFILE *hFile )
  122. {
  123. HRASFILE hRasfile;
  124. if ( strlen(lpszSectionName) > MAX_DEVICE_NAME )
  125. return ERROR_DEVICENAME_TOO_LONG;
  126. // send RasfileLoad() the rasDevGroupFunc() to identify command lines
  127. // as group headers
  128. if ( (hRasfile = RasfileLoad(lpszFileName,RFM_READONLY,
  129. lpszSectionName,rasDevGroupFunc)) == -1 )
  130. return ERROR_FILE_COULD_NOT_BE_OPENED;
  131. // if there is no section header loaded then the device name is invalid
  132. if ( ! RasfileFindFirstLine(hRasfile,RFL_SECTION,RFS_FILE) ) {
  133. RasfileClose(hRasfile);
  134. return ERROR_DEVICENAME_NOT_FOUND;
  135. }
  136. // check if this section has an ALIAS
  137. // current Rasfile line is the section header
  138. if ( RasfileFindNextKeyLine(hRasfile,"ALIAS",RFS_SECTION) ) {
  139. TCHAR szSection[MAX_DEVICE_NAME + 1];
  140. RasfileGetKeyValueFields(hRasfile,NULL,szSection);
  141. RasfileClose(hRasfile);
  142. if ( (hRasfile = RasfileLoad(lpszFileName,RFM_READONLY,
  143. szSection,rasDevGroupFunc)) == -1 )
  144. return ERROR_FILE_COULD_NOT_BE_OPENED;
  145. if ( ! RasfileFindFirstLine(hRasfile,RFL_SECTION,RFS_FILE) ) {
  146. RasfileClose(hRasfile);
  147. return ERROR_DEVICENAME_NOT_FOUND;
  148. }
  149. }
  150. // set the Rasfile current line to the first keyvalue line
  151. RasfileFindFirstLine(hRasfile,RFL_KEYVALUE,RFS_SECTION);
  152. *hFile = hRasfile;
  153. return SUCCESS;
  154. }
  155. /*
  156. * RasDevClose :
  157. * Close an INF file used by the device DLL.
  158. *
  159. * Arguments :
  160. * hFile (IN) - the Rasfile handle of the file to close
  161. *
  162. * Return Value :
  163. * ERROR_INVALID_HANDLE if hFile is invalid, SUCCESS otherwise.
  164. */
  165. void APIENTRY
  166. RasDevClose( HRASFILE hFile )
  167. {
  168. RasfileClose(hFile);
  169. }
  170. /*
  171. * RasDevGetParams :
  172. * Returns in pBuffer a RASMAN_DEVICEINFO structure which contains all of the
  173. * keyword=value pairs between the top of the section loaded and the
  174. * first command.
  175. *
  176. * Assumptions:
  177. * All strings read from INF files are zero terminated.
  178. *
  179. * Arguments :
  180. * hFile (IN) - the Rasfile handle of the opened INF file
  181. * pBuffer (OUT) - the buffer to hold the RASMAN_DEVICEINFO structure
  182. * pdSize (INOUT) - the size of pBuffer, this is filled in with the needed
  183. * buffer size to hold the RASMAN_DEVICEINFO struct if
  184. * pBuffer is too small
  185. *
  186. * Return Value :
  187. * ERROR_BUFFER_TOO_SMALL if pBuffer is too small to contain the
  188. * RASMAN_DEVICEINFO structure, SUCCESS otherwise.
  189. */
  190. DWORD APIENTRY
  191. RasDevGetParams( HRASFILE hFile, BYTE *pBuffer, DWORD *pdSize )
  192. {
  193. RASMAN_DEVICEINFO *pDeviceInfo;
  194. DWORD dParams, dCurrentSize, i, dValueLen;
  195. LPTSTR *alpszLines, *alpszLinesSave, *lppszLine, *alpszMallocedLines;
  196. BOOL bBufferTooSmall = FALSE;
  197. TCHAR szString[RAS_MAXLINEBUFLEN];
  198. if ( ! RasfileFindFirstLine(hFile,RFL_KEYVALUE,RFS_SECTION) ) {
  199. if (*pdSize >= sizeof(DWORD)) {
  200. *((DWORD *)pBuffer) = 0;
  201. *pdSize = sizeof(DWORD);
  202. return SUCCESS;
  203. }
  204. else {
  205. *pdSize = sizeof(DWORD);
  206. return ERROR_BUFFER_TOO_SMALL;
  207. }
  208. }
  209. // count the number of keyvalue lines between the top of section and
  210. // the first command, and the number of bytes to hold all of the lines
  211. dParams = 0;
  212. do {
  213. if ( RasfileGetLineType(hFile) & RFL_GROUP )
  214. break;
  215. dParams++;
  216. } while ( RasfileFindNextLine(hFile,RFL_KEYVALUE,RFS_SECTION) );
  217. RasfileFindFirstLine(hFile,RFL_KEYVALUE,RFS_SECTION);
  218. // malloc enough for two times as many lines as currently exist
  219. lppszLine = alpszLines = malloc(2 * dParams * sizeof(LPTSTR));
  220. alpszMallocedLines = malloc(dParams * sizeof(LPTSTR));
  221. if( (NULL == lppszLine)
  222. || (NULL == alpszMallocedLines))
  223. {
  224. DWORD retcode = GetLastError();
  225. if(NULL != lppszLine)
  226. {
  227. free(lppszLine);
  228. }
  229. if(NULL != alpszMallocedLines)
  230. {
  231. free(alpszMallocedLines);
  232. }
  233. return retcode;
  234. }
  235. // record all Rasfile keyvalue lines until a group header or end of
  236. // section is found
  237. do {
  238. if ( RasfileGetLineType(hFile) & RFL_GROUP )
  239. break;
  240. *lppszLine++ = (LPTSTR)RasfileGetLine(hFile);
  241. } while ( RasfileFindNextLine(hFile,RFL_KEYVALUE,RFS_SECTION) );
  242. // sort the lines by key
  243. rasDevSortParams( alpszLines, dParams );
  244. // check for duplicate keys and remove any that are found
  245. rasDevCheckParams( alpszLines, &dParams );
  246. // insert missing _ON or _OFF macros into the list
  247. rasDevCheckMacros( alpszLines, alpszMallocedLines, &dParams );
  248. // check if given buffer is large enough
  249. dCurrentSize = sizeof(RASMAN_DEVICEINFO)
  250. + ((dParams - 1) * sizeof(RAS_PARAMS));
  251. if ( (NULL == pBuffer)
  252. || (dCurrentSize > *pdSize )) {
  253. *pdSize = dCurrentSize;
  254. lppszLine = alpszMallocedLines;
  255. while ( *lppszLine != NULL )
  256. free(*lppszLine++);
  257. free(alpszMallocedLines);
  258. free(alpszLines);
  259. return ERROR_BUFFER_TOO_SMALL;
  260. }
  261. // fill in pBuffer with RASMAN_DEVICEINFO struct
  262. pDeviceInfo = (RASMAN_DEVICEINFO *) pBuffer;
  263. pDeviceInfo->DI_NumOfParams = (WORD) dParams;
  264. for ( i = 0, alpszLinesSave = alpszLines; i < dParams; i++, alpszLines++) {
  265. RAS_PARAMS *pParam;
  266. pParam = &(pDeviceInfo->DI_Params[i]);
  267. if (!bBufferTooSmall) {
  268. // set the Type and Attributes field
  269. pParam->P_Type = String;
  270. if ( strcspn(*alpszLines,LMS) < strcspn(*alpszLines,"=") )
  271. pParam->P_Attributes = 0;
  272. else
  273. pParam->P_Attributes = ATTRIB_VARIABLE;
  274. // get the key
  275. rasDevExtractKey(*alpszLines,pParam->P_Key);
  276. // if there are continuation lines for this keyword=value pair,
  277. // then set Rasfile line to the proper line
  278. if ( strcspn(*alpszLines,"\\") < strlen(*alpszLines) ) {
  279. TCHAR szFullKey[MAX_PARAM_KEY_SIZE];
  280. if ( ! pParam->P_Attributes ) {
  281. strcpy(szFullKey,LMS);
  282. strcat(szFullKey,pParam->P_Key);
  283. strcat(szFullKey,RMS);
  284. }
  285. else
  286. strcpy(szFullKey,pParam->P_Key);
  287. // find the last occurence of this key
  288. RasfileFindFirstLine(hFile,RFL_KEYVALUE,RFS_SECTION);
  289. while ( RasfileFindNextKeyLine(hFile,szFullKey,RFS_SECTION) )
  290. ;
  291. }
  292. }
  293. // get the value string
  294. rasDevExtractValue(*alpszLines,
  295. szString,
  296. sizeof(szString),
  297. hFile);
  298. dValueLen = strlen(szString);
  299. pParam->P_Value.String.Length = dValueLen;
  300. pParam->P_Value.String.Data = malloc(dValueLen + 1);
  301. if(NULL != pParam->P_Value.String.Data)
  302. {
  303. strcpy(pParam->P_Value.String.Data, szString);
  304. }
  305. }
  306. // free up all mallocs
  307. lppszLine = alpszMallocedLines;
  308. while ( *lppszLine != NULL )
  309. free(*lppszLine++);
  310. free(alpszMallocedLines);
  311. free(alpszLinesSave);
  312. return SUCCESS;
  313. }
  314. /*
  315. * RasDevGetCommand :
  316. * Returns the next command line of the given type and advances
  317. * the Rasfile file pointer to the first line following this command
  318. * line.
  319. *
  320. * Arguments :
  321. * hFile (IN) - the Rasfile file handle for the INF file
  322. * pszCmdTypeSuffix (IN) - the type of command line to search for :
  323. * GENERIC, INIT, DIAL, or LISTEN.
  324. * pMacroXlations (IN) - the Macro Translation table used to expand
  325. * all macros in the command line
  326. * lpsCommand (OUT) - buffer to hold the value string of the found
  327. * command line
  328. * pdwCmdLen (OUT) - length of output string with expanded macros
  329. *
  330. * Return Value :
  331. * ERROR_END_OF_SECTION if no command lines of the given type could
  332. * be found.
  333. * ERROR_MACRO_NOT_DEFINED if no entry in the given Macro Translation table
  334. * for a macro found in the command line could be found.
  335. * SUCCESS otherwise.
  336. */
  337. DWORD APIENTRY
  338. RasDevGetCommand( HRASFILE hFile, PTCH pszCmdTypeSuffix,
  339. MACROXLATIONTABLE *pMacroXlations, PTCH lpsCommand,
  340. DWORD *pdwCmdLen )
  341. {
  342. TCHAR szLineKey[MAX_PARAM_KEY_SIZE], sCommand[MAX_PARAM_KEY_SIZE];
  343. TCHAR szValue[RAS_MAXLINEBUFLEN];
  344. TCHAR sCommandValue[2*MAX_CMD_BUF_LEN];// WARNING : if we ever
  345. // get a command line > this
  346. // size msxwrap could bomb!
  347. LPTSTR lpszLine;
  348. if ( ! (RasfileGetLineType(hFile) & RFL_GROUP) ) {
  349. if ( ! RasfileFindNextLine(hFile,RFL_GROUP,RFS_SECTION) )
  350. return ERROR_END_OF_SECTION;
  351. }
  352. else if ( RasfileGetLineMark(hFile) == EOS_COOKIE ) {
  353. RasfilePutLineMark(hFile,0);
  354. return ERROR_END_OF_SECTION;
  355. }
  356. strcpy(sCommand,"command");
  357. strcat(sCommand,pszCmdTypeSuffix);
  358. for ( ;; ) {
  359. lpszLine = (LPTSTR) RasfileGetLine(hFile);
  360. if(NULL == lpszLine)
  361. {
  362. break;
  363. }
  364. rasDevExtractKey(lpszLine,szLineKey);
  365. if ( ! _stricmp(sCommand,szLineKey) ) {
  366. // get the value string
  367. lpszLine = (LPTSTR) RasfileGetLine(hFile);
  368. if(!lpszLine)
  369. return ERROR_END_OF_SECTION;
  370. rasDevExtractValue((LPTSTR)lpszLine,szValue,
  371. RAS_MAXLINEBUFLEN,hFile);
  372. // expand all macros in the value string
  373. if ( ! rasDevExpandMacros(szValue, sCommandValue, pdwCmdLen,
  374. EXPAND_ALL, pMacroXlations) )
  375. return ERROR_MACRO_NOT_DEFINED;
  376. if ( *pdwCmdLen > MAX_CMD_BUF_LEN )
  377. return ERROR_CMD_TOO_LONG;
  378. else
  379. memcpy(lpsCommand, sCommandValue, *pdwCmdLen);
  380. break;
  381. }
  382. if ( ! RasfileFindNextLine(hFile,RFL_GROUP,RFS_SECTION) )
  383. return ERROR_END_OF_SECTION;
  384. }
  385. // advance to the first response following the command or
  386. // to the next command line; if no such line exists mark the
  387. // current line as the end of the section
  388. if ( ! RasfileFindNextLine(hFile,RFL_ANYACTIVE,RFS_SECTION) )
  389. RasfilePutLineMark(hFile,EOS_COOKIE);
  390. return SUCCESS;
  391. }
  392. /*
  393. * RasDevResetCommand :
  394. * Moves the Rasfile file pointer to the first command of any type
  395. * in the loaded section.
  396. *
  397. * Arguments :
  398. * hFile (IN) - the Rasfile handle to the loaded file
  399. *
  400. * Return Value :
  401. * ERROR_NO_COMMAND_FOUND if no command line could be found,
  402. * SUCCESS otherwise.
  403. */
  404. DWORD APIENTRY
  405. RasDevResetCommand( HRASFILE hFile )
  406. {
  407. if ( ! RasfileFindFirstLine(hFile,RFL_GROUP,RFS_SECTION) )
  408. return ERROR_NO_COMMAND_FOUND;
  409. else
  410. return SUCCESS;
  411. }
  412. /*
  413. * RasDevCheckResponse :
  414. * Returns the keyword found in the line whose value string matches
  415. * the string in lpszReceived. Any macros other than fixed macros
  416. * which are found in the received string have their values copied
  417. * into the Macro Translation table.
  418. * All lines in a Command-Response Set are checked.
  419. *
  420. * Arguments :
  421. * hFile (IN) - the Rasfile handle to the loaded file
  422. * lpszReceived (IN) - the string received from the modem or X25 net
  423. * dReceivedLength (IN) - length of the received string
  424. * pMacroXlations (INOUT) - the Macro Translation table
  425. * lpszResponse (OUT) - buffer to copy the found keyword into
  426. *
  427. * Return Value :
  428. * ERROR_PARTIAL_RESPONSE if a line is matched up to the APPEND_MACRO.
  429. * ERROR_MACRO_NOT_DEFINED if a value for "carrierbaud", "connectbaud",
  430. * or "diagnotics" is found in the received string, but could
  431. * not be found in the given Macro Translation table.
  432. * ERROR_UNRECOGNIZED_RESPONSE if no matching reponse could be
  433. * found.
  434. * ERROR_NO_REPSONSES if when called, the Rasfile current line is a
  435. * command, section header, or is invalid.
  436. * SUCCESS otherwise.
  437. */
  438. DWORD APIENTRY
  439. RasDevCheckResponse( HRASFILE hFile, PTCH lpsReceived, DWORD dReceivedLength,
  440. MACROXLATIONTABLE *pMacroXlations, PTCH lpszResponse )
  441. {
  442. LPTSTR lpszValue, lpsRec, lpszResponseLine;
  443. TCHAR szValueString[RAS_MAXLINEBUFLEN], szValue[RAS_MAXLINEBUFLEN];
  444. MACRO aszMacros[10];
  445. DWORD dwRC, dRecLength, dwValueLen;
  446. WORD wMacros;
  447. BYTE bMatch;
  448. // find the nearest previous COMMAND line (Modem section) or
  449. // the section header (Modem Responses section)
  450. if ( RasfileGetLineMark(hFile) != EOS_COOKIE ) {
  451. RasfileFindPrevLine(hFile,RFL_ANYHEADER,RFS_SECTION);
  452. // set Rasfile line to the first keyvalue line in the response set
  453. RasfileFindNextLine(hFile,RFL_KEYVALUE,RFS_SECTION);
  454. }
  455. // else this line is a COMMAND line and the last line of the section
  456. // and ERROR_NO_RESPONSES will be returned
  457. if ( RasfileGetLine(hFile) == NULL ||
  458. RasfileGetLineType(hFile) & RFL_ANYHEADER )
  459. return ERROR_NO_RESPONSES;
  460. for ( ;; ) {
  461. lpszResponseLine = (LPTSTR)RasfileGetLine(hFile);
  462. if(NULL == lpszResponseLine)
  463. {
  464. return ERROR_NO_RESPONSES;
  465. }
  466. rasDevExtractValue(lpszResponseLine,szValueString,
  467. RAS_MAXLINEBUFLEN,hFile);
  468. // expand <cr> and <lf> macros only
  469. //*** Warning: this could expand line beyond array size!
  470. if ( ! rasDevExpandMacros(szValueString, szValue, &dwValueLen,
  471. EXPAND_FIXED_ONLY, NULL) )
  472. return ERROR_MACRO_NOT_DEFINED;
  473. lpsRec = lpsReceived;
  474. dRecLength = dReceivedLength;
  475. bMatch = 0;
  476. wMacros = 0;
  477. for ( lpszValue = szValue; *lpszValue != '\0' && dRecLength > 0; ) {
  478. // check for a macro
  479. if ( *lpszValue == LMSCH ) {
  480. // check for <<
  481. if (*(lpszValue + 1) == LMSCH) {
  482. if (*lpsRec == LMSCH) {
  483. lpszValue +=2;
  484. lpsRec++;
  485. dRecLength--;
  486. }
  487. else
  488. break; // fond a mismatch
  489. }
  490. // check for <append> macro and simply advance past it
  491. else if ( ! _strnicmp(lpszValue,APPEND_MACRO,
  492. strlen(APPEND_MACRO)) )
  493. lpszValue += strlen(APPEND_MACRO);
  494. // check for <ignore> macro
  495. else if ( ! _strnicmp(lpszValue,IGNORE_MACRO,
  496. strlen(IGNORE_MACRO)) ) {
  497. bMatch = FULL_MATCH;
  498. break;
  499. }
  500. // check for <match> macro
  501. else if ( ! _strnicmp(lpszValue,MATCH_MACRO,
  502. strlen(MATCH_MACRO)) ) {
  503. TCHAR szSubString[RAS_MAXLINEBUFLEN];
  504. memset(szSubString,0,RAS_MAXLINEBUFLEN);
  505. // advance value string to first char in match string
  506. lpszValue += strcspn(lpszValue,"\"") + 1;
  507. // extract match string
  508. strncpy(szSubString,lpszValue,strcspn(lpszValue,"\""));
  509. if ( RasDevSubStr(lpsRec,
  510. dRecLength,
  511. szSubString,
  512. strlen(szSubString)) != NULL ) {
  513. rasDevExtractKey(lpszResponseLine,lpszResponse);
  514. return SUCCESS;
  515. }
  516. else
  517. break; // value string does not match
  518. }
  519. // check for hex macro
  520. else if ( (lpszValue[1] == 'h' || lpszValue[1] == 'H') &&
  521. isxdigit(lpszValue[2]) && isxdigit(lpszValue[3]) &&
  522. lpszValue[4] == RMSCH ) {
  523. char c;
  524. c = (char) (ctox(lpszValue[2]) * 0x10 + ctox(lpszValue[3]));
  525. if ( c == *lpsRec++ ) {
  526. lpszValue += 5; // '<', 'h', two hex digits, and '>'
  527. dRecLength--;
  528. continue;
  529. }
  530. else // does not match
  531. break;
  532. }
  533. // check for wildcard character
  534. else if ( ! _strnicmp(lpszValue,WILDCARD_MACRO,
  535. strlen(WILDCARD_MACRO)) ) {
  536. lpszValue += strlen(WILDCARD_MACRO);
  537. lpsRec++; // advance Receive string one character
  538. dRecLength--;
  539. }
  540. else { // get macro name and value
  541. memset(aszMacros[wMacros].MacroName,0,MAX_PARAM_KEY_SIZE);
  542. // copy macro name
  543. strncpy(aszMacros[wMacros].MacroName, lpszValue + 1,
  544. strcspn(lpszValue,RMS) - 1);
  545. // advance the value string over the macro
  546. lpszValue += strcspn(lpszValue,RMS) + 1 /* past RMS */;
  547. // get macro value
  548. if (rasDevIsDecimalMacro(aszMacros[wMacros].MacroName))
  549. rasDevGetDecimalMacroValue(&lpsRec, &dRecLength,
  550. aszMacros[wMacros++].MacroValue);
  551. else
  552. rasDevGetMacroValue(&lpsRec, &dRecLength,
  553. aszMacros[wMacros++].MacroValue);
  554. }
  555. }
  556. else if ( *lpszValue == *lpsRec ) {
  557. if (*lpszValue == RMSCH && *(lpszValue + 1) == RMSCH)
  558. lpszValue++;
  559. lpszValue++;
  560. lpsRec++;
  561. dRecLength--;
  562. continue;
  563. }
  564. else // found a mismatch
  565. break;
  566. } // for
  567. // If we already have a match break out pf outer loop now
  568. if (bMatch != 0)
  569. break;
  570. // full match. When there is trailing line noise dRecLength will not
  571. // be zero, so check for full match aganist length of expected
  572. // response. Also make sure expected response is not empty.
  573. if ( *lpszValue == '\0' && lpszValue != szValue) {
  574. bMatch |= FULL_MATCH;
  575. break;
  576. }
  577. // partial match
  578. else if ( dRecLength == 0 &&
  579. ! _strnicmp(lpszValue,APPEND_MACRO,strlen(APPEND_MACRO)) ) {
  580. bMatch |= PARTIAL_MATCH;
  581. break;
  582. }
  583. if ( ! RasfileFindNextLine(hFile,RFL_KEYVALUE,RFS_SECTION) )
  584. return ERROR_UNRECOGNIZED_RESPONSE;
  585. if ( RasfileGetLineType(hFile) & RFL_GROUP )
  586. return ERROR_UNRECOGNIZED_RESPONSE;
  587. } // for
  588. // sanity check
  589. if ( ! (bMatch & (FULL_MATCH | PARTIAL_MATCH)) )
  590. return ERROR_UNRECOGNIZED_RESPONSE;
  591. // only get this far if a full or partial match was made
  592. // insert any macro values found in the received string
  593. // into the macro translation table
  594. if ((dwRC = rasDevMacroInsert(aszMacros,wMacros,pMacroXlations)) != SUCCESS)
  595. return(dwRC);
  596. // finally, copy the keyword string into lpszResponse string
  597. rasDevExtractKey(lpszResponseLine,lpszResponse);
  598. return ( bMatch & FULL_MATCH ) ? SUCCESS : ERROR_PARTIAL_RESPONSE;
  599. }
  600. /*
  601. * RasDevResponseExpected :
  602. * Checks the INF for presence of reponses to the current command.
  603. * If the key work "NoResponse" is found on the current line the
  604. * function returns FALSE. Otherwise modems always expect responses.
  605. *
  606. * Arguments :
  607. * hFile (IN) - Rasfile file handle for the INF file.
  608. * eDevType (IN) - The type of the device. (Modem, PAD, or Switch)
  609. *
  610. * Return Value :
  611. * FALSE if the current Rasfile line points to a command line or the
  612. * current line starts with "NoResponse", TRUE otherwise. Except
  613. * modems always return TRUE unless "NoResponse" key word is found.
  614. * (See code.)
  615. */
  616. BOOL APIENTRY
  617. RasDevResponseExpected( HRASFILE hFile, DEVICETYPE eDevType )
  618. {
  619. TCHAR szLine[RAS_MAXLINEBUFLEN];
  620. szLine[0] = TEXT('\0');
  621. RasfileGetLineText( hFile, szLine );
  622. if ( _strnicmp(szLine, MXS_NORESPONSE, strlen(MXS_NORESPONSE)) == 0 )
  623. return( FALSE );
  624. if (eDevType == DT_MODEM)
  625. return( TRUE );
  626. if ( RasfileGetLineType(hFile) & RFL_ANYHEADER )
  627. return( FALSE );
  628. else
  629. return( TRUE );
  630. }
  631. /*
  632. * RasDevEchoExpected :
  633. * Checks the current line of the INF file for the keyword NoEcho.
  634. * If found the function returns FALSE. Otherwise, it returns TRUE.
  635. *
  636. * Arguments :
  637. * hFile (IN) - Rasfile file handle for the INF file.
  638. *
  639. * Return Value :
  640. * FALSE if the current line is "NoEcho", else TRUE.
  641. */
  642. BOOL APIENTRY
  643. RasDevEchoExpected( HRASFILE hFile )
  644. {
  645. TCHAR szLine[RAS_MAXLINEBUFLEN];
  646. szLine[0] = TEXT('\0');
  647. RasfileGetLineText( hFile, szLine );
  648. return( ! (_strnicmp(szLine, MXS_NOECHO, strlen(MXS_NOECHO)) == 0) );
  649. }
  650. /*
  651. * RasDevIdFistCommand :
  652. * Determines the type of the first command in the section.
  653. *
  654. * Arguments :
  655. * hFile (IN) - Rasfile file handle for the INF file.
  656. *
  657. * Assumptions :
  658. * RasDevGetParams has been called previously, that is, the current
  659. * line is the first command.
  660. *
  661. * Return Value :
  662. * FALSE if current line is not a command, otherwise TRUE.
  663. */
  664. CMDTYPE APIENTRY
  665. RasDevIdFirstCommand( HRASFILE hFile )
  666. {
  667. TCHAR szKey[MAX_PARAM_KEY_SIZE + 1];
  668. // Find the first command
  669. if ( ! RasfileFindFirstLine(hFile,RFL_GROUP,RFS_SECTION))
  670. return(CT_UNKNOWN);
  671. if ( ! RasfileGetKeyValueFields(hFile, szKey, NULL))
  672. return(CT_UNKNOWN);
  673. // Convert Key from the line into an enum
  674. if (_stricmp(MXS_GENERIC_COMMAND, szKey) == 0)
  675. return(CT_GENERIC);
  676. else if (_stricmp(MXS_DIAL_COMMAND, szKey) == 0)
  677. return(CT_DIAL);
  678. else if (_stricmp(MXS_INIT_COMMAND, szKey) == 0)
  679. return(CT_INIT);
  680. else if (_stricmp(MXS_LISTEN_COMMAND, szKey) == 0)
  681. return(CT_LISTEN);
  682. else
  683. return(CT_UNKNOWN);
  684. }
  685. /*
  686. * RasDevSubStr :
  687. * Finds a substring and returns a pointer to it. This function works like
  688. * the C runtime function strstr, but works in strings that contain zeros.
  689. *
  690. * Arguments :
  691. * psStr (IN) - the string to be searched for a substring
  692. * dwStrLen (IN) - length of the string to be searched
  693. * psSubStr (IN) - the substring to search for
  694. * dwSubStrLen (IN) - length of the substring
  695. *
  696. * Return Value :
  697. * A pointer to the beginning of the substring, or NULL if the substring
  698. * was not found.
  699. */
  700. LPTSTR APIENTRY
  701. RasDevSubStr( LPTSTR psStr,
  702. DWORD dwStrLen,
  703. LPTSTR psSubStr,
  704. DWORD dwSubStrLen )
  705. {
  706. LPTSTR ps;
  707. if (dwSubStrLen > dwStrLen)
  708. return NULL;
  709. for (ps = psStr; ps <= psStr + dwStrLen - dwSubStrLen; ps++)
  710. if (memcmp(ps, psSubStr, dwSubStrLen) == 0)
  711. return ps;
  712. return NULL;
  713. }
  714. /*****************************************************************************
  715. ** Rasfile Wrapper internal routines **
  716. ****************************************************************************/
  717. /*
  718. * rasDevGroupFunc :
  719. * The PFBISGROUP function passed to RasfileLoad().
  720. *
  721. * Arguments :
  722. * lpszLine (IN) - a Rasfile line
  723. *
  724. * Return Value :
  725. * TRUE if the line is a command line, FALSE otherwise.
  726. */
  727. BOOL rasDevGroupFunc( LPTSTR lpszLine )
  728. {
  729. TCHAR szKey[MAX_PARAM_KEY_SIZE], *lpszKey;
  730. if ( strcspn(lpszLine,"=") == strlen(lpszLine) )
  731. return FALSE;
  732. while ( *lpszLine == ' ' || *lpszLine == '\t' )
  733. lpszLine++;
  734. lpszKey = szKey;
  735. while ( *lpszLine != ' ' && *lpszLine != '\t' && *lpszLine != '=' )
  736. *lpszKey++ = *lpszLine++;
  737. *lpszKey = '\0';
  738. if ( ! _stricmp(szKey,"COMMAND") || ! _stricmp(szKey,"COMMAND_INIT") ||
  739. ! _stricmp(szKey,"COMMAND_DIAL") || ! _stricmp(szKey,"COMMAND_LISTEN") )
  740. return TRUE;
  741. else
  742. return FALSE;
  743. }
  744. /*
  745. * rasDevIsDecimalMacro :
  746. * Indicates whether or not a given macro must have only ascii
  747. * decimal digits for its value.
  748. *
  749. * Arguments:
  750. * lpszMacroName (IN) - macro name
  751. *
  752. * Return Value:
  753. * TRUE if only digits are legal in the macro value; otherwise FALSE.
  754. *
  755. * Remarks:
  756. * Called by API RasDevCheckResponse().
  757. */
  758. BOOL rasDevIsDecimalMacro ( LPTSTR lpszMacroName )
  759. {
  760. if (_stricmp(lpszMacroName, MXS_CONNECTBPS_KEY) == 0 ||
  761. _stricmp(lpszMacroName, MXS_CARRIERBPS_KEY) == 0)
  762. return(TRUE);
  763. else
  764. return(FALSE);
  765. }
  766. /*
  767. * rasDevGetMacroValue :
  768. * Extracts a macro value from string *lppszReceived and copies it
  769. * to string lpszMacro. Also updates the string pointer of
  770. * lppszValue and lppszReceived, and updates dRecLength.
  771. *
  772. * Arguments :
  773. * lppszReceived (INOUT) - received string (from a modem)
  774. * dRecLength (INOUT) - remaining length of the received string
  775. * lpszMacro (OUT) - buffer to receive the macro value
  776. *
  777. * Return Value :
  778. * None.
  779. *
  780. * Remarks :
  781. * Called by API RasDevCheckResponse().
  782. */
  783. void rasDevGetMacroValue ( LPTSTR *lppszReceived, DWORD *dRecLength,
  784. LPTSTR lpszMacroValue )
  785. {
  786. while ( **lppszReceived != CR && **lppszReceived != '\0' ) {
  787. *lpszMacroValue++ = *(*lppszReceived)++;
  788. (*dRecLength)--;
  789. }
  790. *lpszMacroValue = '\0'; // Null terminate the Macro value string
  791. }
  792. /*
  793. * rasDevGetDecimalMacroValue :
  794. * Extracts a macro value from string *lppszReceived and copies it
  795. * to string lpszMacro. Also updates the string pointer of
  796. * lppszReceived, and updates dRecLength.
  797. * This functions only extracts characters which are ascii decimal
  798. * digits.
  799. *
  800. * Arguments :
  801. * lppszReceived (INOUT) - received string (from a modem)
  802. * dRecLength (INOUT) - remaining length of the received string
  803. * lpszMacro (OUT) - buffer to receive the macro value
  804. *
  805. * Return Value :
  806. * None.
  807. *
  808. * Remarks :
  809. * Called by API RasDevCheckResponse().
  810. */
  811. void rasDevGetDecimalMacroValue ( LPTSTR *lppszReceived,
  812. DWORD *dRecLength,
  813. LPTSTR lpszMacroValue )
  814. {
  815. TCHAR szBuffer[16], *pBuf = szBuffer;
  816. WORD wcRightHandDigits = 0;
  817. BOOL bDpFound = FALSE;
  818. ULONG lBps;
  819. while ( isdigit(**lppszReceived) || **lppszReceived == '.' ) {
  820. if (isdigit(**lppszReceived)) {
  821. *pBuf++ = *(*lppszReceived)++;
  822. (*dRecLength)--;
  823. if (bDpFound)
  824. wcRightHandDigits++;
  825. }
  826. else if (!bDpFound && **lppszReceived == '.') {
  827. (*lppszReceived)++;
  828. (*dRecLength)--;
  829. bDpFound = TRUE;
  830. }
  831. else
  832. break;
  833. }
  834. *pBuf = '\0'; // Null terminate the Macro value string
  835. lBps = atol(szBuffer);
  836. switch(wcRightHandDigits)
  837. {
  838. case 0: case 3:
  839. break;
  840. case 1:
  841. lBps *= 100;
  842. break;
  843. case 2:
  844. lBps *= 10;
  845. break;
  846. }
  847. _ltoa(lBps, lpszMacroValue, 10);
  848. }
  849. /*
  850. * rasDevExpandMacros :
  851. * Takes the string lpszLine, and copies it to lpszVal, using
  852. * Macro Translation table pMacroXlations to expand macros.
  853. * <cr>, <lf>, and <hxx> macros are always expanded directly.
  854. * If bFlag == EXPAND_ALL << and >> are converted to < and >.
  855. * (A single > which is not at the end of a macro is simply copied.
  856. * An error could be raised here for such a >, but it is left to
  857. * be caught later when the device chokes on the unexpected >.
  858. * This has the advantage that a > where a >> should be will work.)
  859. *
  860. * Assumptions:
  861. * Expanded macros may contain zeros, therefore output command string
  862. * may contain zeros.
  863. *
  864. * Arguments :
  865. * lpszLine (IN) - a value string from a Rasfile keyword=value line
  866. * lpsVal (OUT) - buffer to copied to with expanded macros
  867. * pdwValLen (OUT) - length of output string with expanded macros
  868. * bFlag (IN) - EXPAND_FIXED_ONLY if only the fixed macros <cr>
  869. * and <lf> macros are to be expanded, and
  870. * EXPAND_ALL if all macros should be expanded
  871. * pMacroXlations (IN) - the Macro Translation table
  872. *
  873. * Return Value :
  874. * FALSE if a needed macro translation could not be found in the
  875. * pMacroXlations table, TRUE otherwise.
  876. *
  877. * Remarks :
  878. * Called by APIs RasDevGetCommand() and RasDevCheckResponse().
  879. */
  880. BOOL rasDevExpandMacros( LPTSTR lpszLine,
  881. LPTSTR lpsVal,
  882. DWORD *pdwValLen,
  883. BYTE bFlag,
  884. MACROXLATIONTABLE *pMacroXlations )
  885. {
  886. TCHAR szMacro[RAS_MAXLINEBUFLEN];
  887. LPTSTR lpsValue;
  888. lpsValue = lpsVal;
  889. for ( ; *lpszLine != '\0'; ) {
  890. // check for RMSCH
  891. // if EXPAND_ALL convert double RMSCH to single RMSCH, and
  892. // simply copy single RMSCH.
  893. if ((bFlag & EXPAND_ALL) && *lpszLine == RMSCH) {
  894. *lpsValue++ = *lpszLine++;
  895. if (*lpszLine == RMSCH)
  896. lpszLine++;
  897. }
  898. // check for a macro or double LMSCH
  899. else if ( *lpszLine == LMSCH ) {
  900. if ((bFlag & EXPAND_ALL) && *(lpszLine + 1) == LMSCH) {
  901. *lpsValue++ = *lpszLine;
  902. lpszLine += 2;
  903. }
  904. else if ( ! _strnicmp(lpszLine,CR_MACRO,4) ) {
  905. *lpsValue++ = CR;
  906. lpszLine += 4;
  907. }
  908. else if ( ! _strnicmp(lpszLine,LF_MACRO,4) ) {
  909. *lpsValue++ = LF;
  910. lpszLine += 4;
  911. }
  912. else if ( ! _strnicmp(lpszLine,APPEND_MACRO,8) &&
  913. (bFlag & EXPAND_ALL) )
  914. lpszLine += 8;
  915. // Hex macro stuff
  916. //
  917. else if ((lpszLine[1] == 'h' || lpszLine[1] == 'H') &&
  918. isxdigit(lpszLine[2]) && isxdigit(lpszLine[3]) &&
  919. (lpszLine[4] == RMSCH) &&
  920. ( bFlag & EXPAND_ALL )) {
  921. char c;
  922. c = (char) (ctox(lpszLine[2]) * 0x10 + ctox(lpszLine[3]));
  923. lpszLine += 5; // '<', 'h', two hex digits, and '>'
  924. *lpsValue++ = c;
  925. }
  926. else if ( bFlag & EXPAND_ALL ) {
  927. LPTSTR lpszStr;
  928. char buf[256];
  929. for ( lpszLine++, lpszStr = szMacro; *lpszLine != RMSCH; )
  930. *lpszStr++ = *lpszLine++;
  931. lpszLine++; // advance past RMSCH
  932. *lpszStr = '\0'; // Null terminate szMacro string
  933. if ( ! rasDevLookupMacro(szMacro,&lpsValue,pMacroXlations) )
  934. return FALSE;
  935. }
  936. else {
  937. // just copy the macro if EXPAND_ALL is not set
  938. while ( *lpszLine != RMSCH )
  939. *lpsValue++ = *lpszLine++;
  940. *lpsValue++ = *lpszLine++;
  941. }
  942. }
  943. else
  944. *lpsValue++ = *lpszLine++;
  945. } // for
  946. *lpsValue = '\0';
  947. *pdwValLen = (DWORD) (lpsValue - lpsVal);
  948. return TRUE;
  949. }
  950. /*
  951. * rasDevLookupMacro :
  952. * Lookup macro lpszMacro in the given Macro Translation table, and
  953. * return it's value in *lppszExpanded if found.
  954. *
  955. * Arguments :
  956. * lpszMacro (IN) - the macro whose value is sought
  957. * lppszExpanded (OUT) - double pointer to increment and copy the
  958. * macro's value to
  959. * pMacroXlations (IN) - the Macro Translation table
  960. *
  961. * Return Value :
  962. * FALSE if the macro could not be found in the given Macro Translation
  963. * table, TRUE otherwise.
  964. *
  965. * Remarks :
  966. * Called by internal function rasDevExpandMacros().
  967. */
  968. BOOL rasDevLookupMacro( LPTSTR lpszMacro, LPTSTR *lppszExpanded,
  969. MACROXLATIONTABLE *pMacroXlations )
  970. {
  971. WORD i;
  972. LPTSTR lpszMacroValue;
  973. for ( i = 0; i < pMacroXlations->MXT_NumOfEntries; i++ ) {
  974. if ( ! _stricmp(pMacroXlations->MXT_Entry[i].E_MacroName, lpszMacro) ) {
  975. lpszMacroValue =
  976. pMacroXlations->MXT_Entry[i].E_Param->P_Value.String.Data;
  977. while (*lpszMacroValue != 0) {
  978. **lppszExpanded = *lpszMacroValue; // copy macro char by char
  979. if ((*lpszMacroValue == LMSCH && *(lpszMacroValue+1) == LMSCH)
  980. || (*lpszMacroValue == RMSCH && *(lpszMacroValue+1) == RMSCH))
  981. lpszMacroValue++; // skip one of double angle brackets
  982. lpszMacroValue++;
  983. (*lppszExpanded)++;
  984. }
  985. return TRUE;
  986. }
  987. }
  988. return FALSE;
  989. }
  990. /*
  991. * rasDevMacroInsert :
  992. * Updates the value of macro lpszMacro with new value lpszNewValue
  993. * in the given Macro Translation table.
  994. *
  995. * Arguments :
  996. * aszMacros (IN) - array of macro name and value pairs
  997. * wMacros (IN) - number of elements of aszMacros array
  998. * pMacroXlations (INOUT) - the Macro Translation table
  999. *
  1000. * Return Value : SUCCESS
  1001. * ERROR_MACRO_NOT_DEFINED
  1002. *
  1003. * Remarks :
  1004. * Called by API RasDevCheckResponse().
  1005. */
  1006. DWORD rasDevMacroInsert( MACRO *aszMacros, WORD wMacros,
  1007. MACROXLATIONTABLE *pMacroXlations )
  1008. {
  1009. int iMacros;
  1010. WORD iXlations;
  1011. DWORD dwRC;
  1012. for ( iMacros = (int)(wMacros - 1); iMacros >= 0; iMacros-- ) {
  1013. for ( iXlations = 0; iXlations < pMacroXlations->MXT_NumOfEntries;
  1014. iXlations++ ) {
  1015. if ( ! _stricmp(pMacroXlations->MXT_Entry[iXlations].E_MacroName,
  1016. aszMacros[iMacros].MacroName) ) {
  1017. dwRC = UpdateParamString(pMacroXlations->MXT_Entry[iXlations].E_Param,
  1018. aszMacros[iMacros].MacroValue,
  1019. strlen(aszMacros[iMacros].MacroValue));
  1020. if (dwRC != SUCCESS)
  1021. return dwRC;
  1022. break;
  1023. }
  1024. }
  1025. if ( iXlations == pMacroXlations->MXT_NumOfEntries )
  1026. return ERROR_MACRO_NOT_DEFINED;
  1027. }
  1028. return SUCCESS;
  1029. }
  1030. /*
  1031. * rasDevExtractKey :
  1032. * Extracts the keyvalue from a Rasfile line.
  1033. *
  1034. * Arguments :
  1035. * lpszString (IN) - Rasfile line pointer.
  1036. * lpszKey (OUT) - buffer to hold the keyvalue
  1037. *
  1038. * Return Value :
  1039. * None.
  1040. *
  1041. * Remarks :
  1042. * Called by APIs RasDevGetParams(), RasDevGetCommand(), and
  1043. * RasDevCheckResponse(), and internal functions rasDevCheckParams()
  1044. * and rasDevCheckMacros().
  1045. */
  1046. void rasDevExtractKey ( LPTSTR lpszString, LPTSTR lpszKey )
  1047. {
  1048. // skip to beginning of keyword (skip '<' if present)
  1049. while ( *lpszString == ' ' || *lpszString == '\t' ||
  1050. *lpszString == LMSCH )
  1051. lpszString++;
  1052. while ( *lpszString != RMSCH && *lpszString != '=' &&
  1053. *lpszString != ' ' && *lpszString != '\t' )
  1054. *lpszKey++ = *lpszString++;
  1055. *lpszKey = '\0'; // Null terminate keyword string
  1056. }
  1057. /*
  1058. * rasDevExtractValue :
  1059. * Extracts the value string for a keyword=value string which
  1060. * begins on Rasfile line lpszString. This function recongizes a
  1061. * backslash \ as a line continuation character and a double
  1062. * backslash \\ as a backslash character.
  1063. *
  1064. * Assumptions: lpszValue output buffer is ALWAYS large enough.
  1065. *
  1066. * Arguments :
  1067. * lpszString (IN) - Rasfile line where the keyword=value string begins
  1068. * lpszValue (OUT) - buffer to hold the value string
  1069. * dSize (IN) - size of the lpszValue buffer
  1070. * hFile (IN) - Rasfile handle, the current line must be the line
  1071. * which lpszString points to
  1072. *
  1073. * Return Value :
  1074. * None.
  1075. *
  1076. * Remarks :
  1077. * Called by APIs RasDevGetParams(), RasDevGetCommand(), and
  1078. * RasDevCheckResponse().
  1079. */
  1080. void rasDevExtractValue ( LPTSTR lpszString, LPTSTR lpszValue,
  1081. DWORD dSize, HRASFILE hFile )
  1082. {
  1083. LPTSTR lpszInputStr;
  1084. BOOL bLineContinues;
  1085. // skip to beginning of value string
  1086. for ( lpszString += strcspn(lpszString,"=") + 1;
  1087. *lpszString == ' ' || *lpszString == '\t'; lpszString++ )
  1088. ;
  1089. // check for continuation lines
  1090. if ( strcspn(lpszString,"\\") == strlen(lpszString) )
  1091. strcpy(lpszValue,lpszString); // copy value string
  1092. else {
  1093. memset(lpszValue,0,dSize);
  1094. lpszInputStr = lpszString;
  1095. for (;;) {
  1096. // copy the current line
  1097. bLineContinues = FALSE;
  1098. while (*lpszInputStr != '\0') {
  1099. if (*lpszInputStr == '\\')
  1100. if (*(lpszInputStr + 1) == '\\') {
  1101. *lpszValue++ = *lpszInputStr; // copy one backslash
  1102. lpszInputStr += 2;
  1103. }
  1104. else {
  1105. bLineContinues = TRUE;
  1106. break;
  1107. }
  1108. else
  1109. *lpszValue++ = *lpszInputStr++;
  1110. }
  1111. if ( ! bLineContinues)
  1112. break;
  1113. // get the next line
  1114. if ( ! RasfileFindNextLine(hFile,RFL_ANYACTIVE,RFS_SECTION) )
  1115. break;
  1116. lpszInputStr = (LPTSTR)RasfileGetLine(hFile);
  1117. }
  1118. }
  1119. }
  1120. /*
  1121. * rasDevSortParams :
  1122. * Sorts an array of Rasfile lines by keyvalue.
  1123. *
  1124. * Arguments :
  1125. * alpszLines (INOUT) - the array of line pointers
  1126. * dParams (IN) - number of elements in the array
  1127. *
  1128. * Return Value :
  1129. * None.
  1130. *
  1131. * Remarks :
  1132. * Called by API RasDevGetParams().
  1133. */
  1134. void rasDevSortParams( LPTSTR *alpszLines, DWORD dParams )
  1135. {
  1136. TCHAR szKey1[MAX_PARAM_KEY_SIZE], szKey2[MAX_PARAM_KEY_SIZE];
  1137. LPTSTR lpszTemp;
  1138. DWORD i,j;
  1139. BOOL changed;
  1140. // If there is nothing to sort, don't try
  1141. if (dParams < 2)
  1142. return;
  1143. /* Bubble sort - it's stable */
  1144. for ( i = dParams - 1; i > 0; i-- ) {
  1145. changed = FALSE;
  1146. for ( j = 0; j < i; j++ ) {
  1147. rasDevExtractKey(alpszLines[j],szKey1);
  1148. rasDevExtractKey(alpszLines[j+1],szKey2);
  1149. // sort by keyvalue
  1150. if ( _stricmp(szKey1,szKey2) > 0 ) {
  1151. lpszTemp = alpszLines[j];
  1152. alpszLines[j] = alpszLines[j+1];
  1153. alpszLines[j+1] = lpszTemp;
  1154. changed = TRUE;
  1155. }
  1156. }
  1157. if ( ! changed )
  1158. return;
  1159. }
  1160. }
  1161. /*
  1162. * rasDevCheckParams :
  1163. * Removes duplicate lines from the alpszLines array of lines.
  1164. * Duplicates lines are those whose keyvalue is identical. The
  1165. * line with the lesser index is removed.
  1166. *
  1167. * Arguments :
  1168. * alpszLines (INOUT) - the array of line pointers
  1169. * pdTotalParams (INOUT) - number of array entries, this is updated
  1170. * if duplicates are removed
  1171. *
  1172. * Return Value :
  1173. * None.
  1174. *
  1175. * Remarks :
  1176. * Called by API RasDevGetParams().
  1177. */
  1178. void rasDevCheckParams( LPTSTR *alpszLines, DWORD *pdTotalParams )
  1179. {
  1180. TCHAR szKey1[MAX_PARAM_KEY_SIZE], szKey2[MAX_PARAM_KEY_SIZE];
  1181. DWORD dParams, i;
  1182. dParams = *pdTotalParams;
  1183. for ( i = 1; i < *pdTotalParams ; i++ ) {
  1184. rasDevExtractKey(alpszLines[i-1],szKey1);
  1185. rasDevExtractKey(alpszLines[i],szKey2);
  1186. if ( _stricmp(szKey1,szKey2) == 0 ) {
  1187. memcpy(&(alpszLines[i-1]),&(alpszLines[i]),
  1188. (*pdTotalParams - i) * sizeof(LPTSTR *));
  1189. (*pdTotalParams)--;
  1190. }
  1191. }
  1192. }
  1193. /*
  1194. * rasDevCheckMacros :
  1195. * Checks the array of lines for missing _ON or _OFF macros
  1196. * in binary macro pairs and inserts any such missing macro
  1197. * into the array of lines.
  1198. *
  1199. * Arguments :
  1200. * alpszLines (INOUT) - array of lines
  1201. * alpszMallocedLines (OUT) - array of newly malloced lines for
  1202. * this routine
  1203. * pdTotalParams (INOUT) - total number of elements in alpszLines
  1204. * array, this is updated if new entries are
  1205. * added
  1206. *
  1207. * Return Value :
  1208. * None.
  1209. *
  1210. * Remarks :
  1211. * Called by API RasDevGetParams().
  1212. */
  1213. void rasDevCheckMacros( LPTSTR *alpszLines, LPTSTR *alpszMallocedLines,
  1214. DWORD *pdTotalParams )
  1215. {
  1216. TCHAR szKey1[MAX_PARAM_KEY_SIZE], szKey2[MAX_PARAM_KEY_SIZE];
  1217. DWORD i, j;
  1218. BYTE bMissing;
  1219. if(alpszLines == NULL)
  1220. {
  1221. return;
  1222. }
  1223. // insert missing _ON and _OFF macros
  1224. for ( i = 0; i < *pdTotalParams; i++ ) {
  1225. if ( strcspn(alpszLines[i],LMS) > strcspn(alpszLines[i],"=") )
  1226. continue; // not a macro
  1227. bMissing = NONE;
  1228. rasDevExtractKey(alpszLines[i],szKey1);
  1229. // if current key is an _OFF macro, check for a missing _ON
  1230. if ( strstr(szKey1,"_OFF") != NULL || strstr(szKey1,"_off") != NULL ) {
  1231. if ( i+1 == *pdTotalParams ) // looking at last parameter
  1232. bMissing = ON;
  1233. // get next key
  1234. else {
  1235. rasDevExtractKey(alpszLines[i+1],szKey2);
  1236. if (_strnicmp(szKey1,szKey2,strlen(szKey1) - strlen("OFF")) != 0)
  1237. bMissing = ON;
  1238. }
  1239. }
  1240. // if current key is an _ON macro, check for a missing _OFF
  1241. if ( strstr(szKey1,"_ON") != NULL || strstr(szKey1,"_on") != NULL ) {
  1242. if ( i == 0 ) // looking at first parameter
  1243. bMissing = OFF;
  1244. // get previous key
  1245. else {
  1246. rasDevExtractKey(alpszLines[i-1],szKey2);
  1247. if (_strnicmp(szKey1,szKey2,strlen(szKey1) - strlen("ON")) != 0)
  1248. bMissing = OFF;
  1249. }
  1250. }
  1251. if ( bMissing != NONE ) {
  1252. // shift everything over one position
  1253. for ( j = *pdTotalParams - 1;
  1254. j >= i + ((bMissing == ON) ? 1 : 0); j-- )
  1255. alpszLines[j+1] = alpszLines[j];
  1256. // point j to the new empty array entry
  1257. j = (bMissing == OFF) ? i : i + 1;
  1258. alpszLines[j] = malloc(sizeof(TCHAR) * RAS_MAXLINEBUFLEN);
  1259. if(NULL == alpszLines[j])
  1260. {
  1261. *alpszMallocedLines = NULL;
  1262. return;
  1263. }
  1264. *alpszMallocedLines++ = alpszLines[j];
  1265. memset(alpszLines[j],0,sizeof(TCHAR) * RAS_MAXLINEBUFLEN);
  1266. strcpy(alpszLines[j],LMS);
  1267. if ( bMissing == ON )
  1268. strncat(alpszLines[j],szKey1,
  1269. strlen(szKey1) - strlen(OFF_STR));
  1270. else // bMissing == OFF
  1271. strncat(alpszLines[j],szKey1,
  1272. strlen(szKey1) - strlen(ON_STR));
  1273. strcat(alpszLines[j], bMissing == ON ? ON_STR : OFF_STR );
  1274. strcat(alpszLines[j], RMS);
  1275. strcat(alpszLines[j], "=");
  1276. (*pdTotalParams)++;
  1277. i++; // increment i to compensate for the new entry
  1278. }
  1279. } // for
  1280. // Null terminate the Malloced Lines array
  1281. *alpszMallocedLines = NULL;
  1282. }
  1283. /*
  1284. * ctox :
  1285. * Convert char hex digit to decimal number.
  1286. */
  1287. BYTE ctox( char ch )
  1288. {
  1289. if ( isdigit(ch) )
  1290. return ch - '0';
  1291. else
  1292. return (tolower(ch) - 'a') + 10;
  1293. }
  1294. //* UpdateParamString ------------------------------------------------------
  1295. //
  1296. // Function: This function copys a new string into a PARAM.P_Value
  1297. // allocating new memory of the new string is longer than
  1298. // the old. The copied string is then zero terminated.
  1299. //
  1300. // NOTE: This function frees and allocates memory and is not
  1301. // suitable for copying into an existing buffer. Use with
  1302. // InfoTable and other RAS_PARAMS with 'unpacked' strings.
  1303. //
  1304. // Arguments:
  1305. // pParam OUT Pointer to Param to update
  1306. // psStr IN Input string
  1307. // dwStrLen IN Length of input string
  1308. //
  1309. // Returns: SUCCESS
  1310. // ERROR_ALLOCATING_MEMORY
  1311. //*
  1312. DWORD
  1313. UpdateParamString(RAS_PARAMS *pParam, TCHAR *psStr, DWORD dwStrLen)
  1314. {
  1315. if (dwStrLen > pParam->P_Value.String.Length)
  1316. {
  1317. free(pParam->P_Value.String.Data);
  1318. GetMem(dwStrLen + 1, &(pParam->P_Value.String.Data));
  1319. if (pParam->P_Value.String.Data == NULL)
  1320. return(ERROR_ALLOCATING_MEMORY);
  1321. }
  1322. pParam->P_Value.String.Length = dwStrLen;
  1323. memcpy(pParam->P_Value.String.Data, psStr, dwStrLen);
  1324. pParam->P_Value.String.Data[dwStrLen] = '\0'; //Zero Terminate
  1325. return(SUCCESS);
  1326. }
  1327. //* GetMem -----------------------------------------------------------------
  1328. //
  1329. // Function: Allocates memory. If the memory allocation fails the output
  1330. // parameter will be NULL.
  1331. //
  1332. // Returns: Nothing.
  1333. //
  1334. //*
  1335. void
  1336. GetMem(DWORD dSize, BYTE **ppMem)
  1337. {
  1338. *ppMem = (BYTE *) calloc(dSize, 1);
  1339. }