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.

951 lines
28 KiB

  1. //--------------------------------------------------------------------------
  2. // OE4Imp.cpp
  3. //--------------------------------------------------------------------------
  4. #include "pch.hxx"
  5. #include "oe4imp.h"
  6. #include "structs.h"
  7. #include "migerror.h"
  8. #include <shared.h>
  9. #include <impapi.h>
  10. #include <shlwapi.h>
  11. #include "dllmain.h"
  12. #include "resource.h"
  13. //--------------------------------------------------------------------------
  14. // Constants
  15. //--------------------------------------------------------------------------
  16. static const char c_szMail[] = "mail";
  17. static const char c_szFoldersNch[] = "folders.nch";
  18. static const char c_szEmpty[] = "";
  19. // --------------------------------------------------------------------------------
  20. // MSG_xxx flags
  21. // --------------------------------------------------------------------------------
  22. #define MSG_DELETED 0x0001
  23. #define MSG_UNREAD 0x0002
  24. #define MSG_SUBMITTED 0x0004
  25. #define MSG_UNSENT 0x0008
  26. #define MSG_RECEIVED 0x0010
  27. #define MSG_NEWSMSG 0x0020
  28. #define MSG_NOSECUI 0x0040
  29. #define MSG_VOICEMAIL 0x0080
  30. #define MSG_REPLIED 0x0100
  31. #define MSG_FORWARDED 0x0200
  32. #define MSG_RCPTSENT 0x0400
  33. #define MSG_FLAGGED 0x0800
  34. #define MSG_LAST 0x0200
  35. #define MSG_EXTERNAL_FLAGS 0x00fe
  36. #define MSG_FLAGS 0x000f
  37. //--------------------------------------------------------------------------
  38. // COE4Import_CreateInstance
  39. //--------------------------------------------------------------------------
  40. COE4Import_CreateInstance(IUnknown *pUnkOuter, IUnknown **ppUnknown)
  41. {
  42. // Trace
  43. TraceCall("COE4Import_CreateInstance");
  44. // Initialize
  45. *ppUnknown = NULL;
  46. // Create me
  47. COE4Import *pNew = new COE4Import();
  48. if (NULL == pNew)
  49. return TraceResult(E_OUTOFMEMORY);
  50. // Cast to unknown
  51. *ppUnknown = SAFECAST(pNew, IMailImport *);
  52. // Done
  53. return(S_OK);
  54. }
  55. // --------------------------------------------------------------------------------
  56. // GetRecordBlock
  57. // --------------------------------------------------------------------------------
  58. HRESULT GetRecordBlock(LPMEMORYFILE pFile, DWORD faRecord, LPRECORDBLOCKV5B1 *ppRecord,
  59. LPBYTE *ppbData, BOOL *pfContinue)
  60. {
  61. // Locals
  62. HRESULT hr=S_OK;
  63. // Trace
  64. TraceCall("GetRecordBlock");
  65. // Bad Length
  66. if (faRecord + sizeof(RECORDBLOCKV5B1) > pFile->cbSize)
  67. {
  68. *pfContinue = TRUE;
  69. hr = TraceResult(MIGRATE_E_OUTOFRANGEADDRESS);
  70. goto exit;
  71. }
  72. // Cast the Record
  73. (*ppRecord) = (LPRECORDBLOCKV5B1)((LPBYTE)pFile->pView + faRecord);
  74. // Invalid Record Signature
  75. if (faRecord != (*ppRecord)->faRecord)
  76. {
  77. *pfContinue = TRUE;
  78. hr = TraceResult(MIGRATE_E_BADRECORDSIGNATURE);
  79. goto exit;
  80. }
  81. // Bad Length
  82. if (faRecord + (*ppRecord)->cbRecord > pFile->cbSize)
  83. {
  84. *pfContinue = TRUE;
  85. hr = TraceResult(MIGRATE_E_OUTOFRANGEADDRESS);
  86. goto exit;
  87. }
  88. // Set pbData
  89. *ppbData = (LPBYTE)((LPBYTE)(*ppRecord) + sizeof(RECORDBLOCKV5B1));
  90. exit:
  91. // Done
  92. return hr;
  93. }
  94. //--------------------------------------------------------------------------
  95. // COE4Import::COE4Import
  96. //--------------------------------------------------------------------------
  97. COE4Import::COE4Import(void)
  98. {
  99. TraceCall("COE4Import::COE4Import");
  100. m_cRef = 1;
  101. m_pList = NULL;
  102. *m_szDirectory = '\0';
  103. m_cFolders = 0;
  104. m_prgFolder = NULL;
  105. }
  106. //--------------------------------------------------------------------------
  107. // COE4Import::~COE4Import
  108. //--------------------------------------------------------------------------
  109. COE4Import::~COE4Import(void)
  110. {
  111. TraceCall("COE4Import::~COE4Import");
  112. _Cleanup();
  113. }
  114. //--------------------------------------------------------------------------
  115. // COE4Import::_FreeFolderList
  116. //--------------------------------------------------------------------------
  117. void COE4Import::_Cleanup(void)
  118. {
  119. _FreeFolderList(m_pList);
  120. m_pList = NULL;
  121. SafeMemFree(m_prgFolder);
  122. m_cFolders = 0;
  123. }
  124. //--------------------------------------------------------------------------
  125. // COE4Import::_FreeFolderList
  126. //--------------------------------------------------------------------------
  127. void COE4Import::_FreeFolderList(IMPFOLDERNODE *pNode)
  128. {
  129. // Locals
  130. IMPFOLDERNODE *pNext;
  131. IMPFOLDERNODE *pCurrent=pNode;
  132. // Loop
  133. while (pCurrent)
  134. {
  135. // Save next
  136. pNext = pCurrent->pnext;
  137. // Free Children ?
  138. if (pCurrent->pchild)
  139. {
  140. // Free
  141. _FreeFolderList(pCurrent->pchild);
  142. }
  143. // Free szName
  144. g_pMalloc->Free(pCurrent->szName);
  145. // Free pCurrent
  146. g_pMalloc->Free(pCurrent);
  147. // Set Current
  148. pCurrent = pNext;
  149. }
  150. }
  151. //--------------------------------------------------------------------------
  152. // COE4Import::QueryInterface
  153. //--------------------------------------------------------------------------
  154. STDMETHODIMP COE4Import::QueryInterface(REFIID riid, LPVOID *ppv)
  155. {
  156. // Locals
  157. HRESULT hr=S_OK;
  158. // Stack
  159. TraceCall("COE4Import::QueryInterface");
  160. // Find IID
  161. if (IID_IUnknown == riid)
  162. *ppv = (IUnknown *)this;
  163. else if (IID_IMailImport == riid)
  164. *ppv = (IMailImport *)this;
  165. else
  166. {
  167. *ppv = NULL;
  168. hr = TraceResult(E_NOINTERFACE);
  169. goto exit;
  170. }
  171. // AddRef It
  172. ((IUnknown *)*ppv)->AddRef();
  173. exit:
  174. // Done
  175. return(hr);
  176. }
  177. //--------------------------------------------------------------------------
  178. // COE4Import::AddRef
  179. //--------------------------------------------------------------------------
  180. STDMETHODIMP_(ULONG) COE4Import::AddRef(void)
  181. {
  182. TraceCall("COE4Import::AddRef");
  183. return InterlockedIncrement(&m_cRef);
  184. }
  185. //--------------------------------------------------------------------------
  186. // COE4Import::Release
  187. //--------------------------------------------------------------------------
  188. STDMETHODIMP_(ULONG) COE4Import::Release(void)
  189. {
  190. TraceCall("COE4Import::Release");
  191. LONG cRef = InterlockedDecrement(&m_cRef);
  192. if (0 == cRef)
  193. delete this;
  194. return (ULONG)cRef;
  195. }
  196. //--------------------------------------------------------------------------
  197. // COE4Import::InitializeImport
  198. //--------------------------------------------------------------------------
  199. STDMETHODIMP COE4Import::InitializeImport(HWND hwnd)
  200. {
  201. // Let Importer Ask for the Directory
  202. return(S_OK);
  203. }
  204. //--------------------------------------------------------------------------
  205. // COE4Import::GetDirectory
  206. //--------------------------------------------------------------------------
  207. STDMETHODIMP COE4Import::GetDirectory(LPSTR pszDir, UINT cch)
  208. {
  209. // Locals
  210. HKEY hKey=NULL;
  211. DWORD dwType;
  212. DWORD cb=cch;
  213. // Try to query the OE4 store root...
  214. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Microsoft\\Outlook Express", 0, KEY_READ, &hKey))
  215. {
  216. // Try to read the value
  217. if (ERROR_SUCCESS == RegQueryValueEx(hKey, "Store Root", NULL, &dwType, (LPBYTE)pszDir, &cb))
  218. goto exit;
  219. }
  220. if (hKey)
  221. {
  222. RegCloseKey(hKey);
  223. hKey = NULL;
  224. }
  225. // Try V1
  226. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Microsoft\\Internet Mail and News", 0, KEY_READ, &hKey))
  227. {
  228. // Query the Store Root
  229. if (ERROR_SUCCESS == RegQueryValueEx(hKey, "Store Root", NULL, &dwType, (LPBYTE)pszDir, &cb))
  230. goto exit;
  231. }
  232. // Null It Out
  233. *pszDir = '\0';
  234. exit:
  235. // Close the Key
  236. if (hKey)
  237. RegCloseKey(hKey);
  238. // Done
  239. return(S_OK);
  240. }
  241. //--------------------------------------------------------------------------
  242. // COE4Import::SetDirectory
  243. //--------------------------------------------------------------------------
  244. STDMETHODIMP COE4Import::SetDirectory(LPSTR pszDir)
  245. {
  246. // Trace
  247. TraceCall("COE4Import::SetDirectory");
  248. // Save the Directory
  249. StrCpyN(m_szDirectory, pszDir, ARRAYSIZE(m_szDirectory));
  250. // Done
  251. return(S_OK);
  252. }
  253. //--------------------------------------------------------------------------
  254. // COE4Import::_EnumerateV1Folders
  255. //--------------------------------------------------------------------------
  256. HRESULT COE4Import::_EnumerateV1Folders(void)
  257. {
  258. // Locals
  259. HRESULT hr=S_OK;
  260. CHAR szRes[255];
  261. CHAR szMbxPath[MAX_PATH + MAX_PATH];
  262. CHAR szSearch[MAX_PATH + MAX_PATH];
  263. WIN32_FIND_DATA fd;
  264. HANDLE hFind=INVALID_HANDLE_VALUE;
  265. DWORD cAllocated=0;
  266. LPFLDINFO pFolder;
  267. DWORD i;
  268. MEMORYFILE MbxFile={0};
  269. LPMBXFILEHEADER pMbxHeader;
  270. // Trace
  271. TraceCall("COE4Import::_EnumerateV1Folders");
  272. // Do we have a sub dir
  273. wnsprintf(szSearch, ARRAYSIZE(szSearch), "%s\\*.mbx", m_szDirectory);
  274. // Find first file
  275. hFind = FindFirstFile(szSearch, &fd);
  276. // Did we find something
  277. if (INVALID_HANDLE_VALUE == hFind)
  278. goto exit;
  279. // Loop for ever
  280. while(1)
  281. {
  282. // If this is not a directory
  283. if (FALSE == ISFLAGSET(fd.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY))
  284. {
  285. // Open the file
  286. IF_FAILEXIT(hr = MakeFilePath(m_szDirectory, fd.cFileName, c_szEmpty, szMbxPath, ARRAYSIZE(szMbxPath)));
  287. // Open the memory file
  288. if (SUCCEEDED(OpenMemoryFile(szMbxPath, &MbxFile)))
  289. {
  290. // Allocate
  291. if (m_cFolders + 1 > cAllocated)
  292. {
  293. // Reallocate
  294. IF_FAILEXIT(hr = HrRealloc((LPVOID *)&m_prgFolder, (cAllocated + 10) * sizeof(FLDINFO)));
  295. // Set cAllocated
  296. cAllocated += 10;
  297. }
  298. // Readability
  299. pFolder = &m_prgFolder[m_cFolders];
  300. // Zero this node
  301. ZeroMemory(pFolder, sizeof(FLDINFO));
  302. // Copy the filename
  303. StrCpyN(pFolder->szFile, fd.cFileName, ARRAYSIZE(pFolder->szFile));
  304. // Strip the Extension Off
  305. PathRemoveExtensionA(pFolder->szFile);
  306. // Copy the folder name
  307. StrCpyN(pFolder->szFolder, pFolder->szFile, ARRAYSIZE(pFolder->szFolder));
  308. // Set Special
  309. pFolder->tySpecial = (FOLDER_TYPE_NORMAL - 1);
  310. // Loop through special folder
  311. for (i=FOLDER_TYPE_INBOX; i<CFOLDERTYPE; i++)
  312. {
  313. // Load the Special Folder Name
  314. LoadString(g_hInstImp, idsInbox + (i - 1), szRes, ARRAYSIZE(szRes));
  315. // Compare with szFile
  316. if (lstrcmpi(pFolder->szFolder, szRes) == 0)
  317. {
  318. // Copy the Folder Name
  319. pFolder->tySpecial = (i - 1);
  320. // Done
  321. break;
  322. }
  323. }
  324. // Read the Mbx File Header
  325. pMbxHeader = (LPMBXFILEHEADER)(MbxFile.pView);
  326. // Get the message Count so progress will work nicely
  327. pFolder->cMessages = pMbxHeader->cMsg;
  328. // Close the memory file
  329. CloseMemoryFile(&MbxFile);
  330. // Increment m_cFolders
  331. m_cFolders++;
  332. }
  333. }
  334. // Find the Next File
  335. if (!FindNextFile(hFind, &fd))
  336. break;
  337. }
  338. exit:
  339. // Cleanup
  340. if (hFind)
  341. FindClose(hFind);
  342. CloseMemoryFile(&MbxFile);
  343. // Done
  344. return(hr);
  345. }
  346. //--------------------------------------------------------------------------
  347. // COE4Import::EnumerateFolders
  348. //--------------------------------------------------------------------------
  349. STDMETHODIMP COE4Import::EnumerateFolders(DWORD_PTR dwCookie, IEnumFOLDERS **ppEnum)
  350. {
  351. // Locals
  352. HRESULT hr=S_OK;
  353. DWORD cchDir;
  354. MEMORYFILE File={0};
  355. LPTABLEHEADERV5B1 pHeader;
  356. LPBYTE pbData;
  357. DWORD faRecord;
  358. LPFLDINFO pFolder;
  359. LPRECORDBLOCKV5B1 pRecord;
  360. BOOL fContinue;
  361. COE4EnumFolders *pEnum=NULL;
  362. CHAR szFilePath[MAX_PATH + MAX_PATH];
  363. IMPFOLDERNODE *pList;
  364. IMPFOLDERNODE *pNode=(IMPFOLDERNODE *)dwCookie;
  365. // Trace
  366. TraceCall("COE4Import::EnumerateFolders");
  367. // Invalid Args
  368. Assert(ppEnum);
  369. // No folders yet ?
  370. if (COOKIE_ROOT == dwCookie)
  371. {
  372. // Reset...
  373. _Cleanup();
  374. // Append \Mail onto m_szDirectory
  375. cchDir = lstrlen(m_szDirectory);
  376. // Is there enough room
  377. if (cchDir + lstrlen(c_szMail) + 2 >= ARRAYSIZE(m_szDirectory))
  378. {
  379. hr = TraceResult(E_FAIL);
  380. goto exit;
  381. }
  382. // Need a Wack ?
  383. PathAddBackslash(m_szDirectory);
  384. // Append \\mail
  385. StrCatBuff(m_szDirectory, c_szMail, ARRAYSIZE(m_szDirectory));
  386. // Make Path to folders.nch file
  387. IF_FAILEXIT(hr = MakeFilePath(m_szDirectory, c_szFoldersNch, c_szEmpty, szFilePath, ARRAYSIZE(szFilePath)));
  388. // If the folders.nch file doesn't exist, just try to enumerate the
  389. if (FALSE == PathFileExists(szFilePath))
  390. {
  391. // EnumerateV1Folders
  392. IF_FAILEXIT(hr = _EnumerateV1Folders());
  393. }
  394. // Otherwise, crack the folders.nch file
  395. else
  396. {
  397. // Open the Folders file
  398. IF_FAILEXIT(hr = OpenMemoryFile(szFilePath, &File));
  399. // Validate Version
  400. pHeader = (LPTABLEHEADERV5B1)File.pView;
  401. // Check the Signature...
  402. if (File.cbSize < sizeof(TABLEHEADERV5B1) || OBJECTDB_SIGNATURE != pHeader->dwSignature || OBJECTDB_VERSION_PRE_V5 != pHeader->wMajorVersion)
  403. {
  404. hr = TraceResult(E_FAIL);
  405. goto exit;
  406. }
  407. // Allocate Folder Array
  408. IF_NULLEXIT(m_prgFolder = (LPFLDINFO)ZeroAllocate(sizeof(FLDINFO) * pHeader->cRecords));
  409. // Initialize faRecord to start
  410. faRecord = pHeader->faFirstRecord;
  411. // While we have a record
  412. while(faRecord)
  413. {
  414. // Readability
  415. pFolder = &m_prgFolder[m_cFolders];
  416. // Get the Record
  417. IF_FAILEXIT(hr = GetRecordBlock(&File, faRecord, &pRecord, &pbData, &fContinue));
  418. // DWORD - hFolder
  419. CopyMemory(&pFolder->idFolder, pbData, sizeof(pFolder->idFolder));
  420. pbData += sizeof(pFolder->idFolder);
  421. // CHAR(MAX_FOLDER_NAME) - szFolder
  422. CopyMemory(pFolder->szFolder, pbData, sizeof(pFolder->szFolder));
  423. pbData += sizeof(pFolder->szFolder);
  424. // CHAR(260) - szFile
  425. CopyMemory(pFolder->szFile, pbData, sizeof(pFolder->szFile));
  426. pbData += sizeof(pFolder->szFile);
  427. // DWORD - idParent
  428. CopyMemory(&pFolder->idParent, pbData, sizeof(pFolder->idParent));
  429. pbData += sizeof(pFolder->idParent);
  430. // DWORD - idChild
  431. CopyMemory(&pFolder->idChild, pbData, sizeof(pFolder->idChild));
  432. pbData += sizeof(pFolder->idChild);
  433. // DWORD - idSibling
  434. CopyMemory(&pFolder->idSibling, pbData, sizeof(pFolder->idSibling));
  435. pbData += sizeof(pFolder->idSibling);
  436. // DWORD - tySpecial
  437. CopyMemory(&pFolder->tySpecial, pbData, sizeof(pFolder->tySpecial));
  438. pbData += sizeof(pFolder->tySpecial);
  439. // DWORD - cChildren
  440. CopyMemory(&pFolder->cChildren, pbData, sizeof(pFolder->cChildren));
  441. pbData += sizeof(pFolder->cChildren);
  442. // DWORD - cMessages
  443. CopyMemory(&pFolder->cMessages, pbData, sizeof(pFolder->cMessages));
  444. pbData += sizeof(pFolder->cMessages);
  445. // DWORD - cUnread
  446. CopyMemory(&pFolder->cUnread, pbData, sizeof(pFolder->cUnread));
  447. pbData += sizeof(pFolder->cUnread);
  448. // DWORD - cbTotal
  449. CopyMemory(&pFolder->cbTotal, pbData, sizeof(pFolder->cbTotal));
  450. pbData += sizeof(pFolder->cbTotal);
  451. // DWORD - cbUsed
  452. CopyMemory(&pFolder->cbUsed, pbData, sizeof(pFolder->cbUsed));
  453. pbData += sizeof(pFolder->cbUsed);
  454. // DWORD - bHierarchy
  455. CopyMemory(&pFolder->bHierarchy, pbData, sizeof(pFolder->bHierarchy));
  456. pbData += sizeof(pFolder->bHierarchy);
  457. // DWORD - dwImapFlags
  458. CopyMemory(&pFolder->dwImapFlags, pbData, sizeof(pFolder->dwImapFlags));
  459. pbData += sizeof(DWORD);
  460. // BLOB - bListStamp
  461. CopyMemory(&pFolder->bListStamp, pbData, sizeof(pFolder->bListStamp));
  462. pbData += sizeof(BYTE);
  463. // DWORD - bReserved[3]
  464. pbData += (3 * sizeof(BYTE));
  465. // DWORD - rgbReserved
  466. pbData += 40;
  467. // Increment Count
  468. m_cFolders++;
  469. // Goto the Next Record
  470. faRecord = pRecord->faNext;
  471. }
  472. }
  473. // Build Import Folder Hierarchy
  474. IF_FAILEXIT(hr = _BuildFolderHierarchy(0, 0, NULL, m_cFolders, m_prgFolder));
  475. }
  476. // Not Folders ?
  477. else if (NULL == m_prgFolder)
  478. {
  479. hr = TraceResult(E_FAIL);
  480. goto exit;
  481. }
  482. // What should I
  483. if (dwCookie == COOKIE_ROOT)
  484. pList = m_pList;
  485. else
  486. pList = pNode->pchild;
  487. // Create Folder Enumerator
  488. IF_NULLEXIT(pEnum = new COE4EnumFolders(pList));
  489. // Return Enumerator
  490. *ppEnum = (IEnumFOLDERS *)pEnum;
  491. // Don't Free
  492. pEnum = NULL;
  493. exit:
  494. // Cleanup
  495. SafeRelease(pEnum);
  496. CloseMemoryFile(&File);
  497. // Done
  498. return(hr);
  499. }
  500. //--------------------------------------------------------------------------
  501. // COE4Import::_BuildFolderHierarchy
  502. //--------------------------------------------------------------------------
  503. HRESULT COE4Import::_BuildFolderHierarchy(DWORD cDepth, DWORD idParent,
  504. IMPFOLDERNODE *pParent, DWORD cFolders, LPFLDINFO prgFolder)
  505. {
  506. // Locals
  507. HRESULT hr=S_OK;
  508. DWORD i;
  509. IMPFOLDERNODE *pPrevious=NULL;
  510. IMPFOLDERNODE *pNode;
  511. // Trace
  512. TraceCall("COE4Import::_BuildFolderHierarchy");
  513. // Walk through prgFolder and find items with parent of idParent
  514. for (i=0; i<cFolders; i++)
  515. {
  516. // Correct Parent ?
  517. if (idParent == prgFolder[i].idParent)
  518. {
  519. // Allocate the Root
  520. IF_NULLEXIT(pNode = (IMPFOLDERNODE *)ZeroAllocate(sizeof(IMPFOLDERNODE)));
  521. // Set Parent
  522. pNode->pparent = pParent;
  523. // Set Depth
  524. pNode->depth = cDepth;
  525. // Copy name
  526. IF_NULLEXIT(pNode->szName = PszDupA(prgFolder[i].szFolder));
  527. // Count of Messages
  528. pNode->cMsg = prgFolder[i].cMessages;
  529. // Set Type
  530. pNode->type = (IMPORTFOLDERTYPE)(prgFolder[i].tySpecial + 1);
  531. // Set lParam
  532. pNode->lparam = i;
  533. // Link pNode into List
  534. if (pPrevious)
  535. pPrevious->pnext = pNode;
  536. else if (pParent)
  537. pParent->pchild = pNode;
  538. else
  539. {
  540. Assert(NULL == m_pList);
  541. m_pList = pNode;
  542. }
  543. // Set pPrevious
  544. pPrevious = pNode;
  545. // Has Children ?
  546. if (prgFolder[i].cChildren)
  547. {
  548. // Enumerate Children
  549. IF_FAILEXIT(hr = _BuildFolderHierarchy(cDepth + 1, prgFolder[i].idFolder, pNode, cFolders, prgFolder));
  550. }
  551. }
  552. }
  553. exit:
  554. // Done
  555. return(hr);
  556. }
  557. //--------------------------------------------------------------------------
  558. // COE4Import::ImportFolder
  559. //--------------------------------------------------------------------------
  560. STDMETHODIMP COE4Import::ImportFolder(DWORD_PTR dwCookie, IFolderImport *pImport)
  561. {
  562. // Locals
  563. HRESULT hr=S_OK;
  564. CHAR szIdxPath[MAX_PATH + MAX_PATH];
  565. CHAR szMbxPath[MAX_PATH + MAX_PATH];
  566. MEMORYFILE IdxFile={0};
  567. MEMORYFILE MbxFile={0};
  568. LPBYTE pbStream;
  569. LPMBXFILEHEADER pMbxHeader;
  570. LPIDXFILEHEADER pIdxHeader;
  571. DWORD faIdxRead;
  572. LPIDXMESSAGEHEADER pIdxMessage;
  573. LPMBXMESSAGEHEADER pMbxMessage;
  574. DWORD cMessages=0;
  575. DWORD dwMsgState;
  576. DWORD i;
  577. DWORD cb;
  578. CByteStream *pStream=NULL;
  579. IMPFOLDERNODE *pNode=(IMPFOLDERNODE *)dwCookie;
  580. LPFLDINFO pFolder;
  581. // Trace
  582. TraceCall("COE4Import::ImportFolder");
  583. // Set pFolder
  584. pFolder = &m_prgFolder[pNode->lparam];
  585. // .idx path
  586. IF_FAILEXIT(hr = MakeFilePath(m_szDirectory, pFolder->szFile, ".idx", szIdxPath, ARRAYSIZE(szIdxPath)));
  587. // .mbx path
  588. IF_FAILEXIT(hr = MakeFilePath(m_szDirectory, pFolder->szFile, ".mbx", szMbxPath, ARRAYSIZE(szMbxPath)));
  589. // Open the memory file
  590. IF_FAILEXIT(hr = OpenMemoryFile(szIdxPath, &IdxFile));
  591. // Open the memory file
  592. IF_FAILEXIT(hr = OpenMemoryFile(szMbxPath, &MbxFile));
  593. // Read the Mbx File Header
  594. pMbxHeader = (LPMBXFILEHEADER)(MbxFile.pView);
  595. // Read the Idx File Header
  596. pIdxHeader = (LPIDXFILEHEADER)(IdxFile.pView);
  597. // Validate the Version of th idx file
  598. if (pIdxHeader->ver != CACHEFILE_VER || pIdxHeader->dwMagic != CACHEFILE_MAGIC)
  599. {
  600. hr = TraceResult(MIGRATE_E_INVALIDIDXHEADER);
  601. goto exit;
  602. }
  603. // Setup faIdxRead
  604. faIdxRead = sizeof(IDXFILEHEADER);
  605. // Set Message Count
  606. pImport->SetMessageCount(pIdxHeader->cMsg);
  607. // Prepare to Loop
  608. for (i=0; i<pIdxHeader->cMsg; i++)
  609. {
  610. // Done
  611. if (faIdxRead >= IdxFile.cbSize)
  612. break;
  613. // Read an idx message header
  614. pIdxMessage = (LPIDXMESSAGEHEADER)((LPBYTE)IdxFile.pView + faIdxRead);
  615. // If this message is not marked as deleted...
  616. if (ISFLAGSET(pIdxMessage->dwState, MSG_DELETED))
  617. goto NextMessage;
  618. // Initialize State
  619. dwMsgState = 0;
  620. // Fixup the Flags
  621. if (ISFLAGSET(pIdxMessage->dwState, MSG_UNREAD))
  622. FLAGSET(dwMsgState, MSG_STATE_UNREAD);
  623. if (ISFLAGSET(pIdxMessage->dwState, MSG_UNSENT))
  624. FLAGSET(dwMsgState, MSG_STATE_UNSENT);
  625. if (ISFLAGSET(pIdxMessage->dwState, MSG_SUBMITTED))
  626. FLAGSET(dwMsgState, MSG_STATE_SUBMITTED);
  627. // Bad
  628. if (pIdxMessage->dwOffset > MbxFile.cbSize)
  629. goto NextMessage;
  630. // Lets read the message header in the mbx file to validate the msgids
  631. pMbxMessage = (LPMBXMESSAGEHEADER)((LPBYTE)MbxFile.pView + pIdxMessage->dwOffset);
  632. // Validate the Message Ids
  633. if (pMbxMessage->msgid != pIdxMessage->msgid)
  634. goto NextMessage;
  635. // Check for magic
  636. if (pMbxMessage->dwMagic != MSGHDR_MAGIC)
  637. goto NextMessage;
  638. // Get the stream pointer
  639. pbStream = (LPBYTE)((LPBYTE)MbxFile.pView + (pIdxMessage->dwOffset + sizeof(MBXMESSAGEHEADER)));
  640. // New byte Stream
  641. IF_NULLEXIT(pStream = new CByteStream(pbStream, pMbxMessage->dwBodySize));
  642. // Import the message
  643. IF_FAILEXIT(hr = pImport->ImportMessage(MSG_TYPE_MAIL, dwMsgState, pStream, NULL, 0));
  644. // Count
  645. cMessages++;
  646. NextMessage:
  647. // Cleanup
  648. if (pStream)
  649. {
  650. pStream->AcquireBytes(&cb, &pbStream, ACQ_DISPLACE);
  651. pStream->Release();
  652. pStream = NULL;
  653. }
  654. // Goto Next Header
  655. Assert(pIdxMessage);
  656. // Update faIdxRead
  657. faIdxRead += pIdxMessage->dwSize;
  658. }
  659. exit:
  660. // Cleanup
  661. if (pStream)
  662. {
  663. pStream->AcquireBytes(&cb, &pbStream, ACQ_DISPLACE);
  664. pStream->Release();
  665. pStream = NULL;
  666. }
  667. CloseMemoryFile(&IdxFile);
  668. CloseMemoryFile(&MbxFile);
  669. // Done
  670. return hr;
  671. }
  672. //--------------------------------------------------------------------------
  673. // COE4EnumFolders::COE4EnumFolders
  674. //--------------------------------------------------------------------------
  675. COE4EnumFolders::COE4EnumFolders(IMPFOLDERNODE *pList)
  676. {
  677. TraceCall("COE4EnumFolders::COE4EnumFolders");
  678. m_cRef = 1;
  679. m_pList = pList;
  680. m_pNext = pList;
  681. }
  682. //--------------------------------------------------------------------------
  683. // COE4EnumFolders::COE4EnumFolders
  684. //--------------------------------------------------------------------------
  685. COE4EnumFolders::~COE4EnumFolders(void)
  686. {
  687. TraceCall("COE4EnumFolders::~COE4EnumFolders");
  688. }
  689. //--------------------------------------------------------------------------
  690. // COE4EnumFolders::COE4EnumFolders
  691. //--------------------------------------------------------------------------
  692. STDMETHODIMP COE4EnumFolders::QueryInterface(REFIID riid, LPVOID *ppv)
  693. {
  694. // Locals
  695. HRESULT hr=S_OK;
  696. // Stack
  697. TraceCall("COE4EnumFolders::QueryInterface");
  698. // Find IID
  699. if (IID_IUnknown == riid)
  700. *ppv = (IUnknown *)this;
  701. else if (IID_IEnumFOLDERS == riid)
  702. *ppv = (IEnumFOLDERS *)this;
  703. else
  704. {
  705. *ppv = NULL;
  706. hr = TraceResult(E_NOINTERFACE);
  707. goto exit;
  708. }
  709. // AddRef It
  710. ((IUnknown *)*ppv)->AddRef();
  711. exit:
  712. // Done
  713. return(hr);
  714. }
  715. //--------------------------------------------------------------------------
  716. // COE4EnumFolders::AddRef
  717. //--------------------------------------------------------------------------
  718. STDMETHODIMP_(ULONG) COE4EnumFolders::AddRef(void)
  719. {
  720. TraceCall("COE4EnumFolders::AddRef");
  721. return InterlockedIncrement(&m_cRef);
  722. }
  723. //--------------------------------------------------------------------------
  724. // COE4EnumFolders::Release
  725. //--------------------------------------------------------------------------
  726. STDMETHODIMP_(ULONG) COE4EnumFolders::Release(void)
  727. {
  728. TraceCall("COE4EnumFolders::Release");
  729. LONG cRef = InterlockedDecrement(&m_cRef);
  730. if (0 == cRef)
  731. delete this;
  732. return (ULONG)cRef;
  733. }
  734. //--------------------------------------------------------------------------
  735. // COE4EnumFolders::Next
  736. //--------------------------------------------------------------------------
  737. STDMETHODIMP COE4EnumFolders::Next(IMPORTFOLDER *pFolder)
  738. {
  739. // Locals
  740. HRESULT hr=S_OK;
  741. // Trace
  742. TraceCall("COE4EnumFolders::Next");
  743. // Invalid Args
  744. Assert(pFolder != NULL);
  745. // Done
  746. if (NULL == m_pNext)
  747. return(S_FALSE);
  748. // Zero
  749. ZeroMemory(pFolder, sizeof(IMPORTFOLDER));
  750. // Store pNext into dwCookie
  751. pFolder->dwCookie = (DWORD_PTR)m_pNext;
  752. // Copy Folder Name
  753. StrCpyN(pFolder->szName, m_pNext->szName, ARRAYSIZE(pFolder->szName));
  754. // Copy Type
  755. pFolder->type = m_pNext->type;
  756. // Has Sub Folders ?
  757. pFolder->fSubFolders = (m_pNext->pchild != NULL);
  758. // Goto Next
  759. m_pNext = m_pNext->pnext;
  760. // Done
  761. return(S_OK);
  762. }
  763. //--------------------------------------------------------------------------
  764. // COE4EnumFolders::Reset
  765. //--------------------------------------------------------------------------
  766. STDMETHODIMP COE4EnumFolders::Reset(void)
  767. {
  768. // Trace
  769. TraceCall("COE4EnumFolders::Reset");
  770. // Reset
  771. m_pNext = m_pList;
  772. // Done
  773. return(S_OK);
  774. }