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.

2857 lines
91 KiB

  1. // --------------------------------------------------------------------------------
  2. // upoe5.cpp
  3. // --------------------------------------------------------------------------------
  4. #include "pch.hxx"
  5. #include "utility.h"
  6. #include "migrate.h"
  7. #include "migerror.h"
  8. #include "structs.h"
  9. #include "resource.h"
  10. #define DEFINE_DIRECTDB
  11. #include <shared.h>
  12. #include <oestore.h>
  13. #include <oerules.h>
  14. #include <mimeole.h>
  15. #include "msident.h"
  16. // --------------------------------------------------------------------------------
  17. // Linearly Incrementing Folder Id
  18. // --------------------------------------------------------------------------------
  19. static DWORD g_idFolderNext=1000;
  20. extern BOOL g_fQuiet;
  21. // --------------------------------------------------------------------------------
  22. // FOLDERIDCHANGE
  23. // --------------------------------------------------------------------------------
  24. typedef struct tagFOLDERIDCHANGE {
  25. FOLDERID idOld;
  26. FOLDERID idNew;
  27. } FOLDERIDCHANGE, *LPFOLDERIDCHANGE;
  28. // --------------------------------------------------------------------------------
  29. // Forward Declarations
  30. // --------------------------------------------------------------------------------
  31. HRESULT SetIMAPSpecialFldrType(LPSTR pszAcctID, LPSTR pszFldrName, SPECIALFOLDER *psfType);
  32. // --------------------------------------------------------------------------------
  33. // SplitMailCacheBlob
  34. // --------------------------------------------------------------------------------
  35. HRESULT SplitMailCacheBlob(IMimePropertySet *pNormalizer, LPBYTE pbCacheInfo,
  36. DWORD cbCacheInfo, LPMESSAGEINFO pMsgInfo, LPSTR *ppszNormal, LPBLOB pOffsets)
  37. {
  38. // Locals
  39. HRESULT hr=S_OK;
  40. ULONG ib;
  41. ULONG cbTree;
  42. ULONG cbProps;
  43. WORD wVersion;
  44. DWORD dw;
  45. DWORD cbMsg;
  46. DWORD dwFlags;
  47. WORD wPriority;
  48. PROPVARIANT Variant;
  49. // Invalid Arg
  50. Assert(pbCacheInfo && cbCacheInfo && pMsgInfo);
  51. // Init
  52. ZeroMemory(pOffsets, sizeof(BLOB));
  53. // Read Version
  54. ib = 0;
  55. IF_FAILEXIT(hr = BlobReadData(pbCacheInfo, cbCacheInfo, &ib, (LPBYTE)&wVersion, sizeof(wVersion)));
  56. // Version Check
  57. if (wVersion != MSG_HEADER_VERSISON)
  58. {
  59. hr = TraceResult(E_FAIL);
  60. goto exit;
  61. }
  62. // Read Flags
  63. IF_FAILEXIT(hr = BlobReadData(pbCacheInfo, cbCacheInfo, &ib, (LPBYTE)&dwFlags, sizeof(dwFlags)));
  64. // IMF_ATTACHMENTS
  65. if (ISFLAGSET(dwFlags, IMF_ATTACHMENTS))
  66. FLAGSET(pMsgInfo->dwFlags, ARF_HASATTACH);
  67. // IMF_SIGNED
  68. if (ISFLAGSET(dwFlags, IMF_SIGNED))
  69. FLAGSET(pMsgInfo->dwFlags, ARF_SIGNED);
  70. // IMF_ENCRYPTED
  71. if (ISFLAGSET(dwFlags, IMF_ENCRYPTED))
  72. FLAGSET(pMsgInfo->dwFlags, ARF_ENCRYPTED);
  73. // IMF_VOICEMAIL
  74. if (ISFLAGSET(dwFlags, IMF_VOICEMAIL))
  75. FLAGSET(pMsgInfo->dwFlags, ARF_VOICEMAIL);
  76. // IMF_NEWS
  77. if (ISFLAGSET(dwFlags, IMF_NEWS))
  78. FLAGSET(pMsgInfo->dwFlags, ARF_NEWSMSG);
  79. // Read Reserved
  80. IF_FAILEXIT(hr = BlobReadData(pbCacheInfo, cbCacheInfo, &ib, (LPBYTE)&dw, sizeof(dw)));
  81. // Read Message Size
  82. IF_FAILEXIT(hr = BlobReadData(pbCacheInfo, cbCacheInfo, &ib, (LPBYTE)&cbMsg, sizeof(cbMsg)));
  83. // Read Byte Count for the content list
  84. IF_FAILEXIT(hr = BlobReadData(pbCacheInfo, cbCacheInfo, &ib, (LPBYTE)&cbTree, sizeof(cbTree)));
  85. // Does the user want the tree ?
  86. if (cbTree)
  87. {
  88. pOffsets->pBlobData = (pbCacheInfo + ib);
  89. pOffsets->cbSize = cbTree;
  90. }
  91. // Increment passed the tree
  92. ib += cbTree;
  93. // Read Byte Count for the content list
  94. IF_FAILEXIT(hr = BlobReadData(pbCacheInfo, cbCacheInfo, &ib, (LPBYTE)&cbProps, sizeof(cbProps)));
  95. // Partial Number
  96. IF_FAILEXIT(hr = BlobReadData(pbCacheInfo, cbCacheInfo, &ib, (LPBYTE)&pMsgInfo->dwPartial, sizeof(pMsgInfo->dwPartial)));
  97. // Receive Time
  98. IF_FAILEXIT(hr = BlobReadData(pbCacheInfo, cbCacheInfo, &ib, (LPBYTE)&pMsgInfo->ftReceived, sizeof(pMsgInfo->ftReceived)));
  99. // Sent Time
  100. IF_FAILEXIT(hr = BlobReadData(pbCacheInfo, cbCacheInfo, &ib, (LPBYTE)&pMsgInfo->ftSent, sizeof(pMsgInfo->ftSent)));
  101. // Priority
  102. IF_FAILEXIT(hr = BlobReadData(pbCacheInfo, cbCacheInfo, &ib, (LPBYTE)&wPriority, sizeof(wPriority)));
  103. // Pritority
  104. pMsgInfo->wPriority = wPriority;
  105. // Subject
  106. IF_FAILEXIT(hr = BlobReadData(pbCacheInfo, cbCacheInfo, &ib, (LPBYTE)&dw, sizeof(dw)));
  107. pMsgInfo->pszSubject = (LPSTR)(pbCacheInfo + ib);
  108. ib += dw;
  109. // Init the Normalizer
  110. pNormalizer->InitNew();
  111. // Set the Subject
  112. Variant.vt = VT_LPSTR;
  113. Variant.pszVal = pMsgInfo->pszSubject;
  114. // Set the Property
  115. IF_FAILEXIT(hr = pNormalizer->SetProp(PIDTOSTR(PID_HDR_SUBJECT), 0, &Variant));
  116. // Get the Normalized Subject back out
  117. if (SUCCEEDED(pNormalizer->GetProp(PIDTOSTR(PID_ATT_NORMSUBJ), 0, &Variant)))
  118. *ppszNormal = pMsgInfo->pszNormalSubj = Variant.pszVal;
  119. // Otherwise, just use the subject
  120. else
  121. pMsgInfo->pszNormalSubj = pMsgInfo->pszSubject;
  122. // Display To
  123. IF_FAILEXIT(hr = BlobReadData(pbCacheInfo, cbCacheInfo, &ib, (LPBYTE)&dw, sizeof(dw)));
  124. pMsgInfo->pszDisplayTo = (LPSTR)(pbCacheInfo + ib);
  125. ib += dw;
  126. // Display From
  127. IF_FAILEXIT(hr = BlobReadData(pbCacheInfo, cbCacheInfo, &ib, (LPBYTE)&dw, sizeof(dw)));
  128. pMsgInfo->pszDisplayFrom = (LPSTR)(pbCacheInfo + ib);
  129. ib += dw;
  130. // Server
  131. IF_FAILEXIT(hr = BlobReadData(pbCacheInfo, cbCacheInfo, &ib, (LPBYTE)&dw, sizeof(dw)));
  132. pMsgInfo->pszServer = (LPSTR)(pbCacheInfo + ib);
  133. ib += dw;
  134. // UIDL
  135. IF_FAILEXIT(hr = BlobReadData(pbCacheInfo, cbCacheInfo, &ib, (LPBYTE)&dw, sizeof(dw)));
  136. pMsgInfo->pszUidl = (LPSTR)(pbCacheInfo + ib);
  137. ib += dw;
  138. // User Name
  139. IF_FAILEXIT(hr = BlobReadData(pbCacheInfo, cbCacheInfo, &ib, (LPBYTE)&dw, sizeof(dw)));
  140. //pMsgInfo->pszUserName = (LPSTR)(pbCacheInfo + ib);
  141. ib += dw;
  142. // Account Name
  143. IF_FAILEXIT(hr = BlobReadData(pbCacheInfo, cbCacheInfo, &ib, (LPBYTE)&dw, sizeof(dw)));
  144. pMsgInfo->pszAcctName = (LPSTR)(pbCacheInfo + ib);
  145. ib += dw;
  146. // Partial Id
  147. IF_FAILEXIT(hr = BlobReadData(pbCacheInfo, cbCacheInfo, &ib, (LPBYTE)&dw, sizeof(dw)));
  148. pMsgInfo->pszPartialId = (LPSTR)(pbCacheInfo + ib);
  149. ib += dw;
  150. // Forward To
  151. IF_FAILEXIT(hr = BlobReadData(pbCacheInfo, cbCacheInfo, &ib, (LPBYTE)&dw, sizeof(dw)));
  152. pMsgInfo->pszForwardTo = (LPSTR)(pbCacheInfo + ib);
  153. ib += dw;
  154. // Sanity Check
  155. Assert(ib == cbCacheInfo);
  156. exit:
  157. // Done
  158. return hr;
  159. }
  160. //--------------------------------------------------------------------------
  161. // GetMsgInfoFromPropertySet
  162. //--------------------------------------------------------------------------
  163. HRESULT GetMsgInfoFromPropertySet(
  164. /* in */ IMimePropertySet *pPropertySet,
  165. /* in,out */ LPMESSAGEINFO pMsgInfo)
  166. {
  167. // Locals
  168. HRESULT hr=S_OK;
  169. IMSGPRIORITY priority;
  170. PROPVARIANT Variant;
  171. SYSTEMTIME st;
  172. FILETIME ftCurrent;
  173. IMimeAddressTable *pAdrTable=NULL;
  174. // Trace
  175. TraceCall("GetMsgInfoFromPropertySet");
  176. // Invalid Args
  177. Assert(pPropertySet && pMsgInfo);
  178. // Default Sent and Received Times...
  179. GetSystemTime(&st);
  180. SystemTimeToFileTime(&st, &ftCurrent);
  181. // Set Variant tyStore
  182. Variant.vt = VT_UI4;
  183. // Priority
  184. if (SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(PID_ATT_PRIORITY), 0, &Variant)))
  185. {
  186. // Set Priority
  187. pMsgInfo->wPriority = (WORD)Variant.ulVal;
  188. }
  189. // Partial Numbers...
  190. if (pPropertySet->IsContentType(STR_CNT_MESSAGE, STR_SUB_PARTIAL) == S_OK)
  191. {
  192. // Locals
  193. WORD cParts=0, iPart=0;
  194. // Get Total
  195. if (SUCCEEDED(pPropertySet->GetProp(STR_PAR_TOTAL, NOFLAGS, &Variant)))
  196. cParts = (WORD)Variant.ulVal;
  197. // Get Number
  198. if (SUCCEEDED(pPropertySet->GetProp(STR_PAR_NUMBER, NOFLAGS, &Variant)))
  199. iPart = (WORD)Variant.ulVal;
  200. // Set Parts
  201. pMsgInfo->dwPartial = MAKELONG(cParts, iPart);
  202. }
  203. // Otherwise, check for user property
  204. else if (SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(PID_ATT_COMBINED), NOFLAGS, &Variant)))
  205. {
  206. // Set the Partial Id
  207. pMsgInfo->dwPartial = Variant.ulVal;
  208. }
  209. // Getting some file times
  210. Variant.vt = VT_FILETIME;
  211. // Get Received Time...
  212. if (SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(PID_ATT_RECVTIME), 0, &Variant)))
  213. pMsgInfo->ftReceived = Variant.filetime;
  214. else
  215. pMsgInfo->ftReceived = ftCurrent;
  216. // Get Sent Time...
  217. if (SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(PID_ATT_SENTTIME), 0, &Variant)))
  218. pMsgInfo->ftSent = Variant.filetime;
  219. else
  220. pMsgInfo->ftSent = ftCurrent;
  221. // Get Address Table
  222. IF_FAILEXIT(hr = pPropertySet->BindToObject(IID_IMimeAddressTable, (LPVOID *)&pAdrTable));
  223. // Display From
  224. pAdrTable->GetFormat(IAT_FROM, AFT_DISPLAY_FRIENDLY, &pMsgInfo->pszDisplayFrom);
  225. // Display To
  226. pAdrTable->GetFormat(IAT_TO, AFT_DISPLAY_FRIENDLY, &pMsgInfo->pszDisplayTo);
  227. // String Properties
  228. Variant.vt = VT_LPSTR;
  229. // pszDisplayFrom as newsgroups
  230. if (NULL == pMsgInfo->pszDisplayFrom && SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(PID_HDR_NEWSGROUPS), NOFLAGS, &Variant)))
  231. pMsgInfo->pszDisplayFrom = Variant.pszVal;
  232. // pszMessageId
  233. if (SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(PID_HDR_MESSAGEID), NOFLAGS, &Variant)))
  234. pMsgInfo->pszMessageId = Variant.pszVal;
  235. // pszXref
  236. if (SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(PID_HDR_XREF), NOFLAGS, &Variant)))
  237. pMsgInfo->pszXref = Variant.pszVal;
  238. // pszReferences
  239. if (SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(STR_HDR_REFS), NOFLAGS, &Variant)))
  240. pMsgInfo->pszReferences = Variant.pszVal;
  241. // pszSubject
  242. if (SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(PID_HDR_SUBJECT), NOFLAGS, &Variant)))
  243. pMsgInfo->pszSubject = Variant.pszVal;
  244. // Normalized Subject
  245. if (SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(PID_ATT_NORMSUBJ), NOFLAGS, &Variant)))
  246. pMsgInfo->pszNormalSubj = Variant.pszVal;
  247. // pszAccount
  248. if (SUCCEEDED(pPropertySet->GetProp(STR_ATT_ACCOUNTNAME, NOFLAGS, &Variant)))
  249. pMsgInfo->pszAcctName = Variant.pszVal;
  250. // pszServer
  251. if (SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(PID_ATT_SERVER), NOFLAGS, &Variant)))
  252. pMsgInfo->pszServer = Variant.pszVal;
  253. // pszUidl
  254. if (SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(PID_ATT_UIDL), NOFLAGS, &Variant)))
  255. pMsgInfo->pszUidl = Variant.pszVal;
  256. // pszPartialId
  257. if (pMsgInfo->dwPartial != 0 && SUCCEEDED(pPropertySet->GetProp(STR_PAR_ID, NOFLAGS, &Variant)))
  258. pMsgInfo->pszPartialId = Variant.pszVal;
  259. // ForwardTo
  260. if (SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(PID_ATT_FORWARDTO), NOFLAGS, &Variant)))
  261. pMsgInfo->pszForwardTo = Variant.pszVal;
  262. exit:
  263. // Cleanup
  264. SafeRelease(pAdrTable);
  265. // Done
  266. return hr;
  267. }
  268. //--------------------------------------------------------------------------
  269. // GetMsgInfoFromMessage
  270. //--------------------------------------------------------------------------
  271. HRESULT GetMsgInfoFromMessage(IMimeMessage *pMessage, LPMESSAGEINFO pMsgInfo,
  272. LPBLOB pOffsets)
  273. {
  274. // Locals
  275. HRESULT hr=S_OK;
  276. DWORD dwImf;
  277. IMSGPRIORITY priority;
  278. PROPVARIANT Variant;
  279. SYSTEMTIME st;
  280. FILETIME ftCurrent;
  281. CByteStream cByteStm;
  282. IMimePropertySet *pPropertySet=NULL;
  283. // Trace
  284. TraceCall("GetMsgInfoFromMessage");
  285. // Invalid Args
  286. Assert(pMessage && pMsgInfo);
  287. // Get the Root Property Set from the Message
  288. IF_FAILEXIT(hr = pMessage->BindToObject(HBODY_ROOT, IID_IMimePropertySet, (LPVOID *)&pPropertySet));
  289. // File pMsgInfo from pPropertySet
  290. IF_FAILEXIT(hr = GetMsgInfoFromPropertySet(pPropertySet, pMsgInfo));
  291. // Get Message Flags
  292. if (SUCCEEDED(pMessage->GetFlags(&dwImf)))
  293. {
  294. // IMF_ATTACHMENTS
  295. if (ISFLAGSET(dwImf, IMF_ATTACHMENTS))
  296. FLAGSET(pMsgInfo->dwFlags, ARF_HASATTACH);
  297. // IMF_SIGNED
  298. if (ISFLAGSET(dwImf, IMF_SIGNED))
  299. FLAGSET(pMsgInfo->dwFlags, ARF_SIGNED);
  300. // IMF_ENCRYPTED
  301. if (ISFLAGSET(dwImf, IMF_ENCRYPTED))
  302. FLAGSET(pMsgInfo->dwFlags, ARF_ENCRYPTED);
  303. // IMF_VOICEMAIL
  304. if (ISFLAGSET(dwImf, IMF_VOICEMAIL))
  305. FLAGSET(pMsgInfo->dwFlags, ARF_VOICEMAIL);
  306. // IMF_NEWS
  307. if (ISFLAGSET(dwImf, IMF_NEWS))
  308. FLAGSET(pMsgInfo->dwFlags, ARF_NEWSMSG);
  309. }
  310. // Get the Message Size
  311. pMessage->GetMessageSize(&pMsgInfo->cbMessage, 0);
  312. // Create the offset table
  313. if (SUCCEEDED(pMessage->SaveOffsetTable(&cByteStm, 0)))
  314. {
  315. // pull the Bytes out of cByteStm
  316. cByteStm.AcquireBytes(&pOffsets->cbSize, &pOffsets->pBlobData, ACQ_DISPLACE);
  317. }
  318. exit:
  319. // Cleanup
  320. SafeRelease(pPropertySet);
  321. // Done
  322. return hr;
  323. }
  324. //--------------------------------------------------------------------------
  325. // FreeMsgInfo
  326. //--------------------------------------------------------------------------
  327. void FreeMsgInfo(
  328. /* in,out */ LPMESSAGEINFO pMsgInfo)
  329. {
  330. // Trace
  331. TraceCall("FreeMsgInfo");
  332. // Invalid Args
  333. Assert(pMsgInfo && NULL == pMsgInfo->pAllocated);
  334. // Free The Dude
  335. g_pMalloc->Free(pMsgInfo->pszMessageId);
  336. g_pMalloc->Free(pMsgInfo->pszNormalSubj);
  337. g_pMalloc->Free(pMsgInfo->pszSubject);
  338. g_pMalloc->Free(pMsgInfo->pszFromHeader);
  339. g_pMalloc->Free(pMsgInfo->pszReferences);
  340. g_pMalloc->Free(pMsgInfo->pszXref);
  341. g_pMalloc->Free(pMsgInfo->pszServer);
  342. g_pMalloc->Free(pMsgInfo->pszDisplayFrom);
  343. g_pMalloc->Free(pMsgInfo->pszEmailFrom);
  344. g_pMalloc->Free(pMsgInfo->pszDisplayTo);
  345. g_pMalloc->Free(pMsgInfo->pszUidl);
  346. g_pMalloc->Free(pMsgInfo->pszPartialId);
  347. g_pMalloc->Free(pMsgInfo->pszForwardTo);
  348. g_pMalloc->Free(pMsgInfo->pszAcctName);
  349. g_pMalloc->Free(pMsgInfo->pszAcctId);
  350. // Zero It
  351. ZeroMemory(pMsgInfo, sizeof(MESSAGEINFO));
  352. }
  353. // --------------------------------------------------------------------------------
  354. // UpgradeLocalStoreFileV5
  355. // --------------------------------------------------------------------------------
  356. HRESULT UpgradeLocalStoreFileV5(LPFILEINFO pInfo, LPMEMORYFILE pFile,
  357. IDatabase *pDB, LPPROGRESSINFO pProgress, BOOL *pfContinue)
  358. {
  359. // Locals
  360. HRESULT hr=S_OK;
  361. CHAR szIdxPath[MAX_PATH];
  362. DWORD i;
  363. LPBYTE pbStream;
  364. LPBYTE pbCacheBlob;
  365. SYSTEMTIME st;
  366. MESSAGEINFO MsgInfo={0};
  367. LPSTR pszNormal=NULL;
  368. MESSAGEINFO MsgInfoFree={0};
  369. DWORD faIdxRead;
  370. IStream *pStream=NULL;
  371. IMimeMessage *pMessage=NULL;
  372. BLOB Offsets;
  373. LPBYTE pbFree=NULL;
  374. MEMORYFILE IdxFile;
  375. LPMEMORYFILE pIdxFile=NULL;
  376. LPMEMORYFILE pMbxFile=pFile;
  377. LPMBXFILEHEADER pMbxHeader=NULL;
  378. LPIDXFILEHEADER pIdxHeader=NULL;
  379. LPIDXMESSAGEHEADER pIdxMessage=NULL;
  380. LPMBXMESSAGEHEADER pMbxMessage=NULL;
  381. IMimePropertySet *pNormalizer=NULL;
  382. LARGE_INTEGER liOrigin={0,0};
  383. // Trace
  384. TraceCall("UpgradeLocalStoreFileV5");
  385. // Get System Time
  386. GetSystemTime(&st);
  387. // Create a Property Set for Normalizing Subjects
  388. IF_FAILEXIT(hr = CoCreateInstance(CLSID_IMimePropertySet, NULL, CLSCTX_INPROC_SERVER, IID_IMimePropertySet, (LPVOID *)&pNormalizer));
  389. // Split the Path
  390. ReplaceExtension(pInfo->szFilePath, ".idx", szIdxPath, ARRAYSIZE(szIdxPath));
  391. // Open the memory file
  392. hr = OpenMemoryFile(szIdxPath, &IdxFile);
  393. if (FAILED(hr))
  394. {
  395. *pfContinue = TRUE;
  396. TraceResult(hr);
  397. goto exit;
  398. }
  399. // Set pIdxFile
  400. pIdxFile = &IdxFile;
  401. // Don't use pFile
  402. pFile = NULL;
  403. // Read the Mbx File Header
  404. pMbxHeader = (LPMBXFILEHEADER)(pMbxFile->pView);
  405. // Read the Idx File Header
  406. pIdxHeader = (LPIDXFILEHEADER)(pIdxFile->pView);
  407. // Validate the Version of th idx file
  408. if (pIdxHeader->ver != CACHEFILE_VER || pIdxHeader->dwMagic != CACHEFILE_MAGIC)
  409. {
  410. *pfContinue = TRUE;
  411. hr = TraceResult(MIGRATE_E_INVALIDIDXHEADER);
  412. goto exit;
  413. }
  414. // Setup faIdxRead
  415. faIdxRead = sizeof(IDXFILEHEADER);
  416. // Prepare to Loop
  417. for (i=0; i<pIdxHeader->cMsg; i++)
  418. {
  419. // Done
  420. if (faIdxRead >= pIdxFile->cbSize)
  421. break;
  422. // Read an idx message header
  423. pIdxMessage = (LPIDXMESSAGEHEADER)((LPBYTE)pIdxFile->pView + faIdxRead);
  424. // If this message is not marked as deleted...
  425. if (ISFLAGSET(pIdxMessage->dwState, MSG_DELETED))
  426. goto NextMessage;
  427. // Zero Out the MsgInfo Structure
  428. ZeroMemory(&MsgInfo, sizeof(MESSAGEINFO));
  429. // Start filling message
  430. MsgInfo.idMessage = (MESSAGEID)IntToPtr(pIdxMessage->msgid);
  431. // Fixup the Flags
  432. if (FALSE == ISFLAGSET(pIdxMessage->dwState, MSG_UNREAD))
  433. FLAGSET(MsgInfo.dwFlags, ARF_READ);
  434. if (ISFLAGSET(pIdxMessage->dwState, MSG_VOICEMAIL))
  435. FLAGSET(MsgInfo.dwFlags, ARF_VOICEMAIL);
  436. if (ISFLAGSET(pIdxMessage->dwState, MSG_REPLIED))
  437. FLAGSET(MsgInfo.dwFlags, ARF_REPLIED);
  438. if (ISFLAGSET(pIdxMessage->dwState, MSG_FORWARDED))
  439. FLAGSET(MsgInfo.dwFlags, ARF_FORWARDED);
  440. if (ISFLAGSET(pIdxMessage->dwState, MSG_FLAGGED))
  441. FLAGSET(MsgInfo.dwFlags, ARF_FLAGGED);
  442. if (ISFLAGSET(pIdxMessage->dwState, MSG_RCPTSENT))
  443. FLAGSET(MsgInfo.dwFlags, ARF_RCPTSENT);
  444. if (ISFLAGSET(pIdxMessage->dwState, MSG_NOSECUI))
  445. FLAGSET(MsgInfo.dwFlags, ARF_NOSECUI);
  446. if (ISFLAGSET(pIdxMessage->dwState, MSG_NEWSMSG))
  447. FLAGSET(MsgInfo.dwFlags, ARF_NEWSMSG);
  448. if (ISFLAGSET(pIdxMessage->dwState, MSG_UNSENT))
  449. FLAGSET(MsgInfo.dwFlags, ARF_UNSENT);
  450. if (ISFLAGSET(pIdxMessage->dwState, MSG_SUBMITTED))
  451. FLAGSET(MsgInfo.dwFlags, ARF_SUBMITTED);
  452. if (ISFLAGSET(pIdxMessage->dwState, MSG_RECEIVED))
  453. FLAGSET(MsgInfo.dwFlags, ARF_RECEIVED);
  454. // Zero Offsets
  455. ZeroMemory(&Offsets, sizeof(BLOB));
  456. // Do the Blob
  457. if (pIdxHeader->verBlob == MAIL_BLOB_VER)
  458. {
  459. // Get the blob
  460. pbCacheBlob = (LPBYTE)((LPBYTE)pIdxFile->pView + (faIdxRead + (sizeof(IDXMESSAGEHEADER) - 4)));
  461. // Split the Cache Blob
  462. if (FAILED(SplitMailCacheBlob(pNormalizer, pbCacheBlob, pIdxMessage->dwHdrSize, &MsgInfo, &pszNormal, &Offsets)))
  463. goto NextMessage;
  464. // Save the Language
  465. MsgInfo.wLanguage = LOWORD(pIdxMessage->dwLanguage);
  466. // Save the Highlight
  467. MsgInfo.wHighlight = HIWORD(pIdxMessage->dwLanguage);
  468. }
  469. // Bad
  470. if (pIdxMessage->dwOffset > pMbxFile->cbSize)
  471. goto NextMessage;
  472. // Lets read the message header in the mbx file to validate the msgids
  473. pMbxMessage = (LPMBXMESSAGEHEADER)((LPBYTE)pMbxFile->pView + pIdxMessage->dwOffset);
  474. // Set Sizes
  475. MsgInfo.cbMessage = pMbxMessage->dwBodySize;
  476. // Validate the Message Ids
  477. if (pMbxMessage->msgid != pIdxMessage->msgid)
  478. goto NextMessage;
  479. // Check for magic
  480. if (pMbxMessage->dwMagic != MSGHDR_MAGIC)
  481. goto NextMessage;
  482. // Has a Body
  483. FLAGSET(MsgInfo.dwFlags, ARF_HASBODY);
  484. // Create a Virtual Stream
  485. IF_FAILEXIT(hr = pDB->CreateStream(&MsgInfo.faStream));
  486. // Open the Stream
  487. IF_FAILEXIT(hr = pDB->OpenStream(ACCESS_WRITE, MsgInfo.faStream, &pStream));
  488. // Get the stream pointer
  489. pbStream = (LPBYTE)((LPBYTE)pMbxFile->pView + (pIdxMessage->dwOffset + sizeof(MBXMESSAGEHEADER)));
  490. // Write this
  491. IF_FAILEXIT(hr = pStream->Write(pbStream, pMbxMessage->dwBodySize, NULL));
  492. // Commit
  493. IF_FAILEXIT(hr = pStream->Commit(STGC_DEFAULT));
  494. // If not an OE4+ blob, then generate the msginfo from the message
  495. if (pIdxHeader->verBlob != MAIL_BLOB_VER)
  496. {
  497. // Create an IMimeMessage
  498. IF_FAILEXIT(hr = CoCreateInstance(CLSID_IMimeMessage, NULL, CLSCTX_INPROC_SERVER, IID_IMimeMessage, (LPVOID *)&pMessage));
  499. // Rewind
  500. if (FAILED(pStream->Seek(liOrigin, STREAM_SEEK_SET, NULL)))
  501. goto NextMessage;
  502. // Load the Message
  503. if (FAILED(pMessage->Load(pStream)))
  504. goto NextMessage;
  505. // Get MsgInfo from the Message
  506. if (FAILED(GetMsgInfoFromMessage(pMessage, &MsgInfo, &Offsets)))
  507. goto NextMessage;
  508. // Free
  509. pbFree = Offsets.pBlobData;
  510. // Free This MsgInfo
  511. CopyMemory(&MsgInfoFree, &MsgInfo, sizeof(MESSAGEINFO));
  512. }
  513. // Set MsgInfo Offsets
  514. MsgInfo.Offsets = Offsets;
  515. // Save Downloaded Time
  516. SystemTimeToFileTime(&st, &MsgInfo.ftDownloaded);
  517. // Lookup Account Id from the Account Name...
  518. if (MsgInfo.pszAcctName)
  519. {
  520. // Loop through the Accounts
  521. for (DWORD i=0; i<g_AcctTable.cAccounts; i++)
  522. {
  523. // Is this the Account
  524. if (lstrcmpi(g_AcctTable.prgAccount[i].szAcctName, MsgInfo.pszAcctName) == 0)
  525. {
  526. MsgInfo.pszAcctId = g_AcctTable.prgAccount[i].szAcctId;
  527. break;
  528. }
  529. }
  530. }
  531. // Count
  532. pInfo->cMessages++;
  533. if (!ISFLAGSET(MsgInfo.dwFlags, ARF_READ))
  534. pInfo->cUnread++;
  535. // Migrated
  536. FLAGSET(MsgInfo.dwFlags, 0x00000010);
  537. // Store the Record
  538. IF_FAILEXIT(hr = pDB->InsertRecord(&MsgInfo));
  539. NextMessage:
  540. // Bump Progress
  541. if(!g_fQuiet)
  542. IncrementProgress(pProgress, pInfo);
  543. // Cleanup
  544. SafeRelease(pStream);
  545. SafeRelease(pMessage);
  546. SafeMemFree(pszNormal);
  547. SafeMemFree(pbFree);
  548. FreeMsgInfo(&MsgInfoFree);
  549. // Goto Next Header
  550. Assert(pIdxMessage);
  551. // Update faIdxRead
  552. faIdxRead += pIdxMessage->dwSize;
  553. }
  554. exit:
  555. // Cleanup
  556. SafeRelease(pStream);
  557. SafeRelease(pMessage);
  558. SafeRelease(pNormalizer);
  559. SafeMemFree(pszNormal);
  560. SafeMemFree(pbFree);
  561. FreeMsgInfo(&MsgInfoFree);
  562. if (pIdxFile)
  563. CloseMemoryFile(pIdxFile);
  564. // Done
  565. return hr;
  566. }
  567. // --------------------------------------------------------------------------------
  568. // GetRecordBlock
  569. // --------------------------------------------------------------------------------
  570. HRESULT GetRecordBlock(LPMEMORYFILE pFile, DWORD faRecord, LPRECORDBLOCKV5B1 *ppRecord,
  571. LPBYTE *ppbData, BOOL *pfContinue)
  572. {
  573. // Locals
  574. HRESULT hr=S_OK;
  575. // Trace
  576. TraceCall("GetRecordBlock");
  577. // Bad Length
  578. if (faRecord + sizeof(RECORDBLOCKV5B1) > pFile->cbSize)
  579. {
  580. *pfContinue = TRUE;
  581. hr = TraceResult(MIGRATE_E_OUTOFRANGEADDRESS);
  582. goto exit;
  583. }
  584. // Cast the Record
  585. (*ppRecord) = (LPRECORDBLOCKV5B1)((LPBYTE)pFile->pView + faRecord);
  586. // Invalid Record Signature
  587. if (faRecord != (*ppRecord)->faRecord)
  588. {
  589. *pfContinue = TRUE;
  590. hr = TraceResult(MIGRATE_E_BADRECORDSIGNATURE);
  591. goto exit;
  592. }
  593. // Bad Length
  594. if (faRecord + (*ppRecord)->cbRecord > pFile->cbSize)
  595. {
  596. *pfContinue = TRUE;
  597. hr = TraceResult(MIGRATE_E_OUTOFRANGEADDRESS);
  598. goto exit;
  599. }
  600. // Set pbData
  601. *ppbData = (LPBYTE)((LPBYTE)(*ppRecord) + sizeof(RECORDBLOCKV5B1));
  602. exit:
  603. // Done
  604. return hr;
  605. }
  606. // --------------------------------------------------------------------------------
  607. // GetStreamBlock
  608. // --------------------------------------------------------------------------------
  609. HRESULT GetStreamBlock(LPMEMORYFILE pFile, DWORD faBlock, LPSTREAMBLOCK *ppBlock,
  610. LPBYTE *ppbData, BOOL *pfContinue)
  611. {
  612. // Locals
  613. HRESULT hr=S_OK;
  614. // Trace
  615. TraceCall("GetStreamBlock");
  616. // Bad Length
  617. if (faBlock + sizeof(STREAMBLOCK) > pFile->cbSize)
  618. {
  619. *pfContinue = TRUE;
  620. hr = TraceResult(MIGRATE_E_OUTOFRANGEADDRESS);
  621. goto exit;
  622. }
  623. // Cast the Record
  624. (*ppBlock) = (LPSTREAMBLOCK)((LPBYTE)pFile->pView + faBlock);
  625. // Invalid Record Signature
  626. if (faBlock != (*ppBlock)->faThis)
  627. {
  628. *pfContinue = TRUE;
  629. hr = TraceResult(MIGRATE_E_BADSTREAMBLOCKSIGNATURE);
  630. goto exit;
  631. }
  632. // Bad Length
  633. if (faBlock + (*ppBlock)->cbBlock > pFile->cbSize)
  634. {
  635. *pfContinue = TRUE;
  636. hr = TraceResult(MIGRATE_E_OUTOFRANGEADDRESS);
  637. goto exit;
  638. }
  639. // Set pbData
  640. *ppbData = (LPBYTE)((LPBYTE)(*ppBlock) + sizeof(STREAMBLOCK));
  641. exit:
  642. // Done
  643. return hr;
  644. }
  645. // --------------------------------------------------------------------------------
  646. // UpgradePropTreeMessageFileV5
  647. // --------------------------------------------------------------------------------
  648. HRESULT UpgradePropTreeMessageFileV5(LPFILEINFO pInfo, LPMEMORYFILE pFile,
  649. IDatabase *pDB, LPPROGRESSINFO pProgress, BOOL *pfContinue)
  650. {
  651. // Locals
  652. HRESULT hr=S_OK;
  653. LPBYTE pbStart;
  654. LPBYTE pbData;
  655. DWORD faRecord;
  656. DWORD faStreamBlock;
  657. FILEADDRESS faDstStream;
  658. MESSAGEINFO MsgInfo;
  659. IStream *pStream=NULL;
  660. FILEADDRESS faStream;
  661. LPFOLDERUSERDATAV4 pUserDataV4;
  662. FOLDERUSERDATA UserDataV5;
  663. LPSTREAMBLOCK pStmBlock;
  664. LPRECORDBLOCKV5B1 pRecord;
  665. LPTABLEHEADERV5B1 pHeader=(LPTABLEHEADERV5B1)pFile->pView;
  666. // Trace
  667. TraceCall("UpgradePropTreeMessageFileV5");
  668. // Validate
  669. Assert(sizeof(FOLDERUSERDATAV4) == sizeof(FOLDERUSERDATA));
  670. // Get CacheInfo
  671. if (sizeof(FOLDERUSERDATA) != pHeader->cbUserData)
  672. {
  673. *pfContinue = TRUE;
  674. hr = TraceResult(MIGRATE_E_USERDATASIZEDIFF);
  675. goto exit;
  676. }
  677. // Get V4 UserData
  678. pUserDataV4 = (LPFOLDERUSERDATAV4)((LPBYTE)pFile->pView + sizeof(TABLEHEADERV5B1));
  679. // If there is a Server Name and acctid is empty...
  680. if ('\0' != *pUserDataV4->szServer && '\0' == *pInfo->szAcctId)
  681. {
  682. // Loop through the Accounts
  683. for (DWORD i=0; i<g_AcctTable.cAccounts; i++)
  684. {
  685. // Is this the Account
  686. if (lstrcmpi(g_AcctTable.prgAccount[i].szServer, pUserDataV4->szServer) == 0)
  687. {
  688. StrCpyN(pInfo->szAcctId, g_AcctTable.prgAccount[i].szAcctId, ARRAYSIZE(pInfo->szAcctId));
  689. break;
  690. }
  691. }
  692. }
  693. // If there is a folder name, copy it
  694. if ('\0' != *pUserDataV4->szGroup)
  695. {
  696. // Copy
  697. StrCpyN(pInfo->szFolder, pUserDataV4->szGroup, ARRAYSIZE(pInfo->szFolder));
  698. }
  699. // Zero New
  700. ZeroMemory(&UserDataV5, sizeof(FOLDERUSERDATA));
  701. // Copy Over Relavent Stuff
  702. UserDataV5.dwUIDValidity = pUserDataV4->dwUIDValidity;
  703. // Set user data
  704. IF_FAILEXIT(hr = pDB->SetUserData(&UserDataV5, sizeof(FOLDERUSERDATA)));
  705. // Initialize faRecord to start
  706. faRecord = pHeader->faFirstRecord;
  707. // While we have a record
  708. while(faRecord)
  709. {
  710. // Get the Record
  711. IF_FAILEXIT(hr = GetRecordBlock(pFile, faRecord, &pRecord, &pbData, pfContinue));
  712. // Set pbStart
  713. pbStart = pbData;
  714. // Clear MsgInfo
  715. ZeroMemory(&MsgInfo, sizeof(MESSAGEINFO));
  716. // DWORD - idMessage
  717. CopyMemory(&MsgInfo.idMessage, pbData, sizeof(MsgInfo.idMessage));
  718. pbData += sizeof(MsgInfo.idMessage);
  719. // Null Message Id
  720. if (0 == MsgInfo.idMessage)
  721. {
  722. // Generate
  723. pDB->GenerateId((LPDWORD)&MsgInfo.idMessage);
  724. }
  725. // DWORD - dwFlags
  726. CopyMemory(&MsgInfo.dwFlags, pbData, sizeof(MsgInfo.dwFlags));
  727. pbData += sizeof(MsgInfo.dwFlags);
  728. // News ?
  729. if (FILE_IS_NEWS_MESSAGES == pInfo->tyFile)
  730. FLAGSET(MsgInfo.dwFlags, ARF_NEWSMSG);
  731. // Priority
  732. if (ISFLAGSET(MsgInfo.dwFlags, 0x00000200))
  733. {
  734. MsgInfo.wPriority = (WORD)IMSG_PRI_HIGH;
  735. FLAGCLEAR(MsgInfo.dwFlags, 0x00000200);
  736. }
  737. else if (ISFLAGSET(MsgInfo.dwFlags, 0x00000100))
  738. {
  739. MsgInfo.wPriority = (WORD)IMSG_PRI_LOW;
  740. FLAGCLEAR(MsgInfo.dwFlags, 0x00000100);
  741. }
  742. else
  743. MsgInfo.wPriority = (WORD)IMSG_PRI_NORMAL;
  744. // DWORD - ftSent
  745. CopyMemory(&MsgInfo.ftSent, pbData, sizeof(MsgInfo.ftSent));
  746. pbData += sizeof(MsgInfo.ftSent);
  747. MsgInfo.ftReceived = MsgInfo.ftSent;
  748. // DWORD - cLines
  749. CopyMemory(&MsgInfo.cLines, pbData, sizeof(MsgInfo.cLines));
  750. pbData += sizeof(MsgInfo.cLines);
  751. // DWORD - faStream
  752. CopyMemory(&faStream, pbData, sizeof(faStream));
  753. pbData += sizeof(faStream);
  754. // Has a Body
  755. if (faStream)
  756. {
  757. // It has a body
  758. FLAGSET(MsgInfo.dwFlags, ARF_HASBODY);
  759. }
  760. // DWORD - cbArticle / cbMessage (VERSION)
  761. CopyMemory(&MsgInfo.cbMessage, pbData, sizeof(MsgInfo.cbMessage));
  762. pbData += sizeof(MsgInfo.cbMessage);
  763. // DWORD - ftDownloaded
  764. CopyMemory(&MsgInfo.ftDownloaded, pbData, sizeof(MsgInfo.ftDownloaded));
  765. pbData += sizeof(MsgInfo.ftDownloaded);
  766. // LPSTR - pszMessageId
  767. MsgInfo.pszMessageId = (LPSTR)pbData;
  768. pbData += (lstrlen(MsgInfo.pszMessageId) + 1);
  769. // LPSTR - pszSubject
  770. MsgInfo.pszSubject = (LPSTR)pbData;
  771. pbData += (lstrlen(MsgInfo.pszSubject) + 1);
  772. // VERSION
  773. MsgInfo.pszNormalSubj = MsgInfo.pszSubject + HIBYTE(HIWORD(MsgInfo.dwFlags));
  774. // LPSTR - pszFromHeader
  775. MsgInfo.pszFromHeader = (LPSTR)pbData;
  776. pbData += (lstrlen(MsgInfo.pszFromHeader) + 1);
  777. // LPSTR - pszReferences
  778. MsgInfo.pszReferences = (LPSTR)pbData;
  779. pbData += (lstrlen(MsgInfo.pszReferences) + 1);
  780. // LPSTR - pszXref
  781. MsgInfo.pszXref = (LPSTR)pbData;
  782. pbData += (lstrlen(MsgInfo.pszXref) + 1);
  783. // LPSTR - pszServer
  784. MsgInfo.pszServer = (LPSTR)pbData;
  785. pbData += (lstrlen(MsgInfo.pszServer) + 1);
  786. // LPSTR - pszDisplayFrom
  787. MsgInfo.pszDisplayFrom = (LPSTR)pbData;
  788. pbData += (lstrlen(MsgInfo.pszDisplayFrom) + 1);
  789. // No Display From and we have a from header
  790. if ('\0' == *MsgInfo.pszDisplayFrom && '\0' != MsgInfo.pszFromHeader)
  791. MsgInfo.pszDisplayFrom = MsgInfo.pszFromHeader;
  792. // LPSTR - pszEmailFrom
  793. MsgInfo.pszEmailFrom = (LPSTR)pbData;
  794. pbData += (lstrlen(MsgInfo.pszEmailFrom) + 1);
  795. // Going to V4 ?
  796. if (pRecord->cbRecord - (DWORD)(pbData - pbStart) - sizeof(RECORDBLOCKV5B1) > 40)
  797. {
  798. // WORD - wLanguage
  799. CopyMemory(&MsgInfo.wLanguage, pbData, sizeof(MsgInfo.wLanguage));
  800. pbData += sizeof(MsgInfo.wLanguage);
  801. // WORD - wReserved
  802. pbData += sizeof(WORD);
  803. // DWORD - cbMessage
  804. CopyMemory(&MsgInfo.cbMessage, pbData, sizeof(MsgInfo.cbMessage));
  805. pbData += sizeof(MsgInfo.cbMessage);
  806. // FILETIME - ftReceived
  807. CopyMemory(&MsgInfo.ftReceived, pbData, sizeof(MsgInfo.ftReceived));
  808. pbData += sizeof(MsgInfo.ftReceived);
  809. // SBAILEY: Raid-76295: News store corrupted when system dates are changed, Find dialog returns dates of 1900, 00 or blank
  810. if (0 == MsgInfo.ftReceived.dwLowDateTime && 0 == MsgInfo.ftReceived.dwHighDateTime)
  811. CopyMemory(&MsgInfo.ftReceived, &MsgInfo.ftSent, sizeof(FILETIME));
  812. // LPSTR - pszDisplayTo
  813. MsgInfo.pszDisplayTo = (LPSTR)pbData;
  814. pbData += (lstrlen(MsgInfo.pszDisplayTo) + 1);
  815. }
  816. // Otherwise
  817. else
  818. {
  819. // Set ftReceived
  820. CopyMemory(&MsgInfo.ftReceived, &MsgInfo.ftSent, sizeof(FILETIME));
  821. }
  822. // Copy over the stream...
  823. if (0 != faStream)
  824. {
  825. // Allocate a new stream
  826. IF_FAILEXIT(hr = pDB->CreateStream(&faDstStream));
  827. // Open the stream
  828. IF_FAILEXIT(hr = pDB->OpenStream(ACCESS_WRITE, faDstStream, &pStream));
  829. // Start Copying Message
  830. faStreamBlock = faStream;
  831. // While we have a stream block
  832. while(faStreamBlock)
  833. {
  834. // Get a stream block
  835. IF_FAILEXIT(hr = GetStreamBlock(pFile, faStreamBlock, &pStmBlock, &pbData, pfContinue));
  836. // Write into the stream
  837. IF_FAILEXIT(hr = pStream->Write(pbData, pStmBlock->cbData, NULL));
  838. // Goto Next Block
  839. faStreamBlock = pStmBlock->faNext;
  840. }
  841. // Commit
  842. IF_FAILEXIT(hr = pStream->Commit(STGC_DEFAULT));
  843. // Set new stream location
  844. MsgInfo.faStream = faDstStream;
  845. // Release the Stream
  846. SafeRelease(pStream);
  847. }
  848. // If No Account Id and we have a server
  849. if ('\0' == *pInfo->szAcctId && '\0' != *MsgInfo.pszServer)
  850. {
  851. // Loop through the Accounts
  852. for (DWORD i=0; i<g_AcctTable.cAccounts; i++)
  853. {
  854. // Is this the Account
  855. if (lstrcmpi(g_AcctTable.prgAccount[i].szServer, MsgInfo.pszServer) == 0)
  856. {
  857. StrCpyN(pInfo->szAcctId, g_AcctTable.prgAccount[i].szAcctId, ARRAYSIZE(pInfo->szAcctId));
  858. break;
  859. }
  860. }
  861. }
  862. // Default to szAcctId
  863. MsgInfo.pszAcctId = pInfo->szAcctId;
  864. // Lookup Account Id from the Account Name...
  865. if (MsgInfo.pszAcctName)
  866. {
  867. // Loop through the Accounts
  868. for (DWORD i=0; i<g_AcctTable.cAccounts; i++)
  869. {
  870. // Is this the Account
  871. if (lstrcmpi(g_AcctTable.prgAccount[i].szAcctName, MsgInfo.pszAcctName) == 0)
  872. {
  873. MsgInfo.pszAcctId = g_AcctTable.prgAccount[i].szAcctId;
  874. break;
  875. }
  876. }
  877. }
  878. // Otherwise, if we have an account Id, get the account name
  879. else if ('\0' != *pInfo->szAcctId)
  880. {
  881. // Loop through the Accounts
  882. for (DWORD i=0; i<g_AcctTable.cAccounts; i++)
  883. {
  884. // Is this the Account
  885. if (lstrcmpi(g_AcctTable.prgAccount[i].szAcctId, MsgInfo.pszAcctId) == 0)
  886. {
  887. MsgInfo.pszAcctName = g_AcctTable.prgAccount[i].szAcctName;
  888. break;
  889. }
  890. }
  891. }
  892. // Count
  893. pInfo->cMessages++;
  894. if (!ISFLAGSET(MsgInfo.dwFlags, ARF_READ))
  895. pInfo->cUnread++;
  896. // Migrated
  897. FLAGSET(MsgInfo.dwFlags, 0x00000010);
  898. // Insert the Record
  899. IF_FAILEXIT(hr = pDB->InsertRecord(&MsgInfo));
  900. // Bump Progress
  901. if(!g_fQuiet)
  902. IncrementProgress(pProgress, pInfo);
  903. // Goto the Next Record
  904. faRecord = pRecord->faNext;
  905. }
  906. exit:
  907. // Cleanup
  908. SafeRelease(pStream);
  909. // Done
  910. return hr;
  911. }
  912. // --------------------------------------------------------------------------------
  913. // ParseFolderFileV5
  914. // --------------------------------------------------------------------------------
  915. HRESULT ParseFolderFileV5(LPMEMORYFILE pFile, LPFILEINFO pInfo,
  916. LPPROGRESSINFO pProgress, LPDWORD pcFolders,
  917. LPFLDINFO *pprgFolder)
  918. {
  919. // Locals
  920. HRESULT hr=S_OK;
  921. LPBYTE pbData;
  922. DWORD faRecord;
  923. LPFLDINFO pFolder;
  924. LPFLDINFO prgFolder=NULL;
  925. LPRECORDBLOCKV5B1 pRecord;
  926. LPTABLEHEADERV5B1 pHeader;
  927. BOOL fContinue;
  928. DWORD cFolders=0;
  929. // Trace
  930. TraceCall("ParseFolderFileV5");
  931. // De-ref the header
  932. pHeader = (LPTABLEHEADERV5B1)pFile->pView;
  933. // Get CacheInfo
  934. if (sizeof(STOREUSERDATA) != pHeader->cbUserData)
  935. {
  936. hr = TraceResult(MIGRATE_E_USERDATASIZEDIFF);
  937. goto exit;
  938. }
  939. // Allocate Folder Array
  940. IF_NULLEXIT(prgFolder = (LPFLDINFO)ZeroAllocate(sizeof(FLDINFO) * pHeader->cRecords));
  941. // Initialize faRecord to start
  942. faRecord = pHeader->faFirstRecord;
  943. // While we have a record
  944. while(faRecord)
  945. {
  946. // Readability
  947. pFolder = &prgFolder[cFolders];
  948. // Get the Record
  949. IF_FAILEXIT(hr = GetRecordBlock(pFile, faRecord, &pRecord, &pbData, &fContinue));
  950. // DWORD - hFolder
  951. CopyMemory(&pFolder->idFolder, pbData, sizeof(pFolder->idFolder));
  952. pbData += sizeof(pFolder->idFolder);
  953. // CHAR(MAX_FOLDER_NAME) - szFolder
  954. CopyMemory(pFolder->szFolder, pbData, sizeof(pFolder->szFolder));
  955. pbData += sizeof(pFolder->szFolder);
  956. // CHAR(260) - szFile
  957. CopyMemory(pFolder->szFile, pbData, sizeof(pFolder->szFile));
  958. pbData += sizeof(pFolder->szFile);
  959. // DWORD - idParent
  960. CopyMemory(&pFolder->idParent, pbData, sizeof(pFolder->idParent));
  961. pbData += sizeof(pFolder->idParent);
  962. // DWORD - idChild
  963. CopyMemory(&pFolder->idChild, pbData, sizeof(pFolder->idChild));
  964. pbData += sizeof(pFolder->idChild);
  965. // DWORD - idSibling
  966. CopyMemory(&pFolder->idSibling, pbData, sizeof(pFolder->idSibling));
  967. pbData += sizeof(pFolder->idSibling);
  968. // DWORD - tySpecial
  969. CopyMemory(&pFolder->tySpecial, pbData, sizeof(pFolder->tySpecial));
  970. pbData += sizeof(pFolder->tySpecial);
  971. // DWORD - cChildren
  972. CopyMemory(&pFolder->cChildren, pbData, sizeof(pFolder->cChildren));
  973. pbData += sizeof(pFolder->cChildren);
  974. // DWORD - cMessages
  975. CopyMemory(&pFolder->cMessages, pbData, sizeof(pFolder->cMessages));
  976. pbData += sizeof(pFolder->cMessages);
  977. // DWORD - cUnread
  978. CopyMemory(&pFolder->cUnread, pbData, sizeof(pFolder->cUnread));
  979. pbData += sizeof(pFolder->cUnread);
  980. // DWORD - cbTotal
  981. CopyMemory(&pFolder->cbTotal, pbData, sizeof(pFolder->cbTotal));
  982. pbData += sizeof(pFolder->cbTotal);
  983. // DWORD - cbUsed
  984. CopyMemory(&pFolder->cbUsed, pbData, sizeof(pFolder->cbUsed));
  985. pbData += sizeof(pFolder->cbUsed);
  986. // DWORD - bHierarchy
  987. CopyMemory(&pFolder->bHierarchy, pbData, sizeof(pFolder->bHierarchy));
  988. pbData += sizeof(pFolder->bHierarchy);
  989. // DWORD - dwImapFlags
  990. CopyMemory(&pFolder->dwImapFlags, pbData, sizeof(pFolder->dwImapFlags));
  991. pbData += sizeof(DWORD);
  992. // BLOB - bListStamp
  993. CopyMemory(&pFolder->bListStamp, pbData, sizeof(pFolder->bListStamp));
  994. pbData += sizeof(BYTE);
  995. // DWORD - bReserved[3]
  996. pbData += (3 * sizeof(BYTE));
  997. // DWORD - rgbReserved
  998. pbData += 40;
  999. // Increment Count
  1000. cFolders++;
  1001. // Bump Progress
  1002. if(!g_fQuiet)
  1003. IncrementProgress(pProgress, pInfo);
  1004. // Goto the Next Record
  1005. faRecord = pRecord->faNext;
  1006. }
  1007. // Return Folder Count
  1008. *pcFolders = cFolders;
  1009. // Return the Array
  1010. *pprgFolder = prgFolder;
  1011. // Don't Free It
  1012. prgFolder = NULL;
  1013. exit:
  1014. // Cleanup
  1015. SafeMemFree(prgFolder);
  1016. // Done
  1017. return hr;
  1018. }
  1019. // --------------------------------------------------------------------------------
  1020. // UpgradePop3UidlFileV5
  1021. // --------------------------------------------------------------------------------
  1022. HRESULT UpgradePop3UidlFileV5(LPFILEINFO pInfo, LPMEMORYFILE pFile,
  1023. IDatabase *pDB, LPPROGRESSINFO pProgress, BOOL *pfContinue)
  1024. {
  1025. // Locals
  1026. HRESULT hr=S_OK;
  1027. LPBYTE pbData;
  1028. DWORD faRecord;
  1029. UIDLRECORD UidlInfo;
  1030. LPRECORDBLOCKV5B1 pRecord;
  1031. LPTABLEHEADERV5B1 pHeader=(LPTABLEHEADERV5B1)pFile->pView;
  1032. // Trace
  1033. TraceCall("UpgradePop3UidlFileV5");
  1034. // Initialize faRecord to start
  1035. faRecord = pHeader->faFirstRecord;
  1036. // While we have a record
  1037. while(faRecord)
  1038. {
  1039. // Get the Record
  1040. IF_FAILEXIT(hr = GetRecordBlock(pFile, faRecord, &pRecord, &pbData, pfContinue));
  1041. // Clear UidlInfo
  1042. ZeroMemory(&UidlInfo, sizeof(UIDLRECORD));
  1043. // FILETIME - ftDownload
  1044. CopyMemory(&UidlInfo.ftDownload, pbData, sizeof(UidlInfo.ftDownload));
  1045. pbData += sizeof(UidlInfo.ftDownload);
  1046. // BYTE - fDownloaded
  1047. CopyMemory(&UidlInfo.fDownloaded, pbData, sizeof(UidlInfo.fDownloaded));
  1048. pbData += sizeof(UidlInfo.fDownloaded);
  1049. // BYTE - fDeleted
  1050. CopyMemory(&UidlInfo.fDeleted, pbData, sizeof(UidlInfo.fDeleted));
  1051. pbData += sizeof(UidlInfo.fDeleted);
  1052. // LPSTR - pszUidl
  1053. UidlInfo.pszUidl = (LPSTR)pbData;
  1054. pbData += (lstrlen(UidlInfo.pszUidl) + 1);
  1055. // LPSTR - pszServer
  1056. UidlInfo.pszServer = (LPSTR)pbData;
  1057. pbData += (lstrlen(UidlInfo.pszServer) + 1);
  1058. // Insert the Record
  1059. IF_FAILEXIT(hr = pDB->InsertRecord(&UidlInfo));
  1060. // Bump Progress
  1061. if(!g_fQuiet)
  1062. IncrementProgress(pProgress, pInfo);
  1063. // Goto the Next Record
  1064. faRecord = pRecord->faNext;
  1065. }
  1066. exit:
  1067. // Done
  1068. return hr;
  1069. }
  1070. // --------------------------------------------------------------------------------
  1071. // UpgradeFileV5
  1072. // --------------------------------------------------------------------------------
  1073. HRESULT UpgradeFileV5(IDatabaseSession *pSession, MIGRATETOTYPE tyMigrate,
  1074. LPFILEINFO pInfo, LPPROGRESSINFO pProgress, BOOL *pfContinue)
  1075. {
  1076. // Locals
  1077. HRESULT hr=S_OK;
  1078. MEMORYFILE File={0};
  1079. IDatabase *pDB=NULL;
  1080. // Trace
  1081. TraceCall("UpgradeFileV5");
  1082. // Local message file
  1083. if (FILE_IS_LOCAL_MESSAGES == pInfo->tyFile)
  1084. {
  1085. // Create an ObjectDatabase (upgrade only runs when OE5 is installed)
  1086. IF_FAILEXIT(hr = pSession->OpenDatabase(pInfo->szDstFile, 0, &g_MessageTableSchema, NULL, &pDB));
  1087. // Get the File Header
  1088. IF_FAILEXIT(hr = OpenMemoryFile(pInfo->szFilePath, &File));
  1089. // UpgradeLocalStoreFileV5
  1090. IF_FAILEXIT(hr = UpgradeLocalStoreFileV5(pInfo, &File, pDB, pProgress, pfContinue));
  1091. }
  1092. // Old News or Imap file
  1093. else if (FILE_IS_NEWS_MESSAGES == pInfo->tyFile || FILE_IS_IMAP_MESSAGES == pInfo->tyFile)
  1094. {
  1095. // Create an ObjectDatabase (upgrade only runs when OE5 is installed)
  1096. IF_FAILEXIT(hr = pSession->OpenDatabase(pInfo->szDstFile, 0, &g_MessageTableSchema, NULL, &pDB));
  1097. // Get the File Header
  1098. IF_FAILEXIT(hr = OpenMemoryFile(pInfo->szFilePath, &File));
  1099. // UpgradePropTreeMessageFileV5
  1100. IF_FAILEXIT(hr = UpgradePropTreeMessageFileV5(pInfo, &File, pDB, pProgress, pfContinue));
  1101. }
  1102. // pop3uidl file
  1103. else if (FILE_IS_POP3UIDL == pInfo->tyFile)
  1104. {
  1105. // Create an ObjectDatabase (upgrade only runs when OE5 is installed)
  1106. IF_FAILEXIT(hr = pSession->OpenDatabase(pInfo->szDstFile, 0, &g_UidlTableSchema, NULL, &pDB));
  1107. // Get the File Header
  1108. IF_FAILEXIT(hr = OpenMemoryFile(pInfo->szFilePath, &File));
  1109. // UpgradePop3UidlFileV5
  1110. IF_FAILEXIT(hr = UpgradePop3UidlFileV5(pInfo, &File, pDB, pProgress, pfContinue));
  1111. }
  1112. exit:
  1113. // Cleanup
  1114. SafeRelease(pDB);
  1115. CloseMemoryFile(&File);
  1116. // Done
  1117. return hr;
  1118. }
  1119. // --------------------------------------------------------------------------------
  1120. // UpgradeProcessFileListV5
  1121. // --------------------------------------------------------------------------------
  1122. HRESULT UpgradeProcessFileListV5(LPCSTR pszStoreSrc, LPCSTR pszStoreDst,
  1123. LPFILEINFO pHead, LPDWORD pcMax, LPDWORD pcbNeeded)
  1124. {
  1125. // Locals
  1126. HRESULT hr=S_OK;
  1127. MEMORYFILE File={0};
  1128. LPFILEINFO pCurrent;
  1129. LPTABLEHEADERV5B1 pHeader;
  1130. // Trace
  1131. TraceCall("UpgradeProcessFileListV5");
  1132. // Init
  1133. *pcMax = 0;
  1134. *pcbNeeded = 0;
  1135. // Loop
  1136. for (pCurrent=pHead; pCurrent!=NULL; pCurrent=pCurrent->pNext)
  1137. {
  1138. // Get the File Header
  1139. hr = OpenMemoryFile(pCurrent->szFilePath, &File);
  1140. // Failure ?
  1141. if (FAILED(hr) || 0 == File.cbSize)
  1142. {
  1143. // Don't Migrate
  1144. pCurrent->fMigrate = FALSE;
  1145. // Set hrMigrate
  1146. pCurrent->hrMigrate = (0 == File.cbSize ? S_OK : hr);
  1147. // Reset hr
  1148. hr = S_OK;
  1149. // Get the LastError
  1150. pCurrent->dwLastError = GetLastError();
  1151. // Goto Next
  1152. goto NextFile;
  1153. }
  1154. // Local message file
  1155. if (FILE_IS_LOCAL_MESSAGES == pCurrent->tyFile)
  1156. {
  1157. // Cast the Header
  1158. LPMBXFILEHEADER pMbxHeader=(LPMBXFILEHEADER)File.pView;
  1159. // Bad Version
  1160. if (File.cbSize < sizeof(MBXFILEHEADER) || pMbxHeader->dwMagic != MSGFILE_MAGIC || pMbxHeader->ver != MSGFILE_VER)
  1161. {
  1162. // Not a file that should be migrate
  1163. pCurrent->fMigrate = FALSE;
  1164. // Set hrMigrate
  1165. pCurrent->hrMigrate = MIGRATE_E_BADVERSION;
  1166. // Goto Next
  1167. goto NextFile;
  1168. }
  1169. // Save the Number of record
  1170. pCurrent->cRecords = pMbxHeader->cMsg;
  1171. }
  1172. // Otherwise, if its a news group list
  1173. else if (FILE_IS_NEWS_SUBLIST == pCurrent->tyFile)
  1174. {
  1175. // De-Ref the header
  1176. LPSUBLISTHEADER pSubList = (LPSUBLISTHEADER)File.pView;
  1177. // Check the Signature...
  1178. if (File.cbSize < sizeof(SUBLISTHEADER) ||
  1179. (SUBFILE_VERSION5 != pSubList->dwVersion &&
  1180. SUBFILE_VERSION4 != pSubList->dwVersion &&
  1181. SUBFILE_VERSION3 != pSubList->dwVersion &&
  1182. SUBFILE_VERSION2 != pSubList->dwVersion))
  1183. {
  1184. // Not a file that should be migrate
  1185. pCurrent->fMigrate = FALSE;
  1186. // Set hrMigrate
  1187. pCurrent->hrMigrate = MIGRATE_E_BADVERSION;
  1188. // Goto Next
  1189. goto NextFile;
  1190. }
  1191. // Save the Number of record
  1192. pCurrent->cRecords = pSubList->cSubscribed;
  1193. }
  1194. // Otherwise, if its a news sub list
  1195. else if (FILE_IS_NEWS_GRPLIST == pCurrent->tyFile)
  1196. {
  1197. // De-Ref the header
  1198. LPGRPLISTHEADER pGrpList = (LPGRPLISTHEADER)File.pView;
  1199. // Check the Signature...
  1200. if (File.cbSize < sizeof(GRPLISTHEADER) || GROUPLISTVERSION != pGrpList->dwVersion)
  1201. {
  1202. // Not a file that should be migrate
  1203. pCurrent->fMigrate = FALSE;
  1204. // Set hrMigrate
  1205. pCurrent->hrMigrate = MIGRATE_E_BADVERSION;
  1206. // Goto Next
  1207. goto NextFile;
  1208. }
  1209. // Save the Number of record
  1210. pCurrent->cRecords = pGrpList->cGroups;
  1211. }
  1212. // Otherwise, objectdb file
  1213. else
  1214. {
  1215. // De-Ref the header
  1216. pHeader = (LPTABLEHEADERV5B1)File.pView;
  1217. // Check the Signature...
  1218. if (File.cbSize < sizeof(TABLEHEADERV5B1) || OBJECTDB_SIGNATURE != pHeader->dwSignature || OBJECTDB_VERSION_PRE_V5 != pHeader->wMajorVersion)
  1219. {
  1220. // Not a file that should be migrate
  1221. pCurrent->fMigrate = FALSE;
  1222. // Set hrMigrate
  1223. pCurrent->hrMigrate = MIGRATE_E_BADVERSION;
  1224. // Goto Next
  1225. goto NextFile;
  1226. }
  1227. // Save the Number of record
  1228. pCurrent->cRecords = pHeader->cRecords;
  1229. }
  1230. // Special Case pop3uidl.dat
  1231. if (FILE_IS_POP3UIDL == pCurrent->tyFile)
  1232. {
  1233. // Compute Real Destination File
  1234. wnsprintf(pCurrent->szDstFile, ARRAYSIZE(pCurrent->szDstFile),"%s\\pop3uidl.dbx", pszStoreDst);
  1235. }
  1236. // Otherwise, generate a unqiue message file name
  1237. else
  1238. {
  1239. // Save the Folder Id
  1240. pCurrent->idFolder = g_idFolderNext;
  1241. // Build New Path
  1242. wnsprintf(pCurrent->szDstFile, ARRAYSIZE(pCurrent->szDstFile), "%s\\%08d.dbx", pszStoreDst, g_idFolderNext);
  1243. // Increment id
  1244. g_idFolderNext++;
  1245. }
  1246. // Initialize counters
  1247. InitializeCounters(&File, pCurrent, pcMax, pcbNeeded, TRUE);
  1248. // Yes, Migrate
  1249. pCurrent->fMigrate = TRUE;
  1250. NextFile:
  1251. // Close the File
  1252. CloseMemoryFile(&File);
  1253. }
  1254. // Done
  1255. return hr;
  1256. }
  1257. // --------------------------------------------------------------------------------
  1258. // UpgradeDeleteFilesV5
  1259. // --------------------------------------------------------------------------------
  1260. void UpgradeDeleteFilesV5(LPCSTR pszStoreDst)
  1261. {
  1262. // Locals
  1263. CHAR szSearch[MAX_PATH + MAX_PATH];
  1264. CHAR szFilePath[MAX_PATH + MAX_PATH];
  1265. HANDLE hFind=INVALID_HANDLE_VALUE;
  1266. WIN32_FIND_DATA fd;
  1267. // Trace
  1268. TraceCall("UpgradeDeleteFilesV5");
  1269. // Do we have a sub dir
  1270. wnsprintf(szSearch, ARRAYSIZE(szSearch),"%s\\*.dbx", pszStoreDst);
  1271. // Find first file
  1272. hFind = FindFirstFile(szSearch, &fd);
  1273. // Did we find something
  1274. if (INVALID_HANDLE_VALUE == hFind)
  1275. goto exit;
  1276. // Loop for ever
  1277. while(1)
  1278. {
  1279. // Make File Path
  1280. MakeFilePath(pszStoreDst, fd.cFileName, "", szFilePath, ARRAYSIZE(szFilePath));
  1281. // Delete
  1282. DeleteFile(szFilePath);
  1283. // Find the Next File
  1284. if (!FindNextFile(hFind, &fd))
  1285. break;
  1286. }
  1287. exit:
  1288. // Cleanup
  1289. if (hFind)
  1290. FindClose(hFind);
  1291. }
  1292. // --------------------------------------------------------------------------------
  1293. // UpgradeDeleteIdxMbxNchDatFilesV5
  1294. // --------------------------------------------------------------------------------
  1295. void UpgradeDeleteIdxMbxNchDatFilesV5(LPFILEINFO pHeadFile)
  1296. {
  1297. // Locals
  1298. CHAR szDstFile[MAX_PATH + MAX_PATH];
  1299. LPFILEINFO pCurrent;
  1300. // Trace
  1301. TraceCall("UpgradeDeleteOdbFilesV5");
  1302. // Delete all old files
  1303. for (pCurrent=pHeadFile; pCurrent!=NULL; pCurrent=pCurrent->pNext)
  1304. {
  1305. // Succeeded
  1306. Assert(SUCCEEDED(pCurrent->hrMigrate));
  1307. // Delete the file
  1308. // DeleteFile(pCurrent->szFilePath);
  1309. // If local message file, need to delete the idx file
  1310. if (FILE_IS_LOCAL_MESSAGES == pCurrent->tyFile)
  1311. {
  1312. // Replace file extension
  1313. ReplaceExtension(pCurrent->szFilePath, ".idx", szDstFile, ARRAYSIZE(szDstFile));
  1314. // Delete the file
  1315. // DeleteFile(szDstFile);
  1316. }
  1317. }
  1318. // Done
  1319. return;
  1320. }
  1321. // --------------------------------------------------------------------------------
  1322. // GetSpecialFolderInfo
  1323. // --------------------------------------------------------------------------------
  1324. HRESULT GetSpecialFolderInfo(LPCSTR pszFilePath, LPSTR pszFolder,
  1325. DWORD cchFolder, DWORD *ptySpecial)
  1326. {
  1327. // Locals
  1328. CHAR szPath[_MAX_PATH];
  1329. CHAR szDrive[_MAX_DRIVE];
  1330. CHAR szDir[_MAX_DIR];
  1331. CHAR szFile[_MAX_FNAME];
  1332. CHAR szExt[_MAX_EXT];
  1333. CHAR szRes[255];
  1334. DWORD i;
  1335. // Trace
  1336. TraceCall("GetSpecialFolderInfo");
  1337. // Initialize
  1338. *ptySpecial = 0xffffffff;
  1339. // Split the Path
  1340. _splitpath(pszFilePath, szDrive, szDir, szFile, szExt);
  1341. // Set Folder Name
  1342. StrCpyN(pszFolder, szFile, cchFolder);
  1343. // Loop through special folder
  1344. for (i=FOLDER_INBOX; i<FOLDER_MAX; i++)
  1345. {
  1346. // Load the Special Folder Name
  1347. LoadString(g_hInst, IDS_INBOX + (i - 1), szRes, ARRAYSIZE(szRes));
  1348. // Compare with szFile
  1349. if (lstrcmpi(szFile, szRes) == 0)
  1350. {
  1351. // Copy the Folder Name
  1352. StrCpyN(pszFolder, szRes, cchFolder);
  1353. // Return special folder type
  1354. *ptySpecial = (i - 1);
  1355. // Success
  1356. return(S_OK);
  1357. }
  1358. }
  1359. // Done
  1360. return(E_FAIL);
  1361. }
  1362. // --------------------------------------------------------------------------------
  1363. // FixupFolderUserData
  1364. // --------------------------------------------------------------------------------
  1365. HRESULT FixupFolderUserData(IDatabaseSession *pSession, FOLDERID idFolder,
  1366. LPCSTR pszName, SPECIALFOLDER tySpecial, LPFILEINFO pCurrent)
  1367. {
  1368. // Locals
  1369. HRESULT hr=S_OK;
  1370. FOLDERUSERDATA UserData;
  1371. IDatabase *pDB=NULL;
  1372. // Trace
  1373. TraceCall("FixupFolderUserData");
  1374. // Better not be in the store yet
  1375. Assert(FALSE == pCurrent->fInStore);
  1376. // Its in the store
  1377. pCurrent->fInStore = TRUE;
  1378. // Create an Ojbect Database
  1379. IF_FAILEXIT(hr = pSession->OpenDatabase(pCurrent->szDstFile, 0, &g_MessageTableSchema, NULL, &pDB));
  1380. // Store the User Data
  1381. IF_FAILEXIT(hr = pDB->GetUserData(&UserData, sizeof(FOLDERUSERDATA)));
  1382. // Its Initialized
  1383. UserData.fInitialized = TRUE;
  1384. // UserData.clsidType
  1385. if (ISFLAGSET(pCurrent->dwServer, SRV_POP3))
  1386. UserData.tyFolder = FOLDER_LOCAL;
  1387. else if (ISFLAGSET(pCurrent->dwServer, SRV_NNTP))
  1388. UserData.tyFolder = FOLDER_NEWS;
  1389. else if (ISFLAGSET(pCurrent->dwServer, SRV_IMAP))
  1390. UserData.tyFolder = FOLDER_IMAP;
  1391. // Copy the Account Id
  1392. StrCpyN(UserData.szAcctId, pCurrent->szAcctId, ARRAYSIZE(UserData.szAcctId));
  1393. // Save Folder Id
  1394. UserData.idFolder = idFolder;
  1395. // Save Special Folder Type
  1396. UserData.tySpecial = tySpecial;
  1397. // Copy the Folder name
  1398. StrCpyN(UserData.szFolder, pszName, ARRAYSIZE(UserData.szFolder));
  1399. // Must be Subscribed
  1400. UserData.fSubscribed = TRUE;
  1401. // Set the Sort Index Information
  1402. UserData.idSort = COLUMN_RECEIVED;
  1403. // Not Ascending
  1404. UserData.fAscending = FALSE;
  1405. // Not threaded
  1406. UserData.fThreaded = FALSE;
  1407. // Basic Filter
  1408. UserData.ridFilter = RULEID_VIEW_ALL;
  1409. // Add Welcome Message Again
  1410. UserData.fWelcomeAdded = FALSE;
  1411. // Show Deleted
  1412. UserData.fShowDeleted = TRUE;
  1413. // New thread model
  1414. UserData.fNewThreadModel = TRUE;
  1415. UserData.fTotalWatched = TRUE;
  1416. UserData.fWatchedCounts = TRUE;
  1417. // Store the User Data
  1418. IF_FAILEXIT(hr = pDB->SetUserData(&UserData, sizeof(FOLDERUSERDATA)));
  1419. exit:
  1420. // Cleanup
  1421. SafeRelease(pDB);
  1422. // Done
  1423. return(hr);
  1424. }
  1425. // --------------------------------------------------------------------------------
  1426. // SetIMAPSpecialFldrType
  1427. // --------------------------------------------------------------------------------
  1428. HRESULT SetIMAPSpecialFldrType(LPSTR pszAcctID, LPSTR pszFldrName, SPECIALFOLDER *psfType)
  1429. {
  1430. char szPath[MAX_PATH + 1];
  1431. SPECIALFOLDER sfResult = FOLDER_NOTSPECIAL;
  1432. TraceCall("SetIMAPSpecialFldrType");
  1433. Assert(NULL != psfType);
  1434. Assert(FOLDER_NOTSPECIAL == *psfType);
  1435. LoadString(g_hInst, IDS_SENTITEMS, szPath, sizeof(szPath));
  1436. if (0 == lstrcmp(szPath, pszFldrName))
  1437. {
  1438. sfResult = FOLDER_SENT;
  1439. goto exit;
  1440. }
  1441. LoadString(g_hInst, IDS_DRAFT, szPath, sizeof(szPath));
  1442. if (0 == lstrcmp(szPath, pszFldrName))
  1443. {
  1444. sfResult = FOLDER_DRAFT;
  1445. goto exit;
  1446. }
  1447. exit:
  1448. *psfType = sfResult;
  1449. return S_OK;
  1450. }
  1451. // --------------------------------------------------------------------------------
  1452. // InsertFolderIntoStore
  1453. // --------------------------------------------------------------------------------
  1454. HRESULT InsertFolderIntoStore(IDatabaseSession *pSession, IMessageStore *pStore,
  1455. LPFLDINFO pThis, DWORD cFolders, LPFLDINFO prgFolder, FOLDERID idParentNew,
  1456. LPFILEINFO pInfo, LPFILEINFO pFileHead, LPFOLDERID pidNew)
  1457. {
  1458. // Locals
  1459. HRESULT hr=S_OK;
  1460. DWORD i;
  1461. CHAR szPath[_MAX_PATH];
  1462. CHAR szDrive[_MAX_DRIVE];
  1463. CHAR szDir[_MAX_DIR];
  1464. CHAR szFile[_MAX_FNAME];
  1465. CHAR szExt[_MAX_EXT];
  1466. CHAR szFilePath[MAX_PATH];
  1467. CHAR szInbox[MAX_PATH];
  1468. BOOL fFound=FALSE;
  1469. LPFILEINFO pCurrent=NULL;
  1470. FOLDERINFO Folder={0};
  1471. // Trace
  1472. TraceCall("InsertFolderIntoStore");
  1473. // Invalid Arg
  1474. //Assert(FILE_IS_LOCAL_FOLDERS == pInfo->tyFile || FILE_IS_IMAP_FOLDERS == pInfo->tyFile);
  1475. // Copy Stuff Over to Folder
  1476. Folder.pszName = pThis->szFolder;
  1477. Folder.idParent = idParentNew;
  1478. Folder.bHierarchy = pThis->bHierarchy;
  1479. Folder.dwFlags = FOLDER_SUBSCRIBED; // $$TODO$$ May need to adjust and map to new flags
  1480. Folder.tySpecial = (0xffffffff == pThis->tySpecial) ? FOLDER_NOTSPECIAL : (BYTE)(pThis->tySpecial + 1);
  1481. Folder.cMessages = pThis->cMessages;
  1482. Folder.cUnread = pThis->cUnread;
  1483. Folder.pszFile = pThis->szFile;
  1484. Folder.dwListStamp = pThis->bListStamp;
  1485. // For IMAP folders, we have to set tySpecial based on registry folder paths
  1486. if (pInfo && FILE_IS_IMAP_FOLDERS == pInfo->tyFile && NULL != pThis &&
  1487. FOLDERID_ROOT == (FOLDERID)IntToPtr(pThis->idParent))
  1488. {
  1489. HRESULT hrTemp;
  1490. if (FOLDER_NOTSPECIAL == Folder.tySpecial)
  1491. {
  1492. hrTemp = SetIMAPSpecialFldrType(pInfo->szAcctId, Folder.pszName, &Folder.tySpecial);
  1493. TraceError(hrTemp);
  1494. Assert(SUCCEEDED(hrTemp) || FOLDER_NOTSPECIAL == Folder.tySpecial);
  1495. }
  1496. else if (FOLDER_INBOX == Folder.tySpecial)
  1497. {
  1498. LoadString(g_hInst, IDS_INBOX, szInbox, ARRAYSIZE(szInbox));
  1499. Folder.pszName = szInbox;
  1500. }
  1501. }
  1502. // Look for Current
  1503. if (pInfo && pFileHead)
  1504. {
  1505. // Locate the file...
  1506. for (pCurrent=pFileHead; pCurrent!=NULL; pCurrent=pCurrent->pNext)
  1507. {
  1508. // Migrate
  1509. if (pCurrent->fMigrate)
  1510. {
  1511. // Local Folder ?
  1512. if (FILE_IS_LOCAL_FOLDERS == pInfo->tyFile && FILE_IS_LOCAL_MESSAGES == pCurrent->tyFile)
  1513. {
  1514. // Get the File Name
  1515. _splitpath(pCurrent->szFilePath, szDrive, szDir, szFile, szExt);
  1516. // Test For File Name
  1517. if (lstrcmpi(szFile, pThis->szFile) == 0)
  1518. {
  1519. // This is It
  1520. fFound = TRUE;
  1521. // Adjust the Flags
  1522. FLAGSET(Folder.dwFlags, FOLDER_SUBSCRIBED);
  1523. }
  1524. }
  1525. // IMAP Folders ?
  1526. else if (FILE_IS_IMAP_FOLDERS == pInfo->tyFile && FILE_IS_IMAP_MESSAGES == pCurrent->tyFile)
  1527. {
  1528. // Same Account
  1529. if (lstrcmpi(pCurrent->szAcctId, pInfo->szAcctId) == 0)
  1530. {
  1531. // Get the File Name
  1532. _splitpath(pCurrent->szFilePath, szDrive, szDir, szFile, szExt);
  1533. // Build File
  1534. wnsprintf(szFilePath, ARRAYSIZE(szFilePath), "%s.nch", szFile);
  1535. // Test For File Name
  1536. if (lstrcmpi(szFilePath, pThis->szFile) == 0)
  1537. {
  1538. // This is It
  1539. fFound = TRUE;
  1540. }
  1541. }
  1542. }
  1543. // Found
  1544. if (fFound)
  1545. {
  1546. // Get the File Name
  1547. _splitpath(pCurrent->szDstFile, szDrive, szDir, szFile, szExt);
  1548. // Build File
  1549. wnsprintf(szFilePath, ARRAYSIZE(szFilePath), "%s.dbx", szFile);
  1550. // Local the File for this folder and set
  1551. Folder.pszFile = szFilePath;
  1552. // Set Folder Counts
  1553. Folder.cMessages = pCurrent->cMessages;
  1554. Folder.cUnread = pCurrent->cUnread;
  1555. // Done
  1556. break;
  1557. }
  1558. }
  1559. }
  1560. }
  1561. // If this is a special folder, then lets try to see if it already exists...
  1562. if (FOLDER_NOTSPECIAL != Folder.tySpecial)
  1563. {
  1564. // Locals
  1565. FOLDERINFO Special;
  1566. // pThis Parent should be invalid
  1567. Assert(FOLDERID_ROOT == (FOLDERID)IntToPtr(pThis->idParent));
  1568. // Try to get the special folder info
  1569. if (FAILED(pStore->GetSpecialFolderInfo(idParentNew, Folder.tySpecial, &Special)))
  1570. {
  1571. // Create the Folder
  1572. IF_FAILEXIT(hr = pStore->CreateFolder(NOFLAGS, &Folder, NOSTORECALLBACK));
  1573. // Update pThis->dwServerHigh with new folderid
  1574. pThis->idNewFolderId = (DWORD_PTR)Folder.idFolder;
  1575. }
  1576. // Otherwise...
  1577. else
  1578. {
  1579. // Update pThis->dwServerHigh with new folderid
  1580. pThis->idNewFolderId = (DWORD_PTR)Special.idFolder;
  1581. // Update the Special folder
  1582. Folder.idFolder = Special.idFolder;
  1583. // Update Special
  1584. Special.bHierarchy = Folder.bHierarchy;
  1585. Special.dwFlags = Folder.dwFlags; // $$TODO$$ May need to adjust and map to new flags
  1586. Special.cMessages = Folder.cMessages;
  1587. Special.cUnread = Folder.cUnread;
  1588. Special.pszFile = Folder.pszFile;
  1589. Special.dwListStamp = Folder.dwListStamp;
  1590. // Update the Record
  1591. IF_FAILEXIT(hr = pStore->UpdateRecord(&Special));
  1592. // Free Special
  1593. pStore->FreeRecord(&Special);
  1594. }
  1595. }
  1596. // Otherwise, just try to create the folder
  1597. else
  1598. {
  1599. // Create the Folder
  1600. IF_FAILEXIT(hr = pStore->CreateFolder(NOFLAGS, &Folder, NOSTORECALLBACK));
  1601. // Update pThis->dwServerHigh with new folderid
  1602. pThis->idNewFolderId = (DWORD_PTR)Folder.idFolder;
  1603. }
  1604. // If We Found a folder...
  1605. if (pCurrent)
  1606. {
  1607. // Update the Folder's UserData
  1608. IF_FAILEXIT(hr = FixupFolderUserData(pSession, Folder.idFolder, pThis->szFolder, Folder.tySpecial, pCurrent));
  1609. }
  1610. // Walk Insert the children of pThis
  1611. for (i=0; i<cFolders; i++)
  1612. {
  1613. // If Parent is equal to idParent, then lets insert this node under the new parent
  1614. if (prgFolder[i].idParent == pThis->idFolder)
  1615. {
  1616. // Can't be null
  1617. Assert(prgFolder[i].idFolder);
  1618. // InsertFolderIntoStore
  1619. IF_FAILEXIT(hr = InsertFolderIntoStore(pSession, pStore, &prgFolder[i], cFolders, prgFolder, Folder.idFolder, pInfo, pFileHead, NULL));
  1620. }
  1621. }
  1622. // Return the New Folder
  1623. if (pidNew)
  1624. *pidNew = Folder.idFolder;
  1625. exit:
  1626. // Done
  1627. return(hr);
  1628. }
  1629. // --------------------------------------------------------------------------------
  1630. // MergeFolderCacheIntoStore
  1631. // --------------------------------------------------------------------------------
  1632. HRESULT MergeFolderCacheIntoStore(IDatabaseSession *pSession, IMessageStore *pStore,
  1633. LPFILEINFO pInfo, LPFILEINFO pHeadFile, LPPROGRESSINFO pProgress)
  1634. {
  1635. // Locals
  1636. HRESULT hr=S_OK;
  1637. MEMORYFILE File={0};
  1638. FOLDERID idServer;
  1639. DWORD cFolders;
  1640. DWORD i;
  1641. LPFLDINFO prgFolder=NULL;
  1642. LPFLDINFO pFolder;
  1643. HKEY hKey=NULL;
  1644. DWORD cbLength;
  1645. LPBYTE pbChange=NULL;
  1646. LPFOLDERIDCHANGE prgidChange;
  1647. IUserIdentityManager *pManager = NULL;
  1648. IUserIdentity *pIdentity = NULL;
  1649. HKEY hkeyID = NULL;
  1650. // Trace
  1651. TraceCall("MergeFolderCacheIntoStore");
  1652. // Find the Server Id
  1653. if (FAILED(pStore->FindServerId(pInfo->szAcctId, &idServer)))
  1654. goto exit;
  1655. // Open the File
  1656. IF_FAILEXIT(hr = OpenMemoryFile(pInfo->szFilePath, &File));
  1657. // Parse the file
  1658. IF_FAILEXIT(hr = ParseFolderFileV5(&File, pInfo, pProgress, &cFolders, &prgFolder));
  1659. // Loop through the folders
  1660. for (i=0; i<cFolders; i++)
  1661. {
  1662. // If this is the root folder node (OE4), remember to migrate the root hierarchy char
  1663. if ((FOLDERID)IntToPtr(prgFolder[i].idFolder) == FOLDERID_ROOT)
  1664. {
  1665. FOLDERINFO fiFolderInfo;
  1666. IF_FAILEXIT(hr = pStore->GetFolderInfo(idServer, &fiFolderInfo));
  1667. fiFolderInfo.bHierarchy = prgFolder[i].bHierarchy;
  1668. hr = pStore->UpdateRecord(&fiFolderInfo);
  1669. pStore->FreeRecord(&fiFolderInfo);
  1670. IF_FAILEXIT(hr);
  1671. }
  1672. // If Parent is equal to idParent, then lets insert this node under the new parent
  1673. else if ((FOLDERID)IntToPtr(prgFolder[i].idParent) == FOLDERID_ROOT)
  1674. {
  1675. // InsertFolderIntoStore
  1676. IF_FAILEXIT(hr = InsertFolderIntoStore(pSession, pStore, &prgFolder[i], cFolders, prgFolder, idServer, pInfo, pHeadFile, NULL));
  1677. }
  1678. }
  1679. // Local Folders
  1680. if (FILE_IS_LOCAL_FOLDERS == pInfo->tyFile)
  1681. {
  1682. // cbLength
  1683. cbLength = (sizeof(DWORD) + (sizeof(FOLDERIDCHANGE) * cFolders));
  1684. // Allocate a folderidchange array
  1685. IF_NULLEXIT(pbChange = (LPBYTE)g_pMalloc->Alloc(cbLength));
  1686. // Store cLocalFolders
  1687. CopyMemory(pbChange, &cFolders, sizeof(DWORD));
  1688. // Set prgidChange
  1689. prgidChange = (LPFOLDERIDCHANGE)(pbChange + sizeof(DWORD));
  1690. // Walk through the list of files and merge the folders, sublist, group lists into pFolder
  1691. for (i=0; i<cFolders; i++)
  1692. {
  1693. prgidChange[i].idOld = (FOLDERID)IntToPtr(prgFolder[i].idFolder);
  1694. prgidChange[i].idNew = (FOLDERID)prgFolder[i].idNewFolderId;
  1695. }
  1696. // Get a user manager
  1697. if (FAILED(CoCreateInstance(CLSID_UserIdentityManager, NULL, CLSCTX_INPROC_SERVER,
  1698. IID_IUserIdentityManager, (void **)&pManager)))
  1699. goto exit;
  1700. Assert(pManager);
  1701. // Get Default Identity
  1702. if (FAILED(pManager->GetIdentityByCookie((GUID*)&UID_GIBC_DEFAULT_USER, &pIdentity)))
  1703. goto exit;
  1704. Assert(pIdentity);
  1705. // Ensure that we have an identity and can get to its registry
  1706. if (FAILED(pIdentity->OpenIdentityRegKey(KEY_WRITE, &hkeyID)))
  1707. goto exit;
  1708. Assert(hkeyID);
  1709. // Open the HKCU
  1710. if (ERROR_SUCCESS != RegOpenKeyEx(hkeyID, "Software\\Microsoft\\Outlook Express\\5.0", 0, KEY_ALL_ACCESS, &hKey))
  1711. {
  1712. hr = TraceResult(MIGRATE_E_REGOPENKEY);
  1713. goto exit;
  1714. }
  1715. // Write it to the registry
  1716. if (ERROR_SUCCESS != RegSetValueEx(hKey, "FolderIdChange", 0, REG_BINARY, pbChange, cbLength))
  1717. {
  1718. hr = TraceResult(MIGRATE_E_REGSETVALUE);
  1719. goto exit;
  1720. }
  1721. }
  1722. exit:
  1723. // Cleanup
  1724. if (hKey)
  1725. RegCloseKey(hKey);
  1726. if (hkeyID)
  1727. RegCloseKey(hkeyID);
  1728. SafeMemFree(pbChange);
  1729. SafeMemFree(prgFolder);
  1730. SafeRelease(pIdentity);
  1731. SafeRelease(pManager);
  1732. CloseMemoryFile(&File);
  1733. // Done
  1734. return(hr);
  1735. }
  1736. // --------------------------------------------------------------------------------
  1737. // MergeNewsGroupList
  1738. // --------------------------------------------------------------------------------
  1739. HRESULT MergeNewsGroupList(IDatabaseSession *pSession, IMessageStore *pStore,
  1740. LPFILEINFO pInfo, LPFILEINFO pHeadFile, LPPROGRESSINFO pProgress)
  1741. {
  1742. // Locals
  1743. HRESULT hr=S_OK;
  1744. DWORD i;
  1745. FOLDERINFO Folder={0};
  1746. MEMORYFILE File={0};
  1747. FOLDERID idServer;
  1748. DWORD cbRead;
  1749. LPSTR pszT;
  1750. LPSTR pszGroup;
  1751. LPSTR pszDescription;
  1752. FOLDERID idFolder;
  1753. LPFILEINFO pSubList=NULL;
  1754. LPFILEINFO pCurrent;
  1755. LPSUBLISTHEADER pSubListHeader;
  1756. IDatabase *pDB=NULL;
  1757. CHAR szPath[_MAX_PATH];
  1758. CHAR szDrive[_MAX_DRIVE];
  1759. CHAR szDir[_MAX_DIR];
  1760. CHAR szFile[_MAX_FNAME];
  1761. CHAR szExt[_MAX_EXT];
  1762. LPGRPLISTHEADER pHeader;
  1763. // Trace
  1764. TraceCall("MergeNewsGroupList");
  1765. // Find the Server Id
  1766. if (FAILED(pStore->FindServerId(pInfo->szAcctId, &idServer)))
  1767. goto exit;
  1768. // Set Progress File
  1769. SetProgressFile(pProgress, pInfo);
  1770. // Open the Group List File
  1771. IF_FAILEXIT(hr = OpenMemoryFile(pInfo->szFilePath, &File));
  1772. // Get the Header
  1773. pHeader = (LPGRPLISTHEADER)File.pView;
  1774. // Initialize cb
  1775. cbRead = sizeof(GRPLISTHEADER);
  1776. // Loop
  1777. for (i=0; i<pHeader->cGroups; i++)
  1778. {
  1779. // Set pszGroup
  1780. pszT = pszGroup = (LPSTR)((LPBYTE)File.pView + cbRead);
  1781. // Increment to end of pszGroup or end of file
  1782. while (*pszT && cbRead < File.cbSize)
  1783. {
  1784. // Increment cb
  1785. cbRead++;
  1786. // End of String
  1787. pszT = (LPSTR)((LPBYTE)File.pView + cbRead);
  1788. }
  1789. // Done
  1790. if (cbRead >= File.cbSize)
  1791. break;
  1792. // Step Over the Null
  1793. cbRead++;
  1794. // Set pszDescription
  1795. pszT = pszDescription = (LPSTR)((LPBYTE)File.pView + cbRead);
  1796. // Increment to end of pszGroup or end of file
  1797. while (*pszT && cbRead < File.cbSize)
  1798. {
  1799. // Increment cb
  1800. cbRead++;
  1801. // End of String
  1802. pszT = (LPSTR)((LPBYTE)File.pView + cbRead);
  1803. }
  1804. // Done
  1805. if (cbRead >= File.cbSize)
  1806. break;
  1807. // Increment over the null
  1808. cbRead++;
  1809. // Step over group type
  1810. cbRead += sizeof(DWORD);
  1811. // Not Empyt
  1812. if ('\0' == *pszGroup)
  1813. break;
  1814. // Set the Folder Info
  1815. Folder.pszName = pszGroup;
  1816. Folder.pszDescription = pszDescription;
  1817. Folder.idParent = idServer;
  1818. Folder.tySpecial = FOLDER_NOTSPECIAL;
  1819. // Create the Folder
  1820. pStore->CreateFolder(0, &Folder, NOSTORECALLBACK);
  1821. // Bump Progress
  1822. if(!g_fQuiet)
  1823. IncrementProgress(pProgress, pInfo);
  1824. }
  1825. // Walk through news message files and create folders for them.
  1826. for (pCurrent=pHeadFile; pCurrent!=NULL; pCurrent=pCurrent->pNext)
  1827. {
  1828. // Find the Sublist for this group
  1829. if (FILE_IS_NEWS_SUBLIST == pCurrent->tyFile && lstrcmpi(pCurrent->szAcctId, pInfo->szAcctId) == 0)
  1830. {
  1831. // Set pSubList
  1832. pSubList = pCurrent;
  1833. // Done
  1834. break;
  1835. }
  1836. }
  1837. // No Sub List
  1838. if (NULL == pSubList)
  1839. goto exit;
  1840. // Close the File
  1841. CloseMemoryFile(&File);
  1842. // Set Progress File
  1843. SetProgressFile(pProgress, pSubList);
  1844. // Open the Group List File
  1845. IF_FAILEXIT(hr = OpenMemoryFile(pSubList->szFilePath, &File));
  1846. // De-Ref the header
  1847. pSubListHeader = (LPSUBLISTHEADER)File.pView;
  1848. // SUBFILE_VERSION5
  1849. if (SUBFILE_VERSION5 == pSubListHeader->dwVersion)
  1850. {
  1851. // Locals
  1852. PGROUPSTATUS5 pStatus;
  1853. DWORD cbRead;
  1854. // Initialize cbRead
  1855. cbRead = sizeof(SUBLISTHEADER) + sizeof(DWORD);
  1856. // PGROUPSTATUS5
  1857. for (i=0; i<pSubListHeader->cSubscribed; i++)
  1858. {
  1859. // De-Ref the Group Status
  1860. pStatus = (PGROUPSTATUS5)((LPBYTE)File.pView + cbRead);
  1861. // Increment cbRead
  1862. cbRead += sizeof(GROUPSTATUS5);
  1863. // Read the Name
  1864. pszGroup = (LPSTR)((LPBYTE)File.pView + cbRead);
  1865. // Increment cbRead
  1866. cbRead += pStatus->cbName + pStatus->cbReadRange + pStatus->cbKnownRange + pStatus->cbMarkedRange + pStatus->cbRequestedRange;
  1867. // Find The Folder...
  1868. Folder.idParent = idServer;
  1869. Folder.pszName = pszGroup;
  1870. // Try to find this folder
  1871. if (DB_S_FOUND == pStore->FindRecord(IINDEX_ALL, COLUMNS_ALL, &Folder, NULL))
  1872. {
  1873. // Locals
  1874. CHAR szSrcFile[MAX_PATH];
  1875. // Subscribe to It
  1876. if (ISFLAGSET(pStatus->dwFlags, GSF_SUBSCRIBED))
  1877. {
  1878. // Its SubScribed
  1879. FLAGSET(Folder.dwFlags, FOLDER_SUBSCRIBED);
  1880. }
  1881. // Format the original file name
  1882. wnsprintf(szSrcFile, ARRAYSIZE(szSrcFile), "%08x", pStatus->dwCacheFileIndex);
  1883. // Try to find the folder in the list of files
  1884. for (pCurrent=pHeadFile; pCurrent!=NULL; pCurrent=pCurrent->pNext)
  1885. {
  1886. // Find the Sublist for this group
  1887. if (pCurrent->fMigrate && FILE_IS_NEWS_MESSAGES == pCurrent->tyFile && lstrcmpi(pCurrent->szAcctId, pInfo->szAcctId) == 0)
  1888. {
  1889. // Get the File Name
  1890. _splitpath(pCurrent->szFilePath, szDrive, szDir, szFile, szExt);
  1891. // Correct file name
  1892. if (lstrcmpi(szFile, szSrcFile) == 0)
  1893. {
  1894. // Get the File Name
  1895. _splitpath(pCurrent->szDstFile, szDrive, szDir, szFile, szExt);
  1896. // Format the original file name
  1897. wnsprintf(szSrcFile, ARRAYSIZE(szSrcFile), "%s%s", szFile, szExt);
  1898. // Set the File Path
  1899. Folder.pszFile = szSrcFile;
  1900. // Set Folder Counts
  1901. Folder.cMessages = pCurrent->cMessages;
  1902. Folder.cUnread = pCurrent->cUnread;
  1903. // FixupFolderUserData(
  1904. FixupFolderUserData(pSession, Folder.idFolder, pszGroup, FOLDER_NOTSPECIAL, pCurrent);
  1905. // Done
  1906. break;
  1907. }
  1908. }
  1909. }
  1910. // Update the Record
  1911. pStore->UpdateRecord(&Folder);
  1912. // Free This
  1913. pStore->FreeRecord(&Folder);
  1914. }
  1915. // Bump Progress
  1916. if(!g_fQuiet)
  1917. IncrementProgress(pProgress, pSubList);
  1918. }
  1919. }
  1920. // SUBFILE_VERSION4
  1921. else if (SUBFILE_VERSION4 == pSubListHeader->dwVersion)
  1922. {
  1923. // Locals
  1924. PGROUPSTATUS4 pStatus;
  1925. DWORD cbRead;
  1926. // Initialize cbRead
  1927. cbRead = sizeof(SUBLISTHEADER);
  1928. // PGROUPSTATUS5
  1929. for (i=0; i<pSubListHeader->cSubscribed; i++)
  1930. {
  1931. // De-Ref the Group Status
  1932. pStatus = (PGROUPSTATUS4)((LPBYTE)File.pView + cbRead);
  1933. // Increment cbRead
  1934. cbRead += sizeof(GROUPSTATUS4);
  1935. // Read the Name
  1936. pszGroup = (LPSTR)((LPBYTE)File.pView + cbRead);
  1937. // Increment cbRead
  1938. cbRead += pStatus->cbName + pStatus->cbReadRange + pStatus->cbKnownRange + pStatus->cbMarkedRange + pStatus->cbRequestedRange;
  1939. // Find The Folder...
  1940. Folder.idParent = idServer;
  1941. Folder.pszName = pszGroup;
  1942. // Try to find this folder
  1943. if (DB_S_FOUND == pStore->FindRecord(IINDEX_ALL, COLUMNS_ALL, &Folder, NULL))
  1944. {
  1945. // Locals
  1946. CHAR szSrcFile[MAX_PATH];
  1947. // Subscribe to It
  1948. if (ISFLAGSET(pStatus->dwFlags, GSF_SUBSCRIBED))
  1949. {
  1950. // Its SubScribed
  1951. FLAGSET(Folder.dwFlags, FOLDER_SUBSCRIBED);
  1952. }
  1953. // Try to find the folder in the list of files
  1954. for (pCurrent=pHeadFile; pCurrent!=NULL; pCurrent=pCurrent->pNext)
  1955. {
  1956. // Find the Sublist for this group
  1957. if (pCurrent->fMigrate && FILE_IS_NEWS_MESSAGES == pCurrent->tyFile && lstrcmpi(pCurrent->szAcctId, pInfo->szAcctId) == 0)
  1958. {
  1959. // Correct file name
  1960. if (lstrcmpi(pszGroup, pCurrent->szFolder) == 0)
  1961. {
  1962. // Get the File Name
  1963. _splitpath(pCurrent->szDstFile, szDrive, szDir, szFile, szExt);
  1964. // Format the original file name
  1965. wnsprintf(szSrcFile, ARRAYSIZE(szSrcFile), "%s%s", szFile, szExt);
  1966. // Set the File Path
  1967. Folder.pszFile = szSrcFile;
  1968. // Set Folder Counts
  1969. Folder.cMessages = pCurrent->cMessages;
  1970. Folder.cUnread = pCurrent->cUnread;
  1971. // FixupFolderUserData(
  1972. FixupFolderUserData(pSession, Folder.idFolder, pszGroup, FOLDER_NOTSPECIAL, pCurrent);
  1973. // Done
  1974. break;
  1975. }
  1976. }
  1977. }
  1978. // Update the Record
  1979. pStore->UpdateRecord(&Folder);
  1980. // Free This
  1981. pStore->FreeRecord(&Folder);
  1982. }
  1983. // Bump Progress
  1984. if(!g_fQuiet)
  1985. IncrementProgress(pProgress, pSubList);
  1986. }
  1987. }
  1988. // SUBFILE_VERSION3
  1989. else if (SUBFILE_VERSION3 == pSubListHeader->dwVersion)
  1990. {
  1991. Assert(FALSE);
  1992. }
  1993. // SUBFILE_VERSION2
  1994. else if (SUBFILE_VERSION2 == pSubListHeader->dwVersion)
  1995. {
  1996. Assert(FALSE);
  1997. }
  1998. exit:
  1999. // Close the File
  2000. CloseMemoryFile(&File);
  2001. // Done
  2002. return(hr);
  2003. }
  2004. // --------------------------------------------------------------------------------
  2005. // BuildUnifiedFolderManager
  2006. // --------------------------------------------------------------------------------
  2007. HRESULT BuildUnifiedFolderManager(IDatabaseSession *pSession, IMessageStore *pStore,
  2008. LPFILEINFO pHeadFile, LPPROGRESSINFO pProgress)
  2009. {
  2010. // Locals
  2011. HRESULT hr=S_OK;
  2012. LPFILEINFO pCurrent;
  2013. // Trace
  2014. TraceCall("BuildUnifiedFolderManager");
  2015. // Walk through the list of files and merge the folders, sublist, group lists into pFolder
  2016. for (pCurrent=pHeadFile; pCurrent!=NULL; pCurrent=pCurrent->pNext)
  2017. {
  2018. // Handle Folders Type
  2019. if (FILE_IS_LOCAL_FOLDERS == pCurrent->tyFile)
  2020. {
  2021. // Merge Local Folder Cache into new Folder Manager
  2022. IF_FAILEXIT(hr = MergeFolderCacheIntoStore(pSession, pStore, pCurrent, pHeadFile, pProgress));
  2023. }
  2024. // IMAP Folder
  2025. else if (FILE_IS_IMAP_FOLDERS == pCurrent->tyFile)
  2026. {
  2027. // Merge IMAP Folder Cache into new Folder Manager
  2028. IF_FAILEXIT(hr = MergeFolderCacheIntoStore(pSession, pStore, pCurrent, pHeadFile, pProgress));
  2029. }
  2030. // News Group List
  2031. else if (FILE_IS_NEWS_GRPLIST == pCurrent->tyFile)
  2032. {
  2033. // Merge IMAP Folder Cache into new Folder Manager
  2034. IF_FAILEXIT(hr = MergeNewsGroupList(pSession, pStore, pCurrent, pHeadFile, pProgress));
  2035. }
  2036. }
  2037. // Walk through any files that were not merged into the store
  2038. for (pCurrent=pHeadFile; pCurrent!=NULL; pCurrent=pCurrent->pNext)
  2039. {
  2040. // Find the Sublist for this group
  2041. if (TRUE == pCurrent->fMigrate && FALSE == pCurrent->fInStore)
  2042. {
  2043. // Local Message File...
  2044. if (FILE_IS_LOCAL_MESSAGES == pCurrent->tyFile)
  2045. {
  2046. // Locals
  2047. FLDINFO Folder={0};
  2048. SPECIALFOLDER tySpecial;
  2049. CHAR szFolder[255];
  2050. CHAR szPath[_MAX_PATH];
  2051. CHAR szDrive[_MAX_DRIVE];
  2052. CHAR szDir[_MAX_DIR];
  2053. CHAR szFile[_MAX_FNAME];
  2054. CHAR szExt[_MAX_EXT];
  2055. // Get Special Folder Info
  2056. GetSpecialFolderInfo(pCurrent->szFilePath, szFolder, ARRAYSIZE(szFolder), &Folder.tySpecial);
  2057. // Special Case for News Special Folders from v1
  2058. if (0xffffffff == Folder.tySpecial && strstr(szFolder, "special folders") != NULL)
  2059. {
  2060. // Locals
  2061. CHAR szRes[255];
  2062. // News Outbox
  2063. LoadString(g_hInst, IDS_POSTEDITEMS, szRes, ARRAYSIZE(szRes));
  2064. // Contains "Posted Items"
  2065. if (strstr(szFolder, szRes) != NULL)
  2066. LoadString(g_hInst, IDS_NEWSPOSTED, szFolder, ARRAYSIZE(szFolder));
  2067. // Contains "Saved Items"
  2068. else
  2069. {
  2070. // News Saved Items
  2071. LoadString(g_hInst, IDS_SAVEDITEMS, szRes, ARRAYSIZE(szRes));
  2072. // Contains "Saved Items"
  2073. if (strstr(szFolder, szRes) != NULL)
  2074. LoadString(g_hInst, IDS_NEWSSAVED, szFolder, ARRAYSIZE(szFolder));
  2075. // Otherwise
  2076. else
  2077. {
  2078. // News Outbox
  2079. LoadString(g_hInst, IDS_OUTBOX, szRes, ARRAYSIZE(szRes));
  2080. // Contains Outbox
  2081. if (strstr(szFolder, szRes) != NULL)
  2082. LoadString(g_hInst, IDS_NEWSOUTBOX, szFolder, ARRAYSIZE(szFolder));
  2083. }
  2084. }
  2085. }
  2086. // Compute the File Name
  2087. _splitpath(pCurrent->szDstFile, szDrive, szDir, szFile, szExt);
  2088. wnsprintf(Folder.szFile, ARRAYSIZE(Folder.szFile), "%s.dbx", szFile);
  2089. // Set the Name
  2090. if ('\0' != *pCurrent->szFolder)
  2091. StrCpyN(Folder.szFolder, pCurrent->szFolder, ARRAYSIZE(Folder.szFolder));
  2092. else if ('\0' != *szFolder)
  2093. StrCpyN(Folder.szFolder, szFolder, ARRAYSIZE(Folder.szFolder));
  2094. else
  2095. StrCpyN(Folder.szFolder, szFile, ARRAYSIZE(Folder.szFolder));
  2096. // Set Message and Unread Count
  2097. Folder.cMessages = pCurrent->cMessages;
  2098. Folder.cUnread = pCurrent->cUnread;
  2099. // Insert into Local Store
  2100. InsertFolderIntoStore(pSession, pStore, &Folder, 0, NULL, FOLDERID_LOCAL_STORE, NULL, NULL, (LPFOLDERID)&Folder.idFolder);
  2101. // Fixup special
  2102. tySpecial = (Folder.tySpecial == 0xffffffff) ? FOLDER_NOTSPECIAL : (BYTE)(Folder.tySpecial + 1);
  2103. // Update the Folder's UserData
  2104. FixupFolderUserData(pSession, (FOLDERID)IntToPtr(Folder.idFolder), Folder.szFolder, tySpecial, pCurrent);
  2105. }
  2106. // Otherwise, just delete the file
  2107. else if (FILE_IS_POP3UIDL != pCurrent->tyFile)
  2108. DeleteFile(pCurrent->szDstFile);
  2109. }
  2110. }
  2111. exit:
  2112. // Done
  2113. return(hr);
  2114. }
  2115. // --------------------------------------------------------------------------------
  2116. // CleanupMessageStore
  2117. // --------------------------------------------------------------------------------
  2118. HRESULT CleanupMessageStore(LPCSTR pszStoreRoot, IMessageStore *pStore)
  2119. {
  2120. // Locals
  2121. HRESULT hr=S_OK;
  2122. FOLDERINFO Folder={0};
  2123. HROWSET hRowset=NULL;
  2124. CHAR szFilePath[MAX_PATH + MAX_PATH];
  2125. // Trace
  2126. TraceCall("CleanupMessageStore");
  2127. // Create a Rowset
  2128. IF_FAILEXIT(hr = pStore->CreateRowset(IINDEX_PRIMARY, 0, &hRowset));
  2129. // Walk the Rowset
  2130. while(S_OK == pStore->QueryRowset(hRowset, 1, (LPVOID *)&Folder, NULL))
  2131. {
  2132. // If it has a file and no messags.
  2133. if (Folder.pszFile && 0 == Folder.cMessages)
  2134. {
  2135. // Delete the file...
  2136. IF_FAILEXIT(hr = MakeFilePath(pszStoreRoot, Folder.pszFile, "", szFilePath, ARRAYSIZE(szFilePath)));
  2137. // Delete the File
  2138. DeleteFile(szFilePath);
  2139. // Reset the filename
  2140. Folder.pszFile = NULL;
  2141. // Update the Record
  2142. IF_FAILEXIT(hr = pStore->UpdateRecord(&Folder));
  2143. }
  2144. // Otherwise, if there is a file, force a folder rename
  2145. else if (Folder.pszFile)
  2146. {
  2147. // Rename the folder
  2148. pStore->RenameFolder(Folder.idFolder, Folder.pszName, 0, NULL);
  2149. }
  2150. // Cleanup
  2151. pStore->FreeRecord(&Folder);
  2152. }
  2153. exit:
  2154. // Cleanup
  2155. pStore->FreeRecord(&Folder);
  2156. pStore->CloseRowset(&hRowset);
  2157. // Done
  2158. return(hr);
  2159. }
  2160. // --------------------------------------------------------------------------------
  2161. // UpgradeV5
  2162. // --------------------------------------------------------------------------------
  2163. HRESULT UpgradeV5(MIGRATETOTYPE tyMigrate, LPCSTR pszStoreSrc, LPCSTR pszStoreDst,
  2164. LPPROGRESSINFO pProgress, LPFILEINFO *ppHeadFile)
  2165. {
  2166. // Locals
  2167. HRESULT hr=S_OK;
  2168. ENUMFILEINFO EnumInfo;
  2169. LPFILEINFO pCurrent;
  2170. DWORD cbNeeded;
  2171. DWORDLONG dwlFree;
  2172. BOOL fContinue;
  2173. CHAR szFolders[MAX_PATH + MAX_PATH];
  2174. CHAR szMsg[512];
  2175. IMessageStore *pStore=NULL;
  2176. IDatabaseSession *pSession=NULL;
  2177. // Trace
  2178. TraceCall("UpgradeV5");
  2179. // Initialize
  2180. *ppHeadFile = NULL;
  2181. // Setup the EnumFile Info
  2182. ZeroMemory(&EnumInfo, sizeof(ENUMFILEINFO));
  2183. EnumInfo.pszExt = ".nch";
  2184. EnumInfo.pszFoldFile = "folders.nch";
  2185. EnumInfo.pszUidlFile = "pop3uidl.dat";
  2186. EnumInfo.pszSubList = "sublist.dat";
  2187. EnumInfo.pszGrpList = "grplist.dat";
  2188. EnumInfo.fFindV1News = TRUE;
  2189. // Enumerate All ODB files in szStoreRoot...
  2190. IF_FAILEXIT(hr = EnumerateStoreFiles(pszStoreSrc, DIR_IS_ROOT, NULL, &EnumInfo, ppHeadFile));
  2191. // Setup the EnumFile Info
  2192. ZeroMemory(&EnumInfo, sizeof(ENUMFILEINFO));
  2193. EnumInfo.pszExt = ".mbx";
  2194. EnumInfo.pszFoldFile = NULL;
  2195. EnumInfo.pszUidlFile = NULL;
  2196. // Enumerate All ODB files in szStoreRoot...
  2197. IF_FAILEXIT(hr = EnumerateStoreFiles(pszStoreSrc, DIR_IS_ROOT, NULL, &EnumInfo, ppHeadFile));
  2198. // Nothing to upgrade
  2199. if (NULL == *ppHeadFile)
  2200. goto exit;
  2201. // Compute some Counts, and validate that the files are valid to migrate...
  2202. IF_FAILEXIT(hr = UpgradeProcessFileListV5(pszStoreSrc, pszStoreDst, *ppHeadFile, &pProgress->cMax, &cbNeeded));
  2203. // Message
  2204. LoadString(g_hInst, IDS_UPGRADEMESSAGE, szMsg, ARRAYSIZE(szMsg));
  2205. // Message
  2206. if(!g_fQuiet)
  2207. MigrateMessageBox(szMsg, MB_OK | MB_ICONINFORMATION | MB_SETFOREGROUND);
  2208. // Delete fles
  2209. UpgradeDeleteFilesV5(pszStoreDst);
  2210. // Create an Ojbect Database
  2211. IF_FAILEXIT(hr = CoCreateInstance(CLSID_DatabaseSession, NULL, CLSCTX_INPROC_SERVER, IID_IDatabaseSession, (LPVOID *)&pSession));
  2212. // Create an Ojbect Database
  2213. IF_FAILEXIT(hr = CoCreateInstance(CLSID_MigrateMessageStore, NULL, CLSCTX_INPROC_SERVER, IID_IMessageStore, (LPVOID *)&pStore));
  2214. // Build the Folders.odb File Path
  2215. wnsprintf(szFolders, ARRAYSIZE(szFolders), "%s\\folders.dbx", pszStoreDst);
  2216. // Delete It First
  2217. DeleteFile(szFolders);
  2218. // Initialize the Store
  2219. IF_FAILEXIT(hr = pStore->Initialize(pszStoreDst));
  2220. // Initialize the Store
  2221. IF_FAILEXIT(hr = pStore->Validate(0));
  2222. // Enought DiskSpace ?
  2223. IF_FAILEXIT(hr = GetAvailableDiskSpace(pszStoreDst, &dwlFree));
  2224. // Not Enought Diskspace
  2225. if (((DWORDLONG) cbNeeded) > dwlFree)
  2226. {
  2227. // cbNeeded is DWORD and in this case we can downgrade dwlFree to DWORD
  2228. g_cbDiskNeeded = cbNeeded; g_cbDiskFree = ((DWORD) dwlFree);
  2229. hr = TraceResult(MIGRATE_E_NOTENOUGHDISKSPACE);
  2230. goto exit;
  2231. }
  2232. // Loop through the files and migrate each one
  2233. for (pCurrent=*ppHeadFile; pCurrent!=NULL; pCurrent=pCurrent->pNext)
  2234. {
  2235. // Migrate this file ?
  2236. if (pCurrent->fMigrate)
  2237. {
  2238. // Set Progress File
  2239. SetProgressFile(pProgress, pCurrent);
  2240. // Assume we will continue
  2241. fContinue = FALSE;
  2242. // Downgrade the file
  2243. hr = pCurrent->hrMigrate = UpgradeFileV5(pSession, tyMigrate, pCurrent, pProgress, &fContinue);
  2244. // Failure ?
  2245. if (FAILED(pCurrent->hrMigrate))
  2246. {
  2247. // Set Last Error
  2248. pCurrent->dwLastError = GetLastError();
  2249. // Stop
  2250. if (FALSE == fContinue)
  2251. break;
  2252. if(!g_fQuiet) {
  2253. // Fixup the progress
  2254. while (pCurrent->cProgCur < pCurrent->cProgMax)
  2255. {
  2256. IncrementProgress(pProgress, pCurrent);
  2257. }
  2258. }
  2259. // We are ok
  2260. hr = S_OK;
  2261. }
  2262. }
  2263. }
  2264. // Process Folder Lists
  2265. hr = BuildUnifiedFolderManager(pSession, pStore, *ppHeadFile, pProgress);
  2266. // Failure, delete all destination files
  2267. if (FAILED(hr))
  2268. {
  2269. // Delete fles
  2270. UpgradeDeleteFilesV5(pszStoreDst);
  2271. }
  2272. // Otherwise, lets force a folder rename to build friendly file names
  2273. else
  2274. {
  2275. // Rename all the folders...
  2276. CleanupMessageStore(pszStoreDst, pStore);
  2277. }
  2278. #if 0
  2279. // Otherwise, delete source files
  2280. else
  2281. {
  2282. // Delete all source files
  2283. UpgradeDeleteIdxMbxNchDatFilesV5(*ppHeadFile);
  2284. }
  2285. #endif
  2286. exit:
  2287. // Cleanup
  2288. SafeRelease(pStore);
  2289. // Done
  2290. return hr;
  2291. }