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 17 PCONTEXT_ENTRY pRootContext = NULL; 18 PCONTEXT_ENTRY pCurrentContext = NULL; 19 20 /* FUNCTIONS ******************************************************************/ 21 22 PCONTEXT_ENTRY 23 AddContext( 24 PCONTEXT_ENTRY pParentContext, 25 PWSTR pszName, 26 GUID *pGuid) 27 { 28 PCONTEXT_ENTRY pEntry; 29 30 if (pParentContext != NULL && pszName == NULL) 31 return NULL; 32 33 /* Allocate the entry */ 34 pEntry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CONTEXT_ENTRY)); 35 if (pEntry == NULL) 36 return NULL; 37 38 /* Allocate the name buffer */ 39 if (pszName != NULL) 40 { 41 pEntry->pszContextName = HeapAlloc(GetProcessHeap(), 42 HEAP_ZERO_MEMORY, 43 (wcslen(pszName) + 1) * sizeof(WCHAR)); 44 if (pEntry->pszContextName == NULL) 45 { 46 HeapFree(GetProcessHeap(), 0, pEntry); 47 return NULL; 48 } 49 50 /* Fill the entry */ 51 wcscpy(pEntry->pszContextName, pszName); 52 } 53 54 pEntry->pParentContext = pParentContext; 55 if (pGuid != NULL) 56 CopyMemory(&pEntry->Guid, pGuid, sizeof(pEntry->Guid)); 57 58 /* Insert it */ 59 if (pParentContext != NULL) 60 { 61 if (pParentContext->pSubContextHead == NULL && pParentContext->pSubContextTail == NULL) 62 { 63 pParentContext->pSubContextHead = pEntry; 64 pParentContext->pSubContextTail = pEntry; 65 } 66 else 67 { 68 pEntry->pPrev = pParentContext->pSubContextTail; 69 pParentContext->pSubContextTail->pNext = pEntry; 70 pParentContext->pSubContextTail = pEntry; 71 } 72 } 73 74 return pEntry; 75 } 76 77 78 PCOMMAND_ENTRY 79 AddContextCommand( 80 PCONTEXT_ENTRY pContext, 81 LPCWSTR pwszCmdToken, 82 PFN_HANDLE_CMD pfnCmdHandler, 83 DWORD dwShortCmdHelpToken, 84 DWORD dwCmdHlpToken, 85 DWORD dwFlags) 86 { 87 PCOMMAND_ENTRY pEntry; 88 89 if (pfnCmdHandler == NULL) 90 return NULL; 91 92 /* Allocate the entry */ 93 pEntry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(COMMAND_ENTRY)); 94 if (pEntry == NULL) 95 return NULL; 96 97 pEntry->pwszCmdToken = HeapAlloc(GetProcessHeap(), 98 HEAP_ZERO_MEMORY, 99 (wcslen(pwszCmdToken) + 1) * sizeof(WCHAR)); 100 if (pEntry->pwszCmdToken == NULL) 101 { 102 HeapFree(GetProcessHeap(), 0, pEntry); 103 return NULL; 104 } 105 106 wcscpy((LPWSTR)pEntry->pwszCmdToken, pwszCmdToken); 107 108 pEntry->pfnCmdHandler = pfnCmdHandler; 109 pEntry->dwShortCmdHelpToken = dwShortCmdHelpToken; 110 pEntry->dwCmdHlpToken = dwCmdHlpToken; 111 pEntry->dwFlags = dwFlags; 112 113 if (pContext->pCommandListHead == NULL && pContext->pCommandListTail == NULL) 114 { 115 pContext->pCommandListHead = pEntry; 116 pContext->pCommandListTail = pEntry; 117 } 118 else 119 { 120 pEntry->pPrev = pContext->pCommandListTail; 121 pContext->pCommandListTail->pNext = pEntry; 122 pContext->pCommandListTail = pEntry; 123 } 124 125 return pEntry; 126 } 127 128 129 PCOMMAND_GROUP 130 AddCommandGroup( 131 PCONTEXT_ENTRY pContext, 132 LPCWSTR pwszCmdGroupToken, 133 DWORD dwShortCmdHelpToken, 134 DWORD dwFlags) 135 { 136 PCOMMAND_GROUP pEntry; 137 138 /* Allocate the entry */ 139 pEntry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(COMMAND_GROUP)); 140 if (pEntry == NULL) 141 return NULL; 142 143 pEntry->pwszCmdGroupToken = HeapAlloc(GetProcessHeap(), 144 HEAP_ZERO_MEMORY, 145 (wcslen(pwszCmdGroupToken) + 1) * sizeof(WCHAR)); 146 if (pEntry->pwszCmdGroupToken == NULL) 147 { 148 HeapFree(GetProcessHeap(), 0, pEntry); 149 return NULL; 150 } 151 152 wcscpy((LPWSTR)pEntry->pwszCmdGroupToken, pwszCmdGroupToken); 153 pEntry->dwShortCmdHelpToken = dwShortCmdHelpToken; 154 pEntry->dwFlags = dwFlags; 155 156 if (pContext->pGroupListHead == NULL && pContext->pGroupListTail == NULL) 157 { 158 pContext->pGroupListHead = pEntry; 159 pContext->pGroupListTail = pEntry; 160 } 161 else 162 { 163 pEntry->pPrev = pContext->pGroupListTail; 164 pContext->pGroupListTail->pNext = pEntry; 165 pContext->pGroupListTail = pEntry; 166 } 167 168 return pEntry; 169 } 170 171 172 PCOMMAND_ENTRY 173 AddGroupCommand( 174 PCOMMAND_GROUP pGroup, 175 LPCWSTR pwszCmdToken, 176 PFN_HANDLE_CMD pfnCmdHandler, 177 DWORD dwShortCmdHelpToken, 178 DWORD dwCmdHlpToken, 179 DWORD dwFlags) 180 { 181 PCOMMAND_ENTRY pEntry; 182 183 if (pfnCmdHandler == NULL) 184 return NULL; 185 186 /* Allocate the entry */ 187 pEntry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(COMMAND_ENTRY)); 188 if (pEntry == NULL) 189 return NULL; 190 191 pEntry->pwszCmdToken = HeapAlloc(GetProcessHeap(), 192 HEAP_ZERO_MEMORY, 193 (wcslen(pwszCmdToken) + 1) * sizeof(WCHAR)); 194 if (pEntry->pwszCmdToken == NULL) 195 { 196 HeapFree(GetProcessHeap(), 0, pEntry); 197 return NULL; 198 } 199 200 wcscpy((LPWSTR)pEntry->pwszCmdToken, pwszCmdToken); 201 202 pEntry->pfnCmdHandler = pfnCmdHandler; 203 pEntry->dwShortCmdHelpToken = dwShortCmdHelpToken; 204 pEntry->dwCmdHlpToken = dwCmdHlpToken; 205 pEntry->dwFlags = dwFlags; 206 207 if (pGroup->pCommandListHead == NULL && pGroup->pCommandListTail == NULL) 208 { 209 pGroup->pCommandListHead = pEntry; 210 pGroup->pCommandListTail = pEntry; 211 } 212 else 213 { 214 pEntry->pPrev = pGroup->pCommandListTail; 215 pGroup->pCommandListTail->pNext = pEntry; 216 pGroup->pCommandListTail = pEntry; 217 } 218 219 return pEntry; 220 } 221 222 223 VOID 224 DeleteContext( 225 PWSTR pszName) 226 { 227 /* Delete all commands */ 228 /* Delete the context */ 229 } 230 231 232 DWORD 233 WINAPI 234 UpCommand( 235 LPCWSTR pwszMachine, 236 LPWSTR *argv, 237 DWORD dwCurrentIndex, 238 DWORD dwArgCount, 239 DWORD dwFlags, 240 LPCVOID pvData, 241 BOOL *pbDone) 242 { 243 if (pCurrentContext != pRootContext) 244 pCurrentContext = pCurrentContext->pParentContext; 245 246 return 0; 247 } 248 249 250 DWORD 251 WINAPI 252 ExitCommand( 253 LPCWSTR pwszMachine, 254 LPWSTR *argv, 255 DWORD dwCurrentIndex, 256 DWORD dwArgCount, 257 DWORD dwFlags, 258 LPCVOID pvData, 259 BOOL *pbDone) 260 { 261 *pbDone = TRUE; 262 return 0; 263 } 264 265 266 DWORD 267 WINAPI 268 RemCommand( 269 LPCWSTR pwszMachine, 270 LPWSTR *argv, 271 DWORD dwCurrentIndex, 272 DWORD dwArgCount, 273 DWORD dwFlags, 274 LPCVOID pvData, 275 BOOL *pbDone) 276 { 277 return 0; 278 } 279 280 281 BOOL 282 CreateRootContext(VOID) 283 { 284 PCOMMAND_GROUP pGroup; 285 286 pRootContext = AddContext(NULL, NULL, NULL); 287 DPRINT1("pRootContext: %p\n", pRootContext); 288 if (pRootContext == NULL) 289 return FALSE; 290 291 pRootContext->hModule = GetModuleHandle(NULL); 292 293 AddContextCommand(pRootContext, L"..", UpCommand, IDS_HLP_UP, IDS_HLP_UP_EX, 0); 294 AddContextCommand(pRootContext, L"?", HelpCommand, IDS_HLP_HELP, IDS_HLP_HELP_EX, 0); 295 AddContextCommand(pRootContext, L"bye", ExitCommand, IDS_HLP_EXIT, IDS_HLP_EXIT_EX, 0); 296 AddContextCommand(pRootContext, L"exit", ExitCommand, IDS_HLP_EXIT, IDS_HLP_EXIT_EX, 0); 297 AddContextCommand(pRootContext, L"help", HelpCommand, IDS_HLP_HELP, IDS_HLP_HELP_EX, 0); 298 AddContextCommand(pRootContext, L"quit", ExitCommand, IDS_HLP_EXIT, IDS_HLP_EXIT_EX, 0); 299 300 pGroup = AddCommandGroup(pRootContext, L"add", IDS_HLP_GROUP_ADD, 0); 301 if (pGroup) 302 { 303 AddGroupCommand(pGroup, L"helper", AddHelperCommand, IDS_HLP_ADD_HELPER, IDS_HLP_ADD_HELPER_EX, 0); 304 } 305 306 pGroup = AddCommandGroup(pRootContext, L"delete", IDS_HLP_GROUP_DELETE, 0); 307 if (pGroup) 308 { 309 AddGroupCommand(pGroup, L"helper", DeleteHelperCommand, IDS_HLP_DEL_HELPER, IDS_HLP_DEL_HELPER_EX, 0); 310 } 311 312 pGroup = AddCommandGroup(pRootContext, L"show", IDS_HLP_GROUP_SHOW, 0); 313 if (pGroup) 314 { 315 AddGroupCommand(pGroup, L"helper", ShowHelperCommand, IDS_HLP_SHOW_HELPER, IDS_HLP_SHOW_HELPER_EX, 0); 316 } 317 318 pCurrentContext = pRootContext; 319 320 return TRUE; 321 } 322 323 324 DWORD 325 WINAPI 326 RegisterContext( 327 _In_ const NS_CONTEXT_ATTRIBUTES *pChildContext) 328 { 329 PCONTEXT_ENTRY pContext; 330 DWORD i; 331 332 DPRINT1("RegisterContext(%p)\n", pChildContext); 333 if (pChildContext == NULL) 334 { 335 DPRINT1("Invalid child context!\n"); 336 return ERROR_INVALID_PARAMETER; 337 } 338 339 if ((pChildContext->pwszContext == NULL) || 340 (wcslen(pChildContext->pwszContext) == 0) || 341 (wcschr(pChildContext->pwszContext, L' ') != 0) || 342 (wcschr(pChildContext->pwszContext, L'=') != 0)) 343 { 344 DPRINT1("Invalid context name!\n"); 345 return ERROR_INVALID_PARAMETER; 346 } 347 348 DPRINT1("Name: %S\n", pChildContext->pwszContext); 349 350 pContext = AddContext(pRootContext, pChildContext->pwszContext, (GUID*)&pChildContext->guidHelper); 351 if (pContext != NULL) 352 { 353 for (i = 0; i < pChildContext->ulNumTopCmds; i++) 354 { 355 AddContextCommand(pContext, 356 pChildContext->pTopCmds[i].pwszCmdToken, 357 pChildContext->pTopCmds[i].pfnCmdHandler, 358 pChildContext->pTopCmds[i].dwShortCmdHelpToken, 359 pChildContext->pTopCmds[i].dwCmdHlpToken, 360 pChildContext->pTopCmds[i].dwFlags); 361 } 362 363 /* Add command groups */ 364 for (i = 0; i < pChildContext->ulNumGroups; i++) 365 { 366 AddCommandGroup(pContext, 367 pChildContext->pCmdGroups[i].pwszCmdGroupToken, 368 pChildContext->pCmdGroups[i].dwShortCmdHelpToken, 369 pChildContext->pCmdGroups[i].dwFlags); 370 } 371 } 372 373 return ERROR_SUCCESS; 374 } 375