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.

930 lines
26 KiB

  1. #include "pch.hxx"
  2. #include "store.h"
  3. #include "instance.h"
  4. #include "storutil.h"
  5. #include <conman.h>
  6. #include <syncop.h>
  7. #include <shared.h>
  8. #include "enumsync.h"
  9. #include "playback.h"
  10. #include "sync.h"
  11. COfflineSync *g_pSync = NULL;
  12. //--------------------------------------------------------------------------
  13. // COfflineSync::COfflineSync
  14. //--------------------------------------------------------------------------
  15. COfflineSync::COfflineSync(void)
  16. {
  17. m_cRef = 1;
  18. m_pDB = NULL;
  19. }
  20. //--------------------------------------------------------------------------
  21. // CFolderSync::~CFolderSync
  22. //--------------------------------------------------------------------------
  23. COfflineSync::~COfflineSync(void)
  24. {
  25. if (m_pDB != NULL)
  26. m_pDB->Release();
  27. }
  28. //--------------------------------------------------------------------------
  29. // CFolderSync::QueryInterface
  30. //--------------------------------------------------------------------------
  31. STDMETHODIMP COfflineSync::QueryInterface(REFIID riid, LPVOID *ppv)
  32. {
  33. if (IID_IUnknown == riid)
  34. *ppv = (IUnknown *)this;
  35. {
  36. *ppv = NULL;
  37. return(E_NOINTERFACE);
  38. }
  39. // AddRef It
  40. ((IUnknown *)*ppv)->AddRef();
  41. return(S_OK);
  42. }
  43. //--------------------------------------------------------------------------
  44. // COfflineSync::AddRef
  45. //--------------------------------------------------------------------------
  46. STDMETHODIMP_(ULONG) COfflineSync::AddRef(void)
  47. {
  48. return InterlockedIncrement(&m_cRef);
  49. }
  50. //--------------------------------------------------------------------------
  51. // COfflineSync::Release
  52. //--------------------------------------------------------------------------
  53. STDMETHODIMP_(ULONG) COfflineSync::Release(void)
  54. {
  55. LONG cRef = InterlockedDecrement(&m_cRef);
  56. if (0 == cRef)
  57. delete this;
  58. return (ULONG)cRef;
  59. }
  60. HRESULT COfflineSync::_SetMessageFlags(IMessageFolder *pFolder, FOLDERID idServer, FOLDERID idFolder, MESSAGEID idMessage, MESSAGEFLAGS dwFlags, LPADJUSTFLAGS pFlags)
  61. {
  62. MESSAGEFLAGS dwAdd, dwRemove;
  63. SYNCOPINFO info;
  64. MESSAGEIDLIST list;
  65. HRESULT hr;
  66. Assert(pFolder != NULL);
  67. Assert(pFlags != NULL);
  68. Assert(0 != pFlags->dwAdd || 0 != pFlags->dwRemove);
  69. // if no new flags are being added or only unset flags are being removed,
  70. // we don't need to do anything
  71. if ((dwFlags | pFlags->dwAdd) == dwFlags &&
  72. (dwFlags & pFlags->dwRemove) == 0)
  73. return(S_OK);
  74. hr = _FindExistingOperation(idServer, idFolder, idMessage,
  75. SYNC_CREATE_MSG | SYNC_SETPROP_MSG, SYNC_COPY_MSG | SYNC_MOVE_MSG, &info);
  76. if (FAILED(hr))
  77. return(hr);
  78. if (hr == S_OK)
  79. {
  80. if (info.tyOperation == SYNC_CREATE_MSG)
  81. {
  82. // this message has been created offline and will be uploaded to the
  83. // server, so we can just set the flags in the message and they will
  84. // get uploaded with the message
  85. }
  86. else
  87. {
  88. dwAdd = pFlags->dwAdd;
  89. dwRemove = pFlags->dwRemove;
  90. dwFlags = info.dwAdd & dwRemove;
  91. if (dwFlags != 0)
  92. {
  93. FLAGCLEAR(info.dwAdd, dwFlags);
  94. FLAGCLEAR(dwRemove, dwFlags);
  95. }
  96. dwFlags = info.dwRemove & dwAdd;
  97. if (dwFlags != 0)
  98. {
  99. FLAGCLEAR(info.dwRemove, dwFlags);
  100. FLAGCLEAR(dwAdd, dwFlags);
  101. }
  102. FLAGSET(info.dwAdd, dwAdd);
  103. FLAGSET(info.dwRemove, dwRemove);
  104. if (info.dwAdd == 0 && info.dwRemove == 0 && info.tyOperation == SYNC_SETPROP_MSG)
  105. {
  106. // no flags are being changed so we can get rid of this operation
  107. hr = m_pDB->DeleteRecord(&info);
  108. }
  109. else
  110. {
  111. hr = m_pDB->UpdateRecord(&info);
  112. }
  113. }
  114. m_pDB->FreeRecord(&info);
  115. if (FAILED(hr))
  116. return(hr);
  117. }
  118. else
  119. {
  120. // no create or set prop operations exist for this message yet,
  121. // so create a new one
  122. ZeroMemory(&info, sizeof(SYNCOPINFO));
  123. hr = m_pDB->GenerateId((LPDWORD)&info.idOperation);
  124. if (FAILED(hr))
  125. return(hr);
  126. info.idServer = idServer;
  127. info.idFolder = idFolder;
  128. info.idMessage = idMessage;
  129. info.tyOperation = SYNC_SETPROP_MSG;
  130. // info.dwFlags
  131. info.dwAdd = (~dwFlags & pFlags->dwAdd);
  132. info.dwRemove = (dwFlags & pFlags->dwRemove);
  133. hr = m_pDB->InsertRecord(&info);
  134. if (FAILED(hr))
  135. return(hr);
  136. }
  137. list.cAllocated = 0;
  138. list.cMsgs = 1;
  139. list.prgidMsg = &idMessage;
  140. hr = pFolder->SetMessageFlags(&list, pFlags, NULL, NULL);
  141. return(hr);
  142. }
  143. HRESULT COfflineSync::SetMessageFlags(IMessageFolder *pFolder, LPMESSAGEIDLIST pList, LPADJUSTFLAGS pFlags)
  144. {
  145. DWORD i;
  146. FOLDERID idFolder, idServer;
  147. MESSAGEINFO Message;
  148. HRESULT hr;
  149. HROWSET hRowset = NULL;
  150. Assert(pFolder != NULL);
  151. Assert(pFlags != NULL);
  152. Assert(0 != pFlags->dwAdd || 0 != pFlags->dwRemove);
  153. hr = pFolder->GetFolderId(&idFolder);
  154. if (FAILED(hr))
  155. return(hr);
  156. hr = GetFolderServerId(idFolder, &idServer);
  157. if (FAILED(hr))
  158. return(hr);
  159. if (NULL == pList)
  160. {
  161. hr = pFolder->CreateRowset(IINDEX_PRIMARY, NOFLAGS, &hRowset);
  162. if (FAILED(hr))
  163. return(hr);
  164. }
  165. for (i = 0; ; i++)
  166. {
  167. if (pList != NULL)
  168. {
  169. if (i >= pList->cMsgs)
  170. break;
  171. Message.idMessage = pList->prgidMsg[i];
  172. hr = pFolder->FindRecord(IINDEX_PRIMARY, COLUMNS_ALL, &Message, NULL);
  173. if (FAILED(hr))
  174. break;
  175. else if (hr != DB_S_FOUND)
  176. continue;
  177. }
  178. else
  179. {
  180. hr = pFolder->QueryRowset(hRowset, 1, (LPVOID *)&Message, NULL);
  181. if (S_FALSE == hr)
  182. {
  183. hr = S_OK;
  184. break;
  185. }
  186. else if (FAILED(hr))
  187. {
  188. break;
  189. }
  190. }
  191. hr = _SetMessageFlags(pFolder, idServer, idFolder, Message.idMessage, Message.dwFlags, pFlags);
  192. pFolder->FreeRecord(&Message);
  193. if (FAILED(hr))
  194. break;
  195. }
  196. if (hRowset != NULL)
  197. pFolder->CloseRowset(&hRowset);
  198. return(hr);
  199. }
  200. HRESULT COfflineSync::DeleteMessages(IMessageFolder *pFolder, DELETEMESSAGEFLAGS dwFlags, LPMESSAGEIDLIST pList)
  201. {
  202. DWORD i;
  203. ADJUSTFLAGS afFlags;
  204. BOOL fNoOp, fImap;
  205. FOLDERINFO Server;
  206. FOLDERID idFolder, idServer;
  207. MESSAGEID idMessage;
  208. SYNCOPINFO info;
  209. MESSAGEIDLIST list;
  210. MESSAGEINFO Message;
  211. HRESULT hr;
  212. HROWSET hRowset = NULL;
  213. // TODO: what about trashcan deletes????
  214. Assert(pFolder != NULL);
  215. hr = pFolder->GetFolderId(&idFolder);
  216. if (FAILED(hr))
  217. return(hr);
  218. hr = GetFolderServer(idFolder, &Server);
  219. if (FAILED(hr))
  220. return(hr);
  221. idServer = Server.idFolder;
  222. fImap = (Server.tyFolder == FOLDER_IMAP);
  223. g_pStore->FreeRecord(&Server);
  224. if (fImap)
  225. {
  226. if (!!(dwFlags & DELETE_MESSAGE_UNDELETE))
  227. {
  228. afFlags.dwAdd = 0;
  229. afFlags.dwRemove = ARF_ENDANGERED;
  230. }
  231. else
  232. {
  233. afFlags.dwAdd = ARF_ENDANGERED;
  234. afFlags.dwRemove = 0;
  235. }
  236. return(SetMessageFlags(pFolder, pList, &afFlags));
  237. }
  238. Assert(0 == (dwFlags & DELETE_MESSAGE_UNDELETE));
  239. if (NULL == pList)
  240. {
  241. hr = pFolder->CreateRowset(IINDEX_PRIMARY, NOFLAGS, &hRowset);
  242. if (FAILED(hr))
  243. return(hr);
  244. }
  245. list.cAllocated = 0;
  246. list.cMsgs = 1;
  247. list.prgidMsg = &idMessage;
  248. afFlags.dwAdd = ARF_DELETED_OFFLINE;
  249. afFlags.dwRemove = 0;
  250. for (i = 0; ; i++)
  251. {
  252. if (pList != NULL)
  253. {
  254. if (i >= pList->cMsgs)
  255. break;
  256. idMessage = pList->prgidMsg[i];
  257. }
  258. else
  259. {
  260. hr = pFolder->QueryRowset(hRowset, 1, (LPVOID *)&Message, NULL);
  261. if (S_FALSE == hr)
  262. {
  263. hr = S_OK;
  264. break;
  265. }
  266. else if (FAILED(hr))
  267. {
  268. break;
  269. }
  270. idMessage = Message.idMessage;
  271. pFolder->FreeRecord(&Message);
  272. }
  273. hr = _FindExistingOperation(idServer, idFolder, idMessage,
  274. SYNC_CREATE_MSG | SYNC_SETPROP_MSG, SYNC_COPY_MSG | SYNC_MOVE_MSG, &info);
  275. if (FAILED(hr))
  276. break;
  277. if (hr == S_OK)
  278. {
  279. fNoOp = TRUE;
  280. if (info.tyOperation == SYNC_CREATE_MSG || info.tyOperation == SYNC_COPY_MSG)
  281. {
  282. // we don't need to do this create or copy anymore because the message is being
  283. // deleted. we don't need to do the delete either because the message
  284. // has never existed on the server
  285. hr = m_pDB->DeleteRecord(&info);
  286. }
  287. else if (info.tyOperation == SYNC_SETPROP_MSG)
  288. {
  289. // if it is a set prop operation, we don't need to do it anymore because the message
  290. // is just getting deleted anyway
  291. fNoOp = FALSE;
  292. hr = m_pDB->DeleteRecord(&info);
  293. }
  294. else
  295. {
  296. Assert(info.tyOperation == SYNC_MOVE_MSG);
  297. // convert it to a delete operation which is the same as moving it then deleting it
  298. info.idFolderDest = 0;
  299. info.idMessageDest = 0;
  300. info.tyOperation = SYNC_DELETE_MSG;
  301. info.dwAdd = 0;
  302. info.dwRemove = 0;
  303. info.dwFlags = dwFlags;
  304. hr = m_pDB->UpdateRecord(&info);
  305. }
  306. m_pDB->FreeRecord(&info);
  307. if (FAILED(hr))
  308. {
  309. break;
  310. }
  311. else if (fNoOp)
  312. {
  313. hr = pFolder->DeleteMessages(dwFlags, &list, NULL, NULL);
  314. if (FAILED(hr))
  315. break;
  316. continue;
  317. }
  318. }
  319. // create the delete operation
  320. ZeroMemory(&info, sizeof(SYNCOPINFO));
  321. hr = m_pDB->GenerateId((LPDWORD)&info.idOperation);
  322. if (FAILED(hr))
  323. break;
  324. info.idServer = idServer;
  325. info.idFolder = idFolder;
  326. info.idMessage = idMessage;
  327. info.tyOperation = SYNC_DELETE_MSG;
  328. info.dwFlags = dwFlags;
  329. // info.dwAdd
  330. // info.dwRemove
  331. hr = m_pDB->InsertRecord(&info);
  332. if (FAILED(hr))
  333. break;
  334. hr = pFolder->SetMessageFlags(&list, &afFlags, NULL, NULL);
  335. if (FAILED(hr))
  336. break;
  337. }
  338. if (hRowset != NULL)
  339. m_pDB->CloseRowset(&hRowset);
  340. return(hr);
  341. }
  342. HRESULT COfflineSync::CreateMessage(IMessageFolder *pFolder,
  343. LPMESSAGEID pidMessage,
  344. SAVEMESSAGEFLAGS dwOptions,
  345. MESSAGEFLAGS dwFlags,
  346. IStream *pStream,
  347. IMimeMessage *pMessage)
  348. {
  349. MESSAGEID idMessage;
  350. HRESULT hr;
  351. SYNCOPINFO info;
  352. FOLDERID idFolder, idServer;
  353. Assert(pFolder != NULL);
  354. Assert(pMessage != NULL);
  355. Assert(!!(dwOptions & SAVE_MESSAGE_GENID));
  356. hr = pFolder->GetFolderId(&idFolder);
  357. if (FAILED(hr))
  358. return(hr);
  359. hr = GetFolderServerId(idFolder, &idServer);
  360. if (FAILED(hr))
  361. return(hr);
  362. ZeroMemory(&info, sizeof(SYNCOPINFO));
  363. hr = m_pDB->GenerateId((LPDWORD)&info.idOperation);
  364. if (FAILED(hr))
  365. return(hr);
  366. hr = pFolder->SaveMessage(&idMessage, SAVE_MESSAGE_GENID, dwFlags, pStream, pMessage, NULL);
  367. if (FAILED(hr))
  368. return(hr);
  369. info.idServer = idServer;
  370. info.idFolder = idFolder;
  371. info.idMessage = idMessage;
  372. info.tyOperation = SYNC_CREATE_MSG;
  373. info.dwFlags = dwOptions;
  374. // info.dwAdd
  375. // info.dwRemove
  376. hr = m_pDB->InsertRecord(&info);
  377. return(hr);
  378. }
  379. HRESULT COfflineSync::CopyMessages(IMessageFolder *pFolder, IMessageFolder *pFolderDest, COPYMESSAGEFLAGS dwCopyFlags, LPMESSAGEIDLIST pList, LPADJUSTFLAGS pFlags)
  380. {
  381. DWORD i;
  382. BOOL fMove, fImap, fCopyToMove;
  383. FOLDERINFO Server;
  384. MESSAGEFLAGS dwFlags;
  385. ADJUSTFLAGS afFlags;
  386. FOLDERID idFolder, idServer, idFolderDest;
  387. MESSAGEID idMessage;
  388. SYNCOPINFO info, infoT;
  389. MESSAGEIDLIST list;
  390. HRESULT hr;
  391. IMimeMessage *pMsg;
  392. HROWSET hRowset = NULL;
  393. MESSAGEINFO Message = { 0 };
  394. Assert(pFolder != NULL);
  395. Assert(pFolderDest != NULL);
  396. hr = pFolder->GetFolderId(&idFolder);
  397. if (FAILED(hr))
  398. return(hr);
  399. hr = pFolderDest->GetFolderId(&idFolderDest);
  400. if (FAILED(hr))
  401. return(hr);
  402. hr = GetFolderServer(idFolder, &Server);
  403. if (FAILED(hr))
  404. return(hr);
  405. idServer = Server.idFolder;
  406. fImap = (Server.tyFolder == FOLDER_IMAP);
  407. g_pStore->FreeRecord(&Server);
  408. #ifdef DEBUG
  409. FOLDERID idServerDest;
  410. Assert(SUCCEEDED(GetFolderServerId(idFolderDest, &idServerDest)));
  411. Assert(SUCCEEDED(hr));
  412. Assert(idServer == idServerDest);
  413. #endif // DEBUG
  414. if (NULL == pList)
  415. {
  416. hr = pFolder->CreateRowset(IINDEX_PRIMARY, NOFLAGS, &hRowset);
  417. if (FAILED(hr))
  418. return(hr);
  419. }
  420. fMove = !!(dwCopyFlags & COPY_MESSAGE_MOVE);
  421. if (fMove)
  422. {
  423. list.cAllocated = 0;
  424. list.cMsgs = 1;
  425. list.prgidMsg = &idMessage;
  426. if (fImap)
  427. {
  428. afFlags.dwAdd = ARF_ENDANGERED;
  429. afFlags.dwRemove = 0;
  430. }
  431. else
  432. {
  433. afFlags.dwAdd = ARF_DELETED_OFFLINE;
  434. afFlags.dwRemove = 0;
  435. }
  436. }
  437. for (i = 0; ; i++)
  438. {
  439. if (pList != NULL)
  440. {
  441. if (i >= pList->cMsgs)
  442. break;
  443. Message.idMessage = pList->prgidMsg[i];
  444. hr = pFolder->FindRecord(IINDEX_PRIMARY, COLUMNS_ALL, &Message, NULL);
  445. if (FAILED(hr))
  446. break;
  447. else if (hr != DB_S_FOUND)
  448. continue;
  449. }
  450. else
  451. {
  452. hr = pFolder->QueryRowset(hRowset, 1, (LPVOID *)&Message, NULL);
  453. if (S_FALSE == hr)
  454. {
  455. hr = S_OK;
  456. break;
  457. }
  458. else if (FAILED(hr))
  459. {
  460. break;
  461. }
  462. }
  463. idMessage = Message.idMessage;
  464. dwFlags = Message.dwFlags;
  465. if (pFlags != NULL)
  466. {
  467. if (pFlags->dwRemove != 0)
  468. Message.dwFlags &= ~pFlags->dwRemove;
  469. if (pFlags->dwAdd != 0)
  470. Message.dwFlags |= pFlags->dwAdd;
  471. }
  472. pMsg = NULL;
  473. hr = pFolder->OpenMessage(idMessage, NOFLAGS, &pMsg, NULL);
  474. if (hr == STORE_E_NOBODY)
  475. {
  476. // just create the header in the destination folder
  477. Assert(pMsg == NULL);
  478. hr = pFolderDest->GenerateId((LPDWORD)&Message.idMessage);
  479. if (SUCCEEDED(hr))
  480. hr = pFolderDest->InsertRecord(&Message);
  481. }
  482. else if (SUCCEEDED(hr))
  483. {
  484. // create the whole message in the destination folder
  485. Assert(pMsg != NULL);
  486. hr = pFolderDest->SaveMessage(&Message.idMessage, SAVE_MESSAGE_GENID, Message.dwFlags, 0, pMsg, NULL);
  487. pMsg->Release();
  488. }
  489. else
  490. {
  491. Assert(pMsg == NULL);
  492. }
  493. if (FAILED(hr))
  494. break;
  495. hr = _FindExistingOperation(idServer, idFolder, idMessage,
  496. SYNC_CREATE_MSG, SYNC_COPY_MSG | SYNC_MOVE_MSG, &info);
  497. if (FAILED(hr))
  498. break;
  499. if (hr == S_OK)
  500. {
  501. if (fMove)
  502. {
  503. // delete source msg because we're moving a msg which doesn't exist on the server
  504. // and then move the previous operation to the destination folder
  505. hr = pFolder->DeleteMessages(DELETE_MESSAGE_NOTRASHCAN | DELETE_MESSAGE_NOPROMPT, &list, NULL, NULL);
  506. if (SUCCEEDED(hr))
  507. {
  508. if (info.tyOperation == SYNC_CREATE_MSG)
  509. {
  510. info.idFolder = idFolderDest;
  511. info.idMessage = Message.idMessage;
  512. }
  513. else
  514. {
  515. info.idFolderDest = idFolderDest;
  516. info.idMessageDest = Message.idMessage;
  517. }
  518. hr = m_pDB->UpdateRecord(&info);
  519. // foo
  520. }
  521. }
  522. else
  523. {
  524. if (info.tyOperation == SYNC_CREATE_MSG)
  525. {
  526. // we can't copy this message because it doesn't exist on the server,
  527. // so we'll add another create operation for the destination message
  528. ZeroMemory(&infoT, sizeof(SYNCOPINFO));
  529. hr = m_pDB->GenerateId((LPDWORD)&infoT.idOperation);
  530. if (SUCCEEDED(hr))
  531. {
  532. infoT.idServer = idServer;
  533. infoT.idFolder = idFolderDest;
  534. infoT.idMessage = Message.idMessage;
  535. infoT.tyOperation = SYNC_CREATE_MSG;
  536. // infoT.dwFlags
  537. // info.dwAdd
  538. // info.dwRemove
  539. hr = m_pDB->InsertRecord(&infoT);
  540. }
  541. }
  542. else if (info.tyOperation == SYNC_COPY_MSG)
  543. {
  544. fCopyToMove = FALSE;
  545. // if there is an earlier operation that will result in the source msg
  546. // being deleted, then we'll find that and remove it (delete) or change
  547. // it (move), and then we'll do a move instead of a copy
  548. hr = _FindExistingOperation(info.idServer, info.idFolder, info.idMessage,
  549. SYNC_DELETE_MSG | SYNC_MOVE_MSG, 0, &infoT);
  550. if (hr == S_OK)
  551. {
  552. if (infoT.tyOperation == SYNC_DELETE_MSG)
  553. {
  554. hr = m_pDB->DeleteRecord(&infoT);
  555. }
  556. else
  557. {
  558. Assert(infoT.tyOperation == SYNC_MOVE_MSG);
  559. infoT.tyOperation = SYNC_COPY_MSG;
  560. hr = m_pDB->UpdateRecord(&infoT);
  561. }
  562. fCopyToMove = TRUE;
  563. m_pDB->FreeRecord(&infoT);
  564. }
  565. if (SUCCEEDED(hr))
  566. {
  567. hr = m_pDB->GenerateId((LPDWORD)&info.idOperation);
  568. if (SUCCEEDED(hr))
  569. {
  570. info.idFolderDest = idFolderDest;
  571. info.idMessageDest = Message.idMessage;
  572. if (fCopyToMove)
  573. info.tyOperation = SYNC_MOVE_MSG;
  574. hr = m_pDB->InsertRecord(&info);
  575. }
  576. }
  577. }
  578. else
  579. {
  580. Assert(info.tyOperation == SYNC_MOVE_MSG);
  581. // instead of doing a move then a copy which wouldn't work so good,
  582. // we'll have the current copy become a move and the earlier move will become a copy
  583. infoT = info;
  584. hr = m_pDB->GenerateId((LPDWORD)&infoT.idOperation);
  585. if (SUCCEEDED(hr))
  586. {
  587. infoT.idFolderDest = idFolderDest;
  588. infoT.idMessageDest = Message.idMessage;
  589. hr = m_pDB->InsertRecord(&infoT);
  590. if (SUCCEEDED(hr))
  591. {
  592. info.tyOperation = SYNC_COPY_MSG;
  593. hr = m_pDB->UpdateRecord(&info);
  594. }
  595. }
  596. }
  597. }
  598. m_pDB->FreeRecord(&info);
  599. if (FAILED(hr))
  600. {
  601. break;
  602. }
  603. else
  604. {
  605. pFolder->FreeRecord(&Message);
  606. continue;
  607. }
  608. }
  609. ZeroMemory(&info, sizeof(SYNCOPINFO));
  610. hr = m_pDB->GenerateId((LPDWORD)&info.idOperation);
  611. if (FAILED(hr))
  612. break;
  613. info.idServer = idServer;
  614. info.idFolder = idFolder;
  615. info.idMessage = idMessage;
  616. info.tyOperation = (fMove && !fImap) ? SYNC_MOVE_MSG : SYNC_COPY_MSG;
  617. // info.dwFlags
  618. if (pFlags != NULL)
  619. {
  620. info.dwAdd = (~dwFlags & pFlags->dwAdd);
  621. info.dwRemove = (dwFlags & pFlags->dwRemove);
  622. }
  623. info.idFolderDest = idFolderDest;
  624. info.idMessageDest = Message.idMessage;
  625. hr = m_pDB->InsertRecord(&info);
  626. // TODO: if this fails, we should probably blow away the new msg we just created...
  627. if (FAILED(hr))
  628. break;
  629. if (fMove)
  630. {
  631. if (fImap)
  632. {
  633. // put this msg in the endangered species list
  634. hr = _SetMessageFlags(pFolder, idServer, idFolder, idMessage, dwFlags, &afFlags);
  635. if (FAILED(hr))
  636. break;
  637. }
  638. else
  639. {
  640. // hide this msg because it is now deleted
  641. pFolder->SetMessageFlags(&list, &afFlags, NULL, NULL);
  642. }
  643. }
  644. pFolder->FreeRecord(&Message);
  645. }
  646. pFolder->FreeRecord(&Message);
  647. if (hRowset != NULL)
  648. pFolder->CloseRowset(&hRowset);
  649. return(hr);
  650. }
  651. HRESULT COfflineSync::Initialize()
  652. {
  653. HRESULT hr;
  654. BOOL fReset;
  655. TABLEINDEX Index;
  656. CHAR szDirectory[MAX_PATH];
  657. CHAR szFilePath[MAX_PATH];
  658. SYNCOPUSERDATA UserData={0};
  659. Assert(g_pStore != NULL);
  660. hr = g_pStore->GetDirectory(szDirectory, ARRAYSIZE(szDirectory));
  661. if (FAILED(hr))
  662. return(hr);
  663. hr = MakeFilePath(szDirectory, c_szOfflineFile, c_szEmpty, szFilePath, ARRAYSIZE(szFilePath));
  664. if (FAILED(hr))
  665. return(hr);
  666. hr = g_pDBSession->OpenDatabase(szFilePath, NOFLAGS, &g_SyncOpTableSchema, NULL, &m_pDB);
  667. if (FAILED(hr))
  668. return(hr);
  669. fReset = FALSE;
  670. // Create the idServer / idFolder Index
  671. if (FAILED(m_pDB->GetIndexInfo(IINDEX_ALL, NULL, &Index)))
  672. fReset = TRUE;
  673. // If still noreset, see of indexes are the same
  674. else if (S_FALSE == CompareTableIndexes(&Index, &g_OpFolderIdIndex))
  675. fReset = TRUE;
  676. // Change the Index
  677. if (fReset)
  678. {
  679. // Create the idParent / FolderName Index
  680. hr = m_pDB->ModifyIndex(IINDEX_ALL, NULL, &g_OpFolderIdIndex);
  681. if (FAILED(hr))
  682. return(hr);
  683. }
  684. hr = m_pDB->GetUserData(&UserData, sizeof(SYNCOPUSERDATA));
  685. if (SUCCEEDED(hr))
  686. {
  687. if (!UserData.fInitialized)
  688. {
  689. UserData.fInitialized = TRUE;
  690. hr = m_pDB->SetUserData(&UserData, sizeof(SYNCOPUSERDATA));
  691. }
  692. }
  693. return(hr);
  694. }
  695. HRESULT COfflineSync::DoPlayback(HWND hwnd, FOLDERID *pId, DWORD cId, FOLDERID idFolderSel)
  696. {
  697. HRESULT hr;
  698. DWORD cOps;
  699. COfflinePlayback *pPlayback;
  700. Assert(pId != NULL);
  701. Assert(cId > 0);
  702. hr = m_pDB->GetRecordCount(IINDEX_PRIMARY, &cOps);
  703. if (SUCCEEDED(hr) && cOps > 0)
  704. {
  705. pPlayback = new COfflinePlayback;
  706. if (pPlayback == NULL)
  707. return(E_OUTOFMEMORY);
  708. hr = pPlayback->DoPlayback(hwnd, m_pDB, pId, cId, idFolderSel);
  709. pPlayback->Release();
  710. }
  711. return(hr);
  712. }
  713. HRESULT COfflineSync::_FindExistingOperation(FOLDERID idServer, FOLDERID idFolder, MESSAGEID idMessage,
  714. DWORD dwFlagsSrc, DWORD dwFlagsDest, LPSYNCOPINFO pInfo)
  715. {
  716. ROWORDINAL iRow;
  717. HRESULT hr;
  718. HROWSET hRowset = NULL;
  719. Assert(pInfo != NULL);
  720. Assert(dwFlagsSrc != 0 || dwFlagsDest != 0);
  721. ZeroMemory(pInfo, sizeof(SYNCOPINFO));
  722. pInfo->idServer = idServer;
  723. hr = m_pDB->FindRecord(IINDEX_ALL, 1, pInfo, &iRow);
  724. if (hr != DB_S_FOUND)
  725. return(S_FALSE);
  726. m_pDB->FreeRecord(pInfo);
  727. hr = m_pDB->CreateRowset(IINDEX_ALL, NOFLAGS, &hRowset);
  728. if (FAILED(hr))
  729. return(hr);
  730. hr = m_pDB->SeekRowset(hRowset, SEEK_ROWSET_BEGIN, iRow - 1, NULL);
  731. if (SUCCEEDED(hr))
  732. {
  733. while (TRUE)
  734. {
  735. hr = m_pDB->QueryRowset(hRowset, 1, (LPVOID *)pInfo, NULL);
  736. if (S_FALSE == hr)
  737. {
  738. break;
  739. }
  740. else if (FAILED(hr))
  741. {
  742. break;
  743. }
  744. if (pInfo->idServer != idServer)
  745. {
  746. hr = S_FALSE;
  747. m_pDB->FreeRecord(pInfo);
  748. break;
  749. }
  750. if (dwFlagsSrc != 0)
  751. {
  752. if (pInfo->idFolder == idFolder && pInfo->idMessage == idMessage)
  753. {
  754. if (!!(dwFlagsSrc & pInfo->tyOperation))
  755. break;
  756. }
  757. }
  758. if (dwFlagsDest != 0)
  759. {
  760. if (pInfo->idFolderDest == idFolder && pInfo->idMessageDest == idMessage)
  761. {
  762. if (!!(dwFlagsDest & pInfo->tyOperation))
  763. break;
  764. }
  765. }
  766. m_pDB->FreeRecord(pInfo);
  767. }
  768. }
  769. m_pDB->CloseRowset(&hRowset);
  770. return(hr);
  771. }