Leaked source code of windows server 2003
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.

609 lines
13 KiB

  1. // WebChangelistEditor.cpp : Implementation of CWebChangelistEditor
  2. #include "stdafx.h"
  3. #include "WebChangelistEditor.h"
  4. #include <fcntl.h>
  5. // CWebChangelistEditor
  6. STDMETHODIMP CWebChangelistEditor::Initialize(BSTR ChangelistKey, BOOL* Result)
  7. {
  8. HKEY hKey = NULL;
  9. DWORD cbData = MAX_PATH * sizeof(WCHAR);
  10. DWORD dwDatatype;
  11. // Initialize the Result return value to FALSE:
  12. if (Result == NULL)
  13. return E_POINTER;
  14. *Result = FALSE;
  15. // Put our Key/Value name into a CComBSTR
  16. m_ChangelistKey = ChangelistKey;
  17. // Make sure we can't be initialized twice:
  18. if (m_fInitialized)
  19. return E_FAIL;
  20. // Sanity check the ChangelistKey argument.
  21. // It must be 40 characters, null-terminated, containing only hex digits.
  22. if (m_ChangelistKey.Length() != 40)
  23. goto Done;
  24. if (m_ChangelistKey[40] != L'\0')
  25. goto Done;
  26. if (wcsspn(m_ChangelistKey, L"ABCDEFabcdef1234567890") != 40)
  27. goto Done;
  28. // Open our Key:
  29. if (RegOpenKeyExW(HKEY_CURRENT_USER,
  30. g_wszRegKey,
  31. 0,
  32. KEY_QUERY_VALUE,
  33. &hKey) != ERROR_SUCCESS)
  34. {
  35. hKey = NULL;
  36. goto Done;
  37. }
  38. // Read the specified subkey:
  39. if ((RegQueryValueExW(hKey,
  40. m_ChangelistKey,
  41. 0,
  42. &dwDatatype,
  43. (LPBYTE)m_wszCLFilename,
  44. &cbData) != ERROR_SUCCESS) ||
  45. (dwDatatype != REG_SZ))
  46. {
  47. goto Done;
  48. }
  49. // Now that we have the filename and key read successfully
  50. // we can parse the file and populate all the properties of this object.
  51. *Result = m_fInitialized = _ReadFile();
  52. Done:
  53. if (hKey != NULL)
  54. RegCloseKey(hKey);
  55. if (!m_fInitialized)
  56. {
  57. // If we failed, clean up nicely.
  58. _WipeRegEntries();
  59. }
  60. return S_OK;
  61. }
  62. STDMETHODIMP CWebChangelistEditor::Save()
  63. {
  64. FILE *CLFile = NULL;
  65. IFilesAndActions *pIFiles = NULL;
  66. IFileAndAction *pIFile = NULL;
  67. long count;
  68. VARIANT varTemp;
  69. CComBSTR bstrFilename;
  70. CComBSTR bstrAction;
  71. BOOL fEnabled;
  72. HKEY hKey;
  73. // Save can't be called unless we've been properly initialized
  74. if (!m_fInitialized)
  75. return E_FAIL;
  76. // Open the file write-only.
  77. // This clears the file contents.
  78. CLFile = _wfopen(m_wszCLFilename, L"wt");
  79. if (CLFile == NULL)
  80. goto Done;
  81. // Print a much shortened comment block:
  82. fwprintf(CLFile, L"# Source Depot Changelist.\n");
  83. // Print the simple stuff
  84. fwprintf(CLFile, L"\nChange:\t%s\n", m_Change);
  85. if (_wcsicmp(m_Status, L"new") != 0)
  86. {
  87. // Only print the Date line if Status != "new"
  88. fwprintf(CLFile, L"\nDate:\t%s\n", m_Date);
  89. }
  90. fwprintf(CLFile, L"\nClient:\t%s\n", m_Client);
  91. fwprintf(CLFile, L"\nUser:\t%s\n", m_User);
  92. fwprintf(CLFile, L"\nStatus:\t%s\n", m_Status);
  93. fwprintf(CLFile, L"\nDescription:\n");
  94. fwprintf(CLFile, L"\t%s\n", m_Description);
  95. fwprintf(CLFile, L"\nFiles:\n");
  96. // Get the FilesAndActions interface
  97. if (FAILED(m_Files->QueryInterface<IFilesAndActions>(&pIFiles)))
  98. goto Done; // This shouldn't ever fail.
  99. varTemp.vt = VT_EMPTY;
  100. // Loop over the entries and remove each entry as we print it
  101. while (SUCCEEDED(pIFiles->get_Count(&count)) &&
  102. (count >= 1))
  103. {
  104. if (SUCCEEDED(pIFiles->get_Item(1, &varTemp)) && // Get item
  105. (varTemp.vt == VT_DISPATCH) && // Check Variant type
  106. (pIFile = (IFileAndAction*)varTemp.pdispVal) && // <-- Yes, this is an assignment
  107. SUCCEEDED(pIFile->get_Filename(&bstrFilename)) &&
  108. SUCCEEDED(pIFile->get_Action(&bstrAction)) &&
  109. SUCCEEDED(pIFile->get_Enabled(&fEnabled)))
  110. {
  111. // If it's enabled, print the complete line.
  112. if (fEnabled)
  113. fwprintf(CLFile, L"\t%s\t# %s\n", bstrFilename, bstrAction);
  114. // Clean up for the next pass
  115. //pIFile->Release();
  116. pIFile = NULL;
  117. VariantClear(&varTemp);
  118. pIFiles->Remove(1);
  119. }
  120. else
  121. break; // This should not happen.
  122. } // End of while loop
  123. Done:
  124. // OK, we're closing. Un-Initialize the thing.
  125. m_fInitialized = FALSE;
  126. // Close the file
  127. if (CLFile)
  128. fclose(CLFile);
  129. // Release the FilesAndActions interface
  130. if (pIFiles)
  131. pIFiles->Release();
  132. // Delete the registry value we used.
  133. // This may trigger the waiting executable to continue, so do
  134. // this _after_ saving and closing the file.
  135. if (RegOpenKeyExW(HKEY_CURRENT_USER,
  136. g_wszRegKey,
  137. 0,
  138. KEY_QUERY_VALUE | KEY_SET_VALUE,
  139. &hKey) == ERROR_SUCCESS)
  140. {
  141. RegDeleteValueW(hKey, m_ChangelistKey);
  142. RegCloseKey(hKey);
  143. }
  144. return S_OK;
  145. }
  146. BOOL CWebChangelistEditor::_ReadFile(void)
  147. {
  148. BOOL fRetVal = FALSE;
  149. FILE *CLFile = NULL;
  150. IFilesAndActions *pIFiles = NULL;
  151. WCHAR wszBuffer[500];
  152. WCHAR wszBuffer2[500];
  153. WCHAR wszBuffer3[50];
  154. long count;
  155. DWORD dwState = 0; // State of parsing engine
  156. // Ensure that we don't have any old Files entries
  157. if (FAILED(m_Files->QueryInterface<IFilesAndActions>(&pIFiles)))
  158. return FALSE;
  159. if (FAILED(pIFiles->get_Count(&count)))
  160. goto Done;
  161. if (count != 0)
  162. goto Done;
  163. // Open the file read-only
  164. CLFile = _wfopen(m_wszCLFilename, L"rt");
  165. if (CLFile == NULL)
  166. goto Done;
  167. while (fwscanf(CLFile, L"%499[^\n]%*[\n]", &wszBuffer) == 1)
  168. {
  169. // Expect a comment block at the top of the file
  170. switch (dwState)
  171. {
  172. case 0: // Comment block at top of file
  173. if (wszBuffer[0] == L'#')
  174. {
  175. // Skip each comment line
  176. break;
  177. }
  178. else
  179. {
  180. // Stop expecting a comment block
  181. dwState++;
  182. // Fall through to status=1 below
  183. }
  184. case 1: // Change field
  185. if (wcsncmp(wszBuffer, L"Change:\t", 8) == 0)
  186. {
  187. // Store the Change string:
  188. m_Change = &wszBuffer[8];
  189. // move on:
  190. dwState++;
  191. break;
  192. }
  193. else
  194. {
  195. // Invalid file.
  196. goto Done;
  197. }
  198. case 2: // Date field
  199. if (wcsncmp(wszBuffer, L"Date:\t", 6) == 0)
  200. {
  201. // Store the Date string:
  202. m_Date = &wszBuffer[6];
  203. // move on:
  204. dwState++;
  205. break;
  206. }
  207. else
  208. {
  209. // Maybe the Date line is missing. Skip it.
  210. dwState++;
  211. // Fall through to status=3 below
  212. }
  213. case 3: // Client field
  214. if (wcsncmp(wszBuffer, L"Client:\t", 8) == 0)
  215. {
  216. // Store the Client string:
  217. m_Client = &wszBuffer[8];
  218. // move on:
  219. dwState++;
  220. break;
  221. }
  222. else
  223. {
  224. // Invalid file.
  225. goto Done;
  226. }
  227. case 4: // User field
  228. if (wcsncmp(wszBuffer, L"User:\t", 6) == 0)
  229. {
  230. // Store the User string:
  231. m_User = &wszBuffer[6];
  232. // move on:
  233. dwState++;
  234. break;
  235. }
  236. else
  237. {
  238. // Invalid file.
  239. goto Done;
  240. }
  241. case 5: // Status field
  242. if (wcsncmp(wszBuffer, L"Status:\t", 8) == 0)
  243. {
  244. // Store the Status string:
  245. m_Status = &wszBuffer[8];
  246. // move on:
  247. dwState++;
  248. break;
  249. }
  250. else
  251. {
  252. // Invalid file.
  253. goto Done;
  254. }
  255. case 6: // Description field name
  256. if (wcscmp(wszBuffer, L"Description:") == 0)
  257. {
  258. // Found it, but the actual Description is on the next line
  259. dwState++;
  260. break;
  261. }
  262. else
  263. {
  264. // Invalid file.
  265. goto Done;
  266. }
  267. case 7: // Description field value
  268. if (wszBuffer[0] == L'\t')
  269. {
  270. // Store the Description string:
  271. m_Description = &wszBuffer[1];
  272. // move on:
  273. dwState++;
  274. break;
  275. }
  276. else
  277. {
  278. // Invalid file.
  279. goto Done;
  280. }
  281. case 8: // Files field name
  282. if (wcscmp(wszBuffer, L"Files:") == 0)
  283. {
  284. // Found it, but the actual Files and Actions are on the following lines
  285. dwState++;
  286. break;
  287. }
  288. else
  289. {
  290. // Invalid file.
  291. goto Done;
  292. }
  293. case 9: // Files and Actions field values
  294. if (swscanf(wszBuffer, L"\t%499[^\t]\t# %49s",
  295. wszBuffer2, wszBuffer3) == 2)
  296. {
  297. // Add the new FileAndAction data
  298. if (_AddFileAndAction(pIFiles, wszBuffer2, wszBuffer3) == FALSE)
  299. {
  300. // Unable to add data. Nothing we can do about it.
  301. goto Done;
  302. }
  303. // move on:
  304. break; // This is the final state. No increment.
  305. }
  306. else
  307. {
  308. // Invalid file.
  309. goto Done;
  310. }
  311. } // end of case statement
  312. } // end of while loop
  313. if ((dwState == 7) || (dwState == 9))
  314. {
  315. // We got to the Description section, so we completed parsing successfully.
  316. fRetVal = TRUE;
  317. }
  318. Done:
  319. if ((dwState == 9) && (fRetVal == FALSE))
  320. {
  321. // We might have to remove some failed files entries
  322. while (SUCCEEDED(pIFiles->get_Count(&count)) &&
  323. (count >= 1))
  324. {
  325. if (FAILED(pIFiles->Remove(1)))
  326. break;
  327. }
  328. }
  329. if (pIFiles)
  330. pIFiles->Release();
  331. if (CLFile)
  332. fclose(CLFile);
  333. return fRetVal;
  334. }
  335. BOOL CWebChangelistEditor::_AddFileAndAction(IFilesAndActions *pIFiles, WCHAR* wszFilename, WCHAR* wszAction)
  336. {
  337. CComBSTR bstrFile = wszFilename;
  338. CComBSTR bstrAction = wszAction;
  339. IFileAndAction *pIFile = NULL;
  340. CComObject<CFileAndAction> *pBase = NULL;
  341. CComVariant varTemp;
  342. // Create a new FileAndAction object
  343. if (FAILED(CComObject<CFileAndAction>::CreateInstance(&pBase)))
  344. {
  345. // Unable to create instance. Nothing we can do about it.
  346. return FALSE;
  347. }
  348. if (FAILED(pBase->QueryInterface<IFileAndAction>(&pIFile)))
  349. {
  350. // Unable to query inferface. Nothing we can do about it.
  351. return FALSE;
  352. }
  353. // Add the data to the new object
  354. if (FAILED(pIFile->put_Action(bstrAction)) ||
  355. FAILED(pIFile->put_Filename(bstrFile)))
  356. {
  357. // Unable to add data. Nothing we can do about it.
  358. pIFile->Release();
  359. return FALSE;
  360. }
  361. // Put the Interface ptr into a Variant, and release the old Interface ptr
  362. varTemp = (IDispatch*)pIFile;
  363. pIFile->Release();
  364. // Add the new object to the collection
  365. if (FAILED(pIFiles->Add(varTemp)))
  366. {
  367. // Unable to add data. Nothing we can do about it.
  368. return FALSE;
  369. }
  370. // Success
  371. return TRUE;
  372. }
  373. void CWebChangelistEditor::_WipeRegEntries(void)
  374. {
  375. HKEY hKey = NULL;
  376. WCHAR wszValueName[41];
  377. DWORD cchValueName = 41;
  378. DWORD dwDatatype;
  379. DWORD dwIndex;
  380. HRESULT hr;
  381. // Open our Key:
  382. if (RegOpenKeyExW(HKEY_CURRENT_USER,
  383. g_wszRegKey,
  384. 0,
  385. KEY_QUERY_VALUE | KEY_SET_VALUE,
  386. &hKey) != ERROR_SUCCESS)
  387. {
  388. hKey = NULL;
  389. goto Done;
  390. }
  391. // For each value under that is named a 40-digit hex value,
  392. // Delete it.
  393. dwIndex = 0;
  394. while ((hr = RegEnumValueW(hKey,
  395. dwIndex,
  396. wszValueName,
  397. &cchValueName,
  398. 0,
  399. &dwDatatype,
  400. NULL, NULL)) != ERROR_NO_MORE_ITEMS)
  401. {
  402. if (FAILED(hr))
  403. {
  404. // This is most likely because the buffers are the wrong size
  405. // but we don't care about the key unless we can read it into
  406. // the buffers we've got, so just move on.
  407. dwIndex++;
  408. cchValueName = 41; // Set it back to the size of the buffer.
  409. continue;
  410. }
  411. // Check the datatype:
  412. if (dwDatatype != REG_SZ)
  413. {
  414. dwIndex++;
  415. cchValueName = 41; // Set it back to the size of the buffer.
  416. continue;
  417. }
  418. // Check the name:
  419. // It must be 40 characters, containing only hex digits.
  420. if ((cchValueName != 40) ||
  421. (wcsspn(wszValueName, L"ABCDEFabcdef1234567890") != 40))
  422. {
  423. dwIndex++;
  424. cchValueName = 41; // Set it back to the size of the buffer.
  425. continue;
  426. }
  427. // If all the above checks succeeded, delete the value.
  428. RegDeleteValueW(hKey, wszValueName);
  429. // Since we've changed the indexing, start over:
  430. cchValueName = 41; // Set it back to the size of the buffer.
  431. dwIndex = 0;
  432. }
  433. Done:
  434. if (hKey != NULL)
  435. RegCloseKey(hKey);
  436. }
  437. STDMETHODIMP CWebChangelistEditor::get_Change(BSTR* pVal)
  438. {
  439. if (pVal == NULL)
  440. return E_POINTER;
  441. if (!m_fInitialized)
  442. return E_FAIL;
  443. return m_Change.CopyTo(pVal);
  444. }
  445. STDMETHODIMP CWebChangelistEditor::put_Change(BSTR newVal)
  446. {
  447. if (!m_fInitialized)
  448. return E_FAIL;
  449. m_Change = newVal;
  450. return S_OK;
  451. }
  452. STDMETHODIMP CWebChangelistEditor::get_Date(BSTR* pVal)
  453. {
  454. if (pVal == NULL)
  455. return E_POINTER;
  456. if (!m_fInitialized)
  457. return E_FAIL;
  458. return m_Date.CopyTo(pVal);
  459. }
  460. STDMETHODIMP CWebChangelistEditor::put_Date(BSTR newVal)
  461. {
  462. if (!m_fInitialized)
  463. return E_FAIL;
  464. m_Date = newVal;
  465. return S_OK;
  466. }
  467. STDMETHODIMP CWebChangelistEditor::get_Client(BSTR* pVal)
  468. {
  469. if (pVal == NULL)
  470. return E_POINTER;
  471. if (!m_fInitialized)
  472. return E_FAIL;
  473. return m_Client.CopyTo(pVal);
  474. }
  475. STDMETHODIMP CWebChangelistEditor::put_Client(BSTR newVal)
  476. {
  477. if (!m_fInitialized)
  478. return E_FAIL;
  479. m_Client = newVal;
  480. return S_OK;
  481. }
  482. STDMETHODIMP CWebChangelistEditor::get_User(BSTR* pVal)
  483. {
  484. if (pVal == NULL)
  485. return E_POINTER;
  486. if (!m_fInitialized)
  487. return E_FAIL;
  488. return m_User.CopyTo(pVal);
  489. }
  490. STDMETHODIMP CWebChangelistEditor::put_User(BSTR newVal)
  491. {
  492. if (!m_fInitialized)
  493. return E_FAIL;
  494. m_User = newVal;
  495. return S_OK;
  496. }
  497. STDMETHODIMP CWebChangelistEditor::get_Status(BSTR* pVal)
  498. {
  499. if (pVal == NULL)
  500. return E_POINTER;
  501. if (!m_fInitialized)
  502. return E_FAIL;
  503. return m_Status.CopyTo(pVal);
  504. }
  505. STDMETHODIMP CWebChangelistEditor::put_Status(BSTR newVal)
  506. {
  507. if (!m_fInitialized)
  508. return E_FAIL;
  509. m_Status = newVal;
  510. return S_OK;
  511. }
  512. STDMETHODIMP CWebChangelistEditor::get_Description(BSTR* pVal)
  513. {
  514. if (pVal == NULL)
  515. return E_POINTER;
  516. if (!m_fInitialized)
  517. return E_FAIL;
  518. return m_Description.CopyTo(pVal);
  519. }
  520. STDMETHODIMP CWebChangelistEditor::put_Description(BSTR newVal)
  521. {
  522. if (!m_fInitialized)
  523. return E_FAIL;
  524. m_Description = newVal;
  525. return S_OK;
  526. }
  527. STDMETHODIMP CWebChangelistEditor::get_Files(IFilesAndActions** pVal)
  528. {
  529. if (pVal == NULL)
  530. return E_POINTER;
  531. if (!m_fInitialized)
  532. return E_FAIL;
  533. return m_Files->QueryInterface<IFilesAndActions>(pVal);
  534. }