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.

2442 lines
58 KiB

  1. /*++
  2. Copyright (c) 1998-1999 Microsoft Corporation
  3. Module Name:
  4. routing\netsh\shell\shell.c
  5. Abstract:
  6. The command shell.
  7. Revision History:
  8. Anand Mahalingam 7/6/98 Created
  9. Dave Thaler 99 Updated
  10. --*/
  11. #include "precomp.h"
  12. #undef EXTRA_DEBUG
  13. //
  14. // Define this when we allow a -r option to do remote config
  15. //
  16. #define ALLOW_REMOTES
  17. #define DEFAULT_STARTUP_CONTEXT L"netsh"
  18. WCHAR RtmonPrompt[MAX_CMD_LEN];
  19. WCHAR g_pwszContext[MAX_CMD_LEN] = DEFAULT_STARTUP_CONTEXT;
  20. WCHAR g_pwszNewContext[MAX_CMD_LEN] = DEFAULT_STARTUP_CONTEXT;
  21. LPWSTR g_pwszRouterName = NULL;
  22. HANDLE g_hModule;
  23. BOOL g_bVerbose = FALSE;
  24. BOOL g_bInteractive = FALSE;
  25. DWORD g_dwContextArgCount;
  26. DWORD g_dwTotalArgCount;
  27. BOOL g_bDone = FALSE;
  28. HANDLE g_hLogFile = NULL;
  29. BOOL
  30. WINAPI
  31. HandlerRoutine(
  32. DWORD dwCtrlType // control signal type
  33. );
  34. //
  35. // If quiet, "Ok" and other informational messages will be suppressed.
  36. //
  37. BOOL g_bQuiet = TRUE;
  38. CMD_ENTRY g_UbiqCmds[] =
  39. {
  40. CREATE_CMD_ENTRY( DUMP, HandleUbiqDump),
  41. CREATE_CMD_ENTRY( HELP1, HandleUbiqHelp),
  42. CREATE_CMD_ENTRY( HELP2, HandleUbiqHelp),
  43. };
  44. ULONG g_ulNumUbiqCmds = sizeof(g_UbiqCmds)/sizeof(CMD_ENTRY);
  45. CMD_ENTRY g_ShellCmds[] =
  46. {
  47. // CREATE_CMD_ENTRY( DUMP, HandleShellDump),
  48. // CREATE_CMD_ENTRY( HELP1, HandleShellHelp),
  49. // CREATE_CMD_ENTRY( HELP2, HandleShellHelp),
  50. CREATE_CMD_ENTRY( LOAD, HandleShellLoad),
  51. CREATE_CMD_ENTRY_EX(QUIT, HandleShellExit, CMD_FLAG_INTERACTIVE),
  52. CREATE_CMD_ENTRY_EX(BYE, HandleShellExit, CMD_FLAG_INTERACTIVE),
  53. CREATE_CMD_ENTRY_EX(EXIT, HandleShellExit, CMD_FLAG_INTERACTIVE),
  54. CREATE_CMD_ENTRY_EX(FLUSH, HandleShellFlush, CMD_FLAG_INTERACTIVE),
  55. CREATE_CMD_ENTRY_EX(SAVE, HandleShellSave, CMD_FLAG_INTERACTIVE),
  56. CREATE_CMD_ENTRY_EX(COMMIT, HandleShellCommit, CMD_FLAG_INTERACTIVE),
  57. CREATE_CMD_ENTRY_EX(UNCOMMIT, HandleShellUncommit,CMD_FLAG_INTERACTIVE),
  58. CREATE_CMD_ENTRY_EX(ALIAS, HandleShellAlias, CMD_FLAG_INTERACTIVE),
  59. CREATE_CMD_ENTRY_EX(UNALIAS, HandleShellUnalias, CMD_FLAG_INTERACTIVE),
  60. CREATE_CMD_ENTRY_EX(UPLEVEL, HandleShellUplevel, CMD_FLAG_INTERACTIVE),
  61. CREATE_CMD_ENTRY_EX(PUSHD, HandleShellPushd, CMD_FLAG_INTERACTIVE),
  62. CREATE_CMD_ENTRY_EX(POPD, HandleShellPopd, CMD_FLAG_INTERACTIVE),
  63. };
  64. ULONG g_ulNumShellCmds = sizeof(g_ShellCmds)/sizeof(CMD_ENTRY);
  65. CMD_ENTRY g_ShellAddCmdTable[] = {
  66. CREATE_CMD_ENTRY_EX(ADD_HELPER, HandleAddHelper, CMD_FLAG_LOCAL),
  67. };
  68. CMD_ENTRY g_ShellSetCmdTable[] = {
  69. CREATE_CMD_ENTRY_EX(SET_MACHINE, HandleSetMachine,CMD_FLAG_ONLINE),
  70. CREATE_CMD_ENTRY_EX(SET_MODE, HandleSetMode, CMD_FLAG_INTERACTIVE),
  71. CREATE_CMD_ENTRY_EX(SET_FILE, HandleSetFile, CMD_FLAG_INTERACTIVE),
  72. };
  73. CMD_ENTRY g_ShellDelCmdTable[] = {
  74. CREATE_CMD_ENTRY_EX(DEL_HELPER, HandleDelHelper, CMD_FLAG_LOCAL),
  75. };
  76. CMD_ENTRY g_ShellShowCmdTable[] = {
  77. CREATE_CMD_ENTRY_EX(SHOW_ALIAS, HandleShowAlias, 0),
  78. CREATE_CMD_ENTRY_EX(SHOW_HELPER, HandleShowHelper, 0),
  79. CREATE_CMD_ENTRY_EX(SHOW_MODE, HandleShowMode, CMD_FLAG_INTERACTIVE),
  80. };
  81. CMD_GROUP_ENTRY g_ShellCmdGroups[] =
  82. {
  83. CREATE_CMD_GROUP_ENTRY(GROUP_ADD, g_ShellAddCmdTable),
  84. CREATE_CMD_GROUP_ENTRY(GROUP_DELETE, g_ShellDelCmdTable),
  85. CREATE_CMD_GROUP_ENTRY(GROUP_SET, g_ShellSetCmdTable),
  86. CREATE_CMD_GROUP_ENTRY(GROUP_SHOW, g_ShellShowCmdTable),
  87. };
  88. ULONG g_ulNumGroups = sizeof(g_ShellCmdGroups)/sizeof(CMD_GROUP_ENTRY);
  89. DWORD
  90. ParseCommand(
  91. IN PLIST_ENTRY pleEntry,
  92. IN BOOL bAlias
  93. )
  94. /*++
  95. Routine Description:
  96. This converts any multi-token arguments into separate arg entries.
  97. If bAlias is set, it also expands any args which are aliases.
  98. Arguments:
  99. ple - Pointer to the argument.
  100. bAlias - To look for alias or not.
  101. Called by: ConvertBufferToArgList(), ProcessCommand()
  102. Return Value:
  103. ERROR_NOT_ENOUGH_MEMORY, NO_ERROR
  104. --*/
  105. {
  106. DWORD dwErr = NO_ERROR, dwLen , i;
  107. LPWSTR pw1, pw2, pwszAlias;
  108. PLIST_ENTRY ple, ple1, pleTmp, plePrev, pleAlias;
  109. PARG_ENTRY pae, paeArg;
  110. WCHAR wcTmp;
  111. paeArg = CONTAINING_RECORD(pleEntry, ARG_ENTRY, le);
  112. if (! paeArg->pwszArg)
  113. {
  114. return NO_ERROR;
  115. }
  116. pw1 = paeArg->pwszArg;
  117. //
  118. // Get each argument in the command. Argument within " must
  119. // be retained as is. The token delimiters are ' ' and '='
  120. //
  121. for (plePrev = pleEntry ; ; )
  122. {
  123. // Skip leading whitespace
  124. for(; *pw1 && *pw1 != L'#' && (*pw1 == L' ' || *pw1 == L'\t'); pw1++);
  125. // If it starts with a #, it's the same as an empty string
  126. if (*pw1 == L'#')
  127. *pw1 = L'\0';
  128. // If it's an empty string, we're done
  129. if (!(*pw1))
  130. {
  131. break;
  132. }
  133. if (*pw1 is L'"')
  134. {
  135. for (pw2 = pw1 + 1; *pw2 && *pw2 != L'"'; pw2++);
  136. if (*pw2)
  137. {
  138. pw2++;
  139. }
  140. }
  141. else if (*pw1 is L'=')
  142. {
  143. pw2 = pw1 + 1;
  144. }
  145. else
  146. {
  147. for(pw2 = pw1 + 1; *pw2 && *pw2 != L' ' && *pw2 != L'=' ; pw2++);
  148. }
  149. //
  150. // Add the new argument to the list.
  151. //
  152. pae = MALLOC(sizeof(ARG_ENTRY));
  153. if (pae is NULL)
  154. {
  155. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  156. break;
  157. }
  158. ple = &(pae->le);
  159. ple->Flink = plePrev->Flink;
  160. ple->Blink = plePrev;
  161. plePrev->Flink = ple;
  162. ple->Flink->Blink = ple;
  163. plePrev = ple;
  164. wcTmp = *pw2;
  165. *pw2 = L'\0';
  166. //
  167. // The argument could be an alias. If so replace it by
  168. // the original string.
  169. //
  170. if (bAlias)
  171. {
  172. ATLookupAliasTable(pw1, &pwszAlias);
  173. }
  174. else
  175. {
  176. pwszAlias = NULL;
  177. }
  178. if (pwszAlias)
  179. {
  180. pw1 = pwszAlias;
  181. dwLen = wcslen(pwszAlias) + 1;
  182. }
  183. else
  184. {
  185. dwLen = (DWORD)(pw2 - pw1 + 1);
  186. }
  187. pae->pwszArg = MALLOC(dwLen * sizeof(WCHAR));
  188. if (pae->pwszArg is NULL)
  189. {
  190. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  191. break;
  192. }
  193. // Convert /? and -? to just ?
  194. if (!wcscmp(pw1, L"/?") or !wcscmp(pw1, L"-?"))
  195. {
  196. pw1++;
  197. }
  198. wcscpy(pae->pwszArg, pw1);
  199. *pw2 = wcTmp;
  200. pw1 = pw2;
  201. }
  202. if (dwErr is NO_ERROR)
  203. {
  204. // Free the argument
  205. FREE(paeArg->pwszArg);
  206. pleEntry->Blink->Flink = pleEntry->Flink;
  207. pleEntry->Flink->Blink = pleEntry->Blink;
  208. FREE(paeArg);
  209. }
  210. return dwErr;
  211. }
  212. DWORD
  213. WINAPI
  214. UpdateNewContext(
  215. IN OUT LPWSTR pwszBuffer,
  216. IN LPCWSTR pwszNewToken,
  217. IN DWORD dwArgs
  218. )
  219. /*++
  220. pwszBuffer - a static buffer (should be g_pwszNewContext)
  221. currently this can't be dynamic since the context buffer
  222. would have to be an IN/OUT parameter to this function
  223. and hence to all monitor Entry points.
  224. --*/
  225. {
  226. DWORD dwErr;
  227. PLIST_ENTRY pleHead, pleNode;
  228. PARG_ENTRY pae;
  229. // Convert buffer to list
  230. dwErr = ConvertBufferToArgList( &pleHead, pwszBuffer );
  231. if (dwErr)
  232. {
  233. return dwErr;
  234. }
  235. // Locate in list
  236. for (pleNode = pleHead->Blink; dwArgs>1; pleNode=pleNode->Blink)
  237. {
  238. if (pleNode->Blink isnot pleHead)
  239. {
  240. pae = CONTAINING_RECORD(pleNode->Blink, ARG_ENTRY, le);
  241. if (!wcscmp(pae->pwszArg,L"="))
  242. {
  243. pleNode=pleNode->Blink; // back up over =
  244. if (pleNode->Blink isnot pleHead)
  245. {
  246. pleNode=pleNode->Blink; // back up over tag too
  247. }
  248. }
  249. }
  250. dwArgs--;
  251. }
  252. // Update in list
  253. pae = CONTAINING_RECORD(pleNode, ARG_ENTRY, le);
  254. FREE(pae->pwszArg);
  255. pae->pwszArg = MALLOC((wcslen(pwszNewToken)+1) * sizeof(WCHAR));
  256. if (pae->pwszArg is NULL)
  257. {
  258. return ERROR_NOT_ENOUGH_MEMORY;
  259. }
  260. wcscpy(pae->pwszArg, pwszNewToken);
  261. // Convert list to buffer
  262. dwErr = ConvertArgListToBuffer( pleHead, pwszBuffer );
  263. return dwErr;
  264. }
  265. DWORD
  266. GetNewContext(
  267. IN LPCWSTR pwszArgument,
  268. OUT LPWSTR *ppwszNewContext,
  269. OUT BOOL *pbContext
  270. )
  271. /*++
  272. Routine Description:
  273. Based on the first command argument and the current context,
  274. determines the context for the new command.
  275. Arguments:
  276. pwszArgument - First argument in the command line.
  277. ppwszNewContext - Pointer to the new context.
  278. pbContext - Is it a new context ?
  279. Return Value:
  280. ERROR_NOT_ENOUGH_MEMORY, NO_ERROR
  281. --*/
  282. {
  283. LPWSTR pwszNewContext, pwcToken, pw1, pwszArgumentCopy, pwszArgumentPtr;
  284. DWORD dwSize;
  285. pwszArgumentCopy = _wcsdup(pwszArgument);
  286. if ( pwszArgumentCopy is NULL )
  287. {
  288. *pbContext = FALSE;
  289. PrintMessageFromModule(g_hModule, MSG_NOT_ENOUGH_MEMORY);
  290. return ERROR_NOT_ENOUGH_MEMORY;
  291. }
  292. pwszArgumentPtr = pwszArgumentCopy;
  293. //
  294. // New Context cannot be longer than the combined lengths
  295. // of pwszArgument and g_pwszContext.
  296. //
  297. dwSize = wcslen(pwszArgumentCopy) + wcslen(g_pwszContext) + 2;
  298. pwszNewContext = MALLOC(dwSize * sizeof(WCHAR));
  299. if (pwszNewContext is NULL)
  300. {
  301. *pbContext = FALSE;
  302. PrintMessageFromModule(g_hModule, MSG_NOT_ENOUGH_MEMORY);
  303. free(pwszArgumentPtr);
  304. return ERROR_NOT_ENOUGH_MEMORY;
  305. }
  306. if (pwszArgumentCopy[0] is L'\\')
  307. {
  308. //
  309. // The context is an absolute one.
  310. //
  311. pwszNewContext[0] = L'\0';
  312. pwszArgumentCopy++;
  313. *pbContext = TRUE;
  314. }
  315. else
  316. {
  317. //
  318. // Context is relative to current.
  319. //
  320. wcscpy(pwszNewContext,g_pwszContext);
  321. }
  322. if ((pwcToken = wcstok(pwszArgumentCopy, L"\\" )) is NULL)
  323. {
  324. *ppwszNewContext = pwszNewContext;
  325. free(pwszArgumentPtr);
  326. return NO_ERROR;
  327. }
  328. do
  329. {
  330. if (_wcsicmp(pwcToken, L"..") == 0)
  331. {
  332. //
  333. // Go back one level. If already at root, ignore.
  334. //
  335. if (_wcsicmp(pwszNewContext,L"\\") == 0)
  336. {
  337. }
  338. else
  339. {
  340. pw1 = wcsrchr(pwszNewContext,L'\\');
  341. if (pw1)
  342. {
  343. *pw1 = L'\0';
  344. }
  345. }
  346. *pbContext = TRUE;
  347. }
  348. else
  349. {
  350. //
  351. // add this level to context
  352. //
  353. wcscat(pwszNewContext,L"\\");
  354. wcscat(pwszNewContext,pwcToken);
  355. *pbContext = TRUE;
  356. }
  357. } while ((pwcToken = wcstok((LPWSTR)NULL, L"\\" )) != NULL);
  358. *ppwszNewContext = pwszNewContext;
  359. free(pwszArgumentPtr);
  360. return NO_ERROR;
  361. }
  362. DWORD
  363. AppendString(
  364. IN OUT LPWSTR *ppwszBuffer,
  365. IN LPCWSTR pwszString
  366. )
  367. {
  368. LPWSTR pwszNewBuffer;
  369. DWORD dwLen;
  370. if (*ppwszBuffer is NULL) {
  371. dwLen = wcslen(pwszString) + 1;
  372. pwszNewBuffer = MALLOC( dwLen * sizeof(WCHAR));
  373. if (pwszNewBuffer) {
  374. pwszNewBuffer[0] = 0;
  375. }
  376. } else {
  377. dwLen = wcslen(*ppwszBuffer) + wcslen(pwszString) + 1;
  378. pwszNewBuffer = REALLOC( *ppwszBuffer, dwLen * sizeof(WCHAR));
  379. }
  380. if (!pwszNewBuffer)
  381. {
  382. return ERROR_NOT_ENOUGH_MEMORY;
  383. }
  384. *ppwszBuffer = pwszNewBuffer;
  385. wcscat(pwszNewBuffer, pwszString);
  386. return NO_ERROR;
  387. }
  388. VOID
  389. ConvertArgArrayToBuffer(
  390. IN DWORD dwArgCount,
  391. IN LPCWSTR *argv,
  392. OUT LPWSTR *ppwszBuffer
  393. )
  394. {
  395. DWORD i;
  396. #ifdef EXTRA_DEBUG
  397. PRINT1("In ConvertArgArrayToBuffer:");
  398. for( i = 0; i < dwArgCount; i++)
  399. {
  400. PRINT(argv[i]);
  401. }
  402. #endif
  403. // Initial string to empty
  404. *ppwszBuffer = NULL;
  405. for (i=0; i<dwArgCount; i++)
  406. {
  407. if (i)
  408. {
  409. AppendString(ppwszBuffer, L" ");
  410. }
  411. if (wcschr(argv[i], L' '))
  412. {
  413. AppendString(ppwszBuffer, L"\"");
  414. AppendString(ppwszBuffer, argv[i]);
  415. AppendString(ppwszBuffer, L"\"");
  416. }
  417. else
  418. {
  419. AppendString(ppwszBuffer, argv[i]);
  420. }
  421. }
  422. #ifdef EXTRA_DEBUG
  423. PRINT1("At end of ConvertArgArrayToBuffer:");
  424. PRINT(*ppwszBuffer);
  425. #endif
  426. }
  427. VOID
  428. SetContext(
  429. IN LPCWSTR wszNewContext
  430. )
  431. {
  432. wcscpy(g_pwszContext, wszNewContext);
  433. _wcslwr(g_pwszContext);
  434. }
  435. BOOL
  436. IsImmediate(
  437. IN DWORD dwCmdFlags,
  438. IN DWORD dwRemainingArgs
  439. )
  440. /*++
  441. Description:
  442. Determines whether a command was "immediate". A command is immediate
  443. if the context in which it exists was the current context in the
  444. shell.
  445. Returns:
  446. TRUE if command is "immediate", FALSE if not
  447. --*/
  448. {
  449. if (!(dwCmdFlags & CMD_FLAG_PRIVATE))
  450. {
  451. return FALSE;
  452. }
  453. // One way to tell is to get the current context arg count,
  454. // the total arg count, and the remaining arg count.
  455. return (g_dwContextArgCount + dwRemainingArgs is g_dwTotalArgCount);
  456. }
  457. DWORD
  458. ProcessHelperCommand2(
  459. IN PCNS_CONTEXT_ATTRIBUTES pContext,
  460. IN DWORD dwArgCount,
  461. IN OUT LPWSTR *argv,
  462. IN DWORD dwDisplayFlags,
  463. OUT BOOL *pbDone
  464. )
  465. {
  466. PNS_CONTEXT_ENTRY_FN pfnEntryPt;
  467. DWORD dwRes, dwIdx;
  468. LPWSTR pwszNewContext = NULL;
  469. LPWSTR pwszOrigContext = NULL;
  470. if (pContext->dwFlags & ~dwDisplayFlags)
  471. {
  472. return ERROR_CMD_NOT_FOUND;
  473. }
  474. pfnEntryPt = (!pContext->pReserved) ? NULL : ((PNS_PRIV_CONTEXT_ATTRIBUTES)pContext->pReserved)->pfnEntryFn;
  475. // If arg was abbreviated, replace argv[0] with expanded name
  476. if (wcscmp(argv[0], pContext->pwszContext))
  477. {
  478. pwszOrigContext = argv[0];
  479. argv[0] = pContext->pwszContext;
  480. }
  481. ConvertArgArrayToBuffer(dwArgCount, argv, &pwszNewContext);
  482. if (pwszNewContext)
  483. {
  484. wcsncpy(g_pwszNewContext, pwszNewContext, MAX_CMD_LEN);
  485. //
  486. // this is something of a hack - we put the NULL 100 chars before the end of the buffer to prevent a buffer overrun later
  487. // in UpdateNewContext: 190933 netsh hit an AV on netsh!._wcsnicmp
  488. //
  489. g_pwszNewContext[ MAX_CMD_LEN - 100 ] = 0;
  490. FREE(pwszNewContext);
  491. pwszNewContext = NULL;
  492. }
  493. //
  494. // Call the entry point of helper.
  495. //
  496. if (pfnEntryPt)
  497. {
  498. dwRes = (*pfnEntryPt)(g_pwszRouterName,
  499. argv, // + 1,
  500. dwArgCount, // - 1,
  501. dwDisplayFlags,
  502. NULL,
  503. g_pwszNewContext);
  504. }
  505. else
  506. {
  507. dwRes = GenericMonitor(pContext,
  508. g_pwszRouterName,
  509. argv, // + 1,
  510. dwArgCount, // - 1,
  511. dwDisplayFlags,
  512. NULL,
  513. g_pwszNewContext);
  514. }
  515. if (pwszOrigContext)
  516. {
  517. argv[0] = pwszOrigContext;
  518. }
  519. if (dwRes isnot NO_ERROR)
  520. {
  521. if (dwRes is ERROR_CONTEXT_SWITCH)
  522. {
  523. if (!(dwDisplayFlags & CMD_FLAG_INTERACTIVE))
  524. {
  525. LPWSTR *argv2 = MALLOC((dwArgCount+1) * sizeof(LPWSTR));
  526. if (argv2 is NULL)
  527. {
  528. return ERROR_NOT_ENOUGH_MEMORY;
  529. }
  530. CopyMemory(argv2, argv, dwArgCount * sizeof(LPWSTR));
  531. argv2[dwArgCount] = MALLOC((wcslen(CMD_HELP2)+1) * sizeof(WCHAR));
  532. if (argv2[dwArgCount] is NULL)
  533. {
  534. dwRes = ERROR_NOT_ENOUGH_MEMORY;
  535. }
  536. else
  537. {
  538. wcscpy(argv2[dwArgCount], CMD_HELP2);
  539. g_dwTotalArgCount = dwArgCount+1;
  540. dwRes = ProcessHelperCommand2(pContext,
  541. dwArgCount+1,
  542. argv2,
  543. dwDisplayFlags,
  544. pbDone);
  545. FREE(argv2[dwArgCount]);
  546. }
  547. FREE(argv2);
  548. return dwRes;
  549. }
  550. //
  551. // A context switch.
  552. //
  553. SetContext(g_pwszNewContext);
  554. dwRes = NO_ERROR;
  555. }
  556. else if (dwRes is ERROR_CONNECT_REMOTE_CONFIG)
  557. {
  558. PrintMessageFromModule(g_hModule, EMSG_REMOTE_CONNECT_FAILED,
  559. g_pwszRouterName);
  560. *pbDone = TRUE;
  561. }
  562. }
  563. return dwRes;
  564. }
  565. DWORD
  566. WINAPI
  567. ProcessHelperCommand(
  568. IN DWORD dwArgCount,
  569. IN OUT LPWSTR *argv,
  570. IN DWORD dwDisplayFlags,
  571. // OUT LPWSTR *ppwszNewContext,
  572. OUT BOOL *pbDone
  573. )
  574. {
  575. PCNS_CONTEXT_ATTRIBUTES pContext;
  576. PNS_CONTEXT_ENTRY_FN pfnEntryPt;
  577. DWORD dwRes, dwIdx;
  578. LPWSTR pwszNewContext = NULL;
  579. LPWSTR pwszOrigContext = NULL;
  580. PNS_HELPER_TABLE_ENTRY pHelper;
  581. dwRes = GetRootContext( &pContext, &pHelper);
  582. if (dwRes)
  583. {
  584. return dwRes;
  585. }
  586. dwRes = GetContextEntry(pHelper, argv[0], &pContext);
  587. if (dwRes isnot NO_ERROR)
  588. {
  589. return ERROR_CMD_NOT_FOUND;
  590. }
  591. if (pContext->dwFlags & ~dwDisplayFlags)
  592. {
  593. return ERROR_CMD_NOT_FOUND;
  594. }
  595. #if 1
  596. pfnEntryPt = (!pContext->pReserved) ? NULL : ((PNS_PRIV_CONTEXT_ATTRIBUTES)pContext->pReserved)->pfnEntryFn;
  597. #else
  598. dwRes = GetHelperAttributes(dwIdx, &pfnEntryPt);
  599. if (dwRes != NO_ERROR)
  600. {
  601. //
  602. // Could not find helper or could not load the DLL
  603. //
  604. return dwRes;
  605. }
  606. #endif
  607. // If arg was abbreviated, replace argv[0] with expanded name
  608. if (wcscmp(argv[0], pContext->pwszContext))
  609. {
  610. pwszOrigContext = argv[0];
  611. argv[0] = pContext->pwszContext;
  612. }
  613. ConvertArgArrayToBuffer(dwArgCount, argv, &pwszNewContext);
  614. if (pwszNewContext)
  615. {
  616. wcsncpy(g_pwszNewContext, pwszNewContext, MAX_CMD_LEN);
  617. g_pwszNewContext[ MAX_CMD_LEN - 1 ] = '\0';
  618. FREE(pwszNewContext);
  619. pwszNewContext = NULL;
  620. }
  621. //
  622. // Call the entry point of helper.
  623. //
  624. if (pfnEntryPt)
  625. {
  626. dwRes = (*pfnEntryPt)(g_pwszRouterName,
  627. argv + 1,
  628. dwArgCount - 1,
  629. dwDisplayFlags,
  630. NULL,
  631. g_pwszNewContext);
  632. }
  633. else
  634. {
  635. dwRes = GenericMonitor(pContext,
  636. g_pwszRouterName,
  637. argv + 1,
  638. dwArgCount - 1,
  639. dwDisplayFlags,
  640. NULL,
  641. g_pwszNewContext);
  642. }
  643. if (pwszOrigContext)
  644. {
  645. argv[0] = pwszOrigContext;
  646. }
  647. if (dwRes isnot NO_ERROR)
  648. {
  649. if (dwRes is ERROR_CONTEXT_SWITCH)
  650. {
  651. if (!(dwDisplayFlags & CMD_FLAG_INTERACTIVE))
  652. {
  653. LPWSTR *argv2 = MALLOC((dwArgCount+1) * sizeof(LPWSTR));
  654. if (argv2 is NULL)
  655. {
  656. return ERROR_NOT_ENOUGH_MEMORY;
  657. }
  658. CopyMemory(argv2, argv, dwArgCount * sizeof(LPWSTR));
  659. argv2[dwArgCount] = MALLOC((wcslen(CMD_HELP2)+1) * sizeof(WCHAR));
  660. if (argv2[dwArgCount] is NULL)
  661. {
  662. dwRes = ERROR_NOT_ENOUGH_MEMORY;
  663. }
  664. else
  665. {
  666. wcscpy(argv2[dwArgCount], CMD_HELP2);
  667. g_dwTotalArgCount = dwArgCount+1;
  668. dwRes = ProcessHelperCommand(dwArgCount+1,
  669. argv2,
  670. dwDisplayFlags,
  671. pbDone);
  672. FREE(argv2[dwArgCount]);
  673. }
  674. FREE(argv2);
  675. return dwRes;
  676. }
  677. //
  678. // A context switch.
  679. //
  680. SetContext(g_pwszNewContext);
  681. dwRes = NO_ERROR;
  682. }
  683. else if (dwRes is ERROR_CONNECT_REMOTE_CONFIG)
  684. {
  685. PrintMessageFromModule(g_hModule, EMSG_REMOTE_CONNECT_FAILED,
  686. g_pwszRouterName);
  687. *pbDone = TRUE;
  688. }
  689. }
  690. return dwRes;
  691. }
  692. DWORD
  693. WINAPI
  694. ExecuteHandler(
  695. IN HANDLE hModule,
  696. IN CMD_ENTRY *pCmdEntry,
  697. IN OUT LPWSTR *argv,
  698. IN DWORD dwNumMatched,
  699. IN DWORD dwArgCount,
  700. IN DWORD dwFlags,
  701. IN LPCVOID pvData,
  702. IN LPCWSTR pwszGroupName,
  703. OUT BOOL *pbDone)
  704. {
  705. DWORD dwErr = NO_ERROR;
  706. if (((dwArgCount - dwNumMatched) == 1)
  707. && IsHelpToken(argv[dwNumMatched]))
  708. {
  709. dwErr = ERROR_SHOW_USAGE;
  710. }
  711. else
  712. {
  713. //
  714. // Call the parsing routine for the command
  715. //
  716. dwErr = pCmdEntry->pfnCmdHandler( g_pwszRouterName,
  717. argv,
  718. dwNumMatched,
  719. dwArgCount,
  720. dwFlags,
  721. pvData,
  722. pbDone );
  723. }
  724. if (dwErr is ERROR_INVALID_SYNTAX)
  725. {
  726. PrintError(NULL, dwErr);
  727. dwErr = ERROR_SHOW_USAGE;
  728. }
  729. switch (dwErr) {
  730. case ERROR_SHOW_USAGE:
  731. //
  732. // If the only argument is a help token, just
  733. // display the help.
  734. //
  735. if (NULL != pwszGroupName)
  736. {
  737. LPWSTR pwszGroupFullCmd = (LPWSTR)
  738. MALLOC( ( wcslen(pwszGroupName) +
  739. wcslen(pCmdEntry->pwszCmdToken) +
  740. 2 // for blank and NULL characters
  741. ) * sizeof(WCHAR)
  742. );
  743. if (NULL == pwszGroupFullCmd)
  744. {
  745. // we still try to print without group name
  746. dwErr = PrintMessageFromModule( hModule,
  747. pCmdEntry->dwCmdHlpToken,
  748. pCmdEntry->pwszCmdToken );
  749. }
  750. else
  751. {
  752. wcscpy(pwszGroupFullCmd, pwszGroupName);
  753. wcscat(pwszGroupFullCmd, L" ");
  754. wcscat(pwszGroupFullCmd, pCmdEntry->pwszCmdToken);
  755. dwErr = PrintMessageFromModule( hModule,
  756. pCmdEntry->dwCmdHlpToken,
  757. pwszGroupFullCmd );
  758. FREE(pwszGroupFullCmd);
  759. }
  760. }
  761. else
  762. {
  763. dwErr = PrintMessageFromModule( hModule,
  764. pCmdEntry->dwCmdHlpToken,
  765. pCmdEntry->pwszCmdToken );
  766. }
  767. break;
  768. case NO_ERROR:
  769. case ERROR_SUPPRESS_OUTPUT:
  770. break;
  771. case ERROR_OKAY:
  772. if (!g_bQuiet)
  773. {
  774. PrintMessageFromModule( NULL, MSG_OKAY);
  775. }
  776. dwErr = NO_ERROR;
  777. break;
  778. default:
  779. PrintError(NULL, dwErr);
  780. break;
  781. }
  782. if (!g_bQuiet)
  783. {
  784. PrintMessage( MSG_NEWLINE );
  785. }
  786. return dwErr;
  787. }
  788. BOOL
  789. ProcessGroupCommand(
  790. IN DWORD dwArgCount,
  791. IN PTCHAR *argv,
  792. IN DWORD dwDisplayFlags,
  793. OUT BOOL *pbDone
  794. )
  795. {
  796. BOOL bFound = FALSE;
  797. DWORD i, j, dwNumMatched, dwErr;
  798. for(i = 0; i < g_ulNumGroups; i++)
  799. {
  800. if (g_ShellCmdGroups[i].dwFlags & ~dwDisplayFlags)
  801. {
  802. continue;
  803. }
  804. if (MatchToken(argv[0],
  805. g_ShellCmdGroups[i].pwszCmdGroupToken))
  806. {
  807. // See if it's a request for help
  808. if ((dwArgCount < 2) || IsHelpToken(argv[1]))
  809. {
  810. PCNS_CONTEXT_ATTRIBUTES pContext;
  811. dwErr = GetRootContext(&pContext, NULL);
  812. if (dwErr is NO_ERROR)
  813. {
  814. dwErr = DisplayContextHelp(
  815. pContext,
  816. CMD_FLAG_PRIVATE,
  817. dwDisplayFlags,
  818. dwArgCount-2+1,
  819. g_ShellCmdGroups[i].pwszCmdGroupToken );
  820. }
  821. return TRUE;
  822. }
  823. //
  824. // Command matched entry i, so look at the table of sub commands
  825. // for this command
  826. //
  827. for (j = 0; j < g_ShellCmdGroups[i].ulCmdGroupSize; j++)
  828. {
  829. if (g_ShellCmdGroups[i].pCmdGroup[j].dwFlags
  830. & ~dwDisplayFlags)
  831. {
  832. continue;
  833. }
  834. if (MatchCmdLine(argv,
  835. dwArgCount,
  836. g_ShellCmdGroups[i].pCmdGroup[j].pwszCmdToken,
  837. &dwNumMatched))
  838. {
  839. bFound = TRUE;
  840. dwErr = ExecuteHandler(g_hModule,
  841. &g_ShellCmdGroups[i].pCmdGroup[j],
  842. argv, dwNumMatched, dwArgCount,
  843. dwDisplayFlags,
  844. NULL,
  845. g_ShellCmdGroups[i].pwszCmdGroupToken,
  846. pbDone);
  847. //
  848. // quit the for(j)
  849. //
  850. break;
  851. }
  852. }
  853. break;
  854. }
  855. }
  856. return bFound;
  857. }
  858. DWORD
  859. LookupCommandHandler(
  860. IN LPCWSTR pwszCmd
  861. )
  862. {
  863. // Eventually, we want to look up commands in sub-contexts first,
  864. // and end up with the global context. For now, we'll just do global.
  865. DWORD i;
  866. for (i = 0; i < g_ulNumShellCmds; i++)
  867. {
  868. if (MatchToken(pwszCmd, g_ShellCmds[i].pwszCmdToken))
  869. {
  870. return i;
  871. }
  872. }
  873. return -1;
  874. }
  875. VOID
  876. FreeArgArray(
  877. DWORD argc,
  878. LPWSTR *argv
  879. )
  880. {
  881. DWORD i;
  882. for (i = 0; i < argc; i++)
  883. {
  884. FREE(argv[i]);
  885. }
  886. FREE(argv);
  887. }
  888. DWORD
  889. ConvertArgListToBuffer(
  890. IN PLIST_ENTRY pleHead,
  891. OUT LPWSTR pwszBuffer
  892. )
  893. {
  894. PLIST_ENTRY ple;
  895. PARG_ENTRY pae;
  896. LPWSTR p = pwszBuffer;
  897. *p = '\0';
  898. for (ple = pleHead->Flink; ple != pleHead; ple = ple->Flink )
  899. {
  900. pae = CONTAINING_RECORD(ple, ARG_ENTRY, le);
  901. if (p isnot pwszBuffer)
  902. {
  903. *p++ = ' ';
  904. }
  905. wcscpy(p, pae->pwszArg);
  906. p += wcslen(p);
  907. }
  908. return NO_ERROR;
  909. }
  910. DWORD
  911. AppendArgument(
  912. IN OUT LPWSTR **pargv,
  913. IN DWORD i,
  914. IN LPCWSTR pwszString
  915. )
  916. {
  917. DWORD dwErr;
  918. dwErr = AppendString( &(*pargv)[i], pwszString );
  919. if ((*pargv)[i] is NULL) {
  920. FreeArgArray(i, *pargv);
  921. *pargv = NULL;
  922. return ERROR_NOT_ENOUGH_MEMORY;
  923. }
  924. return NO_ERROR;
  925. }
  926. DWORD
  927. ConvertArgListToArray(
  928. IN PLIST_ENTRY pleContextHead,
  929. IN PLIST_ENTRY pleHead,
  930. OUT PDWORD pargc,
  931. OUT LPWSTR **pargv,
  932. OUT PDWORD pdwContextArgc
  933. )
  934. {
  935. DWORD dwErr = NO_ERROR;
  936. DWORD argc = 0, i;
  937. LPWSTR *argv = NULL, p;
  938. BOOL bEqualTo;
  939. PLIST_ENTRY ple;
  940. PARG_ENTRY pae;
  941. #ifdef EXTRA_DEBUG
  942. if (pleHead)
  943. {
  944. PLIST_ENTRY ple;
  945. PRINT1("In ConvertArgListToArray:");
  946. for (ple = pleHead->Flink; ple != pleHead; ple = ple->Flink)
  947. {
  948. pae = CONTAINING_RECORD(ple, ARG_ENTRY, le);
  949. PRINT(pae->pwszArg);
  950. }
  951. }
  952. #endif
  953. // Count tokens
  954. if (pleContextHead)
  955. {
  956. for (ple = pleContextHead->Flink; ple != pleContextHead; ple = ple->Flink)
  957. argc++;
  958. }
  959. *pdwContextArgc = argc;
  960. for (ple = pleHead->Flink; ple != pleHead; ple = ple->Flink)
  961. argc++;
  962. do {
  963. if (!argc)
  964. break;
  965. //
  966. // Allocate space for arguments
  967. //
  968. argv = MALLOC(argc * sizeof(LPCWSTR));
  969. if (argv is NULL)
  970. {
  971. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  972. break;
  973. }
  974. memset(argv, 0, argc * sizeof(LPCWSTR));
  975. bEqualTo = FALSE;
  976. //
  977. // Copy the arguments from the list into an argv kind of
  978. // structure. At this point, the arguments tag, '=' and
  979. // the value are made into one argument tag=value.
  980. //
  981. //
  982. // Copy context
  983. //
  984. i = 0;
  985. if (pleContextHead)
  986. {
  987. for (ple = pleContextHead->Flink;
  988. ple != pleContextHead;
  989. ple = ple->Flink)
  990. {
  991. pae = CONTAINING_RECORD(ple, ARG_ENTRY, le);
  992. dwErr = AppendArgument( &argv, i++, pae->pwszArg );
  993. if ( dwErr isnot NO_ERROR ) {
  994. break;
  995. }
  996. }
  997. }
  998. for (ple = pleHead->Flink; ple != pleHead; ple = ple->Flink )
  999. {
  1000. pae = CONTAINING_RECORD(ple, ARG_ENTRY, le);
  1001. //
  1002. // Remove any " from the string name
  1003. //
  1004. if (pae->pwszArg[0] == L'"')
  1005. {
  1006. if (bEqualTo)
  1007. {
  1008. dwErr=AppendArgument(&argv, i-1, pae->pwszArg+1);
  1009. if ( dwErr isnot NO_ERROR ) {
  1010. break;
  1011. }
  1012. bEqualTo = FALSE;
  1013. }
  1014. else
  1015. {
  1016. dwErr=AppendArgument(&argv, i++, pae->pwszArg+1);
  1017. if (dwErr isnot NO_ERROR ) {
  1018. break;
  1019. }
  1020. }
  1021. p = argv[i-1];
  1022. if (p[wcslen(p) - 1] == L'"')
  1023. {
  1024. p[wcslen(p) - 1] = L'\0';
  1025. }
  1026. continue;
  1027. }
  1028. //
  1029. // combine arguments of the form tag = value
  1030. //
  1031. if ((wcscmp(pae->pwszArg,L"=") == 0) || bEqualTo)
  1032. {
  1033. bEqualTo = (bEqualTo) ? FALSE : TRUE;
  1034. if (i > 0)
  1035. {
  1036. i--;
  1037. }
  1038. dwErr = AppendArgument( &argv, i++, pae->pwszArg);
  1039. if (dwErr isnot NO_ERROR ) {
  1040. break;
  1041. }
  1042. }
  1043. else
  1044. {
  1045. dwErr = AppendArgument( &argv, i++, pae->pwszArg);
  1046. if (dwErr isnot NO_ERROR ) {
  1047. break;
  1048. }
  1049. }
  1050. }
  1051. } while (FALSE);
  1052. #ifdef EXTRA_DEBUG
  1053. PRINT1("At end of ConvertArgListToArray:");
  1054. for( i = 0; i < argc; i++)
  1055. {
  1056. PRINT(argv[i]);
  1057. }
  1058. #endif
  1059. *pargc = i;
  1060. *pargv = argv;
  1061. return dwErr;
  1062. }
  1063. DWORD
  1064. ConvertBufferToArgList(
  1065. PLIST_ENTRY *ppleHead,
  1066. LPCWSTR pwszBuffer
  1067. )
  1068. {
  1069. PLIST_ENTRY pleHead = NULL;
  1070. DWORD dwErr = NO_ERROR;
  1071. PARG_ENTRY pae;
  1072. #ifdef EXTRA_DEBUG
  1073. PRINT1("In ConvertBufferToArgList:");
  1074. PRINT(pwszBuffer);
  1075. #endif
  1076. do {
  1077. //
  1078. // First convert the command line to a list of tokens
  1079. //
  1080. pleHead = MALLOC(sizeof(LIST_ENTRY));
  1081. if (pleHead is NULL)
  1082. {
  1083. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  1084. break;
  1085. }
  1086. InitializeListHead(pleHead);
  1087. pae = MALLOC(sizeof(ARG_ENTRY));
  1088. if (pae is NULL)
  1089. {
  1090. FREE(pleHead);
  1091. pleHead = NULL;
  1092. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  1093. break;
  1094. }
  1095. pae->pwszArg = MALLOC((wcslen(pwszBuffer)+1) * sizeof(WCHAR));
  1096. if (pae->pwszArg is NULL)
  1097. {
  1098. FREE(pleHead);
  1099. FREE(pae);
  1100. pleHead = NULL;
  1101. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  1102. break;
  1103. }
  1104. wcscpy(pae->pwszArg, pwszBuffer);
  1105. InsertHeadList(pleHead, &(pae->le));
  1106. dwErr = ParseCommand(pleHead->Flink, FALSE);
  1107. if (dwErr isnot NO_ERROR)
  1108. {
  1109. FREE_ARG_LIST(pleHead);
  1110. pleHead = NULL;
  1111. break;
  1112. }
  1113. } while (FALSE);
  1114. #ifdef EXTRA_DEBUG
  1115. if (pleHead)
  1116. {
  1117. PLIST_ENTRY ple;
  1118. PRINT1("At end of ConvertBufferToArgList:");
  1119. for (ple = pleHead->Flink; ple != pleHead; ple = ple->Flink)
  1120. {
  1121. pae = CONTAINING_RECORD(ple, ARG_ENTRY, le);
  1122. PRINT(pae->pwszArg);
  1123. }
  1124. }
  1125. #endif
  1126. *ppleHead = pleHead;
  1127. if (dwErr is ERROR_NOT_ENOUGH_MEMORY)
  1128. PrintMessageFromModule(g_hModule, MSG_NOT_ENOUGH_MEMORY);
  1129. return dwErr;
  1130. }
  1131. DWORD
  1132. ProcessShellCommand(
  1133. IN DWORD dwArgCount,
  1134. IN OUT LPWSTR *argv,
  1135. IN DWORD dwDisplayFlags,
  1136. // OUT LPWSTR *ppwszNewContext,
  1137. OUT BOOL *pbDone
  1138. )
  1139. {
  1140. DWORD i;
  1141. for (i = 0; i < g_ulNumShellCmds; i++)
  1142. {
  1143. if (g_ShellCmds[i].dwFlags & ~dwDisplayFlags)
  1144. {
  1145. continue;
  1146. }
  1147. if (MatchToken( argv[0],
  1148. g_ShellCmds[i].pwszCmdToken ))
  1149. {
  1150. return ExecuteHandler( g_hModule,
  1151. &g_ShellCmds[i],
  1152. argv,
  1153. 1,
  1154. dwArgCount,
  1155. dwDisplayFlags,
  1156. NULL,
  1157. NULL,
  1158. pbDone );
  1159. }
  1160. }
  1161. return ERROR_CMD_NOT_FOUND;
  1162. }
  1163. DWORD
  1164. ProcessCommand(
  1165. IN LPCWSTR pwszCmdLine,
  1166. OUT BOOL *pbDone
  1167. )
  1168. /*++
  1169. Routine Description:
  1170. Executes command if it is for the shell or else calls the
  1171. corresponding helper routine.
  1172. Arguments:
  1173. pwszCmdLine - The command line to be executed.
  1174. Return Value:
  1175. TRUE, FALSE - (Whether to quit the program or not)
  1176. --*/
  1177. {
  1178. LPCWSTR pwszAliasString = NULL;
  1179. DWORD dwRes = NO_ERROR, i, dwLen, j;
  1180. WCHAR wszAliasString[MAX_CMD_LEN],
  1181. pwszContext[MAX_CMD_LEN];
  1182. WCHAR pwszCommandLine[MAX_CMD_LEN],*pwszNewContext;
  1183. LPCWSTR pwcAliasString, pw1,pw2,pw3;
  1184. BOOL bContext, bEqualTo, bTmp;
  1185. LPCWSTR pwszArg0, pwszArg1, pwszArg2;
  1186. PLIST_ENTRY ple, ple1, ple2, pleHead, pleTmp, pleNext;
  1187. PLIST_ENTRY pleContextHead;
  1188. PARG_ENTRY pae;
  1189. DWORD dwArgCount = 0, dwContextArgCount = 0;
  1190. LPWSTR *argv, pwcNewContext = NULL;
  1191. BOOL bShellCmd, bAlias, bFound = FALSE, dwDisplayFlags;
  1192. PCNS_CONTEXT_ATTRIBUTES pContext;
  1193. *pbDone = FALSE;
  1194. dwDisplayFlags = (g_bInteractive)? CMD_FLAG_INTERACTIVE : 0;
  1195. dwDisplayFlags |= ~CMD_FLAG_LIMIT_MASK;
  1196. // Command is executed on the local machine if router name is null
  1197. if (!g_pwszRouterName)
  1198. {
  1199. dwDisplayFlags |= CMD_FLAG_LOCAL;
  1200. }
  1201. if (g_bCommit)
  1202. {
  1203. dwDisplayFlags |= CMD_FLAG_ONLINE;
  1204. }
  1205. if (g_bVerbose)
  1206. {
  1207. PrintMessage(L"> %1!s!\n", pwszCmdLine);
  1208. }
  1209. dwRes = ConvertBufferToArgList(&pleContextHead, g_pwszContext);
  1210. if (dwRes isnot NO_ERROR)
  1211. {
  1212. *pbDone = TRUE;
  1213. return dwRes;
  1214. }
  1215. dwRes = ConvertBufferToArgList(&pleHead, pwszCmdLine);
  1216. if (dwRes isnot NO_ERROR)
  1217. {
  1218. FREE_ARG_LIST(pleContextHead);
  1219. *pbDone = TRUE;
  1220. return dwRes;
  1221. }
  1222. if (IsListEmpty(pleHead))
  1223. {
  1224. FREE_ARG_LIST(pleHead);
  1225. FREE_ARG_LIST(pleContextHead);
  1226. return NO_ERROR;
  1227. }
  1228. // Expand alias (not recursive)
  1229. dwRes = ParseCommand(pleHead->Flink, TRUE);
  1230. if (dwRes isnot NO_ERROR)
  1231. {
  1232. FREE_ARG_LIST(pleHead);
  1233. FREE_ARG_LIST(pleContextHead);
  1234. *pbDone = TRUE;
  1235. return dwRes;
  1236. }
  1237. #ifdef EXTRA_DEBUG
  1238. PRINT1("In ProcessCommand 2:");
  1239. for (ple = pleHead->Flink; ple != pleHead; ple = ple->Flink)
  1240. {
  1241. pae = CONTAINING_RECORD(ple, ARG_ENTRY, le);
  1242. PRINT(pae->pwszArg);
  1243. }
  1244. #endif
  1245. // Go through and expand any multi-tokens args into separate args
  1246. for (ple = (pleHead->Flink); ple != pleHead; ple = pleNext)
  1247. {
  1248. pleNext = ple->Flink;
  1249. dwRes = ParseCommand(ple, FALSE);
  1250. if (dwRes isnot NO_ERROR)
  1251. {
  1252. break;
  1253. }
  1254. }
  1255. if (dwRes isnot NO_ERROR)
  1256. {
  1257. FREE_ARG_LIST(pleHead);
  1258. FREE_ARG_LIST(pleContextHead);
  1259. *pbDone = TRUE;
  1260. return dwRes;
  1261. }
  1262. #ifdef EXTRA_DEBUG
  1263. PRINT1("In ProcessCommand 3:");
  1264. for (ple = pleHead->Flink; ple != pleHead; ple = ple->Flink)
  1265. {
  1266. pae = CONTAINING_RECORD(ple, ARG_ENTRY, le);
  1267. PRINT(pae->pwszArg);
  1268. }
  1269. #endif
  1270. //
  1271. // At this point, we should have a fully formed command,
  1272. // hopefully operable within the current context.
  1273. // The first token may be a command. If so, then the args
  1274. // will be the context followed by the rest of the tokens.
  1275. // If the first token is not a command, then the args will
  1276. // be the context followed by all the tokens.
  1277. //
  1278. if (IsListEmpty(pleHead))
  1279. {
  1280. FREE_ARG_LIST(pleHead);
  1281. FREE_ARG_LIST(pleContextHead);
  1282. return NO_ERROR;
  1283. }
  1284. pae = CONTAINING_RECORD(pleHead->Flink, ARG_ENTRY, le);
  1285. pwszArg0 = pae->pwszArg;
  1286. GetRootContext( &g_CurrentContext, &g_CurrentHelper );
  1287. do
  1288. {
  1289. // In the first context (only) we try, private commands are valid.
  1290. dwDisplayFlags |= CMD_FLAG_PRIVATE;
  1291. pContext = g_CurrentContext;
  1292. for(;;)
  1293. {
  1294. dwRes = ConvertArgListToArray( pleContextHead,
  1295. pleHead,
  1296. &dwArgCount,
  1297. &argv,
  1298. &dwContextArgCount );
  1299. g_dwTotalArgCount = dwArgCount;
  1300. g_dwContextArgCount = dwContextArgCount;
  1301. #if 1
  1302. # if 1
  1303. dwRes = ProcessHelperCommand2( pContext,
  1304. dwArgCount,
  1305. argv,
  1306. dwDisplayFlags,
  1307. pbDone );
  1308. # else
  1309. dwRes = GenericMonitor( pContext,
  1310. g_pwszRouterName,
  1311. argv,
  1312. dwArgCount,
  1313. dwDisplayFlags,
  1314. NULL,
  1315. g_pwszNewContext );
  1316. # endif
  1317. #else
  1318. {
  1319. if (!ProcessGroupCommand(dwArgCount, argv, dwDisplayFlags, pbDone))
  1320. {
  1321. //
  1322. // Having got the context and the command, see if there
  1323. // is a helper for it.
  1324. //
  1325. dwRes = ProcessHelperCommand( dwArgCount,
  1326. argv,
  1327. dwDisplayFlags,
  1328. // &pwszNewContext,
  1329. pbDone );
  1330. if (dwRes is ERROR_CMD_NOT_FOUND)
  1331. {
  1332. dwRes = ProcessShellCommand( dwArgCount,
  1333. argv,
  1334. dwDisplayFlags,
  1335. // &pwszNewContext,
  1336. pbDone );
  1337. }
  1338. }
  1339. }
  1340. #endif
  1341. FreeArgArray(dwArgCount, argv);
  1342. if (*pbDone or ((dwRes isnot ERROR_CMD_NOT_FOUND)
  1343. && (dwRes isnot ERROR_CONTINUE_IN_PARENT_CONTEXT)))
  1344. {
  1345. break;
  1346. }
  1347. // Make sure we don't look above "netsh"
  1348. if (pleContextHead->Flink->Flink == pleContextHead)
  1349. {
  1350. break;
  1351. }
  1352. // Delete the last element of the context list
  1353. // (Try inheriting a command from one level up)
  1354. ple = pleContextHead->Blink;
  1355. pae = CONTAINING_RECORD(ple, ARG_ENTRY, le);
  1356. if (pae->pwszArg)
  1357. FREE(pae->pwszArg);
  1358. RemoveEntryList(ple);
  1359. FREE(pae);
  1360. GetParentContext(pContext, &pContext);
  1361. dwDisplayFlags &= ~CMD_FLAG_PRIVATE;
  1362. }
  1363. #if 0
  1364. if (pwszNewContext)
  1365. {
  1366. FREE(pwszNewContext);
  1367. pwszNewContext = NULL;
  1368. }
  1369. #endif
  1370. } while (FALSE);
  1371. switch(dwRes)
  1372. {
  1373. case ERROR_OKAY:
  1374. if (!g_bQuiet)
  1375. {
  1376. PrintMessageFromModule(g_hModule, MSG_OKAY);
  1377. }
  1378. break;
  1379. case ERROR_NOT_ENOUGH_MEMORY:
  1380. PrintMessageFromModule(g_hModule, MSG_NOT_ENOUGH_MEMORY);
  1381. *pbDone = TRUE;
  1382. break;
  1383. case ERROR_CMD_NOT_FOUND:
  1384. {
  1385. LPWSTR pwszCmdLineDup = _wcsdup(pwszCmdLine);
  1386. if (!pwszCmdLineDup)
  1387. {
  1388. PrintMessageFromModule(g_hModule, MSG_NOT_ENOUGH_MEMORY);
  1389. return ERROR_NOT_ENOUGH_MEMORY;
  1390. }
  1391. if (wcslen(pwszCmdLineDup) > 256)
  1392. {
  1393. wcscpy(pwszCmdLineDup + 250, L"...");
  1394. }
  1395. PrintMessageFromModule(NULL, ERROR_CMD_NOT_FOUND, pwszCmdLineDup);
  1396. free(pwszCmdLineDup);
  1397. }
  1398. break;
  1399. case ERROR_CONTEXT_SWITCH:
  1400. {
  1401. if (!(dwDisplayFlags & CMD_FLAG_INTERACTIVE))
  1402. {
  1403. LPWSTR *argv2 = MALLOC((dwArgCount+1) * sizeof(LPWSTR));
  1404. if (argv2 is NULL)
  1405. {
  1406. return ERROR_NOT_ENOUGH_MEMORY;
  1407. }
  1408. CopyMemory(argv2, argv, dwArgCount * sizeof(LPWSTR));
  1409. argv2[dwArgCount] = MALLOC((wcslen(CMD_HELP2)+1) * sizeof(WCHAR));
  1410. if (argv2[dwArgCount] is NULL)
  1411. {
  1412. dwRes = ERROR_NOT_ENOUGH_MEMORY;
  1413. }
  1414. else
  1415. {
  1416. wcscpy(argv2[dwArgCount], CMD_HELP2);
  1417. g_dwTotalArgCount = dwArgCount+1;
  1418. dwRes = ProcessHelperCommand(dwArgCount+1,
  1419. argv2,
  1420. dwDisplayFlags,
  1421. pbDone);
  1422. FREE(argv2[dwArgCount]);
  1423. }
  1424. FREE(argv2);
  1425. return dwRes;
  1426. }
  1427. //
  1428. // A context switch.
  1429. //
  1430. SetContext(g_pwszNewContext);
  1431. dwRes = NO_ERROR;
  1432. break;
  1433. }
  1434. case ERROR_CONNECT_REMOTE_CONFIG:
  1435. PrintMessageFromModule(g_hModule, EMSG_REMOTE_CONNECT_FAILED,
  1436. g_pwszRouterName);
  1437. g_bDone = TRUE;
  1438. break;
  1439. }
  1440. FREE_ARG_LIST(pleHead);
  1441. FREE_ARG_LIST(pleContextHead);
  1442. return dwRes;
  1443. }
  1444. // Append line to the full command
  1445. DWORD
  1446. AppendLineToCommand(
  1447. LPCWSTR pwszCmdLine,
  1448. DWORD dwCmdLineLen,
  1449. LPWSTR *ppwszFullCommand,
  1450. DWORD *dwFullCommandLen
  1451. )
  1452. {
  1453. LPWSTR pwszNewCommand;
  1454. DWORD dwErr = NO_ERROR;
  1455. DWORD dwLen;
  1456. // Allocate enough space to hold the full command
  1457. dwLen = *dwFullCommandLen + dwCmdLineLen;
  1458. if (*ppwszFullCommand is NULL)
  1459. {
  1460. pwszNewCommand = MALLOC( (dwLen+1) * sizeof(WCHAR) );
  1461. }
  1462. else
  1463. {
  1464. pwszNewCommand = REALLOC(*ppwszFullCommand, (dwLen+1) * sizeof(WCHAR) );
  1465. }
  1466. if (!pwszNewCommand)
  1467. {
  1468. return ERROR_NOT_ENOUGH_MEMORY;
  1469. }
  1470. // Append cmd
  1471. wcscpy(pwszNewCommand + *dwFullCommandLen, pwszCmdLine);
  1472. // Update the pointer
  1473. *ppwszFullCommand = pwszNewCommand;
  1474. *dwFullCommandLen = dwLen;
  1475. return dwErr;
  1476. }
  1477. DWORD
  1478. MainCommandLoop(
  1479. FILE *fp,
  1480. BOOL bDisplayPrompt
  1481. )
  1482. {
  1483. LPWSTR pwszFullCommand, p, pwszCmdLine;
  1484. DWORD dwFullCommandLen, dwCmdLineLen, dwErr = NO_ERROR;
  1485. DWORD dwAnyErr = NO_ERROR;
  1486. BOOL bEof, bDone;
  1487. for ( ; ; )
  1488. {
  1489. pwszFullCommand = NULL;
  1490. dwFullCommandLen = 0;
  1491. bEof = FALSE;
  1492. if (bDisplayPrompt)
  1493. {
  1494. if (g_pwszRouterName)
  1495. {
  1496. PrintMessage(L"[%1!s!] ", g_pwszRouterName);
  1497. }
  1498. if (g_pwszContext[0] is L'\0')
  1499. {
  1500. PrintMessage(RtmonPrompt);
  1501. }
  1502. else
  1503. {
  1504. PrintMessage(L"%1!s!>",g_pwszContext);
  1505. }
  1506. }
  1507. // Get an entire command
  1508. for (;;)
  1509. {
  1510. // Get a single line, which may be \ terminated
  1511. pwszCmdLine = OEMfgets(&dwCmdLineLen, fp);
  1512. if (pwszCmdLine is NULL)
  1513. {
  1514. bEof = TRUE;
  1515. break;
  1516. }
  1517. p = pwszCmdLine + (dwCmdLineLen-1);
  1518. // Trim trailing whitespace
  1519. while ((p > pwszCmdLine) && iswspace(p[-1]))
  1520. {
  1521. *(--p) = 0;
  1522. }
  1523. if ((p > pwszCmdLine) && (p[-1] is '\\'))
  1524. {
  1525. // Strip '\\' from the end of the line
  1526. *(--p) = 0;
  1527. // Append line to the full command
  1528. AppendLineToCommand( pwszCmdLine,
  1529. (DWORD)(p-pwszCmdLine),
  1530. &pwszFullCommand,
  1531. &dwFullCommandLen );
  1532. FREE(pwszCmdLine);
  1533. continue; // Get more input
  1534. }
  1535. // Append line to the full command
  1536. AppendLineToCommand( pwszCmdLine,
  1537. (DWORD)(p-pwszCmdLine),
  1538. &pwszFullCommand,
  1539. &dwFullCommandLen );
  1540. // We're done
  1541. FREE(pwszCmdLine);
  1542. break;
  1543. }
  1544. if (bEof)
  1545. {
  1546. break;
  1547. }
  1548. dwErr = ProcessCommand(pwszFullCommand, &bDone);
  1549. if (bDone || g_bDone)
  1550. {
  1551. FREE(pwszFullCommand);
  1552. break;
  1553. }
  1554. if (dwErr)
  1555. {
  1556. dwAnyErr = dwErr;
  1557. }
  1558. FREE(pwszFullCommand);
  1559. }
  1560. return dwAnyErr;
  1561. }
  1562. DWORD
  1563. LoadScriptFile(
  1564. IN LPCWSTR pwszFileName
  1565. )
  1566. /*++
  1567. Routine Description:
  1568. Reads in commands from the file and processes them.
  1569. Arguments:
  1570. pwszFileName - Name of script file.
  1571. Return Value:
  1572. TRUE, FALSE
  1573. --*/
  1574. {
  1575. FILE* fp;
  1576. DWORD i, dwErr = NO_ERROR;
  1577. BOOL bOldInteractive = g_bInteractive;
  1578. BOOL bOldQuiet = g_bQuiet;
  1579. if ((fp = _wfopen(pwszFileName,L"r")) is NULL)
  1580. {
  1581. PrintMessageFromModule(g_hModule, MSG_OPEN_FAILED, pwszFileName);
  1582. return GetLastError();
  1583. }
  1584. g_bInteractive = TRUE;
  1585. g_bQuiet = TRUE;
  1586. dwErr = MainCommandLoop(fp, FALSE);
  1587. g_bInteractive = bOldInteractive;
  1588. g_bQuiet = bOldQuiet;
  1589. fclose(fp);
  1590. if (dwErr)
  1591. {
  1592. dwErr = ERROR_SUPPRESS_OUTPUT;
  1593. }
  1594. return dwErr;
  1595. }
  1596. DWORD
  1597. SetMachine(
  1598. LPCWSTR pwszNewRouter
  1599. )
  1600. {
  1601. HRESULT hr;
  1602. if (g_pwszRouterName)
  1603. {
  1604. FREE(g_pwszRouterName);
  1605. }
  1606. if (pwszNewRouter)
  1607. {
  1608. g_pwszRouterName = MALLOC((wcslen(pwszNewRouter) + 1) * sizeof(WCHAR));
  1609. if (!g_pwszRouterName)
  1610. {
  1611. return ERROR_NOT_ENOUGH_MEMORY;
  1612. }
  1613. wcscpy(g_pwszRouterName, pwszNewRouter);
  1614. }
  1615. else
  1616. {
  1617. g_pwszRouterName = NULL;
  1618. }
  1619. // Change back to root context
  1620. SetContext(DEFAULT_STARTUP_CONTEXT);
  1621. hr = UpdateVersionInfoGlobals(g_pwszRouterName);
  1622. if (FAILED(hr))
  1623. {
  1624. if (g_pwszRouterName)
  1625. {
  1626. PrintMessageFromModule(g_hModule, MSG_WARN_COULDNOTVERCHECKHOST, g_pwszRouterName);
  1627. }
  1628. else
  1629. {
  1630. TCHAR szComputerName[MAX_PATH];
  1631. DWORD dwComputerNameLen = MAX_PATH;
  1632. GetComputerName(szComputerName, &dwComputerNameLen);
  1633. PrintMessageFromModule(g_hModule, MSG_WARN_COULDNOTVERCHECKHOST, szComputerName);
  1634. }
  1635. PrintError(NULL, hr);
  1636. }
  1637. return NO_ERROR;
  1638. }
  1639. int
  1640. MainFunction(
  1641. int argc,
  1642. WCHAR *argv[]
  1643. )
  1644. {
  1645. WCHAR pwszCmdLine[MAX_CMD_LEN] = L"\0";
  1646. WCHAR pwszArgContext[MAX_CMD_LEN] = L"\0";
  1647. BOOL bOnce = FALSE, bDone = FALSE;
  1648. LPCWSTR pwszArgAlias = NULL;
  1649. LPCWSTR pwszArgScript = NULL;
  1650. DWORD dwErr = NO_ERROR, i;
  1651. LPCWSTR p;
  1652. HRESULT hr;
  1653. if ((g_hModule = GetModuleHandle(NULL)) is NULL)
  1654. {
  1655. PRINT1("GetModuleHandle failed");
  1656. return 1;
  1657. }
  1658. swprintf(RtmonPrompt, L"%s>", STRING_NETSH);
  1659. //
  1660. // Initialize the Alias Table
  1661. //
  1662. dwErr = ATInitTable();
  1663. if (dwErr isnot NO_ERROR)
  1664. {
  1665. return 0;
  1666. }
  1667. // Initialize the root helper
  1668. AddDllEntry(L"", L"netsh.exe");
  1669. //
  1670. // Load information about the helpers from the registry.
  1671. //
  1672. LoadDllInfoFromRegistry();
  1673. // Need to set the Ctrl Handler so it can catch the Ctrl C and close window events.
  1674. // This is done so the helper dlls can properly be unloaded.
  1675. //
  1676. SetConsoleCtrlHandler(HandlerRoutine,
  1677. TRUE);
  1678. for ( i = 1; i < (DWORD) argc; i++ )
  1679. {
  1680. if (_wcsicmp(argv[i], L"-?")==0 ||
  1681. _wcsicmp(argv[i], L"-h")==0 ||
  1682. _wcsicmp(argv[i], L"?" )==0 ||
  1683. _wcsicmp(argv[i], L"/?")==0)
  1684. {
  1685. PrintMessageFromModule(g_hModule, MSG_NETSH_USAGE, argv[0]);
  1686. ProcessCommand(L"?", &bDone);
  1687. // Need to free the helper DLLs before we exit
  1688. //
  1689. FreeHelpers();
  1690. FreeDlls();
  1691. return 1;
  1692. }
  1693. if (_wcsicmp(argv[i], L"-v") == 0)
  1694. {
  1695. g_bVerbose = TRUE;
  1696. continue;
  1697. }
  1698. if (_wcsicmp(argv[i], L"-a") == 0)
  1699. {
  1700. //
  1701. // alias file
  1702. //
  1703. if (i + 1 >= (DWORD)argc)
  1704. {
  1705. PrintMessageFromModule(g_hModule, MSG_NETSH_USAGE, argv[0]);
  1706. dwErr = ERROR_INVALID_SYNTAX;
  1707. break;
  1708. }
  1709. else
  1710. {
  1711. pwszArgAlias = argv[i+1];
  1712. i++;
  1713. continue;
  1714. }
  1715. }
  1716. if (_wcsicmp(argv[i], L"-c") == 0)
  1717. {
  1718. //
  1719. // starting context
  1720. //
  1721. if (i + 1 >= (DWORD)argc)
  1722. {
  1723. PrintMessageFromModule(g_hModule, MSG_NETSH_USAGE, argv[0]);
  1724. dwErr = ERROR_INVALID_SYNTAX;
  1725. break;
  1726. }
  1727. else
  1728. {
  1729. wcscpy(pwszArgContext, argv[i+1]);
  1730. i++;
  1731. continue;
  1732. }
  1733. }
  1734. if (_wcsicmp(argv[i], L"-f") == 0)
  1735. {
  1736. //
  1737. // command to run
  1738. //
  1739. if (i + 1 >= (DWORD)argc)
  1740. {
  1741. PrintMessageFromModule(g_hModule, MSG_NETSH_USAGE, argv[0]);
  1742. dwErr = ERROR_INVALID_SYNTAX;
  1743. break;
  1744. }
  1745. else
  1746. {
  1747. pwszArgScript = argv[i+1];
  1748. i++;
  1749. bOnce = TRUE;
  1750. continue;
  1751. }
  1752. }
  1753. #ifdef ALLOW_REMOTES
  1754. if (_wcsicmp(argv[i], L"-r") == 0)
  1755. {
  1756. //
  1757. // router name
  1758. //
  1759. if (i + 1 >= (DWORD)argc)
  1760. {
  1761. PrintMessageFromModule(g_hModule, MSG_NETSH_USAGE, argv[0]);
  1762. dwErr = ERROR_INVALID_SYNTAX;
  1763. break;
  1764. }
  1765. else
  1766. {
  1767. if (wcslen(argv[i+1]))
  1768. {
  1769. dwErr = SetMachine( argv[i+1] );
  1770. if (dwErr isnot NO_ERROR)
  1771. {
  1772. PrintMessageFromModule(g_hModule, dwErr);
  1773. return dwErr;
  1774. }
  1775. }
  1776. i++;
  1777. continue;
  1778. }
  1779. }
  1780. #endif
  1781. if (!bOnce)
  1782. {
  1783. while (i < (DWORD)argc)
  1784. {
  1785. if (pwszCmdLine[0])
  1786. {
  1787. wcscat(pwszCmdLine, L" ");
  1788. }
  1789. p = argv[i];
  1790. if (!p[0] || wcschr(argv[i], L' '))
  1791. {
  1792. wcscat(pwszCmdLine, L"\"");
  1793. wcscat(pwszCmdLine, p);
  1794. wcscat(pwszCmdLine, L"\"");
  1795. }
  1796. else
  1797. {
  1798. wcscat(pwszCmdLine, p);
  1799. }
  1800. i++;
  1801. }
  1802. }
  1803. else
  1804. {
  1805. PrintMessageFromModule(g_hModule, MSG_NETSH_USAGE, argv[0]);
  1806. dwErr = ERROR_INVALID_SYNTAX;
  1807. }
  1808. break;
  1809. }
  1810. if (!g_pwszRouterName)
  1811. {
  1812. hr = UpdateVersionInfoGlobals(NULL); // Update the info for the local machine
  1813. if (FAILED(hr))
  1814. {
  1815. if (g_pwszRouterName)
  1816. {
  1817. PrintMessageFromModule(g_hModule, MSG_WARN_COULDNOTVERCHECKHOST, g_pwszRouterName);
  1818. }
  1819. else
  1820. {
  1821. TCHAR szComputerName[MAX_PATH];
  1822. DWORD dwComputerNameLen = MAX_PATH;
  1823. GetComputerName(szComputerName, &dwComputerNameLen);
  1824. PrintMessageFromModule(g_hModule, MSG_WARN_COULDNOTVERCHECKHOST, szComputerName);
  1825. }
  1826. PrintError(NULL, hr);
  1827. }
  1828. }
  1829. do {
  1830. if (dwErr isnot NO_ERROR)
  1831. {
  1832. break;
  1833. }
  1834. if (pwszArgAlias)
  1835. {
  1836. dwErr = LoadScriptFile(pwszArgAlias);
  1837. if (dwErr)
  1838. {
  1839. break;
  1840. }
  1841. }
  1842. if (pwszArgContext[0] != L'\0')
  1843. {
  1844. // The context switch command should be processed in
  1845. // interactive mode (which is the only time a context
  1846. // switch is legal).
  1847. g_bInteractive = TRUE;
  1848. dwErr = ProcessCommand(pwszArgContext, &bDone);
  1849. g_bInteractive = FALSE;
  1850. if (dwErr)
  1851. {
  1852. break;
  1853. }
  1854. }
  1855. if (pwszCmdLine[0] != L'\0')
  1856. {
  1857. g_bQuiet = FALSE; // Bug# 262183
  1858. dwErr = ProcessCommand(pwszCmdLine, &bDone);
  1859. break;
  1860. }
  1861. if (pwszArgScript)
  1862. {
  1863. g_bInteractive = TRUE;
  1864. dwErr = LoadScriptFile(pwszArgScript);
  1865. break;
  1866. }
  1867. g_bInteractive = TRUE;
  1868. g_bQuiet = FALSE;
  1869. // Main command loop
  1870. dwErr = MainCommandLoop(stdin, TRUE);
  1871. } while (FALSE);
  1872. //
  1873. // Clean up
  1874. //
  1875. FreeHelpers();
  1876. FreeDlls();
  1877. FreeAliasTable();
  1878. if(g_pwszRouterName)
  1879. {
  1880. FREE(g_pwszRouterName);
  1881. g_pwszRouterName = NULL;
  1882. }
  1883. // Return 1 on error, 0 if not
  1884. return (dwErr isnot NO_ERROR);
  1885. }
  1886. int _cdecl
  1887. wmain(
  1888. int argc,
  1889. WCHAR *argv[]
  1890. )
  1891. /*++
  1892. Routine Description:
  1893. The main function.
  1894. Arguments:
  1895. Return Value:
  1896. --*/
  1897. {
  1898. HANDLE hStdOut;
  1899. DWORD dwRet;
  1900. CONSOLE_SCREEN_BUFFER_INFO csbi;
  1901. WORD oldXSize;
  1902. char buff[256];
  1903. WSADATA wsaData;
  1904. HRESULT hr;
  1905. #if 0
  1906. hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
  1907. if (hStdOut is INVALID_HANDLE_VALUE)
  1908. {
  1909. PRINT1("Standard output could not be opened.");
  1910. return 0;
  1911. }
  1912. GetConsoleScreenBufferInfo(hStdOut, &csbi);
  1913. oldXSize = csbi.dwSize.X;
  1914. csbi.dwSize.X = 120;
  1915. SetConsoleScreenBufferSize(hStdOut, csbi.dwSize);
  1916. #endif
  1917. #if 0
  1918. WSAStartup(MAKEWORD(2,0), &wsaData);
  1919. if (!gethostname(buff, sizeof(buff)))
  1920. {
  1921. g_pwszRouterName = MALLOC( (strlen(buff)+1) * sizeof(WCHAR) );
  1922. swprintf(g_pwszRouterName, L"%hs", buff);
  1923. }
  1924. #endif
  1925. dwRet = MainFunction(argc, argv);
  1926. #if 0
  1927. GetConsoleScreenBufferInfo(hStdOut, &csbi);
  1928. csbi.dwSize.X = oldXSize;
  1929. SetConsoleScreenBufferSize(hStdOut, csbi.dwSize);
  1930. CloseHandle(hStdOut);
  1931. #endif
  1932. return dwRet;
  1933. }
  1934. BOOL
  1935. IsLocalCommand(
  1936. IN LPCWSTR pwszCmd,
  1937. IN DWORD dwSkipFlags
  1938. )
  1939. /*++
  1940. Arguments:
  1941. pwszCmd - string to see if it matches a command
  1942. dwSkipFlags - any commands with these flags will be ignored.
  1943. This is the opposite semantics of the "dwDisplayFlags"
  1944. parameter used elsewhere (dwSkipFlags = ~dwDisplayFlags)
  1945. --*/
  1946. {
  1947. DWORD i, dwErr;
  1948. PCNS_CONTEXT_ATTRIBUTES pContext, pSubContext;
  1949. PNS_HELPER_TABLE_ENTRY pHelper;
  1950. dwErr = GetRootContext( &pContext, &pHelper );
  1951. if (dwErr)
  1952. {
  1953. return FALSE;
  1954. }
  1955. for (i=0; i<g_ulNumShellCmds; i++)
  1956. {
  1957. if (!(g_ShellCmds[i].dwFlags & dwSkipFlags)
  1958. && !_wcsicmp( pwszCmd,
  1959. g_ShellCmds[i].pwszCmdToken ))
  1960. {
  1961. return TRUE;
  1962. }
  1963. }
  1964. for (i=0; i<g_ulNumGroups; i++)
  1965. {
  1966. if (!(g_ShellCmdGroups[i].dwFlags & dwSkipFlags)
  1967. && !_wcsicmp( pwszCmd,
  1968. g_ShellCmdGroups[i].pwszCmdGroupToken ))
  1969. {
  1970. return TRUE;
  1971. }
  1972. }
  1973. for (i=0; i<pHelper->ulNumSubContexts; i++)
  1974. {
  1975. pSubContext = (PCNS_CONTEXT_ATTRIBUTES)
  1976. (pHelper->pSubContextTable + i*pHelper->ulSubContextSize);
  1977. if (!(pSubContext->dwFlags & dwSkipFlags)
  1978. && !_wcsicmp( pwszCmd,
  1979. pSubContext->pwszContext))
  1980. {
  1981. return TRUE;
  1982. }
  1983. }
  1984. return FALSE;
  1985. }