Reactos
1/*
2 * PROJECT: ReactOS NetSh
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Network Shell context management functions
5 * COPYRIGHT: Copyright 2023 Eric Kohl <eric.kohl@reactos.org>
6 */
7
8/* INCLUDES *******************************************************************/
9
10#include "precomp.h"
11
12#define NDEBUG
13#include <debug.h>
14
15/* GLOBALS ********************************************************************/
16
17typedef struct _CONTEXT_STACK_ENTRY
18{
19 struct _CONTEXT_STACK_ENTRY *pPrev;
20 struct _CONTEXT_STACK_ENTRY *pNext;
21
22 PCONTEXT_ENTRY pContext;
23} CONTEXT_STACK_ENTRY, *PCONTEXT_STACK_ENTRY;
24
25
26PCONTEXT_ENTRY pRootContext = NULL;
27PCONTEXT_ENTRY pCurrentContext = NULL;
28
29PCONTEXT_STACK_ENTRY pContextStackHead = NULL;
30PCONTEXT_STACK_ENTRY pContextStackTail = NULL;
31
32PWSTR pszMachine = NULL;
33
34static BOOL bOnline = TRUE;
35
36/* FUNCTIONS ******************************************************************/
37
38PCONTEXT_ENTRY
39AddContext(
40 PCONTEXT_ENTRY pParentContext,
41 PWSTR pszName,
42 GUID *pGuid)
43{
44 PCONTEXT_ENTRY pEntry;
45
46 DPRINT("AddContext(%S)\n", pszName);
47 if (pParentContext)
48 {
49 DPRINT("ParentContext %S\n", pParentContext->pszContextName);
50 }
51
52 if (pParentContext != NULL && pszName == NULL)
53 return NULL;
54
55 /* Allocate the entry */
56 pEntry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CONTEXT_ENTRY));
57 if (pEntry == NULL)
58 return NULL;
59
60 /* Allocate the name buffer */
61 if (pszName != NULL)
62 {
63 pEntry->pszContextName = HeapAlloc(GetProcessHeap(),
64 HEAP_ZERO_MEMORY,
65 (wcslen(pszName) + 1) * sizeof(WCHAR));
66 if (pEntry->pszContextName == NULL)
67 {
68 HeapFree(GetProcessHeap(), 0, pEntry);
69 return NULL;
70 }
71
72 /* Fill the entry */
73 wcscpy(pEntry->pszContextName, pszName);
74 }
75
76 pEntry->pParentContext = pParentContext;
77 if (pGuid != NULL)
78 CopyMemory(&pEntry->Guid, pGuid, sizeof(pEntry->Guid));
79
80 /* Insert it */
81 if (pParentContext != NULL)
82 {
83 if ((pParentContext->pSubContextHead == NULL) && (pParentContext->pSubContextTail == NULL))
84 {
85 pParentContext->pSubContextHead = pEntry;
86 pParentContext->pSubContextTail = pEntry;
87 }
88 else
89 {
90 pEntry->pPrev = pParentContext->pSubContextTail;
91 pParentContext->pSubContextTail->pNext = pEntry;
92 pParentContext->pSubContextTail = pEntry;
93 }
94 }
95
96 return pEntry;
97}
98
99
100PCOMMAND_ENTRY
101AddContextCommand(
102 PCONTEXT_ENTRY pContext,
103 LPCWSTR pwszCmdToken,
104 PFN_HANDLE_CMD pfnCmdHandler,
105 DWORD dwShortCmdHelpToken,
106 DWORD dwCmdHlpToken,
107 DWORD dwFlags)
108{
109 PCOMMAND_ENTRY pEntry;
110
111 if (pfnCmdHandler == NULL)
112 return NULL;
113
114 /* Allocate the entry */
115 pEntry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(COMMAND_ENTRY));
116 if (pEntry == NULL)
117 return NULL;
118
119 pEntry->pwszCmdToken = HeapAlloc(GetProcessHeap(),
120 HEAP_ZERO_MEMORY,
121 (wcslen(pwszCmdToken) + 1) * sizeof(WCHAR));
122 if (pEntry->pwszCmdToken == NULL)
123 {
124 HeapFree(GetProcessHeap(), 0, pEntry);
125 return NULL;
126 }
127
128 wcscpy((LPWSTR)pEntry->pwszCmdToken, pwszCmdToken);
129
130 pEntry->pfnCmdHandler = pfnCmdHandler;
131 pEntry->dwShortCmdHelpToken = dwShortCmdHelpToken;
132 pEntry->dwCmdHlpToken = dwCmdHlpToken;
133 pEntry->dwFlags = dwFlags;
134
135 if (pContext->pCommandListHead == NULL && pContext->pCommandListTail == NULL)
136 {
137 pContext->pCommandListHead = pEntry;
138 pContext->pCommandListTail = pEntry;
139 }
140 else
141 {
142 pEntry->pPrev = pContext->pCommandListTail;
143 pContext->pCommandListTail->pNext = pEntry;
144 pContext->pCommandListTail = pEntry;
145 }
146
147 return pEntry;
148}
149
150
151PCOMMAND_GROUP
152AddCommandGroup(
153 PCONTEXT_ENTRY pContext,
154 LPCWSTR pwszCmdGroupToken,
155 DWORD dwShortCmdHelpToken,
156 DWORD dwFlags)
157{
158 PCOMMAND_GROUP pEntry;
159
160 DPRINT("AddCommandGroup(%S %lu)\n", pwszCmdGroupToken, dwShortCmdHelpToken);
161
162 /* Allocate the entry */
163 pEntry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(COMMAND_GROUP));
164 if (pEntry == NULL)
165 return NULL;
166
167 pEntry->pwszCmdGroupToken = HeapAlloc(GetProcessHeap(),
168 HEAP_ZERO_MEMORY,
169 (wcslen(pwszCmdGroupToken) + 1) * sizeof(WCHAR));
170 if (pEntry->pwszCmdGroupToken == NULL)
171 {
172 HeapFree(GetProcessHeap(), 0, pEntry);
173 return NULL;
174 }
175
176 wcscpy((LPWSTR)pEntry->pwszCmdGroupToken, pwszCmdGroupToken);
177 pEntry->dwShortCmdHelpToken = dwShortCmdHelpToken;
178 pEntry->dwFlags = dwFlags;
179
180 if (pContext->pGroupListHead == NULL && pContext->pGroupListTail == NULL)
181 {
182 pContext->pGroupListHead = pEntry;
183 pContext->pGroupListTail = pEntry;
184 }
185 else
186 {
187 pEntry->pPrev = pContext->pGroupListTail;
188 pContext->pGroupListTail->pNext = pEntry;
189 pContext->pGroupListTail = pEntry;
190 }
191
192 return pEntry;
193}
194
195
196PCOMMAND_ENTRY
197AddGroupCommand(
198 PCOMMAND_GROUP pGroup,
199 LPCWSTR pwszCmdToken,
200 PFN_HANDLE_CMD pfnCmdHandler,
201 DWORD dwShortCmdHelpToken,
202 DWORD dwCmdHlpToken,
203 DWORD dwFlags)
204{
205 PCOMMAND_ENTRY pEntry;
206
207 if (pfnCmdHandler == NULL)
208 return NULL;
209
210 /* Allocate the entry */
211 pEntry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(COMMAND_ENTRY));
212 if (pEntry == NULL)
213 return NULL;
214
215 pEntry->pwszCmdToken = HeapAlloc(GetProcessHeap(),
216 HEAP_ZERO_MEMORY,
217 (wcslen(pwszCmdToken) + 1) * sizeof(WCHAR));
218 if (pEntry->pwszCmdToken == NULL)
219 {
220 HeapFree(GetProcessHeap(), 0, pEntry);
221 return NULL;
222 }
223
224 wcscpy((LPWSTR)pEntry->pwszCmdToken, pwszCmdToken);
225
226 pEntry->pfnCmdHandler = pfnCmdHandler;
227 pEntry->dwShortCmdHelpToken = dwShortCmdHelpToken;
228 pEntry->dwCmdHlpToken = dwCmdHlpToken;
229 pEntry->dwFlags = dwFlags;
230
231 if (pGroup->pCommandListHead == NULL && pGroup->pCommandListTail == NULL)
232 {
233 pGroup->pCommandListHead = pEntry;
234 pGroup->pCommandListTail = pEntry;
235 }
236 else
237 {
238 pEntry->pPrev = pGroup->pCommandListTail;
239 pGroup->pCommandListTail->pNext = pEntry;
240 pGroup->pCommandListTail = pEntry;
241 }
242
243 return pEntry;
244}
245
246
247VOID
248RemoveContextFromStack(
249 _In_ PCONTEXT_ENTRY pContextEntry)
250{
251 PCONTEXT_STACK_ENTRY pStackEntry, pNextEntry;
252
253 if (pContextStackHead == NULL)
254 return;
255
256 pStackEntry = pContextStackHead;
257 while (1)
258 {
259 if (pStackEntry->pContext == pContextEntry)
260 {
261 if (pStackEntry == pContextStackHead && pStackEntry == pContextStackHead)
262 {
263 pContextStackHead = NULL;
264 pContextStackTail = NULL;
265 HeapFree(GetProcessHeap(), 0, pStackEntry);
266 return;
267 }
268 else if (pStackEntry == pContextStackHead)
269 {
270 pStackEntry->pNext->pPrev = NULL;
271 pContextStackHead = pStackEntry->pNext;
272 HeapFree(GetProcessHeap(), 0, pStackEntry);
273 pStackEntry = pContextStackHead;
274 }
275 else if (pStackEntry == pContextStackTail)
276 {
277 pStackEntry->pPrev->pNext = NULL;
278 pContextStackTail = pStackEntry->pPrev;
279 HeapFree(GetProcessHeap(), 0, pStackEntry);
280 return;
281 }
282 else
283 {
284 pNextEntry = pStackEntry->pNext;
285 pStackEntry->pPrev->pNext = pStackEntry->pNext;
286 pStackEntry->pNext->pPrev = pStackEntry->pPrev;
287 HeapFree(GetProcessHeap(), 0, pStackEntry);
288 pStackEntry = pNextEntry;
289 }
290 }
291 else
292 {
293 if (pStackEntry == pContextStackTail)
294 return;
295
296 pStackEntry = pStackEntry->pNext;
297 }
298 }
299}
300
301
302VOID
303DeleteContext(
304 PWSTR pszName)
305{
306 /* Remove the context from the stack */
307 /* RemoveContextFromStack(); */
308
309 /* Delete all commands */
310 /* Delete the context */
311}
312
313
314static
315int
316ContextCompare(
317 _In_ const void *p1,
318 _In_ const void *p2)
319{
320 return ((PCONTEXT_ENTRY)p1)->ulPriority - ((PCONTEXT_ENTRY)p2)->ulPriority;
321}
322
323
324static
325DWORD
326DumpContext(
327 _In_ PCONTEXT_ENTRY pContext,
328 _In_ LPCWSTR pwszMachine,
329 _In_ LPWSTR *ppwcArguments,
330 _In_ DWORD dwArgCount,
331 _In_ LPCVOID pvData)
332{
333 PCONTEXT_ENTRY pSubContext, *pSortArray = NULL;
334 DWORD dwCount, dwIndex;
335 DWORD dwError = ERROR_SUCCESS;
336
337 DPRINT("DumpContext()\n");
338
339 if (pContext->pfnDumpFn)
340 {
341 dwError = pContext->pfnDumpFn(pwszMachine,
342 ppwcArguments,
343 dwArgCount,
344 pvData);
345 if (dwError != ERROR_SUCCESS)
346 {
347 DPRINT1("Dump function failed (Error %lu)\n", dwError);
348 return dwError;
349 }
350 }
351
352 if (pContext->pSubContextHead == NULL)
353 return dwError;
354
355 /* Count the sub-contexts */
356 dwCount = 0;
357 pSubContext = pContext->pSubContextHead;
358 while (pSubContext)
359 {
360 dwCount++;
361 pSubContext = pSubContext->pNext;
362 }
363
364 /* Allocate the sort array */
365 pSortArray = HeapAlloc(GetProcessHeap(), 0, dwCount * sizeof(PCONTEXT_ENTRY));
366 if (pSortArray == NULL)
367 return ERROR_NOT_ENOUGH_MEMORY;
368
369 /* Fill the sort array */
370 dwIndex = 0;
371 pSubContext = pContext->pSubContextHead;
372 while (pSubContext)
373 {
374 pSortArray[dwIndex] = pSubContext;
375 dwIndex++;
376 pSubContext = pSubContext->pNext;
377 }
378
379 /* Sort the array */
380 qsort(pSortArray, dwCount, sizeof(PCONTEXT_ENTRY), ContextCompare);
381
382 /* Dump the sub-contexts */
383 for (dwIndex = 0; dwIndex < dwCount; dwIndex++)
384 {
385 dwError = DumpContext(pSortArray[dwIndex],
386 pwszMachine,
387 ppwcArguments,
388 dwArgCount,
389 pvData);
390 if (dwError != ERROR_SUCCESS)
391 {
392 DPRINT1("Dump function failed (Error %lu)\n", dwError);
393 break;
394 }
395 }
396
397 /* Free the sort array */
398 HeapFree(GetProcessHeap(), 0, pSortArray);
399
400 return dwError;
401}
402
403static
404DWORD
405CommitContext(
406 _In_ PCONTEXT_ENTRY pContext,
407 _In_ DWORD dwAction)
408{
409 PCONTEXT_ENTRY pSubContext, *pSortArray = NULL;
410 DWORD dwCount, dwIndex;
411 DWORD dwError = ERROR_SUCCESS;
412
413 DPRINT1("CommitContext(%p %lu)\n", pContext, dwAction);
414
415 if (pContext->pfnCommitFn)
416 {
417 dwError = pContext->pfnCommitFn(dwAction);
418 if (dwError != ERROR_SUCCESS)
419 {
420 DPRINT1("Commit function failed (Error %lu)\n", dwError);
421 return dwError;
422 }
423 }
424
425 if (pContext->pSubContextHead == NULL)
426 return dwError;
427
428 /* Count the sub-contexts */
429 dwCount = 0;
430 pSubContext = pContext->pSubContextHead;
431 while (pSubContext)
432 {
433 dwCount++;
434 pSubContext = pSubContext->pNext;
435 }
436
437 /* Allocate the sort array */
438 pSortArray = HeapAlloc(GetProcessHeap(), 0, dwCount * sizeof(PCONTEXT_ENTRY));
439 if (pSortArray == NULL)
440 return ERROR_NOT_ENOUGH_MEMORY;
441
442 /* Fill the sort array */
443 dwIndex = 0;
444 pSubContext = pContext->pSubContextHead;
445 while (pSubContext)
446 {
447 pSortArray[dwIndex] = pSubContext;
448 dwIndex++;
449 pSubContext = pSubContext->pNext;
450 }
451
452 /* Sort the array */
453 qsort(pSortArray, dwCount, sizeof(PCONTEXT_ENTRY), ContextCompare);
454
455 /* Commit the sub-contexts */
456 for (dwIndex = 0; dwIndex < dwCount; dwIndex++)
457 {
458 dwError = CommitContext(pSortArray[dwIndex],
459 dwAction);
460 if (dwError != ERROR_SUCCESS)
461 {
462 DPRINT1("Commit function failed (Error %lu)\n", dwError);
463 break;
464 }
465 }
466
467 /* Free the sort array */
468 HeapFree(GetProcessHeap(), 0, pSortArray);
469
470 return dwError;
471}
472
473
474DWORD
475WINAPI
476UpCommand(
477 _In_ LPCWSTR pwszMachine,
478 _In_ LPWSTR *argv,
479 _In_ DWORD dwCurrentIndex,
480 _In_ DWORD dwArgCount,
481 _In_ DWORD dwFlags,
482 _In_ LPCVOID pvData,
483 _Out_ BOOL *pbDone)
484{
485 if (pCurrentContext != pRootContext)
486 pCurrentContext = pCurrentContext->pParentContext;
487
488 return ERROR_SUCCESS;
489}
490
491
492DWORD
493WINAPI
494AbortCommand(
495 _In_ LPCWSTR pwszMachine,
496 _In_ LPWSTR *argv,
497 _In_ DWORD dwCurrentIndex,
498 _In_ DWORD dwArgCount,
499 _In_ DWORD dwFlags,
500 _In_ LPCVOID pvData,
501 _Out_ BOOL *pbDone)
502{
503 DPRINT("AbortCommand()\n");
504 CommitContext(pRootContext, NETSH_FLUSH);
505 return ERROR_SUCCESS;
506}
507
508
509DWORD
510WINAPI
511CommitCommand(
512 _In_ LPCWSTR pwszMachine,
513 _In_ LPWSTR *argv,
514 _In_ DWORD dwCurrentIndex,
515 _In_ DWORD dwArgCount,
516 _In_ DWORD dwFlags,
517 _In_ LPCVOID pvData,
518 _Out_ BOOL *pbDone)
519{
520 DPRINT("CommitCommand()\n");
521 CommitContext(pRootContext, NETSH_SAVE);
522 return ERROR_SUCCESS;
523}
524
525
526DWORD
527WINAPI
528DumpCommand(
529 _In_ LPCWSTR pwszMachine,
530 _In_ LPWSTR *ppwcArguments,
531 _In_ DWORD dwCurrentIndex,
532 _In_ DWORD dwArgCount,
533 _In_ DWORD dwFlags,
534 _In_ LPCVOID pvData,
535 _Out_ BOOL *pbDone)
536{
537 DPRINT("DumpCommand()\n");
538
539 return DumpContext(pCurrentContext,
540 pwszMachine,
541 ppwcArguments,
542 dwArgCount,
543 pvData);
544}
545
546
547DWORD
548WINAPI
549ExecCommand(
550 _In_ LPCWSTR pwszMachine,
551 _In_ LPWSTR *argv,
552 _In_ DWORD dwCurrentIndex,
553 _In_ DWORD dwArgCount,
554 _In_ DWORD dwFlags,
555 _In_ LPCVOID pvData,
556 _Out_ BOOL *pbDone)
557{
558 DPRINT("ExecCommand()\n");
559
560 if (dwArgCount - dwCurrentIndex != 1)
561 return ERROR_SHOW_USAGE;
562
563 return RunScript(argv[dwCurrentIndex]);
564}
565
566
567DWORD
568WINAPI
569ExitCommand(
570 _In_ LPCWSTR pwszMachine,
571 _In_ LPWSTR *argv,
572 _In_ DWORD dwCurrentIndex,
573 _In_ DWORD dwArgCount,
574 _In_ DWORD dwFlags,
575 _In_ LPCVOID pvData,
576 _Out_ BOOL *pbDone)
577{
578 if (bOnline == FALSE)
579 CommitContext(pRootContext, NETSH_FLUSH);
580
581 *pbDone = TRUE;
582 return ERROR_SUCCESS;
583}
584
585
586DWORD
587WINAPI
588RemCommand(
589 _In_ LPCWSTR pwszMachine,
590 _In_ LPWSTR *argv,
591 _In_ DWORD dwCurrentIndex,
592 _In_ DWORD dwArgCount,
593 _In_ DWORD dwFlags,
594 _In_ LPCVOID pvData,
595 _Out_ BOOL *pbDone)
596{
597 return ERROR_SUCCESS;
598}
599
600
601DWORD
602WINAPI
603OfflineCommand(
604 _In_ LPCWSTR pwszMachine,
605 _In_ LPWSTR *argv,
606 _In_ DWORD dwCurrentIndex,
607 _In_ DWORD dwArgCount,
608 _In_ DWORD dwFlags,
609 _In_ LPCVOID pvData,
610 _Out_ BOOL *pbDone)
611{
612 DPRINT("OfflineCommand()\n");
613 CommitContext(pRootContext, NETSH_UNCOMMIT);
614 bOnline = FALSE;
615 return ERROR_SUCCESS;
616}
617
618
619DWORD
620WINAPI
621OnlineCommand(
622 _In_ LPCWSTR pwszMachine,
623 _In_ LPWSTR *argv,
624 _In_ DWORD dwCurrentIndex,
625 _In_ DWORD dwArgCount,
626 _In_ DWORD dwFlags,
627 _In_ LPCVOID pvData,
628 _Out_ BOOL *pbDone)
629{
630 DPRINT("OnlineCommand()\n");
631 CommitContext(pRootContext, NETSH_COMMIT);
632 bOnline = TRUE;
633 return ERROR_SUCCESS;
634}
635
636
637DWORD
638WINAPI
639PopdCommand(
640 _In_ LPCWSTR pwszMachine,
641 _In_ LPWSTR *argv,
642 _In_ DWORD dwCurrentIndex,
643 _In_ DWORD dwArgCount,
644 _In_ DWORD dwFlags,
645 _In_ LPCVOID pvData,
646 _Out_ BOOL *pbDone)
647{
648 PCONTEXT_STACK_ENTRY pEntry;
649
650 DPRINT("PopdCommand()\n");
651
652 if (pContextStackHead == NULL)
653 return ERROR_SUCCESS;
654
655 pEntry = pContextStackHead;
656
657 pCurrentContext = pEntry->pContext;
658
659 if (pContextStackTail == pEntry)
660 {
661 pContextStackHead = NULL;
662 pContextStackTail = NULL;
663 }
664 else
665 {
666 pContextStackHead = pEntry->pNext;
667 pContextStackHead->pPrev = NULL;
668 }
669
670 HeapFree(GetProcessHeap(), 0, pEntry);
671
672 return ERROR_SUCCESS;
673}
674
675
676DWORD
677WINAPI
678PushdCommand(
679 _In_ LPCWSTR pwszMachine,
680 _In_ LPWSTR *argv,
681 _In_ DWORD dwCurrentIndex,
682 _In_ DWORD dwArgCount,
683 _In_ DWORD dwFlags,
684 _In_ LPCVOID pvData,
685 _Out_ BOOL *pbDone)
686{
687 PCONTEXT_STACK_ENTRY pEntry;
688
689 DPRINT("PushdCommand()\n");
690
691 pEntry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CONTEXT_STACK_ENTRY));
692 if (pEntry == NULL)
693 return ERROR_NOT_ENOUGH_MEMORY;
694
695 pEntry->pContext = pCurrentContext;
696 if (pContextStackHead == NULL)
697 {
698 pContextStackHead = pEntry;
699 pContextStackTail = pEntry;
700 }
701 else
702 {
703 pEntry->pNext = pContextStackHead;
704 pContextStackHead->pPrev = pEntry;
705 pContextStackHead = pEntry;
706 }
707
708 return ERROR_SUCCESS;
709}
710
711
712DWORD
713WINAPI
714SetMachineCommand(
715 _In_ LPCWSTR pwszMachine,
716 _In_ LPWSTR *argv,
717 _In_ DWORD dwCurrentIndex,
718 _In_ DWORD dwArgCount,
719 _In_ DWORD dwFlags,
720 _In_ LPCVOID pvData,
721 _Out_ BOOL *pbDone)
722{
723 DWORD dwError = ERROR_SUCCESS;
724
725 DPRINT("SetMachineCommand(pwszMachine %S dwCurrentIndex %lu dwArgCount %lu)\n",
726 pwszMachine, dwCurrentIndex, dwArgCount);
727
728 if ((dwArgCount - dwCurrentIndex) > 1)
729 return ERROR_SHOW_USAGE;
730
731 if (pszMachine != NULL)
732 {
733 HeapFree(GetProcessHeap(), 0, pszMachine);
734 pszMachine = NULL;
735 }
736
737 if ((dwArgCount - dwCurrentIndex) == 1)
738 {
739 pszMachine = HeapAlloc(GetProcessHeap(), 0, (sizeof(argv[dwCurrentIndex]) + 1) * sizeof(WCHAR));
740 if (pszMachine == NULL)
741 return ERROR_NOT_ENOUGH_MEMORY;
742 wcscpy(pszMachine, argv[dwCurrentIndex]);
743 }
744
745 return dwError;
746}
747
748
749DWORD
750WINAPI
751SetModeCommand(
752 _In_ LPCWSTR pwszMachine,
753 _In_ LPWSTR *argv,
754 _In_ DWORD dwCurrentIndex,
755 _In_ DWORD dwArgCount,
756 _In_ DWORD dwFlags,
757 _In_ LPCVOID pvData,
758 _Out_ BOOL *pbDone)
759{
760 DWORD dwError = ERROR_SUCCESS;
761
762 DPRINT("SetModeCommand(pwszMachine %S dwCurrentIndex %lu dwArgCount %lu)\n",
763 pwszMachine, dwCurrentIndex, dwArgCount);
764
765 if ((dwArgCount - dwCurrentIndex) != 1)
766 return ERROR_SHOW_USAGE;
767
768 if (!_wcsicmp(argv[dwCurrentIndex], L"offline"))
769 {
770 CommitContext(pRootContext, NETSH_UNCOMMIT);
771 bOnline = FALSE;
772 }
773 else if (!_wcsicmp(argv[dwCurrentIndex], L"online"))
774 {
775 CommitContext(pRootContext, NETSH_COMMIT);
776 bOnline = TRUE;
777 }
778 else
779 {
780 dwError = ERROR_INVALID_SYNTAX;
781 }
782
783 return dwError;
784}
785
786
787DWORD
788WINAPI
789ShowModeCommand(
790 _In_ LPCWSTR pwszMachine,
791 _In_ LPWSTR *argv,
792 _In_ DWORD dwCurrentIndex,
793 _In_ DWORD dwArgCount,
794 _In_ DWORD dwFlags,
795 _In_ LPCVOID pvData,
796 _Out_ BOOL *pbDone)
797{
798 DPRINT("ShowModeCommand()\n");
799 ConPuts(StdOut, bOnline ? L"online\n\n" : L"offline\n\n");
800 return ERROR_SUCCESS;
801}
802
803
804BOOL
805CreateRootContext(VOID)
806{
807 PCOMMAND_GROUP pGroup;
808
809 pRootContext = AddContext(NULL, L"netsh", NULL);
810 DPRINT("pRootContext: %p\n", pRootContext);
811 if (pRootContext == NULL)
812 return FALSE;
813
814 pRootContext->hModule = hModule;
815
816 AddContextCommand(pRootContext, L"..", UpCommand, IDS_HLP_UP, IDS_HLP_UP_EX, 0);
817 AddContextCommand(pRootContext, L"?", NULL, IDS_HLP_HELP, IDS_HLP_HELP_EX, 0);
818 AddContextCommand(pRootContext, L"abort", AbortCommand, IDS_HLP_ABORT, IDS_HLP_ABORT_EX, 0);
819 AddContextCommand(pRootContext, L"alias", AliasCommand, IDS_HLP_ALIAS, IDS_HLP_ALIAS_EX, 0);
820 AddContextCommand(pRootContext, L"bye", ExitCommand, IDS_HLP_EXIT, IDS_HLP_EXIT_EX, 0);
821 AddContextCommand(pRootContext, L"commit", CommitCommand, IDS_HLP_COMMIT, IDS_HLP_COMMIT_EX, 0);
822 AddContextCommand(pRootContext, L"dump", DumpCommand, IDS_HLP_DUMP, IDS_HLP_DUMP_EX, 0);
823 AddContextCommand(pRootContext, L"exec", ExecCommand, IDS_HLP_EXEC, IDS_HLP_EXEC_EX, 0);
824 AddContextCommand(pRootContext, L"exit", ExitCommand, IDS_HLP_EXIT, IDS_HLP_EXIT_EX, 0);
825 AddContextCommand(pRootContext, L"help", NULL, IDS_HLP_HELP, IDS_HLP_HELP_EX, 0);
826 AddContextCommand(pRootContext, L"offline", OfflineCommand, IDS_HLP_OFFLINE, IDS_HLP_OFFLINE_EX, 0);
827 AddContextCommand(pRootContext, L"online", OnlineCommand, IDS_HLP_ONLINE, IDS_HLP_ONLINE_EX, 0);
828 AddContextCommand(pRootContext, L"popd", PopdCommand, IDS_HLP_POPD, IDS_HLP_POPD_EX, 0);
829 AddContextCommand(pRootContext, L"pushd", PushdCommand, IDS_HLP_PUSHD, IDS_HLP_PUSHD_EX, 0);
830 AddContextCommand(pRootContext, L"quit", ExitCommand, IDS_HLP_EXIT, IDS_HLP_EXIT_EX, 0);
831 AddContextCommand(pRootContext, L"unalias", UnaliasCommand, IDS_HLP_UNALIAS, IDS_HLP_UNALIAS_EX, 0);
832
833 pGroup = AddCommandGroup(pRootContext, L"add", IDS_HLP_GROUP_ADD, 0);
834 if (pGroup)
835 {
836 AddGroupCommand(pGroup, L"helper", AddHelperCommand, IDS_HLP_ADD_HELPER, IDS_HLP_ADD_HELPER_EX, 0);
837 }
838
839 pGroup = AddCommandGroup(pRootContext, L"delete", IDS_HLP_GROUP_DELETE, 0);
840 if (pGroup)
841 {
842 AddGroupCommand(pGroup, L"helper", DeleteHelperCommand, IDS_HLP_DEL_HELPER, IDS_HLP_DEL_HELPER_EX, 0);
843 }
844
845 pGroup = AddCommandGroup(pRootContext, L"set", IDS_HLP_GROUP_SET, 0);
846 if (pGroup)
847 {
848 AddGroupCommand(pGroup, L"machine", SetMachineCommand, IDS_HLP_SET_MACHINE, IDS_HLP_SET_MACHINE_EX, 0);
849 AddGroupCommand(pGroup, L"mode", SetModeCommand, IDS_HLP_SET_MODE, IDS_HLP_SET_MODE_EX, 0);
850 }
851
852 pGroup = AddCommandGroup(pRootContext, L"show", IDS_HLP_GROUP_SHOW, 0);
853 if (pGroup)
854 {
855 AddGroupCommand(pGroup, L"alias", ShowAliasCommand, IDS_HLP_SHOW_ALIAS, IDS_HLP_SHOW_ALIAS_EX, 0);
856 AddGroupCommand(pGroup, L"helper", ShowHelperCommand, IDS_HLP_SHOW_HELPER, IDS_HLP_SHOW_HELPER_EX, 0);
857 AddGroupCommand(pGroup, L"mode", ShowModeCommand, IDS_HLP_SHOW_MODE, IDS_HLP_SHOW_MODE_EX, 0);
858 }
859
860 pCurrentContext = pRootContext;
861
862 return TRUE;
863}
864
865
866static
867PCONTEXT_ENTRY
868FindSubContextByGuid(
869 PCONTEXT_ENTRY pContext,
870 const GUID *pGuid)
871{
872 PCONTEXT_ENTRY pResultContext, pSubContext;
873
874 DPRINT("FindSubContextByGuid(%p)\n", pContext);
875 DPRINT("%lx <--> %lx\n", pContext->Guid.Data1, pGuid->Data1);
876
877 if (IsEqualGUID(&pContext->Guid, pGuid))
878 {
879 DPRINT("Found!\n");
880 return pContext;
881 }
882
883 pSubContext = pContext->pSubContextHead;
884 while (pSubContext)
885 {
886 pResultContext = FindSubContextByGuid(pSubContext, pGuid);
887 if (pResultContext)
888 return pResultContext;
889
890 pSubContext = pSubContext->pNext;
891 }
892
893 return NULL;
894}
895
896
897PCONTEXT_ENTRY
898FindContextByGuid(
899 const GUID *pGuid)
900{
901 if (pRootContext == NULL)
902 return NULL;
903 return FindSubContextByGuid(pRootContext, pGuid);
904}
905
906
907DWORD
908WINAPI
909RegisterContext(
910 _In_ const NS_CONTEXT_ATTRIBUTES *pChildContext)
911{
912 PHELPER_ENTRY pHelper;
913 PCONTEXT_ENTRY pContext, pParentContext;
914 PCOMMAND_GROUP pGroup;
915 DWORD i, j;
916
917 DPRINT1("RegisterContext(%p)\n", pChildContext);
918 if (pChildContext == NULL)
919 {
920 DPRINT1("Invalid child context!\n");
921 return ERROR_INVALID_PARAMETER;
922 }
923
924 if ((pChildContext->pwszContext == NULL) ||
925 (wcslen(pChildContext->pwszContext) == 0) ||
926 (wcschr(pChildContext->pwszContext, L' ') != 0) ||
927 (wcschr(pChildContext->pwszContext, L'=') != 0))
928 {
929 DPRINT1("Invalid context name!\n");
930 return ERROR_INVALID_PARAMETER;
931 }
932
933 DPRINT("Name: %S\n", pChildContext->pwszContext);
934 DPRINT("Groups: %lu\n", pChildContext->ulNumGroups);
935 DPRINT("Top commands: %lu\n", pChildContext->ulNumTopCmds);
936
937 pHelper = FindHelper(&pChildContext->guidHelper, pHelperListHead);
938 DPRINT("Helper %p\n", pHelper);
939 pParentContext = pRootContext;
940 if (pHelper != NULL)
941 {
942 pParentContext = FindContextByGuid(&pHelper->ParentHelperGuid);
943 DPRINT("pParentContext %p\n", pParentContext);
944 if (pParentContext == NULL)
945 pParentContext = pRootContext;
946 }
947
948 pContext = AddContext(pParentContext, pChildContext->pwszContext, (GUID*)&pChildContext->guidHelper);
949 if (pContext != NULL)
950 {
951 pContext->pfnCommitFn = pChildContext->pfnCommitFn;
952 pContext->pfnDumpFn = pChildContext->pfnDumpFn;
953 pContext->pfnConnectFn = pChildContext->pfnConnectFn;
954 pContext->ulPriority = (pChildContext->dwFlags & CMD_FLAG_PRIORITY) ?
955 pChildContext->ulPriority : DEFAULT_CONTEXT_PRIORITY;
956
957 if ((pHelper != NULL) && (pHelper->pDllEntry != NULL))
958 {
959 pContext->hModule = pHelper->pDllEntry->hModule;
960 }
961
962 for (i = 0; i < pChildContext->ulNumTopCmds; i++)
963 {
964 AddContextCommand(pContext,
965 pChildContext->pTopCmds[i].pwszCmdToken,
966 pChildContext->pTopCmds[i].pfnCmdHandler,
967 pChildContext->pTopCmds[i].dwShortCmdHelpToken,
968 pChildContext->pTopCmds[i].dwCmdHlpToken,
969 pChildContext->pTopCmds[i].dwFlags);
970 }
971
972 /* Add command groups */
973 for (i = 0; i < pChildContext->ulNumGroups; i++)
974 {
975 pGroup = AddCommandGroup(pContext,
976 pChildContext->pCmdGroups[i].pwszCmdGroupToken,
977 pChildContext->pCmdGroups[i].dwShortCmdHelpToken,
978 pChildContext->pCmdGroups[i].dwFlags);
979 if (pGroup != NULL)
980 {
981 for (j = 0; j < pChildContext->pCmdGroups[i].ulCmdGroupSize; j++)
982 {
983 AddGroupCommand(pGroup,
984 pChildContext->pCmdGroups[i].pCmdGroup[j].pwszCmdToken,
985 pChildContext->pCmdGroups[i].pCmdGroup[j].pfnCmdHandler,
986 pChildContext->pCmdGroups[i].pCmdGroup[j].dwShortCmdHelpToken,
987 pChildContext->pCmdGroups[i].pCmdGroup[j].dwCmdHlpToken,
988 pChildContext->pCmdGroups[i].pCmdGroup[j].dwFlags);
989 }
990 }
991 }
992 }
993
994 return ERROR_SUCCESS;
995}
996
997
998VOID
999CleanupContext(VOID)
1000{
1001 /* Delete the context stack */
1002
1003}