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 command interpreter
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 /* FUNCTIONS *****************************************************************/
16 
17 BOOL
18 InterpretCommand(
19     _In_ LPWSTR *argv,
20     _In_ DWORD dwArgCount)
21 {
22     PCONTEXT_ENTRY pContext, pSubContext;
23     PCOMMAND_ENTRY pCommand;
24     PCOMMAND_GROUP pGroup;
25     BOOL bDone = FALSE;
26     DWORD dwHelpLevel = 0;
27     DWORD dwError = ERROR_SUCCESS;
28 
29     /* If no args provided */
30     if (dwArgCount == 0)
31         return TRUE;
32 
33     if (pCurrentContext == NULL)
34     {
35         DPRINT1("InterpretCmd: invalid context %p\n", pCurrentContext);
36         return FALSE;
37     }
38 
39     if ((_wcsicmp(argv[dwArgCount - 1], L"?") == 0) ||
40         (_wcsicmp(argv[dwArgCount - 1], L"help") == 0))
41     {
42         dwHelpLevel = dwArgCount - 1;
43     }
44 
45     pContext = pCurrentContext;
46 
47     while (TRUE)
48     {
49         pCommand = pContext->pCommandListHead;
50         while (pCommand != NULL)
51         {
52             if (_wcsicmp(argv[0], pCommand->pwszCmdToken) == 0)
53             {
54                 if (dwHelpLevel == 1)
55                 {
56                     ConResPrintf(StdOut, pCommand->dwCmdHlpToken);
57                     return TRUE;
58                 }
59                 else
60                 {
61                     dwError = pCommand->pfnCmdHandler(NULL, argv, 0, dwArgCount, 0, NULL, &bDone);
62                     if (dwError != ERROR_SUCCESS)
63                     {
64                         ConPrintf(StdOut, L"Error: %lu\n\n");
65                         ConResPrintf(StdOut, pCommand->dwCmdHlpToken);
66                     }
67                     return !bDone;
68                 }
69             }
70 
71             pCommand = pCommand->pNext;
72         }
73 
74         pGroup = pContext->pGroupListHead;
75         while (pGroup != NULL)
76         {
77             if (_wcsicmp(argv[0], pGroup->pwszCmdGroupToken) == 0)
78             {
79                 if (dwHelpLevel == 1)
80                 {
81                     HelpGroup(pGroup);
82                     return TRUE;
83                 }
84 
85                 pCommand = pGroup->pCommandListHead;
86                 while (pCommand != NULL)
87                 {
88                     if ((dwArgCount > 1) && (_wcsicmp(argv[1], pCommand->pwszCmdToken) == 0))
89                     {
90                         if (dwHelpLevel == 2)
91                         {
92                             ConResPrintf(StdOut, pCommand->dwCmdHlpToken);
93                             return TRUE;
94                         }
95                         else
96                         {
97                             dwError = pCommand->pfnCmdHandler(NULL, argv, 1, dwArgCount, 0, NULL, &bDone);
98                             if (dwError != ERROR_SUCCESS)
99                             {
100                                 ConPrintf(StdOut, L"Error: %lu\n\n");
101                                 ConResPrintf(StdOut, pCommand->dwCmdHlpToken);
102                                 return TRUE;
103                             }
104                             return !bDone;
105                         }
106                     }
107 
108                     pCommand = pCommand->pNext;
109                 }
110 
111                 HelpGroup(pGroup);
112                 return TRUE;
113             }
114 
115             pGroup = pGroup->pNext;
116         }
117 
118         if (pContext == pCurrentContext)
119         {
120             pSubContext = pContext->pSubContextHead;
121             while (pSubContext != NULL)
122             {
123                 if (_wcsicmp(argv[0], pSubContext->pszContextName) == 0)
124                 {
125                     pCurrentContext = pSubContext;
126                     return TRUE;
127                 }
128 
129                 pSubContext = pSubContext->pNext;
130             }
131         }
132 
133         if (pContext == pRootContext)
134             break;
135 
136         pContext = pContext->pParentContext;
137     }
138 
139     ConResPrintf(StdErr, IDS_INVALID_COMMAND, argv[0]);
140 
141     return TRUE;
142 }
143 
144 
145 /*
146  * InterpretScript(char *line):
147  * The main function used for when reading commands from scripts.
148  */
149 BOOL
150 InterpretScript(
151     _In_ LPWSTR pszInputLine)
152 {
153     LPWSTR args_vector[MAX_ARGS_COUNT];
154     DWORD dwArgCount = 0;
155     BOOL bWhiteSpace = TRUE;
156     LPWSTR ptr;
157 
158     memset(args_vector, 0, sizeof(args_vector));
159 
160     ptr = pszInputLine;
161     while (*ptr != 0)
162     {
163         if (iswspace(*ptr) || *ptr == L'\n')
164         {
165             *ptr = 0;
166             bWhiteSpace = TRUE;
167         }
168         else
169         {
170             if ((bWhiteSpace != FALSE) && (dwArgCount < MAX_ARGS_COUNT))
171             {
172                 args_vector[dwArgCount] = ptr;
173                 dwArgCount++;
174             }
175 
176             bWhiteSpace = FALSE;
177         }
178 
179         ptr++;
180     }
181 
182     /* sends the string to find the command */
183     return InterpretCommand(args_vector, dwArgCount);
184 }
185 
186 
187 VOID
188 InterpretInteractive(VOID)
189 {
190     WCHAR input_line[MAX_STRING_SIZE];
191     LPWSTR args_vector[MAX_ARGS_COUNT];
192     DWORD dwArgCount = 0;
193     BOOL bWhiteSpace = TRUE;
194     BOOL bRun = TRUE;
195     LPWSTR ptr;
196 
197     while (bRun != FALSE)
198     {
199         dwArgCount = 0;
200         memset(args_vector, 0, sizeof(args_vector));
201 
202         /* Shown just before the input where the user places commands */
203 //        ConResPuts(StdOut, IDS_APP_PROMPT);
204         ConPuts(StdOut, L"netsh");
205         if (pCurrentContext != pRootContext)
206         {
207             ConPuts(StdOut, L" ");
208             ConPuts(StdOut, pCurrentContext->pszContextName);
209         }
210         ConPuts(StdOut, L">");
211 
212         /* Get input from the user. */
213         fgetws(input_line, MAX_STRING_SIZE, stdin);
214 
215         ptr = input_line;
216         while (*ptr != 0)
217         {
218             if (iswspace(*ptr) || *ptr == L'\n')
219             {
220                 *ptr = 0;
221                 bWhiteSpace = TRUE;
222             }
223             else
224             {
225                 if ((bWhiteSpace != FALSE) && (dwArgCount < MAX_ARGS_COUNT))
226                 {
227                     args_vector[dwArgCount] = ptr;
228                     dwArgCount++;
229                 }
230                 bWhiteSpace = FALSE;
231             }
232             ptr++;
233         }
234 
235         /* Send the string to find the command */
236         bRun = InterpretCommand(args_vector, dwArgCount);
237     }
238 }
239