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.

591 lines
12 KiB

  1. //=======================================================================
  2. //
  3. // Copyright (c) 1999 Microsoft Corporation. All Rights Reserved.
  4. //
  5. // File: history.cpp
  6. //
  7. // Purpose: History log
  8. //
  9. //=======================================================================
  10. #include "history.h"
  11. #define DATE_RTLREADING 0x00000020 // add marks for right to left reading order layout
  12. extern CState g_v3state; //defined in CV3.CPP
  13. static void CheckMigrateV2Log();
  14. static void EscapeSep(LPSTR pszStr, BOOL bEscape);
  15. //This function reads and returns the clients installation history. This history is
  16. //returned as an array of History structures. The caller is responsible for passing
  17. //in a reference to the the History Variable array.
  18. void ReadHistory(
  19. Varray<HISTORYSTRUCT> &History, //Returned History array.
  20. int &iTotalItems //total number of items returned in history array.
  21. )
  22. {
  23. USES_CONVERSION;
  24. const int browserLocale = LOCALE_USER_DEFAULT;
  25. HISTORYSTRUCT his;
  26. char szLineType[32];
  27. char szTemp[32];
  28. SYSTEMTIME st;
  29. // check to see if we have to migrate V2 log
  30. CheckMigrateV2Log();
  31. iTotalItems = 0;
  32. g_v3state.AppLog().StartReading();
  33. while (g_v3state.AppLog().ReadLine())
  34. {
  35. ZeroMemory(&his, sizeof(his));
  36. // get line type (first field)
  37. g_v3state.AppLog().CopyNextField(szLineType, sizeof(szLineType));
  38. if (_stricmp(szLineType, LOG_PSS) == 0)
  39. {
  40. //
  41. // skip this line since it is only meant for PSS
  42. //
  43. continue;
  44. }
  45. else if (_stricmp(szLineType, LOG_V2) == 0)
  46. {
  47. //
  48. // line was migrated from V2
  49. //
  50. his.bV2 = TRUE;
  51. g_v3state.AppLog().CopyNextField(his.szDate, sizeof(his.szDate));
  52. g_v3state.AppLog().CopyNextField(his.szTime, sizeof(his.szTime));
  53. g_v3state.AppLog().CopyNextField(his.szTitle, sizeof(his.szTitle));
  54. EscapeSep(his.szTitle, FALSE);
  55. }
  56. else if ((_stricmp(szLineType, LOG_V3CAT) == 0) || (_stricmp(szLineType, LOG_V3_2) == 0))
  57. {
  58. //
  59. // V3 line
  60. //
  61. int iV3LineVer = 1;
  62. if (_stricmp(szLineType, LOG_V3_2) == 0)
  63. {
  64. iV3LineVer = 2;
  65. }
  66. // puid
  67. g_v3state.AppLog().CopyNextField(szTemp, sizeof(szTemp));
  68. his.puid = atoi(szTemp);
  69. // installed/uninstalled
  70. g_v3state.AppLog().CopyNextField(szTemp, sizeof(szTemp));
  71. his.bInstall = (_stricmp(szTemp, LOG_INSTALL) == 0);
  72. // title
  73. g_v3state.AppLog().CopyNextField(his.szTitle, sizeof(his.szTitle));
  74. EscapeSep(his.szTitle, FALSE);
  75. // version
  76. g_v3state.AppLog().CopyNextField(his.szVersion, sizeof(his.szVersion));
  77. // date and time
  78. if (iV3LineVer == 1)
  79. {
  80. // V3 Beta had two fields for date and time, we simly read these fields
  81. // date
  82. g_v3state.AppLog().CopyNextField(his.szDate, sizeof(his.szDate));
  83. // time
  84. g_v3state.AppLog().CopyNextField(his.szTime, sizeof(his.szTime));
  85. }
  86. else
  87. {
  88. // read the timestamp and convert
  89. // timestamp
  90. g_v3state.AppLog().CopyNextField(szTemp, sizeof(szTemp));
  91. // if time stamp is a valid format, convert and populate the structure
  92. // if its not we will have blank values since we initialized the structure to zero
  93. if (ParseTimeStamp(szTemp, &st))
  94. {
  95. TCHAR szTmp[256];
  96. GetDateFormat(browserLocale, DATE_LONGDATE, &st, NULL, szTmp, sizeof(szTmp)/sizeof(szTmp[0]));
  97. strcpy(his.szDate, T2A(szTmp));
  98. GetTimeFormat(browserLocale, LOCALE_NOUSEROVERRIDE, &st, NULL, szTmp, sizeof(szTmp)/sizeof(szTmp[0]));
  99. strcpy(his.szTime, T2A(szTmp));
  100. }
  101. }
  102. // record type
  103. g_v3state.AppLog().CopyNextField(szTemp, sizeof(szTemp));
  104. his.RecType = (BYTE)atoi(szTemp);
  105. // result
  106. g_v3state.AppLog().CopyNextField(szTemp, sizeof(szTemp));
  107. if (_stricmp(szTemp, LOG_SUCCESS) == 0)
  108. {
  109. his.bResult = OPERATION_SUCCESS;
  110. }
  111. else if (_stricmp(szTemp, LOG_STARTED) == 0)
  112. {
  113. his.bResult = OPERATION_STARTED;
  114. }
  115. else
  116. {
  117. his.bResult = OPERATION_ERROR;
  118. }
  119. // error code
  120. g_v3state.AppLog().CopyNextField(szTemp, sizeof(szTemp));
  121. his.hrError = atoh(szTemp);
  122. }
  123. History[iTotalItems] = his;
  124. iTotalItems++;
  125. }
  126. g_v3state.AppLog().StopReading();
  127. }
  128. void UpdateHistory(
  129. PSELECTITEMINFO pInfo, //Pointer to selected item information.
  130. int iTotalItems, //Total selected items
  131. BOOL bInstall //TRUE for InstallSelectedItems, FALSE for RemoveSelectedItems.
  132. )
  133. {
  134. PINVENTORY_ITEM pItem = NULL;
  135. PWU_VARIABLE_FIELD pvTitle;
  136. PWU_VARIABLE_FIELD pvDriverVer;
  137. char szLine[1024];
  138. char szTemp[256];
  139. BOOL bSuccess;
  140. SYSTEMTIME* pst;
  141. BOOL bPSS;
  142. BOOL bItem = FALSE; // used to check if the function GetCatalogAndItem return value and accordingly to decide pItem
  143. // check to see if we have to migrate V2 log
  144. CheckMigrateV2Log();
  145. for (int i = 0; i < iTotalItems; i++)
  146. {
  147. if (pInfo[i].bInstall != bInstall)
  148. continue;
  149. if (pInfo[i].iStatus == ITEM_STATUS_SUCCESS ||
  150. pInfo[i].iStatus == ITEM_STATUS_SUCCESS_REBOOT_REQUIRED ||
  151. pInfo[i].iStatus == ITEM_STATUS_UNINSTALL_STARTED)
  152. {
  153. bSuccess = TRUE;
  154. }
  155. else
  156. {
  157. bSuccess = FALSE;
  158. }
  159. //
  160. // NTBUG9#161018 PREFIX:dereferencing NULL pointer 'pItem' - waltw 8/16/00
  161. // If GetCatalogAndItem returns FALSE, pItem is invalid.
  162. //
  163. if (bItem = g_v3state.GetCatalogAndItem(pInfo[i].puid, &pItem, NULL))
  164. {
  165. // we write hidden dependencies only as PSS entries
  166. if(NULL != pItem) // pItem should never be NULL, but just to be anal...
  167. {
  168. bPSS = pItem->ps->bHidden;
  169. }
  170. }
  171. else
  172. {
  173. // if GetCatalogAndItem returns False, the pItem is NULL and we shouldn't dereference the pointer
  174. //continue;
  175. //Can be continued as the string can be formed with the other elements, only thing requied is to check for validity of pItem before using it
  176. bPSS = FALSE;
  177. }
  178. //
  179. // start building a line for the log
  180. //
  181. // line type
  182. strcpy(szLine, bPSS ? LOG_PSS : LOG_V3_2);
  183. strcat(szLine, LOG_FIELD_SEPARATOR);
  184. // puid
  185. _itoa(pInfo[i].puid, szTemp, 10);
  186. strcat(szLine, szTemp);
  187. strcat(szLine, LOG_FIELD_SEPARATOR);
  188. // install/uninstall
  189. if (pInfo[i].bInstall)
  190. strcat(szLine, LOG_INSTALL);
  191. else
  192. strcat(szLine, LOG_UNINSTALL);
  193. strcat(szLine, LOG_FIELD_SEPARATOR);
  194. // title
  195. if (bItem)
  196. {
  197. if (pvTitle = pItem->pd->pv->Find(WU_DESCRIPTION_TITLE))
  198. {
  199. WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)(pvTitle->pData), -1, szTemp, sizeof(szTemp), NULL, NULL);
  200. }
  201. EscapeSep(szTemp, TRUE);
  202. strcat(szLine, szTemp);
  203. strcat(szLine, LOG_FIELD_SEPARATOR);
  204. // version
  205. szTemp[0] = '\0';
  206. switch( pItem->recordType )
  207. {
  208. case WU_TYPE_ACTIVE_SETUP_RECORD:
  209. VersionToString(&pItem->pf->a.version, szTemp);
  210. break;
  211. case WU_TYPE_CDM_RECORD:
  212. case WU_TYPE_RECORD_TYPE_PRINTER:
  213. if ((pvDriverVer = pItem->pv->Find(WU_VARIABLE_DRIVERVER)))
  214. strzncpy(szTemp, (char *)pvDriverVer->pData, sizeof(szTemp));
  215. break;
  216. }
  217. strcat(szLine, szTemp);
  218. strcat(szLine, LOG_FIELD_SEPARATOR);
  219. }
  220. // timestamp
  221. pst = &(pInfo[i].stDateTime);
  222. // we expect the date/time format to be (TIMESTAMP_FMT) as follows:
  223. // 01234567890123456789
  224. // YYYY-MM-DD HH:MM:SS
  225. sprintf(szTemp, TIMESTAMP_FMT,
  226. pst->wYear, pst->wMonth, pst->wDay,
  227. pst->wHour, pst->wMinute, pst->wSecond);
  228. strcat(szLine, szTemp);
  229. strcat(szLine, LOG_FIELD_SEPARATOR);
  230. if (bItem)
  231. {
  232. // record type
  233. _itoa(pItem->recordType, szTemp, 10);
  234. strcat(szLine, szTemp);
  235. strcat(szLine, LOG_FIELD_SEPARATOR);
  236. }
  237. // result
  238. if (bSuccess)
  239. {
  240. if (pInfo[i].iStatus == ITEM_STATUS_UNINSTALL_STARTED)
  241. strcat(szLine, LOG_STARTED);
  242. else
  243. strcat(szLine, LOG_SUCCESS);
  244. }
  245. else
  246. {
  247. strcat(szLine, LOG_FAIL);
  248. }
  249. strcat(szLine, LOG_FIELD_SEPARATOR);
  250. // hresult
  251. if (!bSuccess)
  252. {
  253. sprintf(szTemp, "%#08x", pInfo[i].hrError);
  254. strcat(szLine, szTemp);
  255. }
  256. strcat(szLine, LOG_FIELD_SEPARATOR);
  257. // error message
  258. if (!bSuccess)
  259. {
  260. CAppLog::FormatErrMsg(pInfo[i].hrError, szTemp, sizeof(szTemp));
  261. strcat(szLine, szTemp);
  262. }
  263. strcat(szLine, LOG_FIELD_SEPARATOR);
  264. //
  265. // write out the log
  266. //
  267. g_v3state.AppLog().Log(szLine);
  268. }
  269. }
  270. // This function updates the local client installation history
  271. void UpdateInstallHistory(PSELECTITEMINFO pInfo, int iTotalItems)
  272. {
  273. UpdateHistory(pInfo, iTotalItems, TRUE);
  274. }
  275. // This function updates the local client removal history
  276. void UpdateRemoveHistory(PSELECTITEMINFO pInfo, int iTotalItems)
  277. {
  278. UpdateHistory(pInfo, iTotalItems, FALSE);
  279. }
  280. // migrates V2 log into the V3 log. This only happens if V3 log does not exist yet
  281. // this is the condition we use to see we are running for the first time.
  282. static void CheckMigrateV2Log()
  283. {
  284. USES_CONVERSION;
  285. static BOOL bChecked = FALSE;
  286. char szBuf[MAX_PATH];
  287. VARIANT vDate;
  288. SYSTEMTIME st;
  289. if (bChecked)
  290. return;
  291. bChecked = TRUE;
  292. if (FileExists(g_v3state.AppLog().GetLogFile()))
  293. {
  294. // V3 file exists, we will not migrate V2
  295. return;
  296. }
  297. // build V2 log file name
  298. TCHAR szFile[MAX_PATH];
  299. if (! GetWindowsDirectory(szFile, sizeof(szFile) / sizeof(TCHAR)))
  300. {
  301. lstrcat(szFile, _T("C:\\Windows"));
  302. }
  303. AddBackSlash(szFile);
  304. lstrcat(szFile, _T("WULog.txt"));
  305. if (!FileExists(szFile))
  306. {
  307. // V2 file does not exists
  308. return;
  309. }
  310. CAppLog V2Log(szFile);
  311. char szLine[1024];
  312. V2Log.StartReading();
  313. while (V2Log.ReadLine())
  314. {
  315. // line type
  316. strcpy(szLine, LOG_V2);
  317. strcat(szLine, LOG_FIELD_SEPARATOR);
  318. // v2 log starts out with | so we want to skip the first field
  319. V2Log.CopyNextField(szBuf, sizeof(szBuf));
  320. // date
  321. V2Log.CopyNextField(szBuf, sizeof(szBuf));
  322. //
  323. // fixup date to ensure 4 digit year. We use OLE to intelligently parse out the date
  324. // that will most probably be with 2 digit year code. OLE takes care of making sence
  325. // out of it. Then we write the date out with a 4 digit year back to the same buffer
  326. //
  327. VariantInit(&vDate);
  328. vDate.vt = VT_BSTR;
  329. vDate.bstrVal = SysAllocString(A2OLE(szBuf));
  330. if SUCCEEDED(VariantChangeType(&vDate, &vDate, VARIANT_NOVALUEPROP, VT_DATE))
  331. {
  332. if (VariantTimeToSystemTime(vDate.date, &st))
  333. {
  334. sprintf(szBuf, "%4d-%02d-%02d", st.wYear, st.wMonth, st.wDay);
  335. }
  336. }
  337. strcat(szLine, szBuf);
  338. strcat(szLine, LOG_FIELD_SEPARATOR);
  339. // time
  340. V2Log.CopyNextField(szBuf, sizeof(szBuf));
  341. strcat(szLine, szBuf);
  342. strcat(szLine, LOG_FIELD_SEPARATOR);
  343. // title
  344. V2Log.CopyNextField(szBuf, sizeof(szBuf));
  345. EscapeSep(szBuf, TRUE);
  346. strcat(szLine, szBuf);
  347. strcat(szLine, LOG_FIELD_SEPARATOR);
  348. // write out the log line
  349. g_v3state.AppLog().Log(szLine);
  350. }
  351. V2Log.StopReading();
  352. }
  353. //
  354. // we expect the date/time format to be (TIMESTAMP_FMT) as follows:
  355. // 01234567890123456789
  356. // YYYY-MM-DD HH:MM:SS
  357. //
  358. BOOL ParseTimeStamp(LPCSTR pszDateTime, SYSTEMTIME* ptm)
  359. {
  360. char szBuf[20];
  361. if (strlen(pszDateTime) != 19)
  362. {
  363. return FALSE;
  364. }
  365. strcpy(szBuf, pszDateTime);
  366. //
  367. // validate format
  368. //
  369. for (int i = 0; i < 19; i++)
  370. {
  371. switch (i)
  372. {
  373. case 4:
  374. case 7:
  375. if (szBuf[i] != '-')
  376. {
  377. return FALSE;
  378. }
  379. break;
  380. case 10:
  381. if (szBuf[i] != ' ')
  382. {
  383. return FALSE;
  384. }
  385. break;
  386. case 13:
  387. case 16:
  388. if (szBuf[i] != ':')
  389. {
  390. return FALSE;
  391. }
  392. break;
  393. default:
  394. if (szBuf[i] < '0' || pszDateTime[i] > '9')
  395. {
  396. return FALSE;
  397. }
  398. break;
  399. }
  400. }
  401. //
  402. // get values
  403. //
  404. szBuf[4] = '\0';
  405. ptm->wYear = (WORD)atoi(szBuf);
  406. szBuf[7] = '\0';
  407. ptm->wMonth = (WORD)atoi(szBuf + 5);
  408. szBuf[10] = '\0';
  409. ptm->wDay = (WORD)atoi(szBuf + 8);
  410. szBuf[13] = '\0';
  411. ptm->wHour = (WORD)atoi(szBuf + 11);
  412. szBuf[16] = '\0';
  413. ptm->wMinute = (WORD)atoi(szBuf + 14);
  414. ptm->wSecond = (WORD)atoi(szBuf + 17);
  415. ptm->wMilliseconds = 0;
  416. ptm->wDayOfWeek = 0;
  417. //
  418. // convert to file time and back. This will calculate the week day as well as tell us
  419. // if all the fields are set to valid values
  420. //
  421. BOOL bRet;
  422. FILETIME ft;
  423. bRet = SystemTimeToFileTime(ptm, &ft);
  424. if (bRet)
  425. {
  426. bRet = FileTimeToSystemTime(&ft, ptm);
  427. }
  428. return bRet;
  429. }
  430. static void EscapeSep(LPSTR pszStr, BOOL bEscape)
  431. {
  432. char szBuf[256];
  433. char* ps;
  434. char* pb;
  435. if (bEscape)
  436. {
  437. // escape
  438. if (strchr(pszStr, '|') != NULL)
  439. {
  440. ps = pszStr;
  441. pb = szBuf;
  442. for (;;)
  443. {
  444. if (*ps == '|')
  445. {
  446. *pb++ = '~';
  447. *pb++ = '1';
  448. }
  449. else
  450. {
  451. *pb++ = *ps;
  452. }
  453. if (*ps == '\0')
  454. {
  455. break;
  456. }
  457. ps++;
  458. }
  459. strcpy(pszStr, szBuf);
  460. }
  461. }
  462. else
  463. {
  464. // unescape
  465. if (strstr(pszStr, "~1") != NULL)
  466. {
  467. ps = pszStr;
  468. pb = szBuf;
  469. for (;;)
  470. {
  471. if (*ps == '~' && *(ps + 1) == '1')
  472. {
  473. *pb++ = '|';
  474. ps++;
  475. }
  476. else
  477. {
  478. *pb++ = *ps;
  479. }
  480. if (*ps == '\0')
  481. {
  482. break;
  483. }
  484. ps++;
  485. }
  486. strcpy(pszStr, szBuf);
  487. }
  488. }
  489. }