1 /* 2 * PROJECT: ReactOS Applications Manager 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Functions to parse command-line flags and process them 5 * COPYRIGHT: Copyright 2017 Alexander Shaposhnikov (sanchaez@reactos.org) 6 * Copyright 2020 He Yang (1160386205@qq.com) 7 */ 8 9 #include "rapps.h" 10 #include "unattended.h" 11 #include "winmain.h" 12 #include <setupapi.h> 13 #include <conutils.h> 14 15 BOOL MatchCmdOption(LPWSTR argvOption, LPCWSTR szOptToMacth) 16 { 17 WCHAR FirstCharList[] = { L'-', L'/' }; 18 19 for (UINT i = 0; i < _countof(FirstCharList); i++) 20 { 21 if (argvOption[0] == FirstCharList[i]) 22 { 23 return StrCmpIW(argvOption + 1, szOptToMacth) == 0; 24 } 25 } 26 return FALSE; 27 } 28 29 void InitRappsConsole() 30 { 31 // First, try to attach to our parent's console 32 if (!AttachConsole(ATTACH_PARENT_PROCESS)) 33 { 34 // Did we already have a console? 35 if (GetLastError() != ERROR_ACCESS_DENIED) 36 { 37 // No, try to open a new one 38 AllocConsole(); 39 } 40 } 41 ConInitStdStreams(); // Initialize the Console Standard Streams 42 } 43 44 45 BOOL HandleInstallCommand(LPWSTR szCommand, int argcLeft, LPWSTR * argvLeft) 46 { 47 if (argcLeft == 0) 48 { 49 InitRappsConsole(); 50 ConResMsgPrintf(StdOut, NULL, IDS_CMD_NEED_PACKAGE_NAME, szCommand); 51 return FALSE; 52 } 53 54 ATL::CSimpleArray<ATL::CStringW> PkgNameList; 55 56 for (int i = 0; i < argcLeft; i++) 57 { 58 PkgNameList.Add(argvLeft[i]); 59 } 60 61 CAvailableApps apps; 62 apps.UpdateAppsDB(); 63 apps.Enum(ENUM_ALL_AVAILABLE, NULL, NULL); 64 65 ATL::CSimpleArray<CAvailableApplicationInfo> arrAppInfo = apps.FindAppsByPkgNameList(PkgNameList); 66 if (arrAppInfo.GetSize() > 0) 67 { 68 DownloadListOfApplications(arrAppInfo, TRUE); 69 return TRUE; 70 } 71 else 72 { 73 return FALSE; 74 } 75 } 76 77 BOOL HandleSetupCommand(LPWSTR szCommand, int argcLeft, LPWSTR * argvLeft) 78 { 79 if (argcLeft != 1) 80 { 81 InitRappsConsole(); 82 ConResMsgPrintf(StdOut, NULL, IDS_CMD_NEED_FILE_NAME, szCommand); 83 return FALSE; 84 } 85 86 ATL::CSimpleArray<ATL::CStringW> PkgNameList; 87 HINF InfHandle = SetupOpenInfFileW(argvLeft[0], NULL, INF_STYLE_WIN4, NULL); 88 if (InfHandle == INVALID_HANDLE_VALUE) 89 { 90 return FALSE; 91 } 92 93 INFCONTEXT Context; 94 if (SetupFindFirstLineW(InfHandle, L"RAPPS", L"Install", &Context)) 95 { 96 WCHAR szPkgName[MAX_PATH]; 97 do 98 { 99 if (SetupGetStringFieldW(&Context, 1, szPkgName, _countof(szPkgName), NULL)) 100 { 101 PkgNameList.Add(szPkgName); 102 } 103 } while (SetupFindNextLine(&Context, &Context)); 104 } 105 SetupCloseInfFile(InfHandle); 106 107 CAvailableApps apps; 108 apps.UpdateAppsDB(); 109 apps.Enum(ENUM_ALL_AVAILABLE, NULL, NULL); 110 111 ATL::CSimpleArray<CAvailableApplicationInfo> arrAppInfo = apps.FindAppsByPkgNameList(PkgNameList); 112 if (arrAppInfo.GetSize() > 0) 113 { 114 DownloadListOfApplications(arrAppInfo, TRUE); 115 return TRUE; 116 } 117 else 118 { 119 return FALSE; 120 } 121 } 122 123 BOOL CALLBACK CmdFindAppEnum(CAvailableApplicationInfo *Info, BOOL bInitialCheckState, PVOID param) 124 { 125 LPCWSTR lpszSearch = (LPCWSTR)param; 126 if (!SearchPatternMatch(Info->m_szName, lpszSearch) && 127 !SearchPatternMatch(Info->m_szDesc, lpszSearch)) 128 { 129 return TRUE; 130 } 131 132 ConPrintf(StdOut, L"%s (%s)\n", Info->m_szName.GetString(), Info->m_szPkgName.GetString()); 133 return TRUE; 134 } 135 136 BOOL HandleFindCommand(LPWSTR szCommand, int argcLeft, LPWSTR *argvLeft) 137 { 138 if (argcLeft < 1) 139 { 140 ConResMsgPrintf(StdOut, NULL, IDS_CMD_NEED_PARAMS, szCommand); 141 return FALSE; 142 } 143 144 CAvailableApps apps; 145 apps.UpdateAppsDB(); 146 147 for (int i = 0; i < argcLeft; i++) 148 { 149 ConResMsgPrintf(StdOut, NULL, IDS_CMD_FIND_RESULT_FOR, argvLeft[i]); 150 apps.Enum(ENUM_ALL_AVAILABLE, CmdFindAppEnum, argvLeft[i]); 151 ConPrintf(StdOut, L"\n"); 152 } 153 154 return TRUE; 155 } 156 157 BOOL HandleInfoCommand(LPWSTR szCommand, int argcLeft, LPWSTR *argvLeft) 158 { 159 if (argcLeft < 1) 160 { 161 ConResMsgPrintf(StdOut, NULL, IDS_CMD_NEED_PARAMS, szCommand); 162 return FALSE; 163 } 164 165 CAvailableApps apps; 166 apps.UpdateAppsDB(); 167 apps.Enum(ENUM_ALL_AVAILABLE, NULL, NULL); 168 169 for (int i = 0; i < argcLeft; i++) 170 { 171 CAvailableApplicationInfo *AppInfo = apps.FindAppByPkgName(argvLeft[i]); 172 if (!AppInfo) 173 { 174 ConResMsgPrintf(StdOut, NULL, IDS_CMD_PACKAGE_NOT_FOUND, argvLeft[i]); 175 } 176 else 177 { 178 ConResMsgPrintf(StdOut, NULL, IDS_CMD_PACKAGE_INFO, argvLeft[i]); 179 // TODO: code about extracting information from CAvailableApplicationInfo (in appview.cpp, class CAppRichEdit) 180 // is in a mess. It should be refactored, and should not placed in class CAppRichEdit. 181 // and the code here should reused that code after refactor. 182 183 ConPuts(StdOut, AppInfo->m_szName); 184 185 if (AppInfo->m_szVersion) 186 { 187 ConResPrintf(StdOut, IDS_AINFO_VERSION); 188 ConPuts(StdOut, AppInfo->m_szVersion); 189 } 190 191 if (AppInfo->m_szLicense) 192 { 193 ConResPrintf(StdOut, IDS_AINFO_LICENSE); 194 ConPuts(StdOut, AppInfo->m_szLicense); 195 } 196 197 if (AppInfo->m_szSize) 198 { 199 ConResPrintf(StdOut, IDS_AINFO_SIZE); 200 ConPuts(StdOut, AppInfo->m_szSize); 201 } 202 203 if (AppInfo->m_szUrlSite) 204 { 205 ConResPrintf(StdOut, IDS_AINFO_URLSITE); 206 ConPuts(StdOut, AppInfo->m_szUrlSite); 207 } 208 209 if (AppInfo->m_szDesc) 210 { 211 ConResPrintf(StdOut, IDS_AINFO_DESCRIPTION); 212 ConPuts(StdOut, AppInfo->m_szDesc); 213 } 214 215 if (AppInfo->m_szUrlDownload) 216 { 217 ConResPrintf(StdOut, IDS_AINFO_URLDOWNLOAD); 218 ConPuts(StdOut, AppInfo->m_szUrlDownload); 219 } 220 221 ConPrintf(StdOut, L"\n"); 222 } 223 ConPrintf(StdOut, L"\n"); 224 } 225 return TRUE; 226 } 227 228 VOID PrintHelpCommand() 229 { 230 ConPrintf(StdOut, L"\n"); 231 ConResPuts(StdOut, IDS_APPTITLE); 232 ConPrintf(StdOut, L"\n\n"); 233 234 ConResPuts(StdOut, IDS_CMD_USAGE); 235 ConPrintf(StdOut, L"%ls\n", UsageString); 236 } 237 238 BOOL ParseCmdAndExecute(LPWSTR lpCmdLine, BOOL bIsFirstLaunch, int nCmdShow) 239 { 240 INT argc; 241 LPWSTR *argv = CommandLineToArgvW(lpCmdLine, &argc); 242 243 if (!argv) 244 { 245 return FALSE; 246 } 247 248 if (argc == 1) // RAPPS is launched without options 249 { 250 // Check for if rapps MainWindow is already launched in another process 251 HANDLE hMutex; 252 253 hMutex = CreateMutexW(NULL, FALSE, szWindowClass); 254 if ((!hMutex) || (GetLastError() == ERROR_ALREADY_EXISTS)) 255 { 256 /* If already started, it is found its window */ 257 HWND hWindow = FindWindowW(szWindowClass, NULL); 258 259 /* Activate window */ 260 ShowWindow(hWindow, SW_SHOWNORMAL); 261 SetForegroundWindow(hWindow); 262 return FALSE; 263 } 264 265 if (SettingsInfo.bUpdateAtStart || bIsFirstLaunch) 266 CAvailableApps::ForceUpdateAppsDB(); 267 268 MainWindowLoop(nCmdShow); 269 270 if (hMutex) 271 CloseHandle(hMutex); 272 273 return TRUE; 274 } 275 276 if (MatchCmdOption(argv[1], CMD_KEY_INSTALL)) 277 { 278 return HandleInstallCommand(argv[1], argc - 2, argv + 2); 279 } 280 else if (MatchCmdOption(argv[1], CMD_KEY_SETUP)) 281 { 282 return HandleSetupCommand(argv[1], argc - 2, argv + 2); 283 } 284 285 InitRappsConsole(); 286 287 if (MatchCmdOption(argv[1], CMD_KEY_FIND)) 288 { 289 return HandleFindCommand(argv[1], argc - 2, argv + 2); 290 } 291 else if (MatchCmdOption(argv[1], CMD_KEY_INFO)) 292 { 293 return HandleInfoCommand(argv[1], argc - 2, argv + 2); 294 } 295 else if (MatchCmdOption(argv[1], CMD_KEY_HELP) || MatchCmdOption(argv[1], CMD_KEY_HELP_ALT)) 296 { 297 PrintHelpCommand(); 298 return TRUE; 299 } 300 else 301 { 302 // unrecognized/invalid options 303 ConResPuts(StdOut, IDS_CMD_INVALID_OPTION); 304 PrintHelpCommand(); 305 return FALSE; 306 } 307 } 308