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.

451 lines
14 KiB

  1. //+--------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1999
  5. //
  6. // File: main.cpp
  7. //
  8. // Contents: Front end to license "needer"; lists TS licenses
  9. //
  10. // History: 06-05-99 t-BStern Created
  11. //
  12. //---------------------------------------------------------------------------
  13. // The goal here is to export
  14. // all [temporary] licenses [issued between <shortdate1> and <shortdate2>]
  15. // to a file [named <outFile>] [only from server[s] <S>]
  16. //
  17. // So possible command lines are:
  18. // lsls | lsls /T /D 1/1/99 2/2/00 /F outfile ls-server ls2 ls3
  19. #include "lsreport.h"
  20. #include "lsrepdef.h"
  21. #include <oleauto.h>
  22. // I found that ErrorPrintf didn't do %1-style formatting, so this does
  23. // complete formatting and stderr output. It is referenced by code in
  24. // lsreport.cpp, so if the program becomes GUI-based, ShowError needs to
  25. // maintain a presence.
  26. DWORD
  27. ShowError(
  28. IN DWORD dwStatus, // This is both the return value and the resource ID.
  29. IN INT_PTR *args, // Casted to va_list* and passed to FormatMessage.
  30. IN BOOL fSysError // Use the system message table (T) or the module (F)?
  31. ) {
  32. LPTSTR lpSysError;
  33. TCHAR szBuffer[TLS_ERROR_LENGTH];
  34. DWORD dwFlag = FORMAT_MESSAGE_FROM_SYSTEM;
  35. DWORD dwRet;
  36. if ((dwStatus == ERROR_FILE_NOT_FOUND) || !fSysError)
  37. {
  38. // We need to special-case File-not-Found because the system error
  39. // is insufficiently educational. FnF really means that the server
  40. // is not running TS.
  41. int retVal;
  42. retVal = LoadString(NULL, dwStatus, szBuffer, TLS_ERROR_LENGTH);
  43. if (!retVal)
  44. {
  45. // This is a more serious error.
  46. dwStatus = GetLastError();
  47. }
  48. else
  49. {
  50. dwFlag = FORMAT_MESSAGE_FROM_STRING;
  51. }
  52. }
  53. dwRet = FormatMessage(dwFlag |
  54. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  55. FORMAT_MESSAGE_ARGUMENT_ARRAY, // Tell FM to use INT_PTRs internally.
  56. szBuffer,
  57. dwStatus,
  58. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  59. (LPTSTR)&lpSysError,
  60. 0,
  61. (va_list *)args); // FormatMessage requires va_lists, even
  62. // if the arguments are flagged as being INT_PTRs.
  63. if ((dwRet != 0) && (lpSysError != NULL))
  64. {
  65. _fputts(lpSysError, stderr);
  66. LocalFree(lpSysError);
  67. }
  68. return dwStatus;
  69. }
  70. // Used only to enumerate the License Servers around, and thereby build a list
  71. // Used in EnumerateTlsServer()
  72. BOOL
  73. ServerEnumCallBack(
  74. IN TLS_HANDLE hHandle,
  75. IN LPCWSTR pszServerName,
  76. IN HANDLE dwUserData // Really a PServerHolder
  77. ) {
  78. LPWSTR *block;
  79. PServerHolder pSrvHold; // The casts get so hairy that I'll do this.
  80. pSrvHold = (PServerHolder)dwUserData;
  81. if ((hHandle != NULL) && (pSrvHold != NULL))
  82. {
  83. if (pSrvHold->pszNames == NULL)
  84. {
  85. // We need to allocate the names list for the first time.
  86. block = (LPWSTR *)LocalAlloc(0, sizeof (LPWSTR));
  87. } else {
  88. // The names list needs to get bigger.
  89. block = (LPWSTR *)LocalReAlloc(pSrvHold->pszNames,
  90. (1+pSrvHold->dwCount) * sizeof (LPWSTR),
  91. 0);
  92. }
  93. if (block != NULL)
  94. {
  95. // We can add a name to the list.
  96. pSrvHold->pszNames = block;
  97. pSrvHold->pszNames[pSrvHold->dwCount] = _tcsdup(pszServerName);
  98. pSrvHold->dwCount++;
  99. }
  100. // It's okay if we have to stick with the names we already have.
  101. }
  102. return FALSE;
  103. }
  104. BOOL
  105. SortDates(
  106. PSYSTEMTIME pstStart,
  107. PSYSTEMTIME pstEnd)
  108. {
  109. BOOL fSwapped = FALSE;
  110. FILETIME ftStart, ftEnd;
  111. SYSTEMTIME stHolder;
  112. SystemTimeToFileTime(pstStart, &ftStart);
  113. SystemTimeToFileTime(pstEnd, &ftEnd);
  114. if ((ftStart.dwHighDateTime > ftEnd.dwHighDateTime) ||
  115. ((ftStart.dwHighDateTime == ftEnd.dwHighDateTime) &&
  116. (ftStart.dwLowDateTime > ftEnd.dwLowDateTime)))
  117. {
  118. // We need to swap.
  119. stHolder.wYear = pstStart->wYear;
  120. stHolder.wMonth = pstStart->wMonth;
  121. stHolder.wDay = pstStart->wDay;
  122. pstStart->wYear = pstEnd->wYear;
  123. pstStart->wMonth = pstEnd->wMonth;
  124. pstStart->wDay = pstEnd->wDay;
  125. pstEnd->wYear = stHolder.wYear;
  126. pstEnd->wMonth = stHolder.wMonth;
  127. pstEnd->wDay = stHolder.wDay;
  128. fSwapped = TRUE;
  129. }
  130. return fSwapped;
  131. }
  132. // All that wmain needs to do is parse the command line and
  133. // therefore collect a list of machines to connect to, along with
  134. // any options passed, and open & close the (possibly command-line
  135. // specified) output file.
  136. extern "C" int _cdecl
  137. wmain(
  138. int argc,
  139. WCHAR *argv[],
  140. WCHAR // *envp[]
  141. ) {
  142. // These represent which command-line options were chosen.
  143. BOOL fTempOnly = FALSE;
  144. BOOL fError = FALSE;
  145. BOOL fDateSpec = FALSE;
  146. DWORD dwStatus;
  147. DWORD dwSrvLoc; // This is a bitfield.
  148. ServerHolder srvHold; // This holds all the servers.
  149. // These are for parsing the command-line-specified date(s).
  150. DATE startDate;
  151. DATE endDate;
  152. UDATE usDate;
  153. UDATE ueDate;
  154. // Basic file I/O.
  155. TCHAR ofName[MAX_PATH+1] = { 0 };
  156. FILE *outFile;
  157. int i;
  158. INT_PTR arg; // All of my strings have at most 1 parm.
  159. dwSrvLoc = 0;
  160. srvHold.dwCount = 0;
  161. srvHold.pszNames = NULL;
  162. if (!(LoadString(NULL, IDS_DEFAULT_FILE, ofName, MAX_PATH) &&
  163. InitLSReportStrings()))
  164. {
  165. return ShowError(GetLastError(), NULL, TRUE);
  166. }
  167. for (i = 1; (i < argc) && !fError; i++) {
  168. if ((argv[i][0] == '-') || (argv[i][0] == '/'))
  169. {
  170. switch (argv[i][1]) {
  171. case 'F': case 'f': // format: /F [path\]filename
  172. if (i+1 == argc)
  173. {
  174. // They didn't include enough parameters.
  175. fError = TRUE;
  176. } else {
  177. i++;
  178. _tcsncpy(ofName, argv[i], MAX_PATH);
  179. }
  180. break;
  181. case 'D': case 'd': // format: /D startdate [enddate]
  182. // Do a lot of date manipulation.
  183. if (i+1 == argc)
  184. {
  185. fError = TRUE;
  186. }
  187. else
  188. {
  189. i++;
  190. dwStatus = VarDateFromStr(argv[i],
  191. LOCALE_USER_DEFAULT,
  192. VAR_DATEVALUEONLY,
  193. &startDate);
  194. if (dwStatus != S_OK)
  195. {
  196. // The date couldn't get converted.
  197. ShowError(dwStatus, NULL, TRUE);
  198. fError = TRUE;
  199. break;
  200. }
  201. if (VarUdateFromDate(startDate, 0, &usDate) != S_OK)
  202. {
  203. // We don't want to set error, because the user can't
  204. // fix this with command line syntax. We're out of
  205. // memory or something. ABEND.
  206. return ShowError(GetLastError(), NULL, TRUE);
  207. }
  208. i++;
  209. if (i < argc)
  210. {
  211. dwStatus = VarDateFromStr(argv[i],
  212. LOCALE_USER_DEFAULT,
  213. VAR_DATEVALUEONLY,
  214. &endDate);
  215. if (dwStatus != S_OK)
  216. {
  217. ShowError(dwStatus, NULL, TRUE);
  218. fError = TRUE;
  219. break;
  220. }
  221. if (VarUdateFromDate(endDate, 0, &ueDate) != S_OK)
  222. {
  223. return ShowError(GetLastError(), NULL, TRUE);
  224. }
  225. }
  226. else
  227. {
  228. // We have to use today's date, because they didn't
  229. // give us an EndDate.
  230. GetSystemTime(&ueDate.st); // Fill in the SystemTime.
  231. }
  232. // Check if the dates are in the right order.
  233. // If the user gives us only /D 1/1/2022 and it is 1999, I
  234. // choose not to have a fit and die.
  235. SortDates(&usDate.st, &ueDate.st);
  236. fDateSpec = TRUE;
  237. }
  238. break;
  239. case 'T': case 't': // Format: /T
  240. fTempOnly = TRUE;
  241. break;
  242. // case '?': case 'H': case 'h': // Format: /?
  243. default: // Let the default get this, since it'll work the same.
  244. // This'll show syntax help.
  245. fError = TRUE;
  246. break;
  247. } // switch
  248. }
  249. else
  250. {
  251. // It wasn't -T or /F or something.
  252. // It must be a server name, since it's not anything else.
  253. dwSrvLoc |= (1 << i); // Tag this is as a server name.
  254. srvHold.dwCount++;
  255. }
  256. } // argc loop
  257. if (fError)
  258. {
  259. ShowError(IDS_HELP_USAGE1, NULL, FALSE);
  260. // Set the exe name:
  261. arg = (INT_PTR)argv[0];
  262. ShowError(IDS_HELP_USAGE2, &arg, FALSE);
  263. ShowError(IDS_HELP_USAGE3, NULL, FALSE);
  264. ShowError(IDS_HELP_USAGE4, NULL, FALSE);
  265. ShowError(IDS_HELP_USAGE5, NULL, FALSE);
  266. ShowError(IDS_HELP_USAGE6, NULL, FALSE);
  267. ShowError(IDS_HELP_USAGE7, NULL, FALSE);
  268. ShowError(IDS_HELP_USAGE8, NULL, FALSE);
  269. ShowError(IDS_HELP_USAGE9, NULL, FALSE);
  270. ShowError(IDS_HELP_USAGE10, NULL, FALSE);
  271. ShowError(IDS_HELP_USAGE11, NULL, FALSE);
  272. ShowError(IDS_HELP_USAGE12, &arg, FALSE);
  273. ShowError(IDS_HELP_USAGE13, &arg, FALSE);
  274. return ERROR_BAD_SYNTAX;
  275. }
  276. outFile = _tfopen(ofName, _T("w"));
  277. if (outFile == NULL)
  278. {
  279. // This is an extra level of indirection for FormatMessage.
  280. arg = (INT_PTR)&ofName;
  281. ShowError(IDS_NO_FOPEN, &arg, FALSE);
  282. return ShowError(GetLastError(), NULL, TRUE);
  283. }
  284. TLSInit();
  285. if (dwSrvLoc)
  286. {
  287. int holder;
  288. srvHold.pszNames = (LPWSTR *)LocalAlloc(0,
  289. srvHold.dwCount * sizeof (LPWSTR *));
  290. if (srvHold.pszNames == NULL)
  291. {
  292. dwStatus = ShowError(GetLastError(), NULL, TRUE);
  293. goto done;
  294. }
  295. holder = 0;
  296. for (i = 1; i < argc; i++) { // argc (less one) == max # of servers.
  297. if (dwSrvLoc & (1 << i)) {
  298. srvHold.pszNames[holder] = _tcsdup(argv[i]);
  299. holder++;
  300. }
  301. }
  302. }
  303. else
  304. {
  305. // We need to collect a list of servers.
  306. LPTSTR *pszEntSrvNames;
  307. DWORD dwEntSrvNum;
  308. HRESULT hrEntResult;
  309. dwStatus = EnumerateTlsServer(
  310. ServerEnumCallBack,
  311. &srvHold,
  312. 3000, // seems a good timeout
  313. FALSE);
  314. hrEntResult = GetAllEnterpriseServers(&pszEntSrvNames, &dwEntSrvNum);
  315. if (SUCCEEDED(hrEntResult))
  316. {
  317. DWORD j, k;
  318. BOOL fFound;
  319. for (k = 0; k < dwEntSrvNum; k++) {
  320. fFound = FALSE;
  321. for (j = 0; j < srvHold.dwCount; j++) {
  322. if (!_tcscmp(srvHold.pszNames[j], pszEntSrvNames[k]))
  323. {
  324. fFound = TRUE;
  325. break;
  326. }
  327. }
  328. if (!fFound)
  329. {
  330. // This is a new name.
  331. LPTSTR *block;
  332. if (srvHold.pszNames == NULL)
  333. {
  334. // We have to allocate names for the first time.
  335. block = (LPTSTR *)LocalAlloc(0, sizeof (LPTSTR));
  336. }
  337. else
  338. {
  339. // Try to increase the array.
  340. block = (LPTSTR *)LocalReAlloc(srvHold.pszNames,
  341. (1+srvHold.dwCount) * sizeof (LPTSTR),
  342. 0);
  343. }
  344. if (block != NULL)
  345. {
  346. // We can add a name to the list.
  347. srvHold.pszNames = block;
  348. srvHold.pszNames[srvHold.dwCount] = pszEntSrvNames[k];
  349. srvHold.dwCount++;
  350. }
  351. else
  352. {
  353. // If we can't copy it into our array, we should drop it.
  354. LocalFree(pszEntSrvNames[k]);
  355. }
  356. // End need to add name
  357. }
  358. // End loop through existing servers
  359. }
  360. // We've removed all of the names from this one way or the other.
  361. LocalFree(pszEntSrvNames);
  362. // End <GetEntSrv worked>
  363. }
  364. // Autodiscovery complete.
  365. }
  366. if (srvHold.dwCount)
  367. {
  368. dwStatus = ExportLicenses(
  369. outFile,
  370. &srvHold,
  371. fTempOnly,
  372. &usDate.st,
  373. &ueDate.st,
  374. fDateSpec);
  375. do {
  376. free(srvHold.pszNames[--srvHold.dwCount]);
  377. } while (srvHold.dwCount);
  378. LocalFree(srvHold.pszNames);
  379. }
  380. else
  381. {
  382. arg = (INT_PTR)argv[0];
  383. ShowError(IDS_NO_SERVERS, &arg, FALSE);
  384. dwStatus = ERROR_NO_SERVERS;
  385. }
  386. done:
  387. fclose(outFile);
  388. return dwStatus;
  389. }