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.

810 lines
21 KiB

  1. #include "pch.hxx"
  2. #include <progress.h>
  3. #include "store.h"
  4. #include "storutil.h"
  5. #include "storsync.h"
  6. #include "syncop.h"
  7. #include "sync.h"
  8. #include "shlwapip.h"
  9. #include "enumsync.h"
  10. #include "playback.h"
  11. #define WM_NEXT_OPERATION (WM_USER + 69)
  12. HRESULT OpenErrorsFolder(IMessageFolder **ppFolder);
  13. COfflinePlayback::COfflinePlayback()
  14. {
  15. m_cRef = 1;
  16. m_hr = E_FAIL;
  17. m_hwndDlg = NULL;
  18. m_fComplete = TRUE;
  19. m_type = SOT_INVALID;
  20. m_pCancel = NULL;
  21. m_hTimeout = NULL;
  22. m_cMovedToErrors = 0;
  23. m_cFailures = 0;
  24. m_pDB = NULL;
  25. m_pid = NULL;
  26. m_iid = 0;
  27. m_cid = 0;
  28. m_idServer = FOLDERID_INVALID;
  29. m_idFolder = FOLDERID_INVALID;
  30. m_idFolderSel = FOLDERID_INVALID;
  31. m_fSyncSel = FALSE;
  32. m_pServer = NULL;
  33. m_pLocalFolder = NULL;
  34. m_iOps = 0;
  35. m_cOps = 0;
  36. m_pEnum = NULL;
  37. m_pFolderDest = NULL;
  38. }
  39. COfflinePlayback::~COfflinePlayback()
  40. {
  41. Assert(m_pFolderDest == NULL);
  42. CallbackCloseTimeout(&m_hTimeout);
  43. if (m_pCancel != NULL)
  44. m_pCancel->Release();
  45. if (m_pDB != NULL)
  46. m_pDB->Release();
  47. if (m_pid != NULL)
  48. MemFree(m_pid);
  49. if (m_pLocalFolder != NULL)
  50. m_pLocalFolder->Release();
  51. if (m_pServer != NULL)
  52. {
  53. m_pServer->Close(MSGSVRF_HANDS_OFF_SERVER);
  54. m_pServer->Release();
  55. }
  56. if (m_pEnum != NULL)
  57. m_pEnum->Release();
  58. }
  59. HRESULT STDMETHODCALLTYPE COfflinePlayback::QueryInterface(REFIID riid, void **ppvObj)
  60. {
  61. if (IsEqualIID(riid, IID_IUnknown))
  62. *ppvObj = (void*) (IUnknown *)(IStoreCallback *)this;
  63. else if (IsEqualIID(riid, IID_IStoreCallback))
  64. *ppvObj = (void*) (IStoreCallback *)this;
  65. else if (IsEqualIID(riid, IID_ITimeoutCallback))
  66. *ppvObj = (void*) (ITimeoutCallback *)this;
  67. else
  68. {
  69. *ppvObj = NULL;
  70. return E_NOINTERFACE;
  71. }
  72. AddRef();
  73. return S_OK;
  74. }
  75. ULONG STDMETHODCALLTYPE COfflinePlayback::AddRef()
  76. {
  77. return ++m_cRef;
  78. }
  79. ULONG STDMETHODCALLTYPE COfflinePlayback::Release()
  80. {
  81. if (--m_cRef == 0)
  82. {
  83. delete this;
  84. return 0;
  85. }
  86. return m_cRef;
  87. }
  88. HRESULT COfflinePlayback::OnBegin(STOREOPERATIONTYPE tyOperation, STOREOPERATIONINFO *pOpInfo, IOperationCancel *pCancel)
  89. {
  90. Assert(tyOperation != SOT_INVALID);
  91. Assert(m_pCancel == NULL);
  92. m_type = tyOperation;
  93. m_fComplete = FALSE;
  94. if (pCancel != NULL)
  95. {
  96. m_pCancel = pCancel;
  97. m_pCancel->AddRef();
  98. }
  99. return(S_OK);
  100. }
  101. HRESULT STDMETHODCALLTYPE COfflinePlayback::OnProgress(STOREOPERATIONTYPE tyOperation, DWORD dwCurrent, DWORD dwMax, LPCSTR pszStatus)
  102. {
  103. Assert(m_hwndDlg != NULL);
  104. Assert(!m_fComplete);
  105. // Close any timeout dialog, if present
  106. CallbackCloseTimeout(&m_hTimeout);
  107. return(S_OK);
  108. }
  109. HRESULT STDMETHODCALLTYPE COfflinePlayback::OnTimeout(LPINETSERVER pServer, LPDWORD pdwTimeout, IXPTYPE ixpServerType)
  110. {
  111. // Display a timeout dialog
  112. return CallbackOnTimeout(pServer, ixpServerType, *pdwTimeout, (ITimeoutCallback *)this, &m_hTimeout);
  113. }
  114. HRESULT STDMETHODCALLTYPE COfflinePlayback::OnTimeoutResponse(TIMEOUTRESPONSE eResponse)
  115. {
  116. // Call into general timeout response utility
  117. return CallbackOnTimeoutResponse(eResponse, m_pCancel, &m_hTimeout);
  118. }
  119. HRESULT STDMETHODCALLTYPE COfflinePlayback::CanConnect(LPCSTR pszAccountId, DWORD dwFlags)
  120. {
  121. return CallbackCanConnect(pszAccountId, m_hwndDlg, FALSE);
  122. }
  123. HRESULT STDMETHODCALLTYPE COfflinePlayback::OnLogonPrompt(LPINETSERVER pServer, IXPTYPE ixpServerType)
  124. {
  125. // Close any timeout dialog, if present
  126. CallbackCloseTimeout(&m_hTimeout);
  127. // Call into general OnLogonPrompt Utility
  128. return CallbackOnLogonPrompt(m_hwndDlg, pServer, ixpServerType);
  129. }
  130. HRESULT STDMETHODCALLTYPE COfflinePlayback::OnComplete(STOREOPERATIONTYPE tyOperation, HRESULT hrComplete, LPSTOREOPERATIONINFO pOpInfo, LPSTOREERROR pErrorInfo)
  131. {
  132. HRESULT hr;
  133. SYNCOPINFO info;
  134. Assert(m_hwndDlg != NULL);
  135. AssertSz(m_type != SOT_INVALID, "somebody isn't calling OnBegin");
  136. // Close any timeout dialog, if present
  137. CallbackCloseTimeout(&m_hTimeout);
  138. if (m_type != tyOperation)
  139. return(S_OK);
  140. m_fComplete = TRUE;
  141. m_hr = hrComplete;
  142. if (m_pCancel != NULL)
  143. {
  144. m_pCancel->Release();
  145. m_pCancel = NULL;
  146. }
  147. if (m_idOperation == SYNCOPID_INVALID)
  148. {
  149. m_idFolderSel = FOLDERID_INVALID;
  150. }
  151. else
  152. {
  153. ZeroMemory(&info, sizeof(SYNCOPINFO));
  154. info.idOperation = m_idOperation;
  155. hr = m_pDB->FindRecord(IINDEX_PRIMARY, 1, &info, NULL);
  156. if (hr == DB_S_FOUND)
  157. {
  158. switch (info.tyOperation)
  159. {
  160. case SYNC_DELETE_MSG:
  161. hr = _HandleDeleteComplete(hrComplete, &info);
  162. break;
  163. case SYNC_SETPROP_MSG:
  164. hr = _HandleSetPropComplete(hrComplete, &info);
  165. break;
  166. case SYNC_CREATE_MSG:
  167. hr = _HandleCreateComplete(hrComplete, &info);
  168. break;
  169. case SYNC_COPY_MSG:
  170. case SYNC_MOVE_MSG:
  171. hr = _HandleCopyComplete(hrComplete, &info);
  172. break;
  173. default:
  174. Assert(FALSE);
  175. break;
  176. }
  177. m_pDB->DeleteRecord(&info);
  178. m_pDB->FreeRecord(&info);
  179. }
  180. }
  181. PostMessage(m_hwndDlg, WM_NEXT_OPERATION, 0, 0);
  182. return(S_OK);
  183. }
  184. HRESULT STDMETHODCALLTYPE COfflinePlayback::OnPrompt(HRESULT hrError, LPCTSTR pszText, LPCTSTR pszCaption, UINT uType, INT *piUserResponse)
  185. {
  186. // Close any timeout dialog, if present
  187. CallbackCloseTimeout(&m_hTimeout);
  188. // Call into my swanky utility
  189. return CallbackOnPrompt(m_hwndDlg, hrError, pszText, pszCaption, uType, piUserResponse);
  190. }
  191. HRESULT STDMETHODCALLTYPE COfflinePlayback::GetParentWindow(DWORD dwReserved, HWND *phwndParent)
  192. {
  193. Assert(m_hwndDlg != NULL);
  194. *phwndParent = m_hwndDlg;
  195. return(S_OK);
  196. }
  197. HRESULT COfflinePlayback::DoPlayback(HWND hwnd, IDatabase *pDB, FOLDERID *pid, DWORD cid, FOLDERID idFolderSel)
  198. {
  199. FOLDERTYPE type;
  200. int iRet;
  201. char szStoreDir[MAX_PATH + MAX_PATH];
  202. Assert(pDB != NULL);
  203. Assert(pid != NULL);
  204. Assert(cid > 0);
  205. m_pDB = pDB;
  206. m_pDB->AddRef();
  207. m_pEnum = new CEnumerateSyncOps;
  208. if (m_pEnum == NULL)
  209. return(E_OUTOFMEMORY);
  210. if (!MemAlloc((void **)&m_pid, cid * sizeof(FOLDERID)))
  211. return(E_OUTOFMEMORY);
  212. CopyMemory(m_pid, pid, cid * sizeof(FOLDERID));
  213. m_cid = cid;
  214. type = GetFolderType(idFolderSel);
  215. if (type == FOLDER_IMAP || type == FOLDER_HTTPMAIL)
  216. m_idFolderSel = idFolderSel;
  217. iRet = (int) DialogBoxParam(g_hLocRes, MAKEINTRESOURCE(IDD_PLAYBACK), hwnd, PlaybackDlgProc, (LPARAM)this);
  218. if (m_cFailures > 0)
  219. {
  220. AthMessageBoxW(hwnd, MAKEINTRESOURCEW(idsAthena), MAKEINTRESOURCEW(idsOfflineTransactionsFailed),
  221. (m_cMovedToErrors > 0) ? MAKEINTRESOURCEW(idsMovedToOfflineErrors) : NULL, MB_OK | MB_ICONEXCLAMATION);
  222. }
  223. return(S_OK);
  224. }
  225. INT_PTR CALLBACK COfflinePlayback::PlaybackDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  226. {
  227. BOOL fRet;
  228. HRESULT hr;
  229. COfflinePlayback *pThis;
  230. fRet = TRUE;
  231. switch (msg)
  232. {
  233. case WM_INITDIALOG:
  234. pThis = (COfflinePlayback *)lParam;
  235. Assert(pThis != NULL);
  236. SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pThis);
  237. pThis->m_hwndDlg = hwnd;
  238. CenterDialog(hwnd);
  239. Animate_OpenEx(GetDlgItem(hwnd, idcANI), g_hLocRes, MAKEINTRESOURCE(idanOutbox));
  240. PostMessage(hwnd, WM_NEXT_OPERATION, 0, 0);
  241. break;
  242. case WM_NEXT_OPERATION:
  243. pThis = (COfflinePlayback *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  244. Assert(pThis != NULL);
  245. hr = pThis->_DoNextOperation();
  246. if (hr != S_OK)
  247. EndDialog(hwnd, 0);
  248. break;
  249. default:
  250. fRet = FALSE;
  251. break;
  252. }
  253. return(fRet);
  254. }
  255. HRESULT COfflinePlayback::_DoNextOperation()
  256. {
  257. HRESULT hr;
  258. char sz[CCHMAX_STRINGRES], szT[CCHMAX_STRINGRES];
  259. SYNCOPINFO info;
  260. FOLDERINFO Folder;
  261. Assert(m_pEnum != NULL);
  262. Assert(g_pLocalStore != NULL);
  263. if (m_iOps == m_cOps)
  264. {
  265. m_iOps = 0;
  266. m_idServer = FOLDERID_INVALID;
  267. m_idFolder = FOLDERID_INVALID;
  268. if (m_pServer != NULL)
  269. {
  270. m_pServer->Close(MSGSVRF_HANDS_OFF_SERVER);
  271. m_pServer->Release();
  272. m_pServer = NULL;
  273. }
  274. if (m_pLocalFolder != NULL)
  275. {
  276. m_pLocalFolder->Release();
  277. m_pLocalFolder = NULL;
  278. }
  279. while (TRUE)
  280. {
  281. if (m_iid == m_cid)
  282. {
  283. hr = S_FALSE;
  284. if (m_idFolderSel != FOLDERID_INVALID &&
  285. m_fSyncSel)
  286. {
  287. if (SUCCEEDED(g_pLocalStore->GetFolderInfo(m_idFolderSel, &Folder)))
  288. {
  289. if (SUCCEEDED(CreateMessageServerType(Folder.tyFolder, &m_pServer)) &&
  290. SUCCEEDED(g_pLocalStore->OpenFolder(m_idFolderSel, NULL, NOFLAGS, &m_pLocalFolder)) &&
  291. SUCCEEDED(GetFolderServerId(m_idFolderSel, &m_idServer)) &&
  292. SUCCEEDED(m_pServer->Initialize(g_pLocalStore, m_idServer, m_pLocalFolder, m_idFolderSel)))
  293. {
  294. if (E_PENDING == m_pServer->SynchronizeFolder(SYNC_FOLDER_CACHED_HEADERS | SYNC_FOLDER_NEW_HEADERS, 0, this))
  295. {
  296. m_idOperation = SYNCOPID_INVALID;
  297. hr = S_OK;
  298. }
  299. }
  300. g_pLocalStore->FreeRecord(&Folder);
  301. }
  302. }
  303. return(hr);
  304. }
  305. m_idServer = m_pid[m_iid++];
  306. hr = m_pEnum->Initialize(m_pDB, m_idServer);
  307. if (FAILED(hr))
  308. return(hr);
  309. hr = m_pEnum->Count(&m_cOps);
  310. if (FAILED(hr))
  311. return(hr);
  312. if (m_cOps > 0)
  313. {
  314. if (SUCCEEDED(g_pLocalStore->GetFolderInfo(m_idServer, &Folder)))
  315. {
  316. AthLoadString(idsAccountLabelFmt, szT, ARRAYSIZE(szT));
  317. wnsprintf(sz, ARRAYSIZE(sz), szT, Folder.pszName);
  318. SetDlgItemText(m_hwndDlg, IDC_ACCOUNT_STATIC, sz);
  319. g_pLocalStore->FreeRecord(&Folder);
  320. }
  321. SendDlgItemMessage(m_hwndDlg, idcProgBar, PBM_SETRANGE, 0, MAKELPARAM(0, m_cOps));
  322. break;
  323. }
  324. }
  325. }
  326. Assert(m_pEnum != NULL);
  327. hr = m_pEnum->Next(&info);
  328. if (hr != S_OK)
  329. return(hr);
  330. m_iOps++;
  331. if (info.idFolder != m_idFolder)
  332. {
  333. if (m_pServer != NULL)
  334. {
  335. m_pServer->Close(MSGSVRF_HANDS_OFF_SERVER);
  336. m_pServer->Release();
  337. m_pServer = NULL;
  338. }
  339. if (m_pLocalFolder != NULL)
  340. {
  341. m_pLocalFolder->Release();
  342. m_pLocalFolder = NULL;
  343. }
  344. m_idFolder = info.idFolder;
  345. hr = g_pLocalStore->GetFolderInfo(m_idFolder, &Folder);
  346. if (SUCCEEDED(hr))
  347. {
  348. hr = CreateMessageServerType(Folder.tyFolder, &m_pServer);
  349. if (SUCCEEDED(hr))
  350. {
  351. hr = g_pLocalStore->OpenFolder(m_idFolder, NULL, NOFLAGS, &m_pLocalFolder);
  352. if (SUCCEEDED(hr))
  353. {
  354. hr = m_pServer->Initialize(g_pLocalStore, m_idServer, m_pLocalFolder, m_idFolder);
  355. }
  356. }
  357. AthLoadString(idsFolderLabelFmt, szT, ARRAYSIZE(szT));
  358. wnsprintf(sz, ARRAYSIZE(sz), szT, Folder.pszName);
  359. SetDlgItemText(m_hwndDlg, IDC_FOO_STATIC, sz);
  360. g_pLocalStore->FreeRecord(&Folder);
  361. }
  362. if (FAILED(hr))
  363. {
  364. m_pDB->FreeRecord(&info);
  365. return(hr);
  366. }
  367. }
  368. SendDlgItemMessage(m_hwndDlg, idcProgBar, PBM_SETPOS, m_iOps, 0);
  369. switch (info.tyOperation)
  370. {
  371. case SYNC_DELETE_MSG:
  372. hr = _DoDeleteOp(&info);
  373. break;
  374. case SYNC_SETPROP_MSG:
  375. hr = _DoSetPropOp(&info);
  376. break;
  377. case SYNC_CREATE_MSG:
  378. hr = _DoCreateOp(&info);
  379. break;
  380. case SYNC_COPY_MSG:
  381. case SYNC_MOVE_MSG:
  382. hr = _DoCopyOp(&info);
  383. break;
  384. default:
  385. Assert(FALSE);
  386. break;
  387. }
  388. if (FAILED(hr))
  389. {
  390. Assert(hr != E_PENDING);
  391. m_pDB->DeleteRecord(&info);
  392. PostMessage(m_hwndDlg, WM_NEXT_OPERATION, 0, 0);
  393. }
  394. else
  395. {
  396. m_idOperation = info.idOperation;
  397. }
  398. m_pDB->FreeRecord(&info);
  399. return(S_OK);
  400. }
  401. HRESULT COfflinePlayback::_DoDeleteOp(SYNCOPINFO *pInfo)
  402. {
  403. HRESULT hr;
  404. MESSAGEIDLIST list;
  405. Assert(pInfo != NULL);
  406. list.cAllocated = 0;
  407. list.cMsgs = 1;
  408. list.prgidMsg = &pInfo->idMessage;
  409. hr = m_pServer->DeleteMessages(pInfo->dwFlags, &list, this);
  410. if (hr == E_PENDING)
  411. hr = S_OK;
  412. else
  413. Assert(FAILED(hr));
  414. return(hr);
  415. }
  416. HRESULT COfflinePlayback::_DoSetPropOp(SYNCOPINFO *pInfo)
  417. {
  418. HRESULT hr;
  419. MESSAGEIDLIST list;
  420. ADJUSTFLAGS flags;
  421. Assert(pInfo != NULL);
  422. list.cAllocated = 0;
  423. list.cMsgs = 1;
  424. list.prgidMsg = &pInfo->idMessage;
  425. flags.dwRemove = pInfo->dwRemove;
  426. flags.dwAdd = pInfo->dwAdd;
  427. hr = m_pServer->SetMessageFlags(&list, &flags, SET_MESSAGE_FLAGS_FORCE, this);
  428. if (hr == E_PENDING)
  429. hr = S_OK;
  430. else
  431. Assert(FAILED(hr));
  432. return(hr);
  433. }
  434. HRESULT COfflinePlayback::_DoCreateOp(SYNCOPINFO *pInfo)
  435. {
  436. HRESULT hr;
  437. IMimeMessage *pMessage;
  438. IStream *pStream;
  439. MESSAGEINFO Message;
  440. PROPVARIANT rVariant;
  441. LPFILETIME pftRecv;
  442. DWORD dwFlags;
  443. Assert(pInfo != NULL);
  444. hr = m_pLocalFolder->OpenMessage(pInfo->idMessage, 0, &pMessage, NULL);
  445. if (SUCCEEDED(hr))
  446. {
  447. dwFlags = 0;
  448. ZeroMemory(&Message, sizeof(MESSAGEINFO));
  449. Message.idMessage = pInfo->idMessage;
  450. if (DB_S_FOUND == m_pLocalFolder->FindRecord(IINDEX_PRIMARY, COLUMNS_ALL, &Message, NULL))
  451. {
  452. dwFlags = Message.dwFlags;
  453. m_pLocalFolder->FreeRecord(&Message);
  454. }
  455. hr = pMessage->GetMessageSource(&pStream, 0);
  456. if (SUCCEEDED(hr))
  457. {
  458. rVariant.vt = VT_FILETIME;
  459. if (SUCCEEDED(pMessage->GetProp(PIDTOSTR(PID_ATT_RECVTIME), 0, &rVariant)))
  460. pftRecv = &rVariant.filetime;
  461. else
  462. pftRecv = NULL;
  463. hr = m_pServer->PutMessage(m_idFolder, dwFlags, pftRecv, pStream, this);
  464. if (hr == E_PENDING)
  465. hr = S_OK;
  466. else
  467. Assert(FAILED(hr));
  468. pStream->Release();
  469. }
  470. pMessage->Release();
  471. }
  472. return(hr);
  473. }
  474. HRESULT COfflinePlayback::_DoCopyOp(SYNCOPINFO *pInfo)
  475. {
  476. HRESULT hr;
  477. MESSAGEIDLIST list;
  478. MESSAGEINFO infoSrc, infoDest;
  479. ADJUSTFLAGS flags, *pFlags;
  480. Assert(pInfo != NULL);
  481. Assert(pInfo->tyOperation == SYNC_COPY_MSG || pInfo->tyOperation == SYNC_MOVE_MSG);
  482. Assert(m_pFolderDest == NULL);
  483. hr = g_pLocalStore->OpenFolder(pInfo->idFolderDest, NULL, NOFLAGS, &m_pFolderDest);
  484. if (SUCCEEDED(hr))
  485. {
  486. list.cAllocated = 0;
  487. list.cMsgs = 1;
  488. list.prgidMsg = &pInfo->idMessage;
  489. if (pInfo->dwRemove != 0 || pInfo->dwAdd != 0)
  490. {
  491. flags.dwRemove = pInfo->dwRemove;
  492. flags.dwAdd = pInfo->dwAdd;
  493. pFlags = &flags;
  494. }
  495. else
  496. {
  497. pFlags = NULL;
  498. }
  499. hr = m_pServer->CopyMessages(m_pFolderDest, pInfo->tyOperation == SYNC_MOVE_MSG ? COPY_MESSAGE_MOVE : NOFLAGS,
  500. &list, pFlags, this);
  501. if (hr == E_PENDING)
  502. {
  503. hr = S_OK;
  504. }
  505. else
  506. {
  507. Assert(FAILED(hr));
  508. m_pFolderDest->Release();
  509. m_pFolderDest = NULL;
  510. }
  511. }
  512. return(hr);
  513. }
  514. HRESULT COfflinePlayback::_HandleSetPropComplete(HRESULT hrOperation, SYNCOPINFO *pInfo)
  515. {
  516. HRESULT hr;
  517. MESSAGEIDLIST list;
  518. ADJUSTFLAGS flags;
  519. Assert(pInfo != NULL);
  520. Assert(pInfo->tyOperation == SYNC_SETPROP_MSG);
  521. Assert(m_pLocalFolder != NULL);
  522. if (FAILED(hrOperation))
  523. {
  524. m_cFailures++;
  525. list.cAllocated = 0;
  526. list.cMsgs = 1;
  527. list.prgidMsg = &pInfo->idMessage;
  528. flags.dwAdd = pInfo->dwRemove;
  529. flags.dwRemove = pInfo->dwAdd;
  530. hr = m_pLocalFolder->SetMessageFlags(&list, &flags, NULL, NULL);
  531. }
  532. return(S_OK);
  533. }
  534. HRESULT COfflinePlayback::_HandleCreateComplete(HRESULT hrOperation, SYNCOPINFO *pInfo)
  535. {
  536. HRESULT hr;
  537. FOLDERINFO Folder;
  538. MESSAGEIDLIST list;
  539. IMessageFolder *pErrorFolder;
  540. Assert(pInfo != NULL);
  541. Assert(pInfo->tyOperation == SYNC_CREATE_MSG);
  542. Assert(m_pLocalFolder != NULL);
  543. list.cAllocated = 0;
  544. list.cMsgs = 1;
  545. list.prgidMsg = &pInfo->idMessage;
  546. if (FAILED(hrOperation))
  547. {
  548. m_cFailures++;
  549. hr = OpenErrorsFolder(&pErrorFolder);
  550. if (SUCCEEDED(hr))
  551. {
  552. hr = m_pLocalFolder->CopyMessages(pErrorFolder, NOFLAGS, &list, NULL, NULL, NULL);
  553. if (SUCCEEDED(hr))
  554. m_cMovedToErrors++;
  555. pErrorFolder->Release();
  556. }
  557. }
  558. // get rid of the temp offline msg
  559. hr = m_pLocalFolder->DeleteMessages(DELETE_MESSAGE_NOTRASHCAN | DELETE_MESSAGE_NOPROMPT, &list, NULL, NULL);
  560. Assert(SUCCEEDED(hr));
  561. if (pInfo->idFolder == m_idFolderSel)
  562. m_fSyncSel = TRUE;
  563. return(S_OK);
  564. }
  565. HRESULT COfflinePlayback::_HandleDeleteComplete(HRESULT hrOperation, SYNCOPINFO *pInfo)
  566. {
  567. HRESULT hr;
  568. MESSAGEIDLIST list;
  569. ADJUSTFLAGS flags;
  570. Assert(pInfo != NULL);
  571. Assert(pInfo->tyOperation == SYNC_DELETE_MSG);
  572. Assert(m_pLocalFolder != NULL);
  573. if (FAILED(hrOperation))
  574. {
  575. m_cFailures++;
  576. list.cAllocated = 0;
  577. list.cMsgs = 1;
  578. list.prgidMsg = &pInfo->idMessage;
  579. flags.dwAdd = 0;
  580. flags.dwRemove = ARF_DELETED_OFFLINE;
  581. hr = m_pLocalFolder->SetMessageFlags(&list, &flags, NULL, NULL);
  582. }
  583. return(S_OK);
  584. }
  585. HRESULT COfflinePlayback::_HandleCopyComplete(HRESULT hrOperation, SYNCOPINFO *pInfo)
  586. {
  587. HRESULT hr;
  588. MESSAGEIDLIST list;
  589. ADJUSTFLAGS flags;
  590. Assert(pInfo != NULL);
  591. Assert(pInfo->tyOperation == SYNC_COPY_MSG || pInfo->tyOperation == SYNC_MOVE_MSG);
  592. Assert(m_pLocalFolder != NULL);
  593. if (pInfo->tyOperation == SYNC_MOVE_MSG && FAILED(hrOperation))
  594. {
  595. list.cAllocated = 0;
  596. list.cMsgs = 1;
  597. list.prgidMsg = &pInfo->idMessage;
  598. flags.dwAdd = 0;
  599. flags.dwRemove = ARF_DELETED_OFFLINE;
  600. hr = m_pLocalFolder->SetMessageFlags(&list, &flags, NULL, NULL);
  601. }
  602. if (FAILED(hrOperation))
  603. {
  604. m_cFailures++;
  605. // TODO: we need more robust error handling in here
  606. }
  607. list.cAllocated = 0;
  608. list.cMsgs = 1;
  609. list.prgidMsg = &pInfo->idMessageDest;
  610. // get rid of the temp offline msg
  611. hr = m_pFolderDest->DeleteMessages(DELETE_MESSAGE_NOTRASHCAN | DELETE_MESSAGE_NOPROMPT, &list, NULL, NULL);
  612. Assert(SUCCEEDED(hr));
  613. if (pInfo->idFolderDest == m_idFolderSel)
  614. m_fSyncSel = TRUE;
  615. m_pFolderDest->Release();
  616. m_pFolderDest = NULL;
  617. return(S_OK);
  618. }
  619. HRESULT OpenErrorsFolder(IMessageFolder **ppFolder)
  620. {
  621. FOLDERINFO Folder;
  622. HRESULT hr;
  623. char szFolder[CCHMAX_FOLDER_NAME];
  624. Assert(g_pLocalStore != NULL);
  625. Assert(ppFolder != NULL);
  626. hr = g_pLocalStore->GetSpecialFolderInfo(FOLDERID_LOCAL_STORE, FOLDER_ERRORS, &Folder);
  627. if (SUCCEEDED(hr))
  628. {
  629. hr = g_pLocalStore->OpenFolder(Folder.idFolder, NULL, NOFLAGS, ppFolder);
  630. g_pLocalStore->FreeRecord(&Folder);
  631. }
  632. else if (hr == DB_E_NOTFOUND)
  633. {
  634. LoadString(g_hLocRes, idsOfflineErrors, szFolder, ARRAYSIZE(szFolder));
  635. // Fill the Folder Info
  636. ZeroMemory(&Folder, sizeof(FOLDERINFO));
  637. Folder.idParent = FOLDERID_LOCAL_STORE;
  638. Folder.tySpecial = FOLDER_ERRORS;
  639. Folder.pszName = szFolder;
  640. Folder.dwFlags = FOLDER_SUBSCRIBED;
  641. // Create the Folder
  642. hr = g_pLocalStore->CreateFolder(NOFLAGS, &Folder, NOSTORECALLBACK);
  643. if (SUCCEEDED(hr))
  644. hr = g_pLocalStore->OpenFolder(Folder.idFolder, NULL, NOFLAGS, ppFolder);
  645. }
  646. return(hr);
  647. }