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.

1024 lines
32 KiB

  1. // --------------------------------------------------------------------------------
  2. // Utility.cpp
  3. // --------------------------------------------------------------------------------
  4. #include "pch.hxx"
  5. #include "migrate.h"
  6. #include "migerror.h"
  7. #include "utility.h"
  8. #include "resource.h"
  9. #include <shared.h>
  10. extern BOOL g_fQuiet;
  11. /*
  12. * CenterDialog
  13. *
  14. * Purpose:
  15. * This function centers a dialog with respect to its parent
  16. * dialog.
  17. *
  18. * Parameters:
  19. * hwndDlg hwnd of the dialog to center
  20. */
  21. VOID CenterDialog(HWND hwndDlg)
  22. {
  23. HWND hwndOwner;
  24. RECT rc;
  25. RECT rcDlg;
  26. RECT rcOwner;
  27. RECT rcWork;
  28. INT x;
  29. INT y;
  30. INT nAdjust;
  31. // Get the working area rectangle
  32. SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWork, 0);
  33. // Get the owner window and dialog box rectangles.
  34. // The window rect of the destop window is in trouble on multimonitored
  35. // macs. GetWindow only gets the main screen.
  36. if (hwndOwner = GetParent(hwndDlg))
  37. GetWindowRect(hwndOwner, &rcOwner);
  38. else
  39. rcOwner = rcWork;
  40. GetWindowRect(hwndDlg, &rcDlg);
  41. rc = rcOwner;
  42. // Offset the owner and dialog box rectangles so that
  43. // right and bottom values represent the width and
  44. // height, and then offset the owner again to discard
  45. // space taken up by the dialog box.
  46. OffsetRect(&rcDlg, -rcDlg.left, -rcDlg.top);
  47. OffsetRect(&rc, -rc.left, -rc.top);
  48. OffsetRect(&rc, -rcDlg.right, -rcDlg.bottom);
  49. // The new position is the sum of half the remaining
  50. // space and the owner's original position.
  51. // But not less than Zero - jefbai
  52. x= rcOwner.left + (rc.right / 2);
  53. y= rcOwner.top + (rc.bottom / 2);
  54. // Make sure the dialog doesn't go off the right edge of the screen
  55. nAdjust = rcWork.right - (x + rcDlg.right);
  56. if (nAdjust < 0)
  57. x += nAdjust;
  58. //$ Raid 5128: Make sure the left edge is visible
  59. if (x < rcWork.left)
  60. x = rcWork.left;
  61. // Make sure the dialog doesn't go off the bottom edge of the screen
  62. nAdjust = rcWork.bottom - (y + rcDlg.bottom);
  63. if (nAdjust < 0)
  64. y += nAdjust;
  65. //$ Raid 5128: Make sure the top edge is visible
  66. if (y < rcWork.top)
  67. y = rcWork.top;
  68. SetWindowPos(hwndDlg, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
  69. }
  70. // --------------------------------------------------------------------------------
  71. // CommifyString
  72. // --------------------------------------------------------------------------------
  73. #define WHOLENUM_LEN 30
  74. #define LODWORD(_qw) (DWORD)(_qw)
  75. const short pwOrders[] = {IDS_BYTES, IDS_ORDERKB, IDS_ORDERMB,
  76. IDS_ORDERGB, IDS_ORDERTB, IDS_ORDERPB, IDS_ORDEREB};
  77. // takes a DWORD add commas etc to it and puts the result in the buffer
  78. LPSTR CommifyString(DWORD dw, LPSTR pszResult, UINT cchBuf)
  79. {
  80. char szTemp[30];
  81. char szSep[5];
  82. NUMBERFMT nfmt;
  83. nfmt.NumDigits = 0;
  84. nfmt.LeadingZero = 0;
  85. GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, szSep, ARRAYSIZE(szSep));
  86. nfmt.Grouping = atoi(szSep);
  87. GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, szSep, ARRAYSIZE(szSep));
  88. nfmt.lpDecimalSep = nfmt.lpThousandSep = szSep;
  89. nfmt.NegativeOrder = 0;
  90. wnsprintf(szTemp, ARRAYSIZE(szTemp), TEXT("%lu"), dw);
  91. if (GetNumberFormat(LOCALE_USER_DEFAULT, 0, szTemp, &nfmt,pszResult, ARRAYSIZE(szTemp)) == 0)
  92. StrCpyN(pszResult, szTemp, cchBuf);
  93. return pszResult;
  94. }
  95. // --------------------------------------------------------------------------------
  96. // MapDataDirToAcctId
  97. // --------------------------------------------------------------------------------
  98. HRESULT MapDataDirToAcctId(DWORD dwServer, LPCSTR pszSubDir, LPSTR pszAcctId, int cchAcctId)
  99. {
  100. // Locals
  101. LPACCOUNTINFO pAccount;
  102. DWORD i;
  103. // Trace
  104. TraceCall("MapDataDirToAcctId");
  105. // Set Account Id
  106. for (i=0; i<g_AcctTable.cAccounts; i++)
  107. {
  108. // Redability
  109. pAccount = &g_AcctTable.prgAccount[i];
  110. // Looking for News Servers
  111. if (ISFLAGSET(pAccount->dwServer, dwServer))
  112. {
  113. // Same Sub directory
  114. if (lstrcmpi(pAccount->szDataDir, pszSubDir) == 0)
  115. {
  116. // Set Account Id
  117. StrCpyN(pszAcctId, pAccount->szAcctId, cchAcctId);
  118. // Done
  119. return(S_OK);
  120. }
  121. }
  122. }
  123. // Done
  124. return(E_FAIL);
  125. }
  126. // --------------------------------------------------------------------------------
  127. // EnumerateStoreFiles
  128. // --------------------------------------------------------------------------------
  129. HRESULT EnumerateStoreFiles(LPCSTR pszPath, DIRTYPE tyDir, LPCSTR pszSubDir,
  130. LPENUMFILEINFO pEnumInfo, LPFILEINFO *ppHead)
  131. {
  132. // Locals
  133. HRESULT hr=S_OK;
  134. CHAR szFullPath[MAX_PATH + MAX_PATH];
  135. CHAR szSearch[MAX_PATH + MAX_PATH];
  136. WIN32_FIND_DATA fd;
  137. HANDLE hFind=INVALID_HANDLE_VALUE;
  138. DWORD i;
  139. LPACCOUNTINFO pAccount;
  140. LPFILEINFO pNew=NULL;
  141. // Trace
  142. TraceCall("EnumerateStoreFiles");
  143. // Invalid Args
  144. Assert(pszPath && pEnumInfo && pEnumInfo->pszExt && pEnumInfo->pszExt[0] == '.' && ppHead);
  145. // Build Base Path
  146. if (pszSubDir)
  147. wnsprintf(szFullPath, ARRAYSIZE(szFullPath), "%s\\%s", pszPath, pszSubDir);
  148. else
  149. StrCpyN(szFullPath, pszPath, ARRAYSIZE(szFullPath));
  150. // Do we have a sub dir
  151. wnsprintf(szSearch, ARRAYSIZE(szSearch), "%s\\*.*", szFullPath);
  152. // Find first file
  153. hFind = FindFirstFile(szSearch, &fd);
  154. // Did we find something
  155. if (INVALID_HANDLE_VALUE == hFind)
  156. goto exit;
  157. // Loop for ever
  158. while(1)
  159. {
  160. // If this is not a directory
  161. if (ISFLAGSET(fd.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY))
  162. {
  163. // Not . and not ..
  164. if (lstrcmpi(fd.cFileName, ".") != 0 && lstrcmpi(fd.cFileName, "..") != 0)
  165. {
  166. // Default Dirtype
  167. DIRTYPE tyDirNew=tyDir;
  168. // Decide new dir type
  169. if (lstrcmpi(fd.cFileName, "mail") == 0)
  170. tyDirNew = DIR_IS_LOCAL;
  171. else if (lstrcmpi(fd.cFileName, "news") == 0)
  172. tyDirNew = DIR_IS_NEWS;
  173. else if (lstrcmpi(fd.cFileName, "imap") == 0)
  174. tyDirNew = DIR_IS_IMAP;
  175. // Recursive...
  176. IF_FAILEXIT(hr = EnumerateStoreFiles(szFullPath, tyDirNew, fd.cFileName, pEnumInfo, ppHead));
  177. }
  178. }
  179. // Otherwise... don't enumerate any files in the root directory...
  180. else if (DIR_IS_ROOT != tyDir)
  181. {
  182. // Locals
  183. BOOL fIsFile=FALSE;
  184. CHAR szPath[_MAX_PATH];
  185. CHAR szDrive[_MAX_DRIVE];
  186. CHAR szDir[_MAX_DIR];
  187. CHAR szFile[_MAX_FNAME];
  188. CHAR szExt[_MAX_EXT];
  189. // Split the Path
  190. _splitpath(fd.cFileName, szDrive, szDir, szFile, szExt);
  191. // Extension I'm looking for ?
  192. if ('\0' != *szExt)
  193. {
  194. // Ext1
  195. if (lstrcmpi(pEnumInfo->pszExt, szExt) == 0)
  196. fIsFile = TRUE;
  197. // FoldFile
  198. if (pEnumInfo->pszFoldFile && lstrcmpi(pEnumInfo->pszFoldFile, fd.cFileName) == 0)
  199. fIsFile = TRUE;
  200. // UidlFile
  201. if (pEnumInfo->pszUidlFile && lstrcmpi(pEnumInfo->pszUidlFile, fd.cFileName) == 0)
  202. fIsFile = TRUE;
  203. // SubList
  204. if (pEnumInfo->pszSubList && lstrcmpi(pEnumInfo->pszSubList, fd.cFileName) == 0)
  205. fIsFile = TRUE;
  206. // GrpList
  207. if (pEnumInfo->pszGrpList && lstrcmpi(pEnumInfo->pszGrpList, fd.cFileName) == 0)
  208. fIsFile = TRUE;
  209. }
  210. // If Not is file, and caller wants to look for v1 news and I'm in the news directory
  211. if (FALSE == fIsFile && TRUE == pEnumInfo->fFindV1News && DIR_IS_NEWS == tyDir)
  212. {
  213. // If this is a .dat file or a .sub file
  214. if (lstrcmpi(szExt, ".dat") == 0)
  215. fIsFile = TRUE;
  216. // .sub file
  217. else if (lstrcmpi(szExt, ".sub") == 0)
  218. fIsFile = TRUE;
  219. }
  220. // Is File
  221. if (fIsFile)
  222. {
  223. // Allocate a FileInfo
  224. IF_NULLEXIT(pNew = (LPFILEINFO)g_pMalloc->Alloc(sizeof(FILEINFO)));
  225. // Zero alloc
  226. ZeroMemory(pNew, sizeof(FILEINFO));
  227. // Determine File Type
  228. if (DIR_IS_LOCAL == tyDir)
  229. {
  230. // Default file type
  231. pNew->tyFile = FILE_IS_LOCAL_MESSAGES;
  232. // Set Server Type
  233. pNew->dwServer = SRV_POP3;
  234. // Set Account Id
  235. StrCpyN(pNew->szAcctId, "LocalStore", ARRAYSIZE(pNew->szAcctId));
  236. // Folders
  237. if (pEnumInfo->pszFoldFile && lstrcmpi(pEnumInfo->pszFoldFile, fd.cFileName) == 0)
  238. pNew->tyFile = FILE_IS_LOCAL_FOLDERS;
  239. // pop3uidl
  240. else if (pEnumInfo->pszUidlFile && lstrcmpi(pEnumInfo->pszUidlFile, fd.cFileName) == 0)
  241. pNew->tyFile = FILE_IS_POP3UIDL;
  242. }
  243. // News
  244. else if (DIR_IS_NEWS == tyDir)
  245. {
  246. // Default file type
  247. pNew->tyFile = FILE_IS_NEWS_MESSAGES;
  248. // Set Server Type
  249. pNew->dwServer = SRV_NNTP;
  250. // Map to An Account Id
  251. MapDataDirToAcctId(SRV_NNTP, pszSubDir, pNew->szAcctId, ARRAYSIZE(pNew->szAcctId));
  252. // sublist.dat
  253. if (pEnumInfo->pszSubList && lstrcmpi(pEnumInfo->pszSubList, fd.cFileName) == 0)
  254. pNew->tyFile = FILE_IS_NEWS_SUBLIST;
  255. // grplist.dat
  256. else if (pEnumInfo->pszGrpList && lstrcmpi(pEnumInfo->pszGrpList, fd.cFileName) == 0)
  257. pNew->tyFile = FILE_IS_NEWS_GRPLIST;
  258. // If this is a .dat file or a .sub file
  259. else if (pEnumInfo->fFindV1News)
  260. {
  261. // Group List
  262. if (lstrcmpi(szExt, ".dat") == 0)
  263. pNew->tyFile = FILE_IS_NEWS_GRPLIST;
  264. // .sub file
  265. else if (lstrcmpi(szExt, ".sub") == 0)
  266. pNew->tyFile = FILE_IS_NEWS_SUBLIST;
  267. // Try to find the Account (szFile should equal the server name)
  268. for (DWORD i=0; i<g_AcctTable.cAccounts; i++)
  269. {
  270. // Is this the Account
  271. if (lstrcmpi(g_AcctTable.prgAccount[i].szServer, szFile) == 0)
  272. {
  273. StrCpyN(pNew->szAcctId, g_AcctTable.prgAccount[i].szAcctId, ARRAYSIZE(pNew->szAcctId));
  274. break;
  275. }
  276. }
  277. }
  278. }
  279. // IMAP
  280. else if (DIR_IS_IMAP == tyDir)
  281. {
  282. // Default file type
  283. pNew->tyFile = FILE_IS_IMAP_MESSAGES;
  284. // Set Server Type
  285. pNew->dwServer = SRV_IMAP;
  286. // Map to An Account Id
  287. MapDataDirToAcctId(SRV_IMAP, pszSubDir, pNew->szAcctId, ARRAYSIZE(pNew->szAcctId));
  288. // Folders
  289. if (pEnumInfo->pszFoldFile && lstrcmpi(pEnumInfo->pszFoldFile, fd.cFileName) == 0)
  290. pNew->tyFile = FILE_IS_IMAP_FOLDERS;
  291. }
  292. // Format the filename
  293. wnsprintf(pNew->szFilePath, ARRAYSIZE(pNew->szFilePath), "%s\\%s", szFullPath, fd.cFileName);
  294. // Trace This
  295. TraceInfo(_MSG("MigFile: %s", pNew->szFilePath));
  296. // Link It In
  297. pNew->pNext = (*ppHead);
  298. // Set ppHead
  299. *ppHead = pNew;
  300. // Don't Free pNew
  301. pNew = NULL;
  302. }
  303. }
  304. // Find the Next File
  305. if (!FindNextFile(hFind, &fd))
  306. break;
  307. }
  308. exit:
  309. // Cleanup
  310. SafeMemFree(pNew);
  311. if (hFind)
  312. FindClose(hFind);
  313. // Done
  314. return hr;
  315. }
  316. // --------------------------------------------------------------------------------
  317. // FreeFileList
  318. // --------------------------------------------------------------------------------
  319. HRESULT FreeFileList(LPFILEINFO *ppHead)
  320. {
  321. // Locals
  322. LPFILEINFO pCurrent=(*ppHead);
  323. LPFILEINFO pNext;
  324. // Loop
  325. while (pCurrent)
  326. {
  327. // Save Next
  328. pNext = pCurrent->pNext;
  329. // Free Current
  330. g_pMalloc->Free(pCurrent);
  331. // Goto Next
  332. pCurrent = pNext;
  333. }
  334. // Done
  335. return S_OK;
  336. }
  337. // --------------------------------------------------------------------------------
  338. // MigrageDlgProc
  339. // --------------------------------------------------------------------------------
  340. INT_PTR CALLBACK MigrageDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  341. {
  342. // Trace
  343. TraceCall("MigrageDlgProc");
  344. // Handle Message
  345. switch (uMsg)
  346. {
  347. case WM_INITDIALOG:
  348. return TRUE;
  349. }
  350. // Done
  351. return 0;
  352. }
  353. // --------------------------------------------------------------------------------
  354. // InitializeCounters
  355. // --------------------------------------------------------------------------------
  356. void InitializeCounters(LPMEMORYFILE pFile, LPFILEINFO pInfo, LPDWORD pcMax,
  357. LPDWORD pcbNeeded, BOOL fInflate)
  358. {
  359. // Increment pcMax
  360. (*pcMax) += pFile->cbSize;
  361. // Save Size
  362. pInfo->cbFile = pFile->cbSize;
  363. // Set Progress Max
  364. pInfo->cProgMax = pFile->cbSize;
  365. // Set cProgInc
  366. pInfo->cProgInc = pInfo->cRecords > 0 ? (pFile->cbSize / pInfo->cRecords) : pFile->cbSize;
  367. // Increment pcbNeeded
  368. (*pcbNeeded) += pInfo->cbFile;
  369. // Assume the file will be 8% bigger
  370. if (fInflate)
  371. (*pcbNeeded) += ((pInfo->cbFile * 8) / 100);
  372. }
  373. // --------------------------------------------------------------------------------
  374. // IncrementProgress
  375. // --------------------------------------------------------------------------------
  376. void IncrementProgress(LPPROGRESSINFO pProgress, LPFILEINFO pInfo)
  377. {
  378. // Locals
  379. MSG msg;
  380. ULARGE_INTEGER uliCurrent;
  381. ULARGE_INTEGER uliMax;
  382. // Trace
  383. TraceCall("IncrementProgress");
  384. // Increment
  385. pProgress->cCurrent += pInfo->cProgInc;
  386. // Increment per-file progress
  387. pInfo->cProgCur += pInfo->cProgInc;
  388. // If cur is now larget than max ?
  389. if (pProgress->cCurrent > pProgress->cMax)
  390. pProgress->cCurrent = pProgress->cMax;
  391. // Set 64
  392. uliCurrent.QuadPart = pProgress->cCurrent;
  393. uliMax.QuadPart = pProgress->cMax;
  394. // Compute percent
  395. DWORD cPercent = (DWORD)((uliCurrent.QuadPart) * 100 / uliMax.QuadPart);
  396. // Change
  397. if (cPercent != pProgress->cPercent)
  398. {
  399. // Locals
  400. CHAR szRes[50];
  401. CHAR szProgress[50];
  402. // Save It
  403. pProgress->cPercent = cPercent;
  404. // Load the String
  405. LoadString(g_hInst, IDS_COMPLETE, szRes, ARRAYSIZE(szRes));
  406. // Update status
  407. if(!g_fQuiet)
  408. SendMessage(GetDlgItem(pProgress->hwndProgress, IDC_PROGRESS), PBM_SETPOS, pProgress->cPercent, 0);
  409. // Format
  410. wnsprintf(szProgress, ARRAYSIZE(szProgress), szRes, cPercent);
  411. // Update Description...
  412. if(!g_fQuiet)
  413. SetDlgItemText(pProgress->hwndProgress, IDS_STATUS, szProgress);
  414. }
  415. // Pump messages until current cycle is complete
  416. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  417. {
  418. if (!IsDialogMessage(pProgress->hwndProgress, &msg))
  419. {
  420. TranslateMessage(&msg);
  421. DispatchMessage(&msg);
  422. }
  423. }
  424. }
  425. // --------------------------------------------------------------------------------
  426. // SetProgressFile
  427. // --------------------------------------------------------------------------------
  428. void SetProgressFile(LPPROGRESSINFO pProgress, LPFILEINFO pInfo)
  429. {
  430. // Locals
  431. CHAR szRes[255];
  432. CHAR szMsg[255 + MAX_PATH + MAX_PATH];
  433. CHAR szScratch[50];
  434. // Load String
  435. LoadString(g_hInst, IDS_MIGRATING, szRes, ARRAYSIZE(szRes));
  436. // Format the String
  437. wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, pInfo->szFilePath, StrFormatByteSize64A(pInfo->cbFile, szScratch, ARRAYSIZE(szScratch)));
  438. // Update Description...
  439. if(!g_fQuiet)
  440. SetDlgItemText(pProgress->hwndProgress, IDS_DESCRIPT, szMsg);
  441. }
  442. // --------------------------------------------------------------------------------
  443. // WriteMigrationLogFile
  444. // --------------------------------------------------------------------------------
  445. HRESULT WriteMigrationLogFile(HRESULT hrMigrate, DWORD dwLastError,
  446. LPCSTR pszStoreRoot, LPCSTR pszMigrate, LPCSTR pszCmdLine, LPFILEINFO pHeadFile)
  447. {
  448. // Locals
  449. HRESULT hr=S_OK;
  450. HANDLE hFile=NULL;
  451. DWORD cbFile;
  452. CHAR szWrite[2024];
  453. DWORD cbWrote;
  454. CHAR szLogFile[MAX_PATH];
  455. SYSTEMTIME st;
  456. LPFILEINFO pCurrent;
  457. // Trace
  458. TraceCall("WriteMigrationLogFile");
  459. // Invalid Args
  460. Assert(pszStoreRoot && pszCmdLine);
  461. // File name too long....
  462. wnsprintf(szLogFile, ARRAYSIZE(szLogFile), "%s\\%s.log", pszStoreRoot, pszMigrate);
  463. // Open the File
  464. hFile = CreateFile(szLogFile, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_FLAG_RANDOM_ACCESS | FILE_ATTRIBUTE_NORMAL, NULL);
  465. // Failure
  466. if (INVALID_HANDLE_VALUE == hFile)
  467. {
  468. hFile = NULL;
  469. hr = TraceResult(E_FAIL);
  470. goto exit;
  471. }
  472. // Get the Size
  473. cbFile = ::GetFileSize(hFile, NULL);
  474. if (0xFFFFFFFF == cbFile)
  475. {
  476. hr = TraceResult(MIGRATE_E_CANTGETFILESIZE);
  477. goto exit;
  478. }
  479. // If file is getting kind of large
  480. if (cbFile >= 102400)
  481. {
  482. // Seek to the end of the file...
  483. if (0xffffffff == SetFilePointer(hFile, 0, NULL, FILE_BEGIN))
  484. {
  485. hr = TraceResult(MIGRATE_E_CANTSETFILEPOINTER);
  486. goto exit;
  487. }
  488. // Set End Of File
  489. if (0 == SetEndOfFile(hFile))
  490. {
  491. hr = TraceResult(MIGRATE_E_CANTSETENDOFFILE);
  492. goto exit;
  493. }
  494. }
  495. // Seek to the end of the file...
  496. if (0xffffffff == SetFilePointer(hFile, 0, NULL, FILE_END))
  497. {
  498. hr = TraceResult(MIGRATE_E_CANTSETFILEPOINTER);
  499. goto exit;
  500. }
  501. // add a new line
  502. if (!WriteFile(hFile, pszCmdLine, lstrlen(pszCmdLine), &cbWrote, NULL))
  503. {
  504. hr = TraceResult(MIGRATE_E_WRITEFILE);
  505. goto exit;
  506. }
  507. // add a new line
  508. if (!WriteFile(hFile, "\r\n", lstrlen("\r\n"), &cbWrote, NULL))
  509. {
  510. hr = TraceResult(MIGRATE_E_WRITEFILE);
  511. goto exit;
  512. }
  513. // Write the Date
  514. GetLocalTime(&st);
  515. // Build the string
  516. wnsprintf(szWrite, ARRAYSIZE(szWrite), "Date: %.2d/%.2d/%.4d %.2d:%.2d:%.2d\r\n", st.wMonth, st.wDay, st.wYear, st.wHour, st.wMinute, st.wSecond);
  517. // add a new line
  518. if (!WriteFile(hFile, szWrite, lstrlen(szWrite), &cbWrote, NULL))
  519. {
  520. hr = TraceResult(MIGRATE_E_WRITEFILE);
  521. goto exit;
  522. }
  523. // Set Text
  524. wnsprintf(szWrite, ARRAYSIZE(szWrite), "Store Root: %s\r\nGlobal Migrate Result: HRESULT = 0x%08X, GetLastError() = %d\r\n\r\n", pszStoreRoot, hrMigrate, dwLastError);
  525. // Write Store Root
  526. if (!WriteFile(hFile, szWrite, lstrlen(szWrite), &cbWrote, NULL))
  527. {
  528. hr = TraceResult(MIGRATE_E_WRITEFILE);
  529. goto exit;
  530. }
  531. // Loop through the files
  532. for (pCurrent=pHeadFile; pCurrent!=NULL; pCurrent=pCurrent->pNext)
  533. {
  534. // Format the string
  535. wnsprintf(szWrite, ARRAYSIZE(szWrite), "cbFile: %012d, cRecords: %08d, fMigrate: %d, hrMigrate: 0x%08X, GetLastError(): %05d, File: %s\r\n",
  536. pCurrent->cbFile, pCurrent->cRecords, pCurrent->fMigrate, pCurrent->hrMigrate, pCurrent->dwLastError, pCurrent->szFilePath);
  537. // Write Store Root
  538. if (!WriteFile(hFile, szWrite, lstrlen(szWrite), &cbWrote, NULL))
  539. {
  540. hr = TraceResult(MIGRATE_E_WRITEFILE);
  541. goto exit;
  542. }
  543. }
  544. // Write Store Root
  545. if (!WriteFile(hFile, "\r\n\r\n", lstrlen("\r\n\r\n"), &cbWrote, NULL))
  546. {
  547. hr = TraceResult(MIGRATE_E_WRITEFILE);
  548. goto exit;
  549. }
  550. exit:
  551. // Close the file
  552. if (hFile)
  553. CloseHandle(hFile);
  554. // Done
  555. return hr;
  556. }
  557. // --------------------------------------------------------------------------------
  558. // BlobReadData
  559. // --------------------------------------------------------------------------------
  560. HRESULT BlobReadData(LPBYTE lpbBlob, ULONG cbBlob, ULONG *pib, LPBYTE lpbData, ULONG cbData)
  561. {
  562. // Check Parameters
  563. AssertSz(lpbBlob && cbBlob > 0 && pib && cbData > 0 && lpbData, "Bad Parameter");
  564. AssertReadWritePtr(lpbBlob, cbData);
  565. AssertReadWritePtr(lpbData, cbData);
  566. AssertSz(*pib + cbData <= cbBlob, "Blob overflow");
  567. // Copy Data Data
  568. CopyMemory (lpbData, lpbBlob + (*pib), cbData);
  569. *pib += cbData;
  570. // Done
  571. return S_OK;
  572. }
  573. // --------------------------------------------------------------------------------
  574. // ReplaceExtension
  575. // --------------------------------------------------------------------------------
  576. void ReplaceExtension(LPCSTR pszFilePath, LPCSTR pszExtNew, LPSTR pszFilePathNew, int cchFilePathNew)
  577. {
  578. // Locals
  579. CHAR szPath[_MAX_PATH];
  580. CHAR szDrive[_MAX_DRIVE];
  581. CHAR szDir[_MAX_DIR];
  582. CHAR szFile[_MAX_FNAME];
  583. CHAR szExt[_MAX_EXT];
  584. // Trace
  585. TraceCall("ReplaceExtension");
  586. // Split the Path
  587. _splitpath(pszFilePath, szDrive, szDir, szFile, szExt);
  588. // Build New File Path
  589. wnsprintf(pszFilePathNew, cchFilePathNew, "%s%s%s%s", szDrive, szDir, szFile, pszExtNew);
  590. // Done
  591. return;
  592. }
  593. // --------------------------------------------------------------------------------
  594. // GetAvailableDiskSpace
  595. // --------------------------------------------------------------------------------
  596. HRESULT GetAvailableDiskSpace(LPCSTR pszFilePath, DWORDLONG *pdwlFree)
  597. {
  598. // Locals
  599. HRESULT hr=S_OK;
  600. CHAR szDrive[5];
  601. DWORD dwSectorsPerCluster;
  602. DWORD dwBytesPerSector;
  603. DWORD dwNumberOfFreeClusters;
  604. DWORD dwTotalNumberOfClusters;
  605. // Trace
  606. TraceCall("GetAvailableDiskSpace");
  607. // Invalid Args
  608. Assert(pszFilePath && pszFilePath[1] == ':' && pdwlFree);
  609. // Split the path
  610. szDrive[0] = *pszFilePath;
  611. szDrive[1] = ':';
  612. szDrive[2] = '\\';
  613. szDrive[3] = '\0';
  614. // Get free disk space - if it fails, lets pray we have enought disk space
  615. if (!GetDiskFreeSpace(szDrive, &dwSectorsPerCluster, &dwBytesPerSector, &dwNumberOfFreeClusters, &dwTotalNumberOfClusters))
  616. {
  617. hr = TraceResult(E_FAIL);
  618. goto exit;
  619. }
  620. // Return Amount of Free Disk Space
  621. *pdwlFree = (dwNumberOfFreeClusters * (dwSectorsPerCluster * dwBytesPerSector));
  622. exit:
  623. // Done
  624. return hr;
  625. }
  626. // --------------------------------------------------------------------------------
  627. // MyWriteFile
  628. // --------------------------------------------------------------------------------
  629. HRESULT MyWriteFile(HANDLE hFile, DWORD faAddress, LPVOID pData, DWORD cbData)
  630. {
  631. // Locals
  632. DWORD cbWrote;
  633. // Trace
  634. TraceCall("MyWriteFile");
  635. // Seek to the end of the file...
  636. if (0xffffffff == SetFilePointer(hFile, faAddress, NULL, FILE_BEGIN))
  637. return TraceResult(MIGRATE_E_CANTSETFILEPOINTER);
  638. // Write file
  639. if (0 == WriteFile(hFile, pData, cbData, &cbWrote, NULL))
  640. return TraceResult(MIGRATE_E_WRITEFILE);
  641. // Done
  642. return S_OK;
  643. }
  644. // --------------------------------------------------------------------------------
  645. // MigrateMessageBox
  646. // --------------------------------------------------------------------------------
  647. UINT MigrateMessageBox(LPCSTR pszMsg, UINT uType)
  648. {
  649. // Locals
  650. CHAR szTitle[100];
  651. // Load title
  652. LoadString(g_hInst, IDS_TITLE, szTitle, ARRAYSIZE(szTitle));
  653. // MessageBox
  654. return MessageBox(NULL, pszMsg, szTitle, uType);
  655. }
  656. // --------------------------------------------------------------------------------
  657. // CreateAccountDirectory
  658. // --------------------------------------------------------------------------------
  659. HRESULT CreateAccountDirectory(LPCSTR pszStoreRoot, LPCSTR pszBase, DWORD iAccount,
  660. LPSTR pszPath, int cchPath)
  661. {
  662. // Locals
  663. HRESULT hr=S_OK;
  664. CHAR szDir[MAX_PATH + MAX_PATH];
  665. // Trace
  666. TraceCall("CreateAccountDirectory");
  667. // Loop
  668. while(1)
  669. {
  670. // Format the path
  671. wnsprintf(pszPath, cchPath, "Acct%04d", iAccount);
  672. // Format the Path
  673. wnsprintf(szDir, ARRAYSIZE(szDir), "%s\\%s\\%s", pszStoreRoot, pszBase, pszPath);
  674. // Create the Directory
  675. if (CreateDirectory(szDir, NULL))
  676. break;
  677. // If not already exists, failure
  678. if (ERROR_ALREADY_EXISTS != GetLastError())
  679. {
  680. hr = TraceResult(E_FAIL);
  681. goto exit;
  682. }
  683. // Try Again
  684. iAccount++;
  685. }
  686. exit:
  687. // Done
  688. return(hr);
  689. }
  690. // --------------------------------------------------------------------------------
  691. // BuildAccountTable
  692. // --------------------------------------------------------------------------------
  693. HRESULT BuildAccountTable(HKEY hkeyBase, LPCSTR pszRegRoot, LPCSTR pszStoreRoot,
  694. LPACCOUNTTABLE pTable)
  695. {
  696. // Locals
  697. HRESULT hr=S_OK;
  698. HKEY hkeyRoot=NULL;
  699. HKEY hkeyAcct=NULL;
  700. DWORD i;
  701. DWORD cb;
  702. DWORD cAccounts=0;
  703. DWORD dwType;
  704. LONG lResult;
  705. LPACCOUNTINFO pAccount;
  706. // Trace
  707. TraceCall("BuildAccountTable");
  708. // Validate Args
  709. Assert(hkeyBase && pszRegRoot && pTable);
  710. // Initialize
  711. ZeroMemory(pTable, sizeof(ACCOUNTTABLE));
  712. // Open the Root Key
  713. if (ERROR_SUCCESS != RegOpenKeyEx(hkeyBase, pszRegRoot, 0, KEY_ALL_ACCESS, &hkeyRoot))
  714. {
  715. hr = TraceResult(E_FAIL);
  716. goto exit;
  717. }
  718. // Enumerate keys
  719. if (ERROR_SUCCESS != RegQueryInfoKey(hkeyRoot, NULL, NULL, 0, &pTable->cAccounts, NULL, NULL, NULL, NULL, NULL, NULL, NULL))
  720. {
  721. hr = TraceResult(E_FAIL);
  722. goto exit;
  723. }
  724. // Allocate the Account Array
  725. IF_NULLEXIT(pTable->prgAccount = (LPACCOUNTINFO)ZeroAllocate(sizeof(ACCOUNTINFO) * pTable->cAccounts));
  726. // Start Enumerating the keys
  727. for (i=0; i<pTable->cAccounts; i++)
  728. {
  729. // Close Current hkeyAcct
  730. if (hkeyAcct)
  731. {
  732. RegCloseKey(hkeyAcct);
  733. hkeyAcct = NULL;
  734. }
  735. // Readability
  736. pAccount = &pTable->prgAccount[cAccounts];
  737. // Set the size of the account id field
  738. cb = sizeof(pAccount->szAcctId);
  739. // Enum the Key Info
  740. lResult = RegEnumKeyEx(hkeyRoot, i, pAccount->szAcctId, &cb, 0, NULL, NULL, NULL);
  741. // No more items
  742. if (lResult == ERROR_NO_MORE_ITEMS)
  743. break;
  744. // Error, lets move onto the next account
  745. if (lResult != ERROR_SUCCESS)
  746. {
  747. Assert(FALSE);
  748. continue;
  749. }
  750. // Open the Account Key
  751. if (ERROR_SUCCESS != RegOpenKeyEx(hkeyRoot, pAccount->szAcctId, 0, KEY_ALL_ACCESS, &hkeyAcct))
  752. {
  753. Assert(FALSE);
  754. continue;
  755. }
  756. // Set Length of Field
  757. cb = sizeof(pAccount->szAcctName);
  758. // Query the Account Name
  759. if (ERROR_SUCCESS != RegQueryValueEx(hkeyAcct, "Account Name", NULL, &dwType, (LPBYTE)pAccount->szAcctName, &cb))
  760. {
  761. Assert(FALSE);
  762. continue;
  763. }
  764. // Set Length of field
  765. cb = sizeof(pAccount->szServer);
  766. // Try to determine the account type
  767. if (ERROR_SUCCESS == RegQueryValueEx(hkeyAcct, "POP3 Server", NULL, &dwType, (LPBYTE)pAccount->szServer, &cb))
  768. {
  769. // Its a pop3 server
  770. pAccount->dwServer = SRV_POP3;
  771. // Set the Directory
  772. wnsprintf(pAccount->szDirectory, ARRAYSIZE(pAccount->szDirectory), "%s\\Mail", pszStoreRoot);
  773. }
  774. // Otherwise - NNTP
  775. else if (ERROR_SUCCESS == RegQueryValueEx(hkeyAcct, "NNTP Server", NULL, &dwType, (LPBYTE)pAccount->szServer, &cb))
  776. {
  777. // Its an nntp account
  778. pAccount->dwServer = SRV_NNTP;
  779. // Set length of the field
  780. cb = sizeof(pAccount->szDataDir);
  781. // Query the Data Directory
  782. if (ERROR_SUCCESS != RegQueryValueEx(hkeyAcct, "NNTP Data Directory", NULL, &dwType, (LPBYTE)pAccount->szDataDir, &cb))
  783. {
  784. // CreateAccountDirectory
  785. if (FAILED(CreateAccountDirectory(pszStoreRoot, "News", i, pAccount->szDataDir, ARRAYSIZE(pAccount->szDataDir))))
  786. continue;
  787. // Set the Data Directory
  788. if (ERROR_SUCCESS != RegSetValueEx(hkeyAcct, "NNTP Data Directory", 0, REG_SZ, (LPBYTE)pAccount->szDataDir, lstrlen(pAccount->szDataDir) + 1))
  789. continue;
  790. }
  791. // Format the Directory
  792. wnsprintf(pAccount->szDirectory, ARRAYSIZE(pAccount->szDirectory), "%s\\News\\%s", pszStoreRoot, pAccount->szDataDir);
  793. }
  794. // Otherwise - IMAP
  795. else if (ERROR_SUCCESS == RegQueryValueEx(hkeyAcct, "IMAP Server", NULL, &dwType, (LPBYTE)pAccount->szServer, &cb))
  796. {
  797. // Its an IMAP Server
  798. pAccount->dwServer = SRV_IMAP;
  799. // Set length of the field
  800. cb = sizeof(pAccount->szDataDir);
  801. // Query the Data Directory
  802. if (ERROR_SUCCESS != RegQueryValueEx(hkeyAcct, "IMAP Data Directory", NULL, &dwType, (LPBYTE)pAccount->szDataDir, &cb))
  803. {
  804. // CreateAccountDirectory
  805. if (FAILED(CreateAccountDirectory(pszStoreRoot, "IMAP", i, pAccount->szDataDir, ARRAYSIZE(pAccount->szDataDir))))
  806. continue;
  807. // Set the Data Directory
  808. if (ERROR_SUCCESS != RegSetValueEx(hkeyAcct, "IMAP Data Directory", 0, REG_SZ, (LPBYTE)pAccount->szDataDir, lstrlen(pAccount->szDataDir) + 1))
  809. continue;
  810. }
  811. // Format the Directory
  812. wnsprintf(pAccount->szDirectory, ARRAYSIZE(pAccount->szDirectory), "%s\\IMAP\\%s", pszStoreRoot, pAccount->szDataDir);
  813. }
  814. // Othewise, skip the account
  815. else
  816. continue;
  817. // Make sure the directory exists
  818. if (0 == CreateDirectory(pAccount->szDirectory, NULL) && ERROR_ALREADY_EXISTS != GetLastError())
  819. continue;
  820. // Increment Valid Account Count
  821. cAccounts++;
  822. }
  823. // Set Actual Number of Accounts
  824. pTable->cAccounts = cAccounts;
  825. exit:
  826. // Cleanup
  827. if (hkeyAcct)
  828. RegCloseKey(hkeyAcct);
  829. if (hkeyRoot)
  830. RegCloseKey(hkeyRoot);
  831. // Done
  832. return(hr);
  833. }