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.

4196 lines
136 KiB

  1. /*
  2. * h t t p s e r v . cpp
  3. *
  4. * Author: Greg Friedman
  5. *
  6. * Purpose: Derives from IMessageServer to implement HTTPMail-specific
  7. * store communication.
  8. *
  9. * Copyright (C) Microsoft Corp. 1998.
  10. */
  11. #include "pch.hxx"
  12. #include "httpserv.h"
  13. #include "httputil.h"
  14. #include "storutil.h"
  15. #include "serverq.h"
  16. #include "tmap.h"
  17. #include "acctcach.h"
  18. #include "urlmon.h"
  19. #include "useragnt.h"
  20. #include "spoolapi.h"
  21. #include "demand.h"
  22. #define CCHMAX_RES 255
  23. static const char s_szHTTPMailServerWndClass[] = "HTTPMailWndClass";
  24. #define AssertSingleThreaded AssertSz(m_dwThreadId == GetCurrentThreadId(), "Multi-threading makes me sad.")
  25. // explicit template instantiations
  26. template class TMap<FOLDERID, CSimpleString>;
  27. template class TPair<FOLDERID, CSimpleString>;
  28. const UINT WM_HTTP_BEGIN_OP = WM_USER;
  29. // SOT_SYNCING_STORE
  30. static const HTTPSTATEFUNCS c_rgpfnSyncStore[] =
  31. {
  32. { &CHTTPMailServer::Connect, NULL },
  33. { &CHTTPMailServer::GetMsgFolderRoot, &CHTTPMailServer::HandleGetMsgFolderRoot },
  34. { &CHTTPMailServer::ListFolders, &CHTTPMailServer::HandleListFolders },
  35. { &CHTTPMailServer::PurgeFolders, NULL }
  36. };
  37. // SOT_SYNC_FOLDER
  38. static const HTTPSTATEFUNCS c_rgpfnSyncFolder[] =
  39. {
  40. { &CHTTPMailServer::Connect, NULL },
  41. { &CHTTPMailServer::GetMsgFolderRoot, &CHTTPMailServer::HandleGetMsgFolderRoot },
  42. { &CHTTPMailServer::AutoListFolders, &CHTTPMailServer::HandleListFolders },
  43. { &CHTTPMailServer::PurgeFolders, NULL },
  44. { &CHTTPMailServer::BuildFolderUrl, NULL },
  45. { &CHTTPMailServer::ListHeaders, &CHTTPMailServer::HandleListHeaders },
  46. { &CHTTPMailServer::PurgeMessages, NULL },
  47. { &CHTTPMailServer::ResetMessageCounts, NULL }
  48. };
  49. // SOT_GET_MESSAGE
  50. static const HTTPSTATEFUNCS c_rgpfnGetMessage[] =
  51. {
  52. { &CHTTPMailServer::Connect, NULL },
  53. { &CHTTPMailServer::GetMsgFolderRoot, &CHTTPMailServer::HandleGetMsgFolderRoot },
  54. { &CHTTPMailServer::AutoListFolders, &CHTTPMailServer::HandleListFolders },
  55. { &CHTTPMailServer::PurgeFolders, NULL },
  56. { &CHTTPMailServer::BuildFolderUrl, NULL },
  57. { &CHTTPMailServer::GetMessage, &CHTTPMailServer::HandleGetMessage }
  58. };
  59. // SOT_CREATE_FOLDER
  60. static const HTTPSTATEFUNCS c_rgpfnCreateFolder[] =
  61. {
  62. { &CHTTPMailServer::Connect, NULL },
  63. { &CHTTPMailServer::GetMsgFolderRoot, &CHTTPMailServer::HandleGetMsgFolderRoot },
  64. { &CHTTPMailServer::AutoListFolders, &CHTTPMailServer::HandleListFolders },
  65. { &CHTTPMailServer::PurgeFolders, NULL },
  66. { &CHTTPMailServer::CreateFolder, &CHTTPMailServer::HandleCreateFolder }
  67. };
  68. // SOT_RENAME_FOLDER
  69. static const HTTPSTATEFUNCS c_rgpfnRenameFolder[] =
  70. {
  71. { &CHTTPMailServer::Connect, NULL },
  72. { &CHTTPMailServer::GetMsgFolderRoot, &CHTTPMailServer::HandleGetMsgFolderRoot },
  73. { &CHTTPMailServer::AutoListFolders, &CHTTPMailServer::HandleListFolders },
  74. { &CHTTPMailServer::PurgeFolders, NULL },
  75. { &CHTTPMailServer::RenameFolder, &CHTTPMailServer::HandleRenameFolder }
  76. };
  77. // SOT_DELETE_FOLDER
  78. static const HTTPSTATEFUNCS c_rgpfnDeleteFolder[] =
  79. {
  80. { &CHTTPMailServer::Connect, NULL },
  81. { &CHTTPMailServer::GetMsgFolderRoot, &CHTTPMailServer::HandleGetMsgFolderRoot },
  82. { &CHTTPMailServer::AutoListFolders, &CHTTPMailServer::HandleListFolders },
  83. { &CHTTPMailServer::PurgeFolders, NULL },
  84. { &CHTTPMailServer::DeleteFolder, &CHTTPMailServer::HandleDeleteFolder }
  85. };
  86. // SOT_SET_MESSAGEFLAGS
  87. static const HTTPSTATEFUNCS c_rgpfnSetMessageFlags[] =
  88. {
  89. { &CHTTPMailServer::Connect, NULL },
  90. { &CHTTPMailServer::GetMsgFolderRoot, &CHTTPMailServer::HandleGetMsgFolderRoot },
  91. { &CHTTPMailServer::AutoListFolders, &CHTTPMailServer::HandleListFolders },
  92. { &CHTTPMailServer::PurgeFolders, NULL },
  93. { &CHTTPMailServer::BuildFolderUrl, NULL },
  94. { &CHTTPMailServer::SetMessageFlags, &CHTTPMailServer::HandleMemberErrors},
  95. { &CHTTPMailServer::ApplyFlagsToStore, NULL }
  96. };
  97. // SOT_DELETING_MESSAGES
  98. static const HTTPSTATEFUNCS c_rgpfnDeleteMessages[] =
  99. {
  100. { &CHTTPMailServer::Connect, NULL },
  101. { &CHTTPMailServer::GetMsgFolderRoot, &CHTTPMailServer::HandleGetMsgFolderRoot },
  102. { &CHTTPMailServer::AutoListFolders, &CHTTPMailServer::HandleListFolders },
  103. { &CHTTPMailServer::PurgeFolders, NULL },
  104. { &CHTTPMailServer::BuildFolderUrl, NULL },
  105. { &CHTTPMailServer::DeleteMessages, &CHTTPMailServer::HandleMemberErrors },
  106. { &CHTTPMailServer::DeleteFallbackToMove, &CHTTPMailServer::HandleDeleteFallbackToMove },
  107. { &CHTTPMailServer::PurgeDeletedFromStore, NULL }
  108. };
  109. // SOT_PUT_MESSAGE
  110. static const HTTPSTATEFUNCS c_rgpfnPutMessage[] =
  111. {
  112. { &CHTTPMailServer::Connect, NULL },
  113. { &CHTTPMailServer::GetMsgFolderRoot, &CHTTPMailServer::HandleGetMsgFolderRoot },
  114. { &CHTTPMailServer::AutoListFolders, &CHTTPMailServer::HandleListFolders },
  115. { &CHTTPMailServer::PurgeFolders, NULL },
  116. { &CHTTPMailServer::PutMessage, &CHTTPMailServer::HandlePutMessage },
  117. { &CHTTPMailServer::AddPutMessage, NULL }
  118. };
  119. // SOT_COPYMOVE_MESSAGES (copying or moving one message)
  120. static const HTTPSTATEFUNCS c_rgpfnCopyMoveMessage[] =
  121. {
  122. { &CHTTPMailServer::Connect, NULL },
  123. { &CHTTPMailServer::GetMsgFolderRoot, &CHTTPMailServer::HandleGetMsgFolderRoot },
  124. { &CHTTPMailServer::AutoListFolders, &CHTTPMailServer::HandleListFolders },
  125. { &CHTTPMailServer::PurgeFolders, NULL },
  126. { &CHTTPMailServer::BuildFolderUrl, NULL },
  127. { &CHTTPMailServer::CopyMoveMessage, &CHTTPMailServer::HandleCopyMoveMessage }
  128. };
  129. // SOT_COPYMOVE_MESSAGES (moving multiple messages)
  130. static const HTTPSTATEFUNCS c_rgpfnBatchCopyMoveMessages[] =
  131. {
  132. { &CHTTPMailServer::Connect, NULL },
  133. { &CHTTPMailServer::GetMsgFolderRoot, &CHTTPMailServer::HandleGetMsgFolderRoot },
  134. { &CHTTPMailServer::AutoListFolders, &CHTTPMailServer::HandleListFolders },
  135. { &CHTTPMailServer::PurgeFolders, NULL },
  136. { &CHTTPMailServer::BuildFolderUrl, NULL },
  137. { &CHTTPMailServer::BatchCopyMoveMessages, &CHTTPMailServer::HandleBatchCopyMoveMessages},
  138. { &CHTTPMailServer::FinalizeBatchCopyMove, NULL }
  139. };
  140. // SOT_GET_ADURL (gets ad url from Hotmail)
  141. static const HTTPSTATEFUNCS c_rgpfnGetAdUrl[] =
  142. {
  143. { &CHTTPMailServer::Connect, NULL },
  144. { &CHTTPMailServer::GetAdBarUrlFromServer, NULL }
  145. };
  146. // SOT_GET_HTTP_MINPOLLINGINTERVAL (gets Minimum polling interval from http server)
  147. static const HTTPSTATEFUNCS c_rgpfnGetMinPollingInterval[] =
  148. {
  149. { &CHTTPMailServer::Connect, NULL },
  150. { &CHTTPMailServer::GetMinPollingInterval, NULL }
  151. };
  152. class CFolderList
  153. {
  154. public:
  155. // Public factory function.
  156. static HRESULT Create(IMessageStore *pStore, FOLDERID idRoot, CFolderList **ppFolderList);
  157. private:
  158. // Constructor is private. Use "Create" to instantiate.
  159. CFolderList();
  160. ~CFolderList();
  161. private:
  162. // unimplemented copy constructor/assignment operator
  163. CFolderList(const CFolderList& other);
  164. CFolderList& operator=(const CFolderList& other);
  165. public:
  166. ULONG AddRef(void);
  167. ULONG Release(void);
  168. FOLDERID FindAndRemove(LPSTR pszUrlComponent, DWORD *pcMessages, DWORD *pcUnread);
  169. FOLDERID FindAndRemove(SPECIALFOLDER tySpecial, DWORD *pcMessages, DWORD *pcUnread);
  170. void PurgeRemainingFromStore(void);
  171. private:
  172. typedef struct tagFOLDERLISTNODE
  173. {
  174. LPSTR pszUrlComponent;
  175. FLDRFLAGS dwFlags;
  176. FOLDERID idFolder;
  177. SPECIALFOLDER tySpecial;
  178. DWORD cMessages;
  179. DWORD cUnread;
  180. tagFOLDERLISTNODE *pflnNext;
  181. } FOLDERLISTNODE, *LPFOLDERLISTNODE;
  182. LPFOLDERLISTNODE _AllocNode(void)
  183. {
  184. LPFOLDERLISTNODE pflnNode = new FOLDERLISTNODE;
  185. if (pflnNode)
  186. {
  187. pflnNode->pszUrlComponent = NULL;
  188. pflnNode->dwFlags = 0;
  189. pflnNode->idFolder = FOLDERID_INVALID;
  190. pflnNode->tySpecial = FOLDER_NOTSPECIAL;
  191. pflnNode->cMessages = 0;
  192. pflnNode->cUnread = 0;
  193. pflnNode->pflnNext = NULL;
  194. }
  195. return pflnNode;
  196. }
  197. HRESULT HrInitialize(IMessageStore *pStore, FOLDERID idRoot);
  198. void _FreeNode(LPFOLDERLISTNODE pflnNode)
  199. {
  200. if (pflnNode)
  201. {
  202. SafeMemFree(pflnNode->pszUrlComponent);
  203. delete pflnNode;
  204. }
  205. }
  206. void _FreeList(void);
  207. private:
  208. ULONG m_cRef;
  209. IMessageStore *m_pStore;
  210. LPFOLDERLISTNODE m_pflnList;
  211. };
  212. //----------------------------------------------------------------------
  213. // CFolderList::Create
  214. //----------------------------------------------------------------------
  215. HRESULT CFolderList::Create(IMessageStore *pStore, FOLDERID idRoot, CFolderList **ppFolderList)
  216. {
  217. HRESULT hr = S_OK;
  218. CFolderList *pFolderList = NULL;
  219. if (NULL == pStore || FOLDERID_INVALID == idRoot || NULL == ppFolderList)
  220. {
  221. hr = TraceResult(E_INVALIDARG);
  222. goto exit;
  223. }
  224. *ppFolderList = NULL;
  225. pFolderList = new CFolderList();
  226. if (!pFolderList)
  227. {
  228. hr = E_OUTOFMEMORY;
  229. goto exit;
  230. }
  231. IF_FAILEXIT(hr = pFolderList->HrInitialize(pStore, idRoot));
  232. *ppFolderList = pFolderList;
  233. pFolderList = NULL;
  234. exit:
  235. SafeRelease(pFolderList);
  236. return hr;
  237. }
  238. //----------------------------------------------------------------------
  239. // CFolderList::CFolderList
  240. //----------------------------------------------------------------------
  241. CFolderList::CFolderList(void) :
  242. m_cRef(1),
  243. m_pStore(NULL),
  244. m_pflnList(NULL)
  245. {
  246. // nothing to do
  247. }
  248. //----------------------------------------------------------------------
  249. // CFolderList::~CFolderList
  250. //----------------------------------------------------------------------
  251. CFolderList::~CFolderList(void)
  252. {
  253. _FreeList();
  254. SafeRelease(m_pStore);
  255. }
  256. //----------------------------------------------------------------------
  257. // CFolderList::AddRef
  258. //----------------------------------------------------------------------
  259. ULONG CFolderList::AddRef(void)
  260. {
  261. return (++m_cRef);
  262. }
  263. //----------------------------------------------------------------------
  264. // CFolderList::Release
  265. //----------------------------------------------------------------------
  266. ULONG CFolderList::Release(void)
  267. {
  268. if (0 == --m_cRef)
  269. {
  270. delete this;
  271. return 0;
  272. }
  273. else
  274. return m_cRef;
  275. }
  276. //----------------------------------------------------------------------
  277. // CFolderList::_FreeList
  278. //----------------------------------------------------------------------
  279. void CFolderList::_FreeList(void)
  280. {
  281. LPFOLDERLISTNODE pflnDeleteMe;
  282. while (m_pflnList)
  283. {
  284. pflnDeleteMe = m_pflnList;
  285. m_pflnList = m_pflnList->pflnNext;
  286. _FreeNode(pflnDeleteMe);
  287. }
  288. }
  289. //----------------------------------------------------------------------
  290. // CFolderList::HrInitialize
  291. //----------------------------------------------------------------------
  292. HRESULT CFolderList::HrInitialize(IMessageStore *pStore, FOLDERID idRoot)
  293. {
  294. HRESULT hr=S_OK;
  295. IEnumerateFolders *pFldrEnum = NULL;
  296. FOLDERINFO fi;
  297. FOLDERLISTNODE flnDummyHead= { NULL, 0, 0, NULL };
  298. LPFOLDERLISTNODE pflnTail = &flnDummyHead;
  299. LPFOLDERLISTNODE pflnNewNode = NULL;
  300. if (NULL == pStore)
  301. {
  302. hr = TraceResult(E_INVALIDARG);
  303. return hr;
  304. }
  305. if (NULL != m_pflnList)
  306. {
  307. hr = TraceResult(ERROR_ALREADY_INITIALIZED);
  308. return hr;
  309. }
  310. m_pStore = pStore;
  311. m_pStore->AddRef();
  312. // this function assumes that the folder list is flat.
  313. // it needs to be modified to support a hierarchical store.
  314. IF_FAILEXIT(hr = pStore->EnumChildren(idRoot, FALSE, &pFldrEnum));
  315. pFldrEnum->Reset();
  316. // build a linked list of folder nodes
  317. while (S_OK == pFldrEnum->Next(1, &fi, NULL))
  318. {
  319. pflnNewNode = _AllocNode();
  320. if (NULL == pflnNewNode)
  321. {
  322. hr = TraceResult(E_OUTOFMEMORY);
  323. pStore->FreeRecord(&fi);
  324. _FreeList();
  325. goto exit;
  326. }
  327. pflnNewNode->pszUrlComponent = PszDupA(fi.pszUrlComponent);
  328. pflnNewNode->dwFlags = fi.dwFlags;
  329. pflnNewNode->idFolder = fi.idFolder;
  330. pflnNewNode->tySpecial = fi.tySpecial;
  331. pflnNewNode->cMessages = fi.cMessages;
  332. pflnNewNode->cUnread = fi.cUnread;
  333. pflnTail->pflnNext = pflnNewNode;
  334. pflnTail = pflnNewNode;
  335. pflnNewNode = NULL;
  336. pStore->FreeRecord(&fi);
  337. }
  338. m_pflnList = flnDummyHead.pflnNext;
  339. exit:
  340. ReleaseObj(pFldrEnum);
  341. return hr;
  342. }
  343. //----------------------------------------------------------------------
  344. // CFolderList::FindAndRemove
  345. //----------------------------------------------------------------------
  346. FOLDERID CFolderList::FindAndRemove(LPSTR pszUrlComponent,
  347. DWORD *pcMessages,
  348. DWORD *pcUnread)
  349. {
  350. LPFOLDERLISTNODE pflnPrev = NULL;
  351. LPFOLDERLISTNODE pflnCur = m_pflnList;
  352. FOLDERID idFound = FOLDERID_INVALID;
  353. if (NULL == pszUrlComponent)
  354. return FOLDERID_INVALID;
  355. if (pcMessages)
  356. *pcMessages = 0;
  357. if (pcUnread)
  358. *pcUnread = 0;
  359. while (pflnCur)
  360. {
  361. if ((NULL != pflnCur->pszUrlComponent) && (0 == lstrcmp(pflnCur->pszUrlComponent, pszUrlComponent)))
  362. {
  363. if (NULL == pflnPrev)
  364. m_pflnList = pflnCur->pflnNext;
  365. else
  366. pflnPrev->pflnNext = pflnCur->pflnNext;
  367. idFound = pflnCur->idFolder;
  368. if (pcMessages)
  369. *pcMessages = pflnCur->cMessages;
  370. if (pcUnread)
  371. *pcUnread = pflnCur->cUnread;
  372. _FreeNode(pflnCur);
  373. break;
  374. }
  375. pflnPrev = pflnCur;
  376. pflnCur = pflnCur->pflnNext;
  377. }
  378. return idFound;
  379. }
  380. //----------------------------------------------------------------------
  381. // CFolderList::FindAndRemove
  382. //----------------------------------------------------------------------
  383. FOLDERID CFolderList::FindAndRemove(SPECIALFOLDER tySpecial,
  384. DWORD *pcMessages,
  385. DWORD *pcUnread)
  386. {
  387. LPFOLDERLISTNODE pflnPrev = NULL;
  388. LPFOLDERLISTNODE pflnCur = m_pflnList;
  389. FOLDERID idFound = FOLDERID_INVALID;
  390. if (FOLDER_NOTSPECIAL == tySpecial)
  391. return FOLDERID_INVALID;
  392. if (pcMessages)
  393. *pcMessages = 0;
  394. if (pcUnread)
  395. *pcUnread = 0;
  396. while (pflnCur)
  397. {
  398. if (pflnCur->tySpecial == tySpecial)
  399. {
  400. if (NULL == pflnPrev)
  401. m_pflnList = pflnCur->pflnNext;
  402. else
  403. pflnPrev->pflnNext = pflnCur->pflnNext;
  404. idFound = pflnCur->idFolder;
  405. if (pcMessages)
  406. *pcMessages = pflnCur->cMessages;
  407. if (pcUnread)
  408. *pcUnread = pflnCur->cUnread;
  409. _FreeNode(pflnCur);
  410. break;
  411. }
  412. pflnPrev = pflnCur;
  413. pflnCur = pflnCur->pflnNext;
  414. }
  415. return idFound;
  416. }
  417. //----------------------------------------------------------------------
  418. // CFolderList::PurgeRemainingFromStore
  419. //----------------------------------------------------------------------
  420. void CFolderList::PurgeRemainingFromStore(void)
  421. {
  422. HRESULT hr = S_OK;
  423. LPFOLDERLISTNODE pflnCur = m_pflnList;
  424. LPFOLDERLISTNODE pflnDeleteMe = NULL;
  425. // take ownership of the list
  426. m_pflnList = NULL;
  427. while (pflnCur)
  428. {
  429. m_pStore->DeleteFolder(pflnCur->idFolder, DELETE_FOLDER_DELETESPECIAL | DELETE_FOLDER_NOTRASHCAN, NULL);
  430. pflnDeleteMe = pflnCur;
  431. pflnCur = pflnCur->pflnNext;
  432. _FreeNode(pflnDeleteMe);
  433. }
  434. }
  435. //----------------------------------------------------------------------
  436. // FreeNewMessageInfo
  437. //----------------------------------------------------------------------
  438. static void __cdecl FreeNewMessageInfo(LPVOID pnmi)
  439. {
  440. Assert(NULL != pnmi);
  441. SafeMemFree(((LPNEWMESSAGEINFO)pnmi)->pszUrlComponent);
  442. MemFree(pnmi);
  443. }
  444. #ifndef NOHTTPMAIL
  445. //----------------------------------------------------------------------
  446. // CreateHTTPMailStore (factory function)
  447. //----------------------------------------------------------------------
  448. HRESULT CreateHTTPMailStore(IUnknown *pUnkOuter, IUnknown **ppUnknown)
  449. {
  450. HRESULT hr = S_OK;
  451. // Trace
  452. TraceCall("CreateHTTPMailStore");
  453. // Invalid Args
  454. Assert(NULL != ppUnknown);
  455. if (NULL == ppUnknown)
  456. return E_INVALIDARG;
  457. // Initialize
  458. *ppUnknown = NULL;
  459. // Create me
  460. CHTTPMailServer *pNew = new CHTTPMailServer();
  461. if (NULL == pNew)
  462. return TraceResult(E_OUTOFMEMORY);
  463. // Cast to unknown
  464. //*ppUnknown = SAFECAST(pNew, IMessageServer *);
  465. hr = CreateServerQueue(pNew, (IMessageServer **)ppUnknown);
  466. pNew->Release(); // Since we're not returning this ptr, bump down refcount
  467. // Done
  468. return hr;
  469. }
  470. #endif
  471. //----------------------------------------------------------------------
  472. // CHTTPMailServer::CHTTPMailServer
  473. //----------------------------------------------------------------------
  474. CHTTPMailServer::CHTTPMailServer(void) :
  475. m_cRef(1),
  476. m_hwnd(NULL),
  477. m_pStore(NULL),
  478. m_pFolder(NULL),
  479. m_pTransport(NULL),
  480. m_pszFldrLeafName(NULL),
  481. m_pszMsgFolderRoot(NULL),
  482. m_idServer(FOLDERID_INVALID),
  483. m_idFolder(FOLDERID_INVALID),
  484. m_tySpecialFolder(FOLDER_NOTSPECIAL),
  485. m_pszFolderUrl(NULL),
  486. m_fConnected(FALSE),
  487. m_pTransport2(NULL),
  488. m_pAccount(NULL)
  489. {
  490. _FreeOperation(FALSE);
  491. ZeroMemory(&m_rInetServerInfo, sizeof(INETSERVER));
  492. m_szAccountName[0] = '\0';
  493. m_szAccountId[0] = '\0';
  494. m_op.pszAdUrl = NULL;
  495. #ifdef DEBUG
  496. m_dwThreadId = GetCurrentThreadId();
  497. #endif // DEBUG
  498. }
  499. //----------------------------------------------------------------------
  500. // CHTTPMailServer::~CHTTPMailServer
  501. //----------------------------------------------------------------------
  502. CHTTPMailServer::~CHTTPMailServer(void)
  503. {
  504. // Close the window
  505. if ((NULL != m_hwnd) && (FALSE != IsWindow(m_hwnd)))
  506. SendMessage(m_hwnd, WM_CLOSE, 0, 0);
  507. ZeroMemory(&m_rInetServerInfo, sizeof(m_rInetServerInfo)); // Done for security
  508. SafeRelease(m_pStore);
  509. SafeRelease(m_pFolder);
  510. SafeRelease(m_pTransport);
  511. SafeRelease(m_pTransport2);
  512. SafeRelease(m_pAccount);
  513. SafeMemFree(m_pszFldrLeafName);
  514. SafeMemFree(m_pszMsgFolderRoot);
  515. SafeMemFree(m_pszFolderUrl);
  516. }
  517. //----------------------------------------------------------------------
  518. // IUnknown Members
  519. //----------------------------------------------------------------------
  520. //----------------------------------------------------------------------
  521. // CHTTPMailServer::QueryInterface
  522. //----------------------------------------------------------------------
  523. STDMETHODIMP CHTTPMailServer::QueryInterface(REFIID riid, LPVOID *ppv)
  524. {
  525. HRESULT hr = S_OK;
  526. TraceCall("CHTTPMailServer::QueryInterface");
  527. if (NULL == ppv)
  528. {
  529. hr = E_INVALIDARG;
  530. goto exit;
  531. }
  532. if (IID_IUnknown == riid || IID_IMessageServer == riid)
  533. *ppv = (IMessageServer *)this;
  534. else if (IID_ITransportCallback == riid)
  535. *ppv = (ITransportCallback *)this;
  536. else if (IID_IHTTPMailCallback == riid)
  537. *ppv = (IHTTPMailCallback *)this;
  538. else
  539. {
  540. *ppv = NULL;
  541. hr = E_NOINTERFACE;
  542. goto exit;
  543. }
  544. // the interface was found. addref it
  545. ((IUnknown *)*ppv)->AddRef();
  546. exit:
  547. // done
  548. return hr;
  549. }
  550. //----------------------------------------------------------------------
  551. // CHTTPMailServer::AddRef
  552. //----------------------------------------------------------------------
  553. STDMETHODIMP_(ULONG) CHTTPMailServer::AddRef(void)
  554. {
  555. TraceCall("CHTTPMailServer::AddRef");
  556. return InterlockedIncrement(&m_cRef);
  557. }
  558. //----------------------------------------------------------------------
  559. // CHTTPMailServer::AddRef
  560. //----------------------------------------------------------------------
  561. STDMETHODIMP_(ULONG) CHTTPMailServer::Release(void)
  562. {
  563. TraceCall("CHTTPMailServer::Release");
  564. ULONG cRef = InterlockedDecrement(&m_cRef);
  565. Assert(((LONG)cRef) >= 0);
  566. if (0 == cRef)
  567. delete this;
  568. return cRef;
  569. }
  570. //----------------------------------------------------------------------
  571. // IMessageServer Members
  572. //----------------------------------------------------------------------
  573. //----------------------------------------------------------------------
  574. // CHTTPMailServer::Initialize
  575. //----------------------------------------------------------------------
  576. STDMETHODIMP CHTTPMailServer::Initialize( IMessageStore *pStore,
  577. FOLDERID idStoreRoot,
  578. IMessageFolder *pFolder,
  579. FOLDERID idFolder)
  580. {
  581. HRESULT hr = S_OK;
  582. FOLDERINFO fi;
  583. AssertSingleThreaded;
  584. if (NULL == pStore || FOLDERID_INVALID == idStoreRoot)
  585. return TraceResult(E_INVALIDARG);
  586. if (!_CreateWnd())
  587. return E_FAIL;
  588. m_idServer = idStoreRoot;
  589. m_idFolder = idFolder;
  590. ReplaceInterface(m_pFolder, pFolder);
  591. ReplaceInterface(m_pStore, pStore);
  592. if (FAILED(hr = m_pStore->GetFolderInfo(idStoreRoot, &fi)))
  593. goto exit;
  594. Assert(!!(fi.dwFlags & FOLDER_SERVER));
  595. StrCpyN(m_szAccountId, fi.pszAccountId, ARRAYSIZE(m_szAccountId));
  596. m_pStore->FreeRecord(&fi);
  597. // if we were passed a valid folder id, check to see if this folder is special?
  598. // we might get passed a bad folder id when we are syncing the store.
  599. if (FOLDERID_INVALID != idFolder)
  600. {
  601. if (FAILED(hr = m_pStore->GetFolderInfo(idFolder, &fi)))
  602. goto exit;
  603. m_tySpecialFolder = fi.tySpecial;
  604. m_pStore->FreeRecord(&fi);
  605. }
  606. exit:
  607. return hr;
  608. }
  609. STDMETHODIMP CHTTPMailServer::ResetFolder( IMessageFolder *pFolder,
  610. FOLDERID idFolder)
  611. {
  612. return(E_NOTIMPL);
  613. }
  614. //----------------------------------------------------------------------
  615. // CHTTPMailServer::SetIdleCallback
  616. //----------------------------------------------------------------------
  617. STDMETHODIMP CHTTPMailServer::SetIdleCallback(IStoreCallback *pDefaultCallback)
  618. {
  619. return E_NOTIMPL;
  620. }
  621. //----------------------------------------------------------------------
  622. // CHTTPMailServer::SynchronizeFolder
  623. //----------------------------------------------------------------------
  624. STDMETHODIMP CHTTPMailServer::SynchronizeFolder(
  625. SYNCFOLDERFLAGS dwFlags,
  626. DWORD cHeaders,
  627. IStoreCallback *pCallback)
  628. {
  629. TraceCall("CHTTPMailServer::SynchronizeFolder");
  630. AssertSingleThreaded;
  631. Assert(NULL != pCallback);
  632. Assert(SOT_INVALID == m_op.tyOperation);
  633. Assert(NULL != m_pStore);
  634. if (NULL == pCallback)
  635. return E_INVALIDARG;
  636. m_op.tyOperation = SOT_SYNC_FOLDER;
  637. m_op.iState = 0;
  638. m_op.pfnState = c_rgpfnSyncFolder;
  639. m_op.cState = ARRAYSIZE(c_rgpfnSyncFolder);
  640. m_op.dwSyncFlags = dwFlags;
  641. m_op.pCallback = pCallback;
  642. m_op.pCallback->AddRef();
  643. return _BeginDeferredOperation();
  644. }
  645. //----------------------------------------------------------------------
  646. // CHTTPMailServer::GetMessage
  647. //----------------------------------------------------------------------
  648. STDMETHODIMP CHTTPMailServer::GetMessage(
  649. MESSAGEID idMessage,
  650. IStoreCallback *pCallback)
  651. {
  652. HRESULT hr = S_OK;
  653. TraceCall("CHTTPMailServer::GetMessage");
  654. AssertSingleThreaded;
  655. Assert(NULL != pCallback);
  656. Assert(SOT_INVALID == m_op.tyOperation);
  657. Assert(NULL != m_pStore);
  658. if (NULL == pCallback)
  659. return E_INVALIDARG;
  660. if (FAILED(hr = CreatePersistentWriteStream(m_pFolder, &m_op.pMessageStream, &m_op.faStream)))
  661. goto exit;
  662. m_op.tyOperation = SOT_GET_MESSAGE;
  663. m_op.pfnState = c_rgpfnGetMessage;
  664. m_op.iState = 0;
  665. m_op.cState = ARRAYSIZE(c_rgpfnGetMessage);
  666. m_op.pCallback = pCallback;
  667. m_op.pCallback->AddRef();
  668. m_op.idMessage = idMessage;
  669. hr = _BeginDeferredOperation();
  670. exit:
  671. return hr;
  672. }
  673. //----------------------------------------------------------------------
  674. // CHTTPMailServer::PutMessage
  675. //----------------------------------------------------------------------
  676. STDMETHODIMP CHTTPMailServer::PutMessage(
  677. FOLDERID idFolder,
  678. MESSAGEFLAGS dwFlags,
  679. LPFILETIME pftReceived,
  680. IStream *pStream,
  681. IStoreCallback *pCallback)
  682. {
  683. TraceCall("CHTTPMailServer::PutMessage");
  684. AssertSingleThreaded;
  685. Assert(NULL != pCallback);
  686. Assert(SOT_INVALID == m_op.tyOperation);
  687. Assert(NULL != m_pStore);
  688. if (NULL == pStream || NULL == pCallback)
  689. return E_INVALIDARG;
  690. if (FOLDER_MSNPROMO == m_tySpecialFolder)
  691. return SP_E_HTTP_CANTMODIFYMSNFOLDER;
  692. m_op.tyOperation = SOT_PUT_MESSAGE;
  693. m_op.pfnState = c_rgpfnPutMessage;
  694. m_op.iState = 0;
  695. m_op.cState = ARRAYSIZE(c_rgpfnPutMessage);
  696. m_op.pCallback = pCallback;
  697. m_op.pCallback->AddRef();
  698. m_op.idFolder = idFolder;
  699. m_op.pMessageStream = pStream;
  700. m_op.pMessageStream->AddRef();
  701. m_op.dwMsgFlags = dwFlags;
  702. return _BeginDeferredOperation();
  703. }
  704. //----------------------------------------------------------------------
  705. // CHTTPMailServer::CopyMessages
  706. //----------------------------------------------------------------------
  707. STDMETHODIMP CHTTPMailServer::CopyMessages(
  708. IMessageFolder *pDest,
  709. COPYMESSAGEFLAGS dwOptions,
  710. LPMESSAGEIDLIST pList,
  711. LPADJUSTFLAGS pFlags,
  712. IStoreCallback *pCallback)
  713. {
  714. HRESULT hr = S_OK;
  715. FOLDERID idFolder;
  716. FOLDERINFO fi = {0};
  717. LPFOLDERINFO pfiFree = NULL;
  718. TraceCall("CHTTPMailServer::CopyMessages");
  719. if (NULL == pDest)
  720. return E_INVALIDARG;
  721. Assert(NULL != m_pStore);
  722. // disallow moving or copying into the msn promo folder
  723. IF_FAILEXIT(hr = pDest->GetFolderId(&idFolder));
  724. IF_FAILEXIT(hr = m_pStore->GetFolderInfo(idFolder, &fi));
  725. pfiFree = &fi;
  726. if (FOLDER_MSNPROMO == fi.tySpecial)
  727. {
  728. hr = TraceResult(SP_E_HTTP_CANTMODIFYMSNFOLDER);
  729. goto exit;
  730. }
  731. // convert moves out of the promo folder into copies
  732. if (FOLDER_MSNPROMO == m_tySpecialFolder)
  733. dwOptions = (dwOptions & ~COPY_MESSAGE_MOVE);
  734. hr = _DoCopyMoveMessages(SOT_COPYMOVE_MESSAGE, pDest, dwOptions, pList, pCallback);
  735. exit:
  736. if (NULL != pfiFree)
  737. m_pStore->FreeRecord(pfiFree);
  738. return hr;
  739. }
  740. //----------------------------------------------------------------------
  741. // CHTTPMailServer::DeleteMessages
  742. //----------------------------------------------------------------------
  743. STDMETHODIMP CHTTPMailServer::DeleteMessages(DELETEMESSAGEFLAGS dwOptions,
  744. LPMESSAGEIDLIST pList,
  745. IStoreCallback *pCallback)
  746. {
  747. TraceCall("CHTTPMailServer::DeleteMessages");
  748. AssertSingleThreaded;
  749. Assert(NULL == pList || pList->cMsgs > 0);
  750. Assert(SOT_INVALID == m_op.tyOperation);
  751. Assert(NULL != m_pStore);
  752. // we don't allow messages to be deleted out of the msnpromo folder
  753. if (FOLDER_MSNPROMO == m_tySpecialFolder)
  754. {
  755. // this is a hack. we test this flag to determine that the
  756. //operation is being performed as the last phase of a move
  757. // into a local folder. when this is the case, we fail
  758. // silently.
  759. if (!!(DELETE_MESSAGE_MAYIGNORENOTRASH & dwOptions))
  760. return S_OK;
  761. else
  762. return SP_E_HTTP_CANTMODIFYMSNFOLDER;
  763. }
  764. if ((NULL !=pList && 0 == pList->cMsgs) || NULL == pCallback)
  765. return E_INVALIDARG;
  766. HRESULT hr = S_OK;
  767. IMessageFolder *pDeletedItems = NULL;
  768. m_op.dwDelMsgFlags = dwOptions;
  769. // if the current folder is the deleted items folder, then delete the
  770. // messages, otherwise move them to deleted items
  771. if (FOLDER_DELETED != m_tySpecialFolder && !(dwOptions & DELETE_MESSAGE_NOTRASHCAN))
  772. {
  773. // find the deleted items folder
  774. if (SUCCEEDED(m_pStore->OpenSpecialFolder(m_idServer, NULL, FOLDER_DELETED, &pDeletedItems)) && NULL != pDeletedItems)
  775. {
  776. hr = _DoCopyMoveMessages(SOT_DELETING_MESSAGES, pDeletedItems, COPY_MESSAGE_MOVE, pList, pCallback);
  777. goto exit;
  778. }
  779. }
  780. // handle the case where the messages are not in the deleted items folder
  781. // if pList is null, apply the operation to the entire folder
  782. if (NULL != pList)
  783. hr = CloneMessageIDList(pList, &m_op.pIDList);
  784. else
  785. hr = m_pFolder->CreateRowset(IINDEX_PRIMARY, NOFLAGS, &m_op.hRowSet);
  786. if (FAILED(hr))
  787. goto exit;
  788. m_op.tyOperation = SOT_DELETING_MESSAGES;
  789. m_op.pfnState = c_rgpfnDeleteMessages;
  790. m_op.iState = 0;
  791. m_op.cState = ARRAYSIZE(c_rgpfnDeleteMessages);
  792. m_op.pCallback = pCallback;
  793. m_op.pCallback->AddRef();
  794. hr = _BeginDeferredOperation();
  795. exit:
  796. SafeRelease(pDeletedItems);
  797. return hr;
  798. }
  799. //----------------------------------------------------------------------
  800. // CHTTPMailServer::SetMessageFlags
  801. //----------------------------------------------------------------------
  802. STDMETHODIMP CHTTPMailServer::SetMessageFlags(
  803. LPMESSAGEIDLIST pList,
  804. LPADJUSTFLAGS pFlags,
  805. SETMESSAGEFLAGSFLAGS dwFlags,
  806. IStoreCallback *pCallback)
  807. {
  808. TraceCall("CHTTPMailServer::SetMessageFlags");
  809. AssertSingleThreaded;
  810. Assert(NULL == pList || pList->cMsgs > 0);
  811. Assert(NULL != pCallback);
  812. Assert(m_op.tyOperation == SOT_INVALID);
  813. Assert(m_pStore != NULL);
  814. if ((NULL !=pList && 0 == pList->cMsgs) || NULL == pFlags || NULL == pCallback)
  815. return E_INVALIDARG;
  816. // the only remote flag supported by httpmail is the "read" flag
  817. // it is an error to attempt to set or unset any other flag
  818. Assert(0 == (pFlags->dwRemove & ~ARF_READ));
  819. Assert(0 == (pFlags->dwAdd & ~ARF_READ));
  820. Assert((ARF_READ == (ARF_READ & pFlags->dwRemove)) || (ARF_READ == (ARF_READ & pFlags->dwAdd)));
  821. HRESULT hr = S_OK;
  822. // if pList is null, apply the operation to the entire folder
  823. if (NULL != pList)
  824. hr = CloneMessageIDList(pList, &m_op.pIDList);
  825. else
  826. hr = m_pFolder->CreateRowset(IINDEX_PRIMARY, NOFLAGS, &m_op.hRowSet);
  827. if (FAILED(hr))
  828. return hr;
  829. m_op.tyOperation = SOT_SET_MESSAGEFLAGS;
  830. m_op.pfnState = c_rgpfnSetMessageFlags;
  831. m_op.cState = ARRAYSIZE(c_rgpfnSetMessageFlags);
  832. m_op.iState = 0;
  833. m_op.pCallback = pCallback;
  834. m_op.pCallback->AddRef();
  835. m_op.fMarkRead = !!(pFlags->dwAdd & ARF_READ);
  836. m_op.dwSetFlags = dwFlags;
  837. return _BeginDeferredOperation();
  838. }
  839. //----------------------------------------------------------------------
  840. // CHTTPMailServer::GetServerMessageFlags
  841. //----------------------------------------------------------------------
  842. STDMETHODIMP CHTTPMailServer::GetServerMessageFlags(MESSAGEFLAGS *pFlags)
  843. {
  844. if (NULL == pFlags)
  845. return E_INVALIDARG;
  846. *pFlags = ARF_READ;
  847. return S_OK;
  848. }
  849. //----------------------------------------------------------------------
  850. // CHTTPMailServer::SynchronizeStore
  851. //----------------------------------------------------------------------
  852. STDMETHODIMP CHTTPMailServer::SynchronizeStore(
  853. FOLDERID idParent,
  854. SYNCSTOREFLAGS dwFlags,
  855. IStoreCallback *pCallback)
  856. {
  857. TraceCall("CHTTPMailServer::SynchronizeStore");
  858. AssertSingleThreaded;
  859. Assert(pCallback != NULL);
  860. Assert(m_op.tyOperation == SOT_INVALID);
  861. Assert(m_pStore != NULL);
  862. if (NULL == pCallback)
  863. return E_INVALIDARG;
  864. m_op.tyOperation = SOT_SYNCING_STORE;
  865. m_op.pfnState = c_rgpfnSyncStore;
  866. m_op.iState = 0;
  867. m_op.cState = ARRAYSIZE(c_rgpfnSyncStore);
  868. m_op.pCallback = pCallback;
  869. m_op.pCallback->AddRef();
  870. return _BeginDeferredOperation();
  871. }
  872. //----------------------------------------------------------------------
  873. // CHTTPMailServer::CreateFolder
  874. //----------------------------------------------------------------------
  875. STDMETHODIMP CHTTPMailServer::CreateFolder(
  876. FOLDERID idParent,
  877. SPECIALFOLDER tySpecial,
  878. LPCSTR pszName,
  879. FLDRFLAGS dwFlags,
  880. IStoreCallback *pCallback)
  881. {
  882. TraceCall("CHTTPMailServer::CreateFolder");
  883. AssertSingleThreaded;
  884. Assert(NULL != pCallback);
  885. Assert(m_op.tyOperation == SOT_INVALID);
  886. Assert(NULL != m_pStore);
  887. // why would we be called to create a special folder?
  888. Assert(FOLDER_NOTSPECIAL == tySpecial);
  889. if (NULL == pCallback || NULL == pszName)
  890. return E_INVALIDARG;
  891. // hotmail doesn't support hierarchical folders.
  892. Assert(m_idServer == idParent);
  893. if (m_idServer != idParent)
  894. return E_FAIL;
  895. m_op.pszFolderName = PszDupA(pszName);
  896. if (NULL == m_op.pszFolderName)
  897. return E_OUTOFMEMORY;
  898. m_op.tyOperation = SOT_CREATE_FOLDER;
  899. m_op.pfnState = c_rgpfnCreateFolder;
  900. m_op.iState = 0;
  901. m_op.cState = ARRAYSIZE(c_rgpfnCreateFolder);
  902. m_op.pCallback = pCallback;
  903. m_op.pCallback->AddRef();
  904. m_op.dwFldrFlags = dwFlags;
  905. return _BeginDeferredOperation();
  906. }
  907. //----------------------------------------------------------------------
  908. // CHTTPMailServer::MoveFolder
  909. //----------------------------------------------------------------------
  910. STDMETHODIMP CHTTPMailServer::MoveFolder(FOLDERID idFolder, FOLDERID idParentNew, IStoreCallback *pCallback)
  911. {
  912. return E_NOTIMPL;
  913. }
  914. //----------------------------------------------------------------------
  915. // CHTTPMailServer::RenameFolder
  916. //----------------------------------------------------------------------
  917. STDMETHODIMP CHTTPMailServer::RenameFolder(FOLDERID idFolder,
  918. LPCSTR pszName,
  919. IStoreCallback *pCallback)
  920. {
  921. TraceCall("CHTTPMailServer::RenameFolder");
  922. AssertSingleThreaded;
  923. Assert(NULL != pCallback);
  924. Assert(SOT_INVALID == m_op.tyOperation);
  925. Assert(NULL != m_pStore);
  926. Assert(NULL != pszName);
  927. // don't allow the user to rename the promo folder
  928. if (FOLDER_MSNPROMO == m_tySpecialFolder)
  929. return SP_E_HTTP_CANTMODIFYMSNFOLDER;
  930. if (NULL == pszName || NULL == pCallback)
  931. return E_INVALIDARG;
  932. m_op.pszFolderName = PszDupA(pszName);
  933. if (NULL == m_op.pszFolderName)
  934. {
  935. TraceResult(E_OUTOFMEMORY);
  936. return E_OUTOFMEMORY;
  937. }
  938. m_op.idFolder = idFolder;
  939. m_op.tyOperation = SOT_RENAME_FOLDER;
  940. m_op.iState = 0;
  941. m_op.pfnState = c_rgpfnRenameFolder;
  942. m_op.cState = ARRAYSIZE(c_rgpfnRenameFolder);
  943. m_op.pCallback = pCallback;
  944. m_op.pCallback->AddRef();
  945. return _BeginDeferredOperation();
  946. }
  947. //----------------------------------------------------------------------
  948. // CHTTPMailServer::DeleteFolder
  949. //----------------------------------------------------------------------
  950. STDMETHODIMP CHTTPMailServer::DeleteFolder(FOLDERID idFolder,
  951. DELETEFOLDERFLAGS dwFlags,
  952. IStoreCallback *pCallback)
  953. {
  954. TraceCall("CHTTPMailServer::DeleteFolder");
  955. AssertSingleThreaded;
  956. Assert(NULL != pCallback);
  957. Assert(SOT_INVALID == m_op.tyOperation);
  958. Assert(NULL != m_pStore);
  959. Assert(FOLDERID_INVALID != idFolder);
  960. // don't allow the user to delete the msn promo folder
  961. if (FOLDER_MSNPROMO == m_tySpecialFolder)
  962. return SP_E_HTTP_CANTMODIFYMSNFOLDER;
  963. // we don't support hierarchical folders - if we are asked to delete
  964. // the children of a folder, just return immediately
  965. if (!!(DELETE_FOLDER_CHILDRENONLY & dwFlags))
  966. return S_OK;
  967. if (NULL == pCallback || FOLDERID_INVALID == idFolder)
  968. return E_INVALIDARG;
  969. m_op.idFolder = idFolder;
  970. m_op.tyOperation = SOT_DELETE_FOLDER;
  971. m_op.iState = 0;
  972. m_op.pfnState = c_rgpfnDeleteFolder;
  973. m_op.cState = ARRAYSIZE(c_rgpfnDeleteFolder);
  974. m_op.pCallback = pCallback;
  975. m_op.pCallback->AddRef();
  976. return _BeginDeferredOperation();
  977. }
  978. //----------------------------------------------------------------------
  979. // CHTTPMailServer::SubscribeToFolder
  980. //----------------------------------------------------------------------
  981. STDMETHODIMP CHTTPMailServer::SubscribeToFolder(FOLDERID idFolder, BOOL fSubscribe, IStoreCallback *pCallback)
  982. {
  983. return E_NOTIMPL;
  984. }
  985. //----------------------------------------------------------------------
  986. // CHTTPMailServer::Close
  987. //----------------------------------------------------------------------
  988. STDMETHODIMP CHTTPMailServer::Close(DWORD dwFlags)
  989. {
  990. // if we are processing a command, cancel it
  991. Cancel(CT_CANCEL);
  992. if (dwFlags & MSGSVRF_DROP_CONNECTION)
  993. _SetConnected(FALSE);
  994. if (dwFlags & MSGSVRF_HANDS_OFF_SERVER)
  995. {
  996. if (m_pTransport)
  997. {
  998. m_pTransport->DropConnection();
  999. m_pTransport->HandsOffCallback();
  1000. m_pTransport->Release();
  1001. m_pTransport = NULL;
  1002. }
  1003. }
  1004. return S_OK;
  1005. }
  1006. //----------------------------------------------------------------------
  1007. // CHTTPMailServer::GetFolderCounts
  1008. //----------------------------------------------------------------------
  1009. STDMETHODIMP CHTTPMailServer::GetFolderCounts(FOLDERID idFolder, IStoreCallback *pCallback)
  1010. {
  1011. return E_NOTIMPL;
  1012. }
  1013. //----------------------------------------------------------------------
  1014. // CHTTPMailServer::GetNewGroups
  1015. //----------------------------------------------------------------------
  1016. STDMETHODIMP CHTTPMailServer::GetNewGroups(LPSYSTEMTIME pSysTime, IStoreCallback *pCallback)
  1017. {
  1018. return E_NOTIMPL;
  1019. }
  1020. //----------------------------------------------------------------------
  1021. // CHTTPMailServer::OnLogonPrompt
  1022. //----------------------------------------------------------------------
  1023. STDMETHODIMP CHTTPMailServer::OnLogonPrompt(
  1024. LPINETSERVER pInetServer,
  1025. IInternetTransport *pTransport)
  1026. {
  1027. HRESULT hr = S_OK;
  1028. LPSTR pszCachedPassword = NULL;
  1029. INETSERVER rInetServer;
  1030. TraceCall("CHTTPMailServer::OnLogonPrompt");
  1031. AssertSingleThreaded;
  1032. Assert(pInetServer != NULL);
  1033. Assert(pTransport != NULL);
  1034. Assert(m_op.tyOperation != SOT_INVALID);
  1035. Assert(m_op.pCallback != NULL);
  1036. // pull password out of the cache
  1037. GetAccountPropStrA(m_szAccountId, CAP_PASSWORD, &pszCachedPassword);
  1038. if (NULL != pszCachedPassword && 0 != lstrcmp(pszCachedPassword, pInetServer->szPassword))
  1039. {
  1040. StrCpyN(pInetServer->szPassword, pszCachedPassword, ARRAYSIZE(pInetServer->szPassword));
  1041. goto exit;
  1042. }
  1043. hr = m_op.pCallback->OnLogonPrompt(pInetServer, IXP_HTTPMail);
  1044. if (S_OK == hr)
  1045. {
  1046. // cache the password
  1047. HrCacheAccountPropStrA(m_szAccountId, CAP_PASSWORD, pInetServer->szPassword);
  1048. // copy the new username and password into our local server info
  1049. StrCpyN(m_rInetServerInfo.szPassword, pInetServer->szPassword, ARRAYSIZE(m_rInetServerInfo.szPassword));
  1050. StrCpyN(m_rInetServerInfo.szUserName, pInetServer->szUserName, ARRAYSIZE(m_rInetServerInfo.szUserName));
  1051. }
  1052. exit:
  1053. SafeMemFree(pszCachedPassword);
  1054. return hr;
  1055. }
  1056. //----------------------------------------------------------------------
  1057. // CHTTPMailServer::OnPrompt
  1058. //----------------------------------------------------------------------
  1059. STDMETHODIMP_(INT) CHTTPMailServer::OnPrompt(
  1060. HRESULT hrError,
  1061. LPCTSTR pszText,
  1062. LPCTSTR pszCaption,
  1063. UINT uType,
  1064. IInternetTransport *pTransport)
  1065. {
  1066. return 0;
  1067. }
  1068. //----------------------------------------------------------------------
  1069. // CHTTPMailServer::OnStatus
  1070. //----------------------------------------------------------------------
  1071. STDMETHODIMP CHTTPMailServer::OnStatus(
  1072. IXPSTATUS ixpstatus,
  1073. IInternetTransport *pTransport)
  1074. {
  1075. // Stack
  1076. TraceCall("CHTTPMailServer::OnStatus");
  1077. AssertSingleThreaded;
  1078. // If we were disconnected, then clean up some internal state.
  1079. if (IXP_DISCONNECTED == ixpstatus)
  1080. {
  1081. if (m_op.tyOperation != SOT_INVALID)
  1082. {
  1083. Assert(m_op.pCallback != NULL);
  1084. if (m_op.fCancel && !m_op.fNotifiedComplete)
  1085. {
  1086. IXPRESULT rIxpResult;
  1087. // Fake an IXPRESULT
  1088. ZeroMemory(&rIxpResult, sizeof(rIxpResult));
  1089. rIxpResult.hrResult = STORE_E_OPERATION_CANCELED;
  1090. // Return meaningful error information
  1091. _FillStoreError(&m_op.error, &rIxpResult);
  1092. Assert(STORE_E_OPERATION_CANCELED == m_op.error.hrResult);
  1093. m_op.fNotifiedComplete = TRUE;
  1094. m_op.pCallback->OnComplete(m_op.tyOperation, m_op.error.hrResult, NULL, &m_op.error);
  1095. _FreeOperation();
  1096. }
  1097. }
  1098. m_fConnected = FALSE;
  1099. }
  1100. return(S_OK);
  1101. }
  1102. //----------------------------------------------------------------------
  1103. // CHTTPMailServer::OnError
  1104. //----------------------------------------------------------------------
  1105. STDMETHODIMP CHTTPMailServer::OnError(
  1106. IXPSTATUS ixpstatus,
  1107. LPIXPRESULT pIxpResult,
  1108. IInternetTransport *pTransport)
  1109. {
  1110. return E_NOTIMPL;
  1111. }
  1112. //----------------------------------------------------------------------
  1113. // CHTTPMailServer::OnProgress
  1114. //----------------------------------------------------------------------
  1115. STDMETHODIMP CHTTPMailServer::OnProgress(
  1116. DWORD dwIncrement,
  1117. DWORD dwCurrent,
  1118. DWORD dwMaximum,
  1119. IInternetTransport *pTransport)
  1120. {
  1121. return E_NOTIMPL;
  1122. }
  1123. //----------------------------------------------------------------------
  1124. // CHTTPMailServer::OnCommand
  1125. //----------------------------------------------------------------------
  1126. STDMETHODIMP CHTTPMailServer::OnCommand(
  1127. CMDTYPE cmdtype,
  1128. LPSTR pszLine,
  1129. HRESULT hrResponse,
  1130. IInternetTransport *pTransport)
  1131. {
  1132. return E_NOTIMPL;
  1133. }
  1134. //----------------------------------------------------------------------
  1135. // CHTTPMailServer::OnTimeout
  1136. //----------------------------------------------------------------------
  1137. STDMETHODIMP CHTTPMailServer::OnTimeout(
  1138. DWORD *pdwTimeout,
  1139. IInternetTransport *pTransport)
  1140. {
  1141. return E_NOTIMPL;
  1142. }
  1143. //----------------------------------------------------------------------
  1144. // CHTTPMailServer::OnResponse
  1145. //----------------------------------------------------------------------
  1146. STDMETHODIMP CHTTPMailServer::OnResponse(
  1147. LPHTTPMAILRESPONSE pResponse)
  1148. {
  1149. HRESULT hr = S_OK;
  1150. HRESULT hrResponse;
  1151. HRESULT hrSaved;
  1152. BOOL fInvokeResponseHandler = TRUE;
  1153. AssertSingleThreaded;
  1154. Assert(SOT_INVALID != m_op.tyOperation);
  1155. if (!m_op.fCancel && !m_op.fNotifiedComplete &&
  1156. (SOT_GET_ADURL == m_op.tyOperation || SOT_GET_HTTP_MINPOLLINGINTERVAL == m_op.tyOperation))
  1157. {
  1158. STOREOPERATIONINFO StoreInfo = {0};
  1159. m_op.fNotifiedComplete = TRUE;
  1160. if (SOT_GET_ADURL == m_op.tyOperation)
  1161. {
  1162. StoreInfo.pszUrl = pResponse->rGetPropInfo.pszProp;
  1163. pResponse->rGetPropInfo.pszProp = NULL;
  1164. }
  1165. if (SOT_GET_HTTP_MINPOLLINGINTERVAL == m_op.tyOperation)
  1166. {
  1167. StoreInfo.dwMinPollingInterval = pResponse->rGetPropInfo.dwProp;
  1168. }
  1169. m_op.pCallback->OnComplete(m_op.tyOperation, pResponse->rIxpResult.hrResult, &StoreInfo, NULL);
  1170. _FreeOperation();
  1171. MemFree(StoreInfo.pszUrl);
  1172. goto cleanup;
  1173. }
  1174. if (FAILED(pResponse->rIxpResult.hrResult))
  1175. {
  1176. Assert(pResponse->fDone);
  1177. // Hotmail hack. Hotmail does not support deleting message. This interferes with operations
  1178. // such as moving messages from a hotmail folder into the local store. we attempt to send
  1179. // a delete to the server, since we don't know whether or not the server supports the command.
  1180. // if it fails, we check the delete messages flag to determine if we are allowed to fallback
  1181. // to a move operation.
  1182. if (SOT_DELETING_MESSAGES == m_op.tyOperation &&
  1183. (HTTPMAIL_DELETE == pResponse->command || HTTPMAIL_BDELETE == pResponse->command) &&
  1184. IXP_E_HTTP_METHOD_NOT_ALLOW == pResponse->rIxpResult.hrResult &&
  1185. FOLDER_DELETED != m_tySpecialFolder &&
  1186. !!(m_op.dwDelMsgFlags & DELETE_MESSAGE_MAYIGNORENOTRASH))
  1187. {
  1188. m_op.fFallbackToMove = TRUE;
  1189. fInvokeResponseHandler = FALSE;
  1190. // cache the fact that this acct doesn't support msg delete so we don't
  1191. // have to go through this nonsense again
  1192. HrCacheAccountPropStrA(m_szAccountId, CAP_HTTPNOMESSAGEDELETES, "TRUE");
  1193. }
  1194. else
  1195. {
  1196. hrSaved = pResponse->rIxpResult.hrResult;
  1197. if (IXP_E_HTTP_ROOT_PROP_NOT_FOUND == hrSaved)
  1198. pResponse->rIxpResult.hrResult = SP_E_HTTP_SERVICEDOESNTWORK;
  1199. else if ((HTTPMAIL_DELETE == pResponse->command || HTTPMAIL_BDELETE == pResponse->command) && IXP_E_HTTP_METHOD_NOT_ALLOW == hrSaved)
  1200. pResponse->rIxpResult.hrResult = SP_E_HTTP_NODELETESUPPORT;
  1201. _FillStoreError(&m_op.error, &pResponse->rIxpResult);
  1202. pResponse->rIxpResult.hrResult = hrSaved;
  1203. if (!m_op.fNotifiedComplete)
  1204. {
  1205. m_op.fNotifiedComplete = TRUE;
  1206. m_op.pCallback->OnComplete(m_op.tyOperation, m_op.error.hrResult, NULL, &m_op.error);
  1207. _FreeOperation();
  1208. }
  1209. return S_OK;
  1210. }
  1211. }
  1212. Assert(NULL != m_op.pfnState[m_op.iState].pfnResp);
  1213. // by default, state advances occur when the the response indicates
  1214. // that io is done. response functions can override this behavior
  1215. // by setting fStateWillAdvance to FALSE to maintain the current state.
  1216. m_op.fStateWillAdvance = pResponse->fDone;
  1217. // invoke the response function
  1218. if (fInvokeResponseHandler)
  1219. hr = (this->*(m_op.pfnState[m_op.iState].pfnResp))(pResponse);
  1220. cleanup:
  1221. if (FAILED(hr))
  1222. {
  1223. if (_FConnected())
  1224. {
  1225. m_pTransport->DropConnection();
  1226. m_pTransport->HandsOffCallback();
  1227. SafeRelease(m_pTransport);
  1228. }
  1229. if (!m_op.fNotifiedComplete)
  1230. {
  1231. m_op.fNotifiedComplete = TRUE;
  1232. m_op.pCallback->OnComplete(m_op.tyOperation, hr, NULL, NULL);
  1233. _FreeOperation();
  1234. }
  1235. }
  1236. else if (SUCCEEDED(hr) && m_op.fStateWillAdvance)
  1237. {
  1238. m_op.iState++;
  1239. _DoOperation();
  1240. }
  1241. return S_OK;
  1242. }
  1243. //----------------------------------------------------------------------
  1244. // CHTTPMailServer::GetParentWindow
  1245. //----------------------------------------------------------------------
  1246. HRESULT CHTTPMailServer::GetParentWindow(HWND *phwndParent)
  1247. {
  1248. HRESULT hr = E_FAIL;
  1249. AssertSingleThreaded;
  1250. if (m_op.tyOperation != SOT_INVALID && NULL != m_op.pCallback)
  1251. hr = m_op.pCallback->GetParentWindow(0, phwndParent);
  1252. return hr;
  1253. }
  1254. //----------------------------------------------------------------------
  1255. // IOperationCancel Members
  1256. //----------------------------------------------------------------------
  1257. //----------------------------------------------------------------------
  1258. // CHTTPMailServer::Cancel
  1259. //----------------------------------------------------------------------
  1260. STDMETHODIMP CHTTPMailServer::Cancel(CANCELTYPE tyCancel)
  1261. {
  1262. if (m_op.tyOperation != SOT_INVALID)
  1263. {
  1264. m_op.fCancel = TRUE;
  1265. _Disconnect();
  1266. }
  1267. return S_OK;
  1268. }
  1269. //----------------------------------------------------------------------
  1270. // CHTTPMailServer Implementation
  1271. //----------------------------------------------------------------------
  1272. // --------------------------------------------------------------------------------
  1273. // CHTTPMailServer::_CreateWnd
  1274. // --------------------------------------------------------------------------------
  1275. BOOL CHTTPMailServer::_CreateWnd()
  1276. {
  1277. WNDCLASS wc;
  1278. IxpAssert(!m_hwnd);
  1279. if (m_hwnd)
  1280. return TRUE;
  1281. if (!GetClassInfo(g_hInst, s_szHTTPMailServerWndClass, &wc))
  1282. {
  1283. wc.style = 0;
  1284. wc.lpfnWndProc = CHTTPMailServer::_WndProc;
  1285. wc.cbClsExtra = 0;
  1286. wc.cbWndExtra = 0;
  1287. wc.hInstance = g_hInst;
  1288. wc.hIcon = NULL;
  1289. wc.hCursor = NULL;
  1290. wc.hbrBackground = NULL;
  1291. wc.lpszMenuName = NULL;
  1292. wc.lpszClassName = s_szHTTPMailServerWndClass;
  1293. RegisterClass(&wc);
  1294. }
  1295. m_hwnd = CreateWindowEx(WS_EX_TOPMOST,
  1296. s_szHTTPMailServerWndClass,
  1297. s_szHTTPMailServerWndClass,
  1298. WS_POPUP,
  1299. CW_USEDEFAULT,
  1300. CW_USEDEFAULT,
  1301. CW_USEDEFAULT,
  1302. CW_USEDEFAULT,
  1303. NULL,
  1304. NULL,
  1305. g_hInst,
  1306. (LPVOID)this);
  1307. return (NULL != m_hwnd);
  1308. }
  1309. // --------------------------------------------------------------------------------
  1310. // CHTTPMailServer::_WndProc
  1311. // --------------------------------------------------------------------------------
  1312. LRESULT CALLBACK CHTTPMailServer::_WndProc(HWND hwnd,
  1313. UINT msg,
  1314. WPARAM wParam,
  1315. LPARAM lParam)
  1316. {
  1317. CHTTPMailServer *pThis = (CHTTPMailServer*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  1318. LRESULT lr = 0;
  1319. switch (msg)
  1320. {
  1321. case WM_NCCREATE:
  1322. IxpAssert(!pThis);
  1323. pThis = (CHTTPMailServer*)((LPCREATESTRUCT)lParam)->lpCreateParams;
  1324. SetWindowLongPtr(hwnd, GWLP_USERDATA, (LPARAM)pThis);
  1325. lr = DefWindowProc(hwnd, msg, wParam, lParam);
  1326. break;
  1327. case WM_HTTP_BEGIN_OP:
  1328. IxpAssert(pThis);
  1329. pThis->_DoOperation();
  1330. break;
  1331. default:
  1332. lr = DefWindowProc(hwnd, msg, wParam, lParam);
  1333. break;
  1334. }
  1335. return lr;
  1336. }
  1337. //----------------------------------------------------------------------
  1338. // CHTTPMailServer::_BeginDeferredOperation
  1339. //----------------------------------------------------------------------
  1340. HRESULT CHTTPMailServer::_BeginDeferredOperation(void)
  1341. {
  1342. return (PostMessage(m_hwnd, WM_HTTP_BEGIN_OP, 0, 0) ? E_PENDING : E_FAIL);
  1343. }
  1344. //----------------------------------------------------------------------
  1345. // CHTTPMailServer::HandleGetMsgFolderRoot
  1346. //----------------------------------------------------------------------
  1347. HRESULT CHTTPMailServer::HandleGetMsgFolderRoot(LPHTTPMAILRESPONSE pResponse)
  1348. {
  1349. HRESULT hr = S_OK;
  1350. Assert(HTTPMAIL_GETPROP == pResponse->command);
  1351. Assert(NULL == m_pszMsgFolderRoot);
  1352. Assert(HTTPMAIL_PROP_MSGFOLDERROOT == pResponse->rGetPropInfo.type);
  1353. if (NULL == pResponse->rGetPropInfo.pszProp)
  1354. {
  1355. hr = E_FAIL;
  1356. goto exit;
  1357. }
  1358. m_pszMsgFolderRoot = pResponse->rGetPropInfo.pszProp;
  1359. pResponse->rGetPropInfo.pszProp = NULL;
  1360. // add it to the account data cache
  1361. HrCacheAccountPropStrA(m_szAccountId, CAP_HTTPMAILMSGFOLDERROOT, m_pszMsgFolderRoot);
  1362. exit:
  1363. return hr;
  1364. }
  1365. //----------------------------------------------------------------------
  1366. // CHTTPMailServer::HandleListFolders
  1367. //----------------------------------------------------------------------
  1368. HRESULT CHTTPMailServer::HandleListFolders(LPHTTPMAILRESPONSE pResponse)
  1369. {
  1370. HRESULT hr = S_OK;
  1371. SPECIALFOLDER tySpecial = FOLDER_NOTSPECIAL;
  1372. FOLDERINFO fiNewFolder;
  1373. FOLDERID idFound = FOLDERID_INVALID;
  1374. LPHTTPMEMBERINFOLIST pMemberList = &pResponse->rMemberInfoList;
  1375. LPHTTPMEMBERINFO pMemberInfo;
  1376. CHAR szUrlComponent[MAX_PATH];
  1377. DWORD dwUrlComponentLen;
  1378. CHAR szSpecialFolder[CCHMAX_STRINGRES];
  1379. DWORD cMessages;
  1380. DWORD cUnread;
  1381. FOLDERINFO fi = {0};
  1382. for (ULONG ulIndex = 0; ulIndex < pMemberList->cMemberInfo; ++ulIndex)
  1383. {
  1384. idFound = FOLDERID_INVALID;
  1385. pMemberInfo = &pMemberList->prgMemberInfo[ulIndex];
  1386. // skip anything that isn't a folder
  1387. if (!pMemberInfo->fIsFolder)
  1388. continue;
  1389. dwUrlComponentLen = ARRAYSIZE(szUrlComponent);
  1390. IF_FAILEXIT(hr = Http_NameFromUrl(pMemberInfo->pszHref, szUrlComponent, &dwUrlComponentLen));
  1391. // [shaheedp] Bug# 84477
  1392. // If szUrlComponent is null, then we should not be adding this folder to the store.
  1393. if (!(*szUrlComponent))
  1394. {
  1395. hr = E_FAIL;
  1396. goto exit;
  1397. }
  1398. // if we've found a reserved folder, translate the httpmail
  1399. // special folder constant into the equivalent oe store
  1400. // special folder type.
  1401. tySpecial = _TranslateHTTPSpecialFolderType(pMemberInfo->tySpecial);
  1402. if (FOLDER_NOTSPECIAL != tySpecial)
  1403. idFound = m_op.pFolderList->FindAndRemove(tySpecial, &cMessages, &cUnread);
  1404. // if the folder wasn't found, try to find it by name
  1405. if (FOLDERID_INVALID == idFound)
  1406. {
  1407. idFound = m_op.pFolderList->FindAndRemove(szUrlComponent, &cMessages, &cUnread);
  1408. // if it still wasn't found, then add it
  1409. if (FOLDERID_INVALID == idFound)
  1410. {
  1411. // fill in the folderinfo
  1412. ZeroMemory(&fiNewFolder, sizeof(FOLDERINFO));
  1413. fiNewFolder.idParent = m_idServer;
  1414. fiNewFolder.tySpecial = tySpecial;
  1415. fiNewFolder.tyFolder = FOLDER_HTTPMAIL;
  1416. fiNewFolder.pszName = pMemberInfo->pszDisplayName;
  1417. if (FOLDER_NOTSPECIAL != tySpecial)
  1418. {
  1419. if (_LoadSpecialFolderName(tySpecial, szSpecialFolder, sizeof(szSpecialFolder)))
  1420. fiNewFolder.pszName = szSpecialFolder;
  1421. }
  1422. fiNewFolder.pszUrlComponent = szUrlComponent;
  1423. fiNewFolder.dwFlags = (FOLDER_SUBSCRIBED | FOLDER_NOCHILDCREATE);
  1424. // message counts
  1425. fiNewFolder.cMessages = pMemberInfo->dwVisibleCount;
  1426. fiNewFolder.cUnread = pMemberInfo->dwUnreadCount;
  1427. if (tySpecial == FOLDER_INBOX)
  1428. fiNewFolder.dwFlags |= FOLDER_DOWNLOADALL;
  1429. // Add the folder to the store
  1430. IF_FAILEXIT(hr = m_pStore->CreateFolder(NOFLAGS, &fiNewFolder, NULL));
  1431. }
  1432. }
  1433. // if the folder was found, update its message counts
  1434. if (FOLDERID_INVALID != idFound)
  1435. {
  1436. if (SUCCEEDED(hr = m_pStore->GetFolderInfo(idFound, &fi)))
  1437. {
  1438. BOOL bUpdate = FALSE;
  1439. // only update folders that changed. always update the MSN_PROMO folder.
  1440. // [shaheedp] Bug# 84477
  1441. // If the folder's pszUrlComponent was null or it is different, then reset it.
  1442. if ((fi.pszUrlComponent == NULL) ||
  1443. (lstrcmpi(fi.pszUrlComponent, szUrlComponent)))
  1444. {
  1445. bUpdate = TRUE;
  1446. fi.pszUrlComponent = szUrlComponent;
  1447. }
  1448. if ((FOLDER_MSNPROMO == tySpecial) ||
  1449. (cMessages != pMemberInfo->dwVisibleCount) ||
  1450. (cUnread != pMemberInfo->dwUnreadCount))
  1451. {
  1452. fi.cMessages = pMemberInfo->dwVisibleCount;
  1453. // special handling for the promo folder - messages on the
  1454. // server are never marked unread.
  1455. if (FOLDER_MSNPROMO == fi.tySpecial)
  1456. {
  1457. // we attempt to approximate the number of unread msgs in
  1458. // the promo folder. we assume that the server will not track
  1459. // the read/unread state of promo messages. we figure out how
  1460. // many messages were read before we got the new counts, and
  1461. // subtract that number from the current number of visible
  1462. // messages to get the unread count. this number will not always
  1463. // be accurate, but since all we know is the counts, and we
  1464. // don't know how the count changed (additions vs deletions),
  1465. // this is the best we can do and it always errors on the side
  1466. // of a too-small count to avoid bothering the user with
  1467. // unread counts when no unread msgs exist.
  1468. DWORD dwReadMessages = cMessages - cUnread;
  1469. if (fi.cMessages > dwReadMessages)
  1470. fi.cUnread = fi.cMessages - dwReadMessages;
  1471. else
  1472. fi.cUnread = 0;
  1473. }
  1474. else
  1475. fi.cUnread = pMemberInfo->dwUnreadCount;
  1476. if (cMessages != fi.cMessages || cUnread != fi.cUnread)
  1477. bUpdate = TRUE;
  1478. }
  1479. if (bUpdate)
  1480. m_pStore->UpdateRecord(&fi);
  1481. m_pStore->FreeRecord(&fi);
  1482. }
  1483. }
  1484. // if we are syncing the store, notify the client of our progress
  1485. if (SOT_SYNCING_STORE == m_op.tyOperation && NULL != m_op.pCallback)
  1486. m_op.pCallback->OnProgress(
  1487. SOT_SYNCING_STORE,
  1488. 0,
  1489. 0,
  1490. m_rInetServerInfo.szServerName);
  1491. }
  1492. IF_FAILEXIT(hr = m_pAccount->SetPropSz(AP_HTTPMAIL_ROOTTIMESTAMP, pMemberList->pszRootTimeStamp));
  1493. IF_FAILEXIT(hr = m_pAccount->SetPropSz(AP_HTTPMAIL_ROOTINBOXTIMESTAMP, pMemberList->pszFolderTimeStamp));
  1494. exit:
  1495. return hr;
  1496. }
  1497. //----------------------------------------------------------------------
  1498. // CHTTPMailServer::HandleGetMessage
  1499. //----------------------------------------------------------------------
  1500. HRESULT CHTTPMailServer::HandleGetMessage(LPHTTPMAILRESPONSE pResponse)
  1501. {
  1502. HRESULT hr;
  1503. IF_FAILEXIT(hr = m_op.pMessageStream->Write(
  1504. pResponse->rGetInfo.pvBody,
  1505. pResponse->rGetInfo.cbIncrement,
  1506. NULL));
  1507. if (m_op.pCallback && pResponse->rGetInfo.cbTotal > 0)
  1508. {
  1509. m_op.pCallback->OnProgress(m_op.tyOperation,
  1510. pResponse->rGetInfo.cbCurrent,
  1511. pResponse->rGetInfo.cbTotal,
  1512. NULL);
  1513. }
  1514. // if not done yet, bail out
  1515. if (!pResponse->fDone)
  1516. goto exit;
  1517. // we're done...write the stream out
  1518. hr = Http_SetMessageStream(m_pFolder, m_op.idMessage, m_op.pMessageStream, &m_op.faStream, FALSE);
  1519. exit:
  1520. return hr;
  1521. }
  1522. //----------------------------------------------------------------------
  1523. // CHTTPMailServer::_DoOperation
  1524. //----------------------------------------------------------------------
  1525. HRESULT CHTTPMailServer::_DoOperation(void)
  1526. {
  1527. HRESULT hr = S_OK;
  1528. STOREOPERATIONINFO soi = { sizeof(STOREOPERATIONINFO), MESSAGEID_INVALID };
  1529. STOREOPERATIONINFO *psoi = NULL;
  1530. BOOL fCallComplete = TRUE;
  1531. if (m_op.tyOperation == SOT_INVALID)
  1532. return E_FAIL;
  1533. Assert(m_op.tyOperation != SOT_INVALID);
  1534. Assert(m_op.pfnState != NULL);
  1535. Assert(m_op.cState > 0);
  1536. Assert(m_op.iState <= m_op.cState);
  1537. if (m_op.iState == 0)
  1538. {
  1539. if (m_op.tyOperation == SOT_GET_MESSAGE)
  1540. {
  1541. // provide message id on get message start
  1542. soi.idMessage = m_op.idMessage;
  1543. psoi = &soi;
  1544. }
  1545. if (m_op.tyOperation == SOT_GET_ADURL)
  1546. m_op.pszAdUrl = NULL;
  1547. m_op.pCallback->OnBegin(m_op.tyOperation, psoi, (IOperationCancel *)this);
  1548. }
  1549. while (m_op.iState < m_op.cState)
  1550. {
  1551. hr = (this->*(m_op.pfnState[m_op.iState].pfnOp))();
  1552. if (FAILED(hr))
  1553. break;
  1554. m_op.iState++;
  1555. }
  1556. if ((m_op.iState == m_op.cState) || (FAILED(hr) && hr != E_PENDING))
  1557. {
  1558. LPSTOREERROR perr = NULL;
  1559. // provide message id
  1560. if (m_op.tyOperation == SOT_PUT_MESSAGE && MESSAGEID_INVALID != m_op.idPutMessage)
  1561. {
  1562. soi.idMessage = m_op.idPutMessage;
  1563. psoi = &soi;
  1564. }
  1565. switch (m_op.tyOperation)
  1566. {
  1567. case SOT_GET_ADURL:
  1568. {
  1569. if (SUCCEEDED(hr))
  1570. {
  1571. psoi = &soi;
  1572. psoi->pszUrl = m_op.pszAdUrl;
  1573. }
  1574. else
  1575. {
  1576. psoi = NULL;
  1577. fCallComplete = FALSE;
  1578. }
  1579. perr = NULL;
  1580. break;
  1581. }
  1582. case SOT_GET_HTTP_MINPOLLINGINTERVAL:
  1583. {
  1584. if (SUCCEEDED(hr))
  1585. {
  1586. psoi = &soi;
  1587. psoi->dwMinPollingInterval = m_op.dwMinPollingInterval;
  1588. }
  1589. else
  1590. {
  1591. psoi = NULL;
  1592. fCallComplete = FALSE;
  1593. }
  1594. perr = NULL;
  1595. break;
  1596. }
  1597. default:
  1598. {
  1599. if (FAILED(hr))
  1600. {
  1601. IXPRESULT rIxpResult;
  1602. // Fake an IXPRESULT
  1603. ZeroMemory(&rIxpResult, sizeof(rIxpResult));
  1604. rIxpResult.hrResult = hr;
  1605. // Return meaningful error information
  1606. _FillStoreError(&m_op.error, &rIxpResult);
  1607. Assert(m_op.error.hrResult == hr);
  1608. }
  1609. else
  1610. m_op.error.hrResult = hr;
  1611. if (!m_op.fNotifiedComplete)
  1612. perr = &m_op.error;
  1613. break;
  1614. }
  1615. }
  1616. if (!m_op.fNotifiedComplete && fCallComplete)
  1617. {
  1618. m_op.fNotifiedComplete = TRUE;
  1619. m_op.pCallback->OnComplete(m_op.tyOperation, hr, psoi, perr);
  1620. _FreeOperation();
  1621. }
  1622. }
  1623. return hr;
  1624. }
  1625. //----------------------------------------------------------------------
  1626. // CHTTPMailServer::_FreeOperation
  1627. //----------------------------------------------------------------------
  1628. void CHTTPMailServer::_FreeOperation(BOOL fValidState)
  1629. {
  1630. if (fValidState)
  1631. {
  1632. if (m_op.pCallback != NULL)
  1633. m_op.pCallback->Release();
  1634. if (m_op.pFolderList != NULL)
  1635. m_op.pFolderList->Release();
  1636. if (m_op.pMessageFolder)
  1637. m_op.pMessageFolder->Release();
  1638. SafeMemFree(m_op.pszProblem);
  1639. if (0 != m_op.faStream)
  1640. {
  1641. Assert(m_pFolder);
  1642. m_pFolder->DeleteStream(m_op.faStream);
  1643. }
  1644. if (m_op.pMessageStream)
  1645. m_op.pMessageStream->Release();
  1646. if (m_op.pmapMessageId)
  1647. delete m_op.pmapMessageId;
  1648. if (m_op.psaNewMessages)
  1649. delete m_op.psaNewMessages;
  1650. if (m_op.pPropPatchRequest)
  1651. m_op.pPropPatchRequest->Release();
  1652. SafeMemFree(m_op.pszDestFolderUrl);
  1653. SafeMemFree(m_op.pszDestUrl);
  1654. SafeMemFree(m_op.pIDList);
  1655. if (NULL != m_op.hRowSet)
  1656. m_pFolder->CloseRowset(&m_op.hRowSet);
  1657. SafeMemFree(m_op.pszFolderName);
  1658. if (m_op.pTargets)
  1659. Http_FreeTargetList(m_op.pTargets);
  1660. SafeMemFree(m_op.pszAdUrl);
  1661. }
  1662. ZeroMemory(&m_op, sizeof(HTTPOPERATION));
  1663. m_op.tyOperation = SOT_INVALID;
  1664. m_op.idPutMessage = MESSAGEID_INVALID;
  1665. }
  1666. //----------------------------------------------------------------------
  1667. // CHTTPMailServer::Connect
  1668. //----------------------------------------------------------------------
  1669. HRESULT CHTTPMailServer::Connect()
  1670. {
  1671. HRESULT hr = S_OK;
  1672. INETSERVER rInetServerInfo;
  1673. BOOL fInetInit = FALSE;
  1674. LPSTR pszCache = NULL;
  1675. AssertSingleThreaded;
  1676. Assert(m_op.pCallback != NULL);
  1677. if (!m_pAccount)
  1678. {
  1679. IF_FAILEXIT(hr = g_pAcctMan->FindAccount(AP_ACCOUNT_ID, m_szAccountId, &m_pAccount));
  1680. IF_FAILEXIT(hr = _LoadAccountInfo(m_pAccount));
  1681. }
  1682. if (_FConnected())
  1683. {
  1684. Assert(m_pTransport != NULL);
  1685. IF_FAILEXIT(hr = m_pTransport->InetServerFromAccount(m_pAccount, &rInetServerInfo));
  1686. // compare the current account from the account whose data we saved.
  1687. // if the account has changed, drop the connection, and reconnect
  1688. Assert(m_rInetServerInfo.szServerName[0] != 0);
  1689. if (m_rInetServerInfo.rasconntype == rInetServerInfo.rasconntype &&
  1690. m_rInetServerInfo.dwPort == rInetServerInfo.dwPort &&
  1691. m_rInetServerInfo.fSSL == rInetServerInfo.fSSL &&
  1692. m_rInetServerInfo.fTrySicily == rInetServerInfo.fTrySicily &&
  1693. m_rInetServerInfo.dwTimeout == rInetServerInfo.dwTimeout &&
  1694. 0 == lstrcmp(m_rInetServerInfo.szUserName, rInetServerInfo.szUserName) &&
  1695. ('\0' == rInetServerInfo.szPassword[0] ||
  1696. 0 == lstrcmp(m_rInetServerInfo.szPassword, rInetServerInfo.szPassword)) &&
  1697. 0 == lstrcmp(m_rInetServerInfo.szServerName, rInetServerInfo.szServerName) &&
  1698. 0 == lstrcmp(m_rInetServerInfo.szConnectoid, rInetServerInfo.szConnectoid))
  1699. {
  1700. goto exit;
  1701. }
  1702. fInetInit = TRUE;
  1703. // synchronously drop the connection
  1704. m_pTransport->DropConnection();
  1705. }
  1706. hr = m_op.pCallback->CanConnect(m_szAccountId, NOFLAGS);
  1707. if (S_OK != hr)
  1708. {
  1709. if (hr == S_FALSE)
  1710. hr = HR_E_USER_CANCEL_CONNECT;
  1711. goto exit;
  1712. }
  1713. if (NULL == m_pTransport)
  1714. IF_FAILEXIT(hr = _LoadTransport());
  1715. // initialize the server info if we haven't already
  1716. if (!fInetInit)
  1717. IF_FAILEXIT(hr = m_pTransport->InetServerFromAccount(m_pAccount, &m_rInetServerInfo));
  1718. else
  1719. CopyMemory(&m_rInetServerInfo, &rInetServerInfo, sizeof(INETSERVER));
  1720. GetAccountPropStrA(m_szAccountId, CAP_PASSWORD, &pszCache);
  1721. if (NULL != pszCache)
  1722. {
  1723. StrCpyN(m_rInetServerInfo.szPassword, pszCache, sizeof(m_rInetServerInfo.szPassword));
  1724. SafeMemFree(pszCache);
  1725. }
  1726. // connect to the server. the transport won't actually connect until
  1727. // a command is issued.
  1728. IF_FAILEXIT(hr = m_pTransport->Connect(&m_rInetServerInfo, TRUE, FALSE));
  1729. _SetConnected(TRUE);
  1730. exit:
  1731. return hr;
  1732. }
  1733. //----------------------------------------------------------------------
  1734. // CHTTPMailServer::GetMsgFolderRoot
  1735. //----------------------------------------------------------------------
  1736. HRESULT CHTTPMailServer::GetMsgFolderRoot(void)
  1737. {
  1738. HRESULT hr = S_OK;
  1739. // bail if we've already got it
  1740. if (NULL != m_pszMsgFolderRoot)
  1741. goto exit;
  1742. // try to pull it out of the account data cache
  1743. if (GetAccountPropStrA(m_szAccountId, CAP_HTTPMAILMSGFOLDERROOT, &m_pszMsgFolderRoot))
  1744. goto exit;
  1745. if (SUCCEEDED(hr = m_pTransport->GetProperty(HTTPMAIL_PROP_MSGFOLDERROOT, &m_pszMsgFolderRoot)))
  1746. {
  1747. Assert(NULL != m_pszMsgFolderRoot);
  1748. if (NULL == m_pszMsgFolderRoot)
  1749. {
  1750. hr = E_FAIL;
  1751. goto exit;
  1752. }
  1753. // add it to the account data cache
  1754. HrCacheAccountPropStrA(m_szAccountId, CAP_HTTPMAILMSGFOLDERROOT, m_pszMsgFolderRoot);
  1755. }
  1756. exit:
  1757. return hr;
  1758. }
  1759. //----------------------------------------------------------------------
  1760. // CHTTPMailServer::BuildFolderUrl
  1761. //----------------------------------------------------------------------
  1762. HRESULT CHTTPMailServer::BuildFolderUrl(void)
  1763. {
  1764. HRESULT hr = S_OK;
  1765. FOLDERINFO fi;
  1766. LPFOLDERINFO fiFree = NULL;
  1767. // just bail if we've already got it
  1768. if (NULL != m_pszFolderUrl)
  1769. goto exit;
  1770. Assert(NULL != m_pszMsgFolderRoot);
  1771. if (NULL == m_pszMsgFolderRoot)
  1772. {
  1773. hr = TraceResult(E_UNEXPECTED);
  1774. goto exit;
  1775. }
  1776. if (FAILED(hr = m_pStore->GetFolderInfo(m_idFolder, &fi)))
  1777. goto exit;
  1778. fiFree = &fi;
  1779. Assert(fi.pszUrlComponent);
  1780. hr = _BuildUrl(fi.pszUrlComponent, NULL, &m_pszFolderUrl);
  1781. exit:
  1782. if (fiFree)
  1783. m_pStore->FreeRecord(fiFree);
  1784. return hr;
  1785. }
  1786. //----------------------------------------------------------------------
  1787. // CHTTPMailServer::ListFolders
  1788. //----------------------------------------------------------------------
  1789. HRESULT CHTTPMailServer::ListFolders(void)
  1790. {
  1791. HRESULT hr = S_OK;
  1792. CHAR szRootTimeStamp[CCHMAX_RES];
  1793. CHAR szInboxTimeStamp[CCHMAX_RES];
  1794. Assert(NULL == m_op.pFolderList);
  1795. // cache a value that the account has been synced.
  1796. HrCacheAccountPropStrA(m_szAccountId, CAP_HTTPAUTOSYNCEDFOLDERS, c_szTrue);
  1797. // build the folder list
  1798. IF_FAILEXIT(hr = CFolderList::Create(m_pStore, m_idServer, &m_op.pFolderList));
  1799. hr = m_pAccount->GetPropSz(AP_HTTPMAIL_ROOTTIMESTAMP, szRootTimeStamp, ARRAYSIZE(szRootTimeStamp));
  1800. if (FAILED(hr))
  1801. *szRootTimeStamp = 0;
  1802. hr = m_pAccount->GetPropSz(AP_HTTPMAIL_ROOTINBOXTIMESTAMP, szInboxTimeStamp, ARRAYSIZE(szInboxTimeStamp));
  1803. if (FAILED(hr))
  1804. *szInboxTimeStamp = 0;
  1805. // execute the listfolders command
  1806. IF_FAILEXIT(hr = m_pTransport2->RootMemberInfo(m_pszMsgFolderRoot, HTTP_MEMBERINFO_FOLDERPROPS,
  1807. 1, FALSE, 0, szRootTimeStamp, szInboxTimeStamp));
  1808. hr = E_PENDING;
  1809. exit:
  1810. return hr;
  1811. }
  1812. //----------------------------------------------------------------------
  1813. // CHTTPMailServer::AutoListFolders
  1814. //----------------------------------------------------------------------
  1815. HRESULT CHTTPMailServer::AutoListFolders(void)
  1816. {
  1817. LPSTR pszAutoSynced = NULL;
  1818. HRESULT hr = S_OK;
  1819. // look for a cached property that indicates that the folder list
  1820. // for this server has been synchronized at least once this session
  1821. if (GetAccountPropStrA(m_szAccountId, CAP_HTTPAUTOSYNCEDFOLDERS, &pszAutoSynced))
  1822. goto exit;
  1823. // initiate the sync
  1824. hr = ListFolders();
  1825. exit:
  1826. SafeMemFree(pszAutoSynced);
  1827. return hr;
  1828. }
  1829. //----------------------------------------------------------------------
  1830. // CHTTPMailServer::ListHeaders
  1831. //----------------------------------------------------------------------
  1832. HRESULT CHTTPMailServer::ListHeaders(void)
  1833. {
  1834. HRESULT hr = S_OK;
  1835. TABLEINDEX index;
  1836. CHAR szTimeStamp[CCHMAX_RES];
  1837. Assert(NULL != m_pszFolderUrl);
  1838. Assert(NULL != m_pTransport);
  1839. Assert(NULL != m_pStore);
  1840. Assert(NULL == m_op.psaNewMessages);
  1841. // look for an index on pszMessageID
  1842. if ( FAILED(m_pFolder->GetIndexInfo(IINDEX_HTTPURL, NULL, &index)) ||
  1843. (CompareTableIndexes(&index, &g_HttpUrlIndex) != S_OK) )
  1844. {
  1845. // the index didn't exist - create it
  1846. IF_FAILEXIT(hr = m_pFolder->ModifyIndex(IINDEX_HTTPURL, NULL, &g_HttpUrlIndex));
  1847. }
  1848. IF_FAILEXIT(hr = _CreateMessageIDMap(&m_op.pmapMessageId));
  1849. IF_FAILEXIT(hr = CSortedArray::Create(NULL, FreeNewMessageInfo, &m_op.psaNewMessages));
  1850. hr = m_pAccount->GetPropSz(AP_HTTPMAIL_INBOXTIMESTAMP, szTimeStamp, ARRAYSIZE(szTimeStamp));
  1851. if (FAILED(hr))
  1852. *szTimeStamp = 0;
  1853. // For now we are passing in null folder name. This is meant for future purposes.
  1854. IF_FAILEXIT(hr = m_pTransport2->FolderMemberInfo(m_pszFolderUrl, HTTP_MEMBERINFO_MESSAGEPROPS,
  1855. 1, FALSE, 0, szTimeStamp, NULL));
  1856. hr = E_PENDING;
  1857. exit:
  1858. return hr;
  1859. }
  1860. //----------------------------------------------------------------------
  1861. // CHTTPMailServer::HandleListHeaders
  1862. //----------------------------------------------------------------------
  1863. HRESULT CHTTPMailServer::HandleListHeaders(LPHTTPMAILRESPONSE pResponse)
  1864. {
  1865. HRESULT hr = S_OK;
  1866. LPHTTPMEMBERINFOLIST pMemberList = &pResponse->rMemberInfoList;
  1867. LPHTTPMEMBERINFO pMemberInfo;
  1868. TPair<CSimpleString, MARKEDMESSAGE> *pFoundPair = NULL;
  1869. CSimpleString ss;
  1870. char szUrlComponent[MAX_PATH];
  1871. DWORD dwUrlComponentLen;
  1872. Assert(NULL != m_op.pmapMessageId);
  1873. for (ULONG ulIndex = 0; ulIndex < pMemberList->cMemberInfo; ++ulIndex)
  1874. {
  1875. pMemberInfo = &pMemberList->prgMemberInfo[ulIndex];
  1876. // skip folders
  1877. if (pMemberInfo->fIsFolder)
  1878. continue;
  1879. dwUrlComponentLen = MAX_PATH;
  1880. if (FAILED(hr = Http_NameFromUrl(pMemberInfo->pszHref, szUrlComponent, &dwUrlComponentLen)))
  1881. goto exit;
  1882. // look for the message by its server-assigned id in the local map
  1883. if (FAILED(hr = ss.SetString(szUrlComponent)))
  1884. goto exit;
  1885. pFoundPair = m_op.pmapMessageId->Find(ss);
  1886. // if the message was found, synchronize its read state, otherwise
  1887. // add the new message to the store
  1888. if (pFoundPair)
  1889. {
  1890. pFoundPair->m_value.fMarked = TRUE;
  1891. // if not syncing the msn promo folder, adopt the server's read state
  1892. if (FOLDER_MSNPROMO != m_tySpecialFolder)
  1893. {
  1894. if ((!!(pFoundPair->m_value.dwFlags & ARF_READ)) != pMemberInfo->fRead)
  1895. hr = _MarkMessageRead(pFoundPair->m_value.idMessage, pMemberInfo->fRead);
  1896. }
  1897. }
  1898. else
  1899. {
  1900. if (FAILED(hr = Http_AddMessageToFolder(m_pFolder,
  1901. m_szAccountId,
  1902. pMemberInfo,
  1903. FOLDER_DRAFT == m_tySpecialFolder ? ARF_UNSENT : NOFLAGS,
  1904. pMemberInfo->pszHref,
  1905. NULL)))
  1906. {
  1907. if (DB_E_DUPLICATE == hr)
  1908. hr = S_OK;
  1909. else
  1910. goto exit;
  1911. }
  1912. }
  1913. // update our message and unread message counts
  1914. m_op.cMessages++;
  1915. // if syncing the promo folder, no headers on the server will
  1916. // ever appear to be read.
  1917. if (FOLDER_MSNPROMO == m_tySpecialFolder)
  1918. {
  1919. if (!pFoundPair || !(pFoundPair->m_value.dwFlags & ARF_READ))
  1920. m_op.cUnread++;
  1921. }
  1922. else if (!pMemberInfo->fRead)
  1923. m_op.cUnread++;
  1924. }
  1925. if (pMemberList->pszFolderTimeStamp)
  1926. {
  1927. IF_FAILEXIT(hr = m_pAccount->SetPropSz(AP_HTTPMAIL_INBOXTIMESTAMP, pMemberList->pszFolderTimeStamp));
  1928. }
  1929. exit:
  1930. return hr;
  1931. }
  1932. //----------------------------------------------------------------------
  1933. // CHTTPMailServer::_Disconnect
  1934. //----------------------------------------------------------------------
  1935. void CHTTPMailServer::_Disconnect(void)
  1936. {
  1937. if (m_pTransport)
  1938. m_pTransport->DropConnection();
  1939. }
  1940. //----------------------------------------------------------------------
  1941. // CHTTPMailServer::_BuildUrl
  1942. //----------------------------------------------------------------------
  1943. HRESULT CHTTPMailServer::_BuildUrl(LPCSTR pszFolderComponent,
  1944. LPCSTR pszNameComponent,
  1945. LPSTR *ppszUrl)
  1946. {
  1947. HRESULT hr = S_OK;
  1948. DWORD cchMsgFolderRoot = 0;
  1949. DWORD cchFolderComponent = 0;
  1950. DWORD cchNameComponent = 0;
  1951. DWORD cchWritten = 0;
  1952. LPSTR pszUrl = NULL;
  1953. CHAR chSlash = '/';
  1954. Assert(NULL != m_pszMsgFolderRoot);
  1955. Assert(NULL != ppszUrl);
  1956. *ppszUrl = NULL;
  1957. if (NULL == m_pszMsgFolderRoot)
  1958. {
  1959. hr = E_UNEXPECTED;
  1960. goto exit;
  1961. }
  1962. cchMsgFolderRoot = lstrlen(m_pszMsgFolderRoot);
  1963. if (pszFolderComponent)
  1964. cchFolderComponent = lstrlen(pszFolderComponent);
  1965. if (pszNameComponent)
  1966. cchNameComponent = lstrlen(pszNameComponent);
  1967. // add three bytes - two for trailing slashes and one for the eos
  1968. if (!MemAlloc((void **)&pszUrl, cchMsgFolderRoot + cchFolderComponent + cchNameComponent + 3))
  1969. {
  1970. hr = E_OUTOFMEMORY;
  1971. goto exit;
  1972. }
  1973. *ppszUrl = pszUrl;
  1974. CopyMemory(pszUrl, m_pszMsgFolderRoot, cchMsgFolderRoot);
  1975. cchWritten = cchMsgFolderRoot;
  1976. // make sure the msg folder root is terminated with a '/'
  1977. if (chSlash != pszUrl[cchWritten - 1])
  1978. pszUrl[cchWritten++] = chSlash;
  1979. if (cchFolderComponent)
  1980. {
  1981. CopyMemory(&pszUrl[cchWritten], pszFolderComponent, cchFolderComponent);
  1982. cchWritten += cchFolderComponent;
  1983. if (chSlash != pszUrl[cchWritten - 1])
  1984. pszUrl[cchWritten++] = chSlash;
  1985. }
  1986. if (cchNameComponent)
  1987. {
  1988. CopyMemory(&pszUrl[cchWritten], pszNameComponent, cchNameComponent);
  1989. cchWritten += cchNameComponent;
  1990. }
  1991. // null terminate the string
  1992. pszUrl[cchWritten] = 0;
  1993. exit:
  1994. return hr;
  1995. }
  1996. //----------------------------------------------------------------------
  1997. // CHTTPMailServer::_BuildMessageUrl
  1998. //----------------------------------------------------------------------
  1999. HRESULT CHTTPMailServer::_BuildMessageUrl(LPCSTR pszFolderUrl,
  2000. LPSTR pszNameComponent,
  2001. LPSTR *ppszUrl)
  2002. {
  2003. DWORD cchFolderUrlLen;
  2004. DWORD cchNameComponentLen;
  2005. if (NULL != ppszUrl)
  2006. *ppszUrl = NULL;
  2007. if (NULL == pszFolderUrl || NULL == pszNameComponent || NULL == ppszUrl)
  2008. return E_INVALIDARG;
  2009. cchFolderUrlLen = lstrlen(pszFolderUrl);
  2010. cchNameComponentLen = lstrlen(pszNameComponent);
  2011. // allocate two extra bytes - one for the '/' delimeter and one for the eos
  2012. DWORD cchTotal = (cchFolderUrlLen + cchNameComponentLen + 2);
  2013. if (!MemAlloc((void **)ppszUrl, cchTotal * sizeof((*ppszUrl)[0])))
  2014. return E_OUTOFMEMORY;
  2015. if ('/' == pszFolderUrl[cchFolderUrlLen - 1])
  2016. wnsprintf(*ppszUrl, cchTotal, "%s%s", pszFolderUrl, pszNameComponent);
  2017. else
  2018. wnsprintf(*ppszUrl, cchTotal, "%s/%s", pszFolderUrl, pszNameComponent);
  2019. return S_OK;
  2020. }
  2021. //----------------------------------------------------------------------
  2022. // CHTTPMailServer::_MarkMessageRead
  2023. //----------------------------------------------------------------------
  2024. HRESULT CHTTPMailServer::_MarkMessageRead(MESSAGEID id, BOOL fRead)
  2025. {
  2026. HRESULT hr;
  2027. MESSAGEINFO mi = {0};
  2028. BOOL fFoundRecord = FALSE;
  2029. ZeroMemory(&mi, sizeof(MESSAGEINFO));
  2030. mi.idMessage = id;
  2031. // find the message in the database
  2032. if (FAILED(hr = GetMessageInfo(m_pFolder, id, &mi)))
  2033. goto exit;
  2034. fFoundRecord = TRUE;
  2035. if (fRead)
  2036. mi.dwFlags |= ARF_READ;
  2037. else
  2038. mi.dwFlags &= ~ARF_READ;
  2039. hr = m_pFolder->UpdateRecord(&mi);
  2040. exit:
  2041. if (fFoundRecord)
  2042. m_pFolder->FreeRecord(&mi);
  2043. return hr;
  2044. }
  2045. //----------------------------------------------------------------------
  2046. // CHTTPMailServer::CreateFolder
  2047. //----------------------------------------------------------------------
  2048. HRESULT CHTTPMailServer::CreateFolder(void)
  2049. {
  2050. HRESULT hr = S_OK;
  2051. CHAR szEncodedName[MAX_PATH];
  2052. DWORD cb = sizeof(szEncodedName);
  2053. Assert(NULL != m_pTransport);
  2054. Assert(NULL != m_op.pszFolderName);
  2055. IF_FAILEXIT(hr = UrlEscapeA(m_op.pszFolderName,
  2056. szEncodedName,
  2057. &cb,
  2058. URL_ESCAPE_UNSAFE | URL_ESCAPE_PERCENT | URL_ESCAPE_SEGMENT_ONLY));
  2059. IF_FAILEXIT(hr = _BuildUrl(szEncodedName, NULL, &m_op.pszDestFolderUrl));
  2060. IF_FAILEXIT(hr = m_pTransport->CommandMKCOL(m_op.pszDestFolderUrl, 0));
  2061. hr = E_PENDING;
  2062. exit:
  2063. return hr;
  2064. }
  2065. //----------------------------------------------------------------------
  2066. // CHTTPMailServer::RenameFolder
  2067. //----------------------------------------------------------------------
  2068. HRESULT CHTTPMailServer::RenameFolder(void)
  2069. {
  2070. HRESULT hr = S_OK;
  2071. FOLDERINFO fi = {0};
  2072. LPFOLDERINFO pfiFree = NULL;
  2073. LPSTR pszSourceUrl = NULL;
  2074. LPSTR pszDestUrl = NULL;
  2075. CHAR szEncodedName[MAX_PATH];
  2076. DWORD cb = sizeof(szEncodedName);
  2077. // build the source url
  2078. IF_FAILEXIT(hr = m_pStore->GetFolderInfo(m_op.idFolder, &fi));
  2079. pfiFree = &fi;
  2080. IF_FAILEXIT(hr = _BuildUrl(fi.pszUrlComponent, NULL, &pszSourceUrl));
  2081. // escape the new folder name
  2082. IF_FAILEXIT(hr = UrlEscapeA(m_op.pszFolderName,
  2083. szEncodedName,
  2084. &cb,
  2085. URL_ESCAPE_UNSAFE | URL_ESCAPE_PERCENT | URL_ESCAPE_SEGMENT_ONLY));
  2086. // build the destination url
  2087. IF_FAILEXIT(hr = _BuildUrl(szEncodedName, NULL, &pszDestUrl));
  2088. // send the MOVE command to the transport
  2089. IF_FAILEXIT(hr = m_pTransport->CommandMOVE(pszSourceUrl, pszDestUrl, TRUE, 0));
  2090. hr = E_PENDING;
  2091. exit:
  2092. if (pfiFree)
  2093. m_pStore->FreeRecord(pfiFree);
  2094. SafeMemFree(pszSourceUrl);
  2095. SafeMemFree(pszDestUrl);
  2096. return hr;
  2097. }
  2098. //----------------------------------------------------------------------
  2099. // CHTTPMailServer::DeleteFolder
  2100. //----------------------------------------------------------------------
  2101. HRESULT CHTTPMailServer::DeleteFolder(void)
  2102. {
  2103. HRESULT hr = S_OK;
  2104. FOLDERINFO fi = {0};
  2105. LPFOLDERINFO pfiFree = NULL;
  2106. LPSTR pszUrl = NULL;
  2107. // build the folder's url
  2108. if (FAILED(hr = m_pStore->GetFolderInfo(m_op.idFolder, &fi)))
  2109. goto exit;
  2110. pfiFree = &fi;
  2111. if (FAILED(hr = _BuildUrl(fi.pszUrlComponent, NULL, &pszUrl)))
  2112. goto exit;
  2113. // send the delete command to the transport
  2114. hr = m_pTransport->CommandDELETE(pszUrl, 0);
  2115. if (SUCCEEDED(hr))
  2116. hr = E_PENDING;
  2117. exit:
  2118. if (pfiFree)
  2119. m_pStore->FreeRecord(pfiFree);
  2120. SafeMemFree(pszUrl);
  2121. return hr;
  2122. }
  2123. //----------------------------------------------------------------------
  2124. // CHTTPMailServer::HandleCreateFolder
  2125. //----------------------------------------------------------------------
  2126. HRESULT CHTTPMailServer::HandleCreateFolder(LPHTTPMAILRESPONSE pResponse)
  2127. {
  2128. FOLDERINFO fi;
  2129. CHAR szUrlComponent[MAX_PATH];
  2130. DWORD dwUrlComponentLen = MAX_PATH;
  2131. HRESULT hr = pResponse->rIxpResult.hrResult;
  2132. if (SUCCEEDED(hr))
  2133. {
  2134. // if the server specified a location, use it. otherwise, use
  2135. // the url that we included in the request
  2136. if (NULL != pResponse->rMkColInfo.pszLocation)
  2137. IF_FAILEXIT(hr = Http_NameFromUrl(pResponse->rMkColInfo.pszLocation, szUrlComponent, &dwUrlComponentLen));
  2138. else
  2139. IF_FAILEXIT(hr = Http_NameFromUrl(m_op.pszDestFolderUrl, szUrlComponent, &dwUrlComponentLen));
  2140. // [shaheedp] Bug# 84477
  2141. // If szUrlComponent is null, then we should not be adding this folder to the store.
  2142. if (!(*szUrlComponent))
  2143. {
  2144. hr = E_FAIL;
  2145. goto exit;
  2146. }
  2147. ZeroMemory(&fi, sizeof(FOLDERINFO));
  2148. fi.idParent = m_idServer;
  2149. fi.tySpecial = FOLDER_NOTSPECIAL;
  2150. fi.tyFolder = FOLDER_HTTPMAIL;
  2151. fi.pszName = m_op.pszFolderName;
  2152. fi.pszUrlComponent = szUrlComponent;
  2153. fi.dwFlags = (FOLDER_SUBSCRIBED | FOLDER_NOCHILDCREATE);
  2154. m_pStore->CreateFolder(NOFLAGS, &fi, NULL);
  2155. }
  2156. exit:
  2157. return hr;
  2158. }
  2159. //----------------------------------------------------------------------
  2160. // CHTTPMailServer::HandleRenameFolder
  2161. //----------------------------------------------------------------------
  2162. HRESULT CHTTPMailServer::HandleRenameFolder(LPHTTPMAILRESPONSE pResponse)
  2163. {
  2164. HRESULT hr = S_OK;
  2165. char szUrlComponent[MAX_PATH];
  2166. DWORD dwUrlComponentLen = MAX_PATH;
  2167. FOLDERINFO fi = {0};
  2168. LPFOLDERINFO pfiFree = NULL;
  2169. // REVIEW: if the server doesn't return a response, return an error
  2170. Assert(NULL != pResponse->rCopyMoveInfo.pszLocation);
  2171. if (NULL != pResponse->rCopyMoveInfo.pszLocation)
  2172. {
  2173. if (FAILED(hr = Http_NameFromUrl(pResponse->rCopyMoveInfo.pszLocation, szUrlComponent, &dwUrlComponentLen)))
  2174. goto exit;
  2175. if (FAILED(hr = m_pStore->GetFolderInfo(m_op.idFolder, &fi)))
  2176. goto exit;
  2177. pfiFree = &fi;
  2178. fi.pszName = m_op.pszFolderName;
  2179. fi.pszUrlComponent = szUrlComponent;
  2180. hr = m_pStore->UpdateRecord(&fi);
  2181. }
  2182. exit:
  2183. if (NULL != pfiFree)
  2184. m_pStore->FreeRecord(pfiFree);
  2185. return hr;
  2186. }
  2187. //----------------------------------------------------------------------
  2188. // CHTTPMailServer::HandleDeleteFolder
  2189. //----------------------------------------------------------------------
  2190. HRESULT CHTTPMailServer::HandleDeleteFolder(LPHTTPMAILRESPONSE pResponse)
  2191. {
  2192. return m_pStore->DeleteFolder(m_op.idFolder, DELETE_FOLDER_NOTRASHCAN, NULL);
  2193. }
  2194. //----------------------------------------------------------------------
  2195. // CHTTPMailServer::PurgeFolders
  2196. //----------------------------------------------------------------------
  2197. HRESULT CHTTPMailServer::PurgeFolders(void)
  2198. {
  2199. // the folder list will be null if we didn't need
  2200. // to do an auto-sync
  2201. if (NULL != m_op.pFolderList)
  2202. m_op.pFolderList->PurgeRemainingFromStore();
  2203. return S_OK;
  2204. }
  2205. //----------------------------------------------------------------------
  2206. // CHTTPMailServer::PurgeMessages
  2207. //----------------------------------------------------------------------
  2208. HRESULT CHTTPMailServer::PurgeMessages(void)
  2209. {
  2210. TPair<CSimpleString, MARKEDMESSAGE> *pPair;
  2211. MESSAGEID idMessage = MESSAGEID_INVALID;
  2212. MESSAGEIDLIST rIdList = { 1, 1, &idMessage };
  2213. Assert(NULL != m_op.pmapMessageId);
  2214. long lMapLength = m_op.pmapMessageId->GetLength();
  2215. for (long lIndex = 0; lIndex < lMapLength; lIndex++)
  2216. {
  2217. pPair = m_op.pmapMessageId->GetItemAt(lIndex);
  2218. if (NULL != pPair && !pPair->m_value.fMarked)
  2219. {
  2220. idMessage = pPair->m_value.idMessage;
  2221. m_pFolder->DeleteMessages(DELETE_MESSAGE_NOTRASHCAN | DELETE_MESSAGE_NOPROMPT, &rIdList, NULL, NULL /* m_op.pCallback */);
  2222. }
  2223. }
  2224. // don't need the map anymore
  2225. SafeDelete(m_op.pmapMessageId);
  2226. return S_OK;
  2227. }
  2228. //----------------------------------------------------------------------
  2229. // CHTTPMailServer::ResetMessageCounts
  2230. //----------------------------------------------------------------------
  2231. HRESULT CHTTPMailServer::ResetMessageCounts(void)
  2232. {
  2233. HRESULT hr = S_OK;
  2234. FOLDERINFO fi;
  2235. LPFOLDERINFO pfiFree = NULL;
  2236. // find the folder
  2237. IF_FAILEXIT(hr = m_pStore->GetFolderInfo(m_idFolder, &fi));
  2238. pfiFree = &fi;
  2239. // update the counts
  2240. if (fi.cMessages != m_op.cMessages || fi.cUnread != m_op.cUnread)
  2241. {
  2242. fi.cMessages = m_op.cMessages;
  2243. fi.cUnread = m_op.cUnread;
  2244. }
  2245. hr = m_pStore->UpdateRecord(&fi);
  2246. exit:
  2247. if (pfiFree)
  2248. m_pStore->FreeRecord(pfiFree);
  2249. return hr;
  2250. }
  2251. //----------------------------------------------------------------------
  2252. // CHTTPMailServer::GetMessage
  2253. //----------------------------------------------------------------------
  2254. HRESULT CHTTPMailServer::GetMessage(void)
  2255. {
  2256. HRESULT hr = S_OK;
  2257. MESSAGEINFO mi = {0};
  2258. BOOL fFoundRecord = FALSE;
  2259. LPCSTR rgszAcceptTypes[] = { c_szAcceptTypeRfc822, c_szAcceptTypeWildcard, NULL };
  2260. LPSTR pszUrl = NULL;
  2261. TCHAR szRes[CCHMAX_STRINGRES];
  2262. // pull the message info out of the store
  2263. if (FAILED(hr = GetMessageInfo(m_pFolder, m_op.idMessage, &mi)))
  2264. goto exit;
  2265. fFoundRecord = TRUE;
  2266. Assert(mi.pszUrlComponent);
  2267. if (FAILED(hr =_BuildMessageUrl(m_pszFolderUrl, mi.pszUrlComponent, &pszUrl)))
  2268. goto exit;
  2269. AthLoadString(idsRequestingArt, szRes, ARRAYSIZE(szRes));
  2270. if (m_op.pCallback)
  2271. m_op.pCallback->OnProgress(m_op.tyOperation, 0, 0, szRes);
  2272. if (FAILED(hr = m_pTransport->CommandGET(pszUrl, rgszAcceptTypes, FALSE, 0)))
  2273. goto exit;
  2274. hr = E_PENDING;
  2275. exit:
  2276. if (fFoundRecord)
  2277. m_pFolder->FreeRecord(&mi);
  2278. SafeMemFree(pszUrl);
  2279. return hr;
  2280. }
  2281. //----------------------------------------------------------------------
  2282. // CHTTPMailServer::CreateSetFlagsRequest
  2283. //----------------------------------------------------------------------
  2284. HRESULT CHTTPMailServer::CreateSetFlagsRequest(void)
  2285. {
  2286. HRESULT hr;
  2287. hr = CoCreateInstance(CLSID_IPropPatchRequest, NULL, CLSCTX_INPROC_SERVER, IID_IPropPatchRequest, (LPVOID *)&m_op.pPropPatchRequest);
  2288. if (FAILED(hr))
  2289. goto exit;
  2290. if (m_op.fMarkRead)
  2291. hr = m_op.pPropPatchRequest->SetProperty(DAVNAMESPACE_HTTPMAIL, "read", "1");
  2292. else
  2293. hr = m_op.pPropPatchRequest->SetProperty(DAVNAMESPACE_HTTPMAIL, "read", "0");
  2294. exit:
  2295. return hr;
  2296. }
  2297. //----------------------------------------------------------------------
  2298. // CHTTPMailServer::SetMessageFlags
  2299. //----------------------------------------------------------------------
  2300. HRESULT CHTTPMailServer::SetMessageFlags(void)
  2301. {
  2302. HRESULT hr = S_OK;
  2303. LPHTTPTARGETLIST pTargets = NULL;
  2304. LPSTR pszMessageUrl = NULL;
  2305. ADJUSTFLAGS af;
  2306. af.dwAdd = m_op.fMarkRead ? ARF_READ : 0;
  2307. af.dwRemove = !m_op.fMarkRead ? ARF_READ : 0;
  2308. // if we have a rowset, we shouldn't have an ID List.
  2309. Assert(NULL == m_op.hRowSet || NULL == m_op.pIDList);
  2310. IF_FAILEXIT(hr = _HrBuildMapAndTargets(m_op.pIDList, m_op.hRowSet, &af, m_op.dwSetFlags, &m_op.pmapMessageId, &pTargets));
  2311. // if the folder is the msnpromo folder, advance to the next state.
  2312. // don't actually send the command to the server
  2313. if (FOLDER_MSNPROMO == m_tySpecialFolder)
  2314. goto exit;
  2315. // if there is only one target, build a complete url for the target
  2316. // and invoke the non-batch version of the command. if there are no targets,
  2317. // return S_OK, and don't send any commands to the xport
  2318. if (1 == pTargets->cTarget)
  2319. {
  2320. IF_FAILEXIT(hr = _BuildMessageUrl(m_pszFolderUrl, const_cast<char *>(pTargets->prgTarget[0]), &pszMessageUrl));
  2321. IF_FAILEXIT(hr = m_pTransport->MarkRead(pszMessageUrl, NULL, m_op.fMarkRead, 0));
  2322. hr = E_PENDING;
  2323. }
  2324. else if (pTargets->cTarget > 0)
  2325. {
  2326. IF_FAILEXIT(hr = m_pTransport->MarkRead(m_pszFolderUrl, pTargets, m_op.fMarkRead, 0));
  2327. hr = E_PENDING;
  2328. }
  2329. exit:
  2330. if (pTargets)
  2331. Http_FreeTargetList(pTargets);
  2332. SafeMemFree(pszMessageUrl);
  2333. return hr;
  2334. }
  2335. //----------------------------------------------------------------------
  2336. // CHTTPMailServer::ApplyFlagsToStore
  2337. //----------------------------------------------------------------------
  2338. HRESULT CHTTPMailServer::ApplyFlagsToStore(void)
  2339. {
  2340. HRESULT hr = S_OK;
  2341. TPair<CSimpleString, MARKEDMESSAGE> *pPair;
  2342. long lMapLength = m_op.pmapMessageId->GetLength();
  2343. ADJUSTFLAGS af;
  2344. BOOL fFoundMarked = FALSE;
  2345. long lIndex;
  2346. af.dwAdd = m_op.fMarkRead ? ARF_READ : 0;
  2347. af.dwRemove = !m_op.fMarkRead ? ARF_READ : 0;
  2348. // if the operation was requested on the entire folder,
  2349. // check to see if anything failed. if it did, then
  2350. // build up an IDList so we can mark only the msgs that
  2351. // were successfully modified
  2352. if (NULL != m_op.hRowSet)
  2353. {
  2354. Assert(NULL == m_op.pIDList);
  2355. for (lIndex = 0; lIndex < lMapLength && !fFoundMarked; lIndex++)
  2356. {
  2357. pPair = m_op.pmapMessageId->GetItemAt(lIndex);
  2358. Assert(NULL != pPair);
  2359. if (pPair && pPair->m_value.fMarked)
  2360. fFoundMarked = TRUE;
  2361. }
  2362. // if no messages were marked, apply the operation to the entire folder
  2363. if (!fFoundMarked)
  2364. {
  2365. hr = m_pFolder->SetMessageFlags(NULL, &af, NULL, NULL);
  2366. // we're done
  2367. goto exit;
  2368. }
  2369. // if one or more msgs were marked, allocate an idlist
  2370. if (fFoundMarked)
  2371. {
  2372. // allocate the list structure
  2373. if (!MemAlloc((void **)&m_op.pIDList, sizeof(MESSAGEIDLIST)))
  2374. {
  2375. hr = TrapError(E_OUTOFMEMORY);
  2376. goto exit;
  2377. }
  2378. ZeroMemory(m_op.pIDList, sizeof(MESSAGEIDLIST));
  2379. // allocate storage
  2380. if (!MemAlloc((void **)&m_op.pIDList->prgidMsg, sizeof(MESSAGEID) * lMapLength))
  2381. {
  2382. hr = TrapError(E_OUTOFMEMORY);
  2383. goto exit;
  2384. }
  2385. m_op.pIDList->cAllocated = lMapLength;
  2386. m_op.pIDList->cMsgs = 0;
  2387. }
  2388. }
  2389. // we need to apply the setflags operation to the local store. we
  2390. // can't just pass the message id list that we got originally,
  2391. // because some of the operation may have failed. instead, we
  2392. // rebuild the id list (in place, since we know the successful
  2393. // operations will never outnumber the attempted operations),
  2394. // and send that into the store
  2395. Assert(NULL != m_op.pIDList);
  2396. Assert(NULL != m_op.pmapMessageId);
  2397. Assert(m_op.pIDList->cMsgs >= (DWORD)lMapLength);
  2398. m_op.pIDList->cMsgs = 0;
  2399. for (lIndex = 0; lIndex < lMapLength; lIndex++)
  2400. {
  2401. pPair = m_op.pmapMessageId->GetItemAt(lIndex);
  2402. Assert(NULL != pPair);
  2403. // if the item isn't marked, then it was successfully modified
  2404. if (pPair && !pPair->m_value.fMarked)
  2405. m_op.pIDList->prgidMsg[m_op.pIDList->cMsgs++] = pPair->m_value.idMessage;
  2406. }
  2407. // if the resulting id list contains at least one message, perform the operation
  2408. if (m_op.pIDList->cMsgs > 0)
  2409. hr = m_pFolder->SetMessageFlags(m_op.pIDList, &af, NULL, NULL);
  2410. // todo: alert user if the operation failed in part
  2411. exit:
  2412. return hr;
  2413. }
  2414. //----------------------------------------------------------------------
  2415. // CHTTPMailServer::HandleMemberErrors
  2416. //----------------------------------------------------------------------
  2417. HRESULT CHTTPMailServer::HandleMemberErrors(LPHTTPMAILRESPONSE pResponse)
  2418. {
  2419. HRESULT hr = S_OK;
  2420. LPHTTPMEMBERERROR pme = NULL;
  2421. CHAR szUrlComponent[MAX_PATH];
  2422. DWORD dwComponentBytes;
  2423. CSimpleString ss;
  2424. TPair<CSimpleString, MARKEDMESSAGE> *pFoundPair = NULL;
  2425. // loop through the response looking for errors. we ignore
  2426. // per-item success.
  2427. for (DWORD dw = 0; dw < pResponse->rMemberErrorList.cMemberError; dw++)
  2428. {
  2429. pme = &pResponse->rMemberErrorList.prgMemberError[dw];
  2430. if (SUCCEEDED(pme->hrResult))
  2431. continue;
  2432. Assert(NULL != pme->pszHref);
  2433. if (NULL == pme->pszHref)
  2434. continue;
  2435. dwComponentBytes = ARRAYSIZE(szUrlComponent);
  2436. if (FAILED(Http_NameFromUrl(pme->pszHref, szUrlComponent, &dwComponentBytes)))
  2437. continue;
  2438. IF_FAILEXIT(hr = ss.SetString(szUrlComponent));
  2439. // find and mark the found message
  2440. pFoundPair = m_op.pmapMessageId->Find(ss);
  2441. Assert(NULL != pFoundPair);
  2442. if (NULL != pFoundPair)
  2443. pFoundPair->m_value.fMarked = TRUE;
  2444. }
  2445. exit:
  2446. return hr;
  2447. }
  2448. //----------------------------------------------------------------------
  2449. // CHTTPMailServer::DeleteMessages
  2450. //----------------------------------------------------------------------
  2451. HRESULT CHTTPMailServer::DeleteMessages(void)
  2452. {
  2453. HRESULT hr = S_OK;
  2454. LPSTR pszMessageUrl = NULL;
  2455. LPSTR pszNoDeleteSupport = NULL;
  2456. // if we have a rowset, we shouldn't have an ID List
  2457. Assert(NULL == m_op.hRowSet || NULL == m_op.pIDList);
  2458. IF_FAILEXIT(hr = _HrBuildMapAndTargets(m_op.pIDList, m_op.hRowSet, NULL, 0, &m_op.pmapMessageId, &m_op.pTargets));
  2459. // look for an already cached property that indicates that the server
  2460. // isn't going to support deleting messages (Hotmail doesn't)
  2461. if (GetAccountPropStrA(m_szAccountId, CAP_HTTPNOMESSAGEDELETES, &pszNoDeleteSupport))
  2462. {
  2463. if (!!(DELETE_MESSAGE_MAYIGNORENOTRASH & m_op.dwDelMsgFlags))
  2464. m_op.fFallbackToMove = TRUE;
  2465. else
  2466. hr = SP_E_HTTP_NODELETESUPPORT;
  2467. goto exit;
  2468. }
  2469. // if there is only one target, build a complete url for the target,
  2470. // and call the non-batch version of the command. if there are no targets,
  2471. // return S_OK and don't issue any commands
  2472. if (!m_op.pTargets)
  2473. {
  2474. hr = E_FAIL;
  2475. goto exit;
  2476. }
  2477. if (1 == m_op.pTargets->cTarget)
  2478. {
  2479. IF_FAILEXIT(hr = _BuildMessageUrl(m_pszFolderUrl, const_cast<char *>(m_op.pTargets->prgTarget[0]), &pszMessageUrl));
  2480. IF_FAILEXIT(hr = m_pTransport->CommandDELETE(pszMessageUrl, 0));
  2481. }
  2482. else
  2483. IF_FAILEXIT(hr = m_pTransport->CommandBDELETE(m_pszFolderUrl, m_op.pTargets, 0));
  2484. hr = E_PENDING;
  2485. exit:
  2486. SafeMemFree(pszNoDeleteSupport);
  2487. SafeMemFree(pszMessageUrl);
  2488. return hr;
  2489. }
  2490. //----------------------------------------------------------------------
  2491. // CHTTPMailServer::DeleteFallbackToMove
  2492. //----------------------------------------------------------------------
  2493. HRESULT CHTTPMailServer::DeleteFallbackToMove(void)
  2494. {
  2495. HRESULT hr = S_OK;
  2496. IMessageFolder *pDeletedItems = NULL;
  2497. if (!m_op.fFallbackToMove)
  2498. goto exit;
  2499. // find the deleted items folder
  2500. IF_FAILEXIT(hr = m_pStore->OpenSpecialFolder(m_idServer, NULL, FOLDER_DELETED, &pDeletedItems));
  2501. if (NULL == pDeletedItems)
  2502. {
  2503. hr = TraceResult(IXP_E_HTTP_NOT_FOUND);
  2504. goto exit;
  2505. }
  2506. IF_FAILEXIT(hr = pDeletedItems->GetFolderId(&m_op.idFolder));
  2507. Assert(NULL == m_op.pMessageFolder);
  2508. // should already have a targets list by this point
  2509. Assert(NULL != m_op.pTargets);
  2510. m_op.pMessageFolder = pDeletedItems;
  2511. pDeletedItems = NULL;
  2512. m_op.dwOptions = COPY_MESSAGE_MOVE;
  2513. if (1 == m_op.pTargets->cTarget)
  2514. hr = CopyMoveMessage();
  2515. else
  2516. hr = BatchCopyMoveMessages();
  2517. exit:
  2518. SafeRelease(pDeletedItems);
  2519. return hr;
  2520. }
  2521. //----------------------------------------------------------------------
  2522. // CHTTPMailServer::HandleDeleteFallbackToMove
  2523. //----------------------------------------------------------------------
  2524. HRESULT CHTTPMailServer::HandleDeleteFallbackToMove(LPHTTPMAILRESPONSE pResponse)
  2525. {
  2526. HRESULT hr = S_OK;
  2527. if (1 == m_op.pTargets->cTarget)
  2528. hr = HandleCopyMoveMessage(pResponse);
  2529. else
  2530. hr = HandleBatchCopyMoveMessages(pResponse);
  2531. return hr;
  2532. }
  2533. //----------------------------------------------------------------------
  2534. // CHTTPMailServer::PutMessage
  2535. //----------------------------------------------------------------------
  2536. HRESULT CHTTPMailServer::PutMessage(void)
  2537. {
  2538. HRESULT hr = S_OK;
  2539. FOLDERINFO fi;
  2540. LPFOLDERINFO pfiFree = NULL;
  2541. IF_FAILEXIT(hr = m_pStore->GetFolderInfo(m_op.idFolder, &fi));
  2542. pfiFree = &fi;
  2543. IF_FAILEXIT(hr = _BuildUrl(fi.pszUrlComponent, NULL, &m_op.pszDestFolderUrl));
  2544. IF_FAILEXIT(hr = m_pTransport->CommandPOST(m_op.pszDestFolderUrl, m_op.pMessageStream, c_szAcceptTypeRfc822, 0));
  2545. hr = E_PENDING;
  2546. exit:
  2547. //SafeMemFree(pv);
  2548. if (pfiFree)
  2549. m_pStore->FreeRecord(pfiFree);
  2550. return hr;
  2551. }
  2552. //----------------------------------------------------------------------
  2553. // CHTTPMailServer::BatchCopyMoveMessages
  2554. //----------------------------------------------------------------------
  2555. HRESULT CHTTPMailServer::BatchCopyMoveMessages(void)
  2556. {
  2557. HRESULT hr = S_OK;
  2558. FOLDERINFO fi = {0};
  2559. LPFOLDERINFO pfiFree = NULL;
  2560. // build the destination folder urls
  2561. IxpAssert(NULL == m_op.pszDestFolderUrl);
  2562. if (FAILED(hr = m_pStore->GetFolderInfo(m_op.idFolder, &fi)))
  2563. {
  2564. TraceResult(hr);
  2565. goto exit;
  2566. }
  2567. pfiFree = &fi;
  2568. if (FAILED(hr = _BuildUrl(fi.pszUrlComponent, NULL, &m_op.pszDestFolderUrl)))
  2569. goto exit;
  2570. Assert(NULL == m_op.pTargets || m_op.fFallbackToMove);
  2571. // build the target list and the message id map
  2572. if (NULL == m_op.pTargets)
  2573. IF_FAILEXIT(hr = _HrBuildMapAndTargets(m_op.pIDList, NULL, NULL, 0, &m_op.pmapMessageId, &m_op.pTargets));
  2574. if (!!(m_op.dwOptions & COPY_MESSAGE_MOVE))
  2575. hr = m_pTransport->CommandBMOVE(m_pszFolderUrl, m_op.pTargets, m_op.pszDestFolderUrl, NULL, TRUE, 0);
  2576. else
  2577. hr = m_pTransport->CommandBCOPY(m_pszFolderUrl, m_op.pTargets, m_op.pszDestFolderUrl, NULL, TRUE, 0);
  2578. if (SUCCEEDED(hr))
  2579. hr = E_PENDING;
  2580. exit:
  2581. if (pfiFree)
  2582. m_pStore->FreeRecord(pfiFree);
  2583. return hr;
  2584. }
  2585. //----------------------------------------------------------------------
  2586. // CHTTPMailServer::CopyMoveMessage
  2587. //----------------------------------------------------------------------
  2588. HRESULT CHTTPMailServer::CopyMoveMessage(void)
  2589. {
  2590. HRESULT hr = S_OK;
  2591. FOLDERINFO fi = {0};
  2592. LPFOLDERINFO pfiFree = NULL;
  2593. // build the destination folder urls
  2594. IxpAssert(NULL == m_op.pszDestFolderUrl);
  2595. if (FAILED(hr = m_pStore->GetFolderInfo(m_op.idFolder, &fi)))
  2596. {
  2597. TraceResult(hr);
  2598. goto exit;
  2599. }
  2600. pfiFree = &fi;
  2601. if (FAILED(hr = _BuildUrl(fi.pszUrlComponent, NULL, &m_op.pszDestFolderUrl)))
  2602. goto exit;
  2603. hr = _CopyMoveNextMessage();
  2604. exit:
  2605. if (pfiFree)
  2606. m_pStore->FreeRecord(pfiFree);
  2607. return hr;
  2608. }
  2609. //----------------------------------------------------------------------
  2610. // CHTTPMailServer::FinalizeBatchCopyMove
  2611. //----------------------------------------------------------------------
  2612. HRESULT CHTTPMailServer::FinalizeBatchCopyMove(void)
  2613. {
  2614. HRESULT hr = S_OK;
  2615. if (NOFLAGS != m_op.dwCopyMoveErrorFlags)
  2616. {
  2617. hr = E_FAIL;
  2618. if (HTTPCOPYMOVE_OUTOFSPACE == m_op.dwCopyMoveErrorFlags)
  2619. m_op.pszProblem = AthLoadString(idsHttpBatchCopyNoStorage, NULL, 0);
  2620. else
  2621. m_op.pszProblem = AthLoadString(idsHttpBatchCopyErrors, NULL , 0);
  2622. }
  2623. return hr;
  2624. }
  2625. //----------------------------------------------------------------------
  2626. // CHTTPMailServer::PurgeDeletedFromStore
  2627. //----------------------------------------------------------------------
  2628. HRESULT CHTTPMailServer::PurgeDeletedFromStore(void)
  2629. {
  2630. HRESULT hr = S_OK;
  2631. TPair<CSimpleString, MARKEDMESSAGE> *pPair;
  2632. long lMapLength = m_op.pmapMessageId->GetLength();
  2633. BOOL fFoundMarked = FALSE;
  2634. long lIndex;
  2635. if (m_op.fFallbackToMove)
  2636. goto exit;
  2637. // if the operation was requested on the entire folder,
  2638. // check to see if anything failed. if it did, then build
  2639. // up an IDList so we can mark only the msgs that were
  2640. // successfully modified
  2641. if (NULL != m_op.hRowSet)
  2642. {
  2643. Assert(NULL == m_op.pIDList);
  2644. for (lIndex = 0; lIndex < lMapLength && !fFoundMarked; lIndex++)
  2645. {
  2646. pPair = m_op.pmapMessageId->GetItemAt(lIndex);
  2647. Assert(NULL != pPair);
  2648. if (pPair && pPair->m_value.fMarked)
  2649. fFoundMarked = TRUE;
  2650. }
  2651. // if no messages were marked, apply the operation to the entire folder
  2652. if (!fFoundMarked)
  2653. {
  2654. hr = m_pFolder->DeleteMessages(DELETE_MESSAGE_NOTRASHCAN | DELETE_MESSAGE_NOPROMPT, NULL, NULL, NULL);
  2655. // we're done
  2656. goto exit;
  2657. }
  2658. // if one or more msgs were marked, allocate an idlist
  2659. if (fFoundMarked)
  2660. {
  2661. // allocate the list structure
  2662. if (!MemAlloc((void **)&m_op.pIDList, sizeof(MESSAGEIDLIST)))
  2663. {
  2664. hr = TrapError(E_OUTOFMEMORY);
  2665. goto exit;
  2666. }
  2667. ZeroMemory(m_op.pIDList, sizeof(MESSAGEIDLIST));
  2668. // allocate storage
  2669. if (!MemAlloc((void **)&m_op.pIDList->prgidMsg, sizeof(MESSAGEID) * lMapLength))
  2670. {
  2671. hr = TrapError(E_OUTOFMEMORY);
  2672. goto exit;
  2673. }
  2674. m_op.pIDList->cAllocated = lMapLength;
  2675. m_op.pIDList->cMsgs = 0;
  2676. }
  2677. }
  2678. // apply the delete operation to the local store. we can't just pass
  2679. // the message id list that we got originally, because some of the operation
  2680. // may have failed. instead, we rebuild the id list (in place, since we know
  2681. // the successful operations will never outnumber the attempted operations,
  2682. // and send that to the store.
  2683. Assert(NULL != m_op.pIDList);
  2684. Assert(NULL != m_op.pmapMessageId);
  2685. Assert(m_op.pIDList->cMsgs >= (DWORD)lMapLength);
  2686. // set the idlist count to 0. we will re-populate the
  2687. // idlist with ids from the messageID map. We know that
  2688. // the idlist is the same size as the map, so there won't
  2689. // be an overflow problem.
  2690. m_op.pIDList->cMsgs = 0;
  2691. for (lIndex = 0; lIndex < lMapLength; lIndex++)
  2692. {
  2693. pPair = m_op.pmapMessageId->GetItemAt(lIndex);
  2694. Assert(NULL != pPair);
  2695. // if the item isn't marked, then it was successfully modified
  2696. if (pPair && !pPair->m_value.fMarked)
  2697. m_op.pIDList->prgidMsg[m_op.pIDList->cMsgs++] = pPair->m_value.idMessage;
  2698. }
  2699. // if the resulting id list contains at least one message, perform the operation
  2700. if (m_op.pIDList->cMsgs > 0)
  2701. hr = m_pFolder->DeleteMessages(DELETE_MESSAGE_NOTRASHCAN | DELETE_MESSAGE_NOPROMPT, m_op.pIDList, NULL, NULL);
  2702. // todo: alert user if the operation failed in part
  2703. exit:
  2704. return hr;
  2705. }
  2706. //----------------------------------------------------------------------
  2707. // CHTTPMailServer::HandlePutMessage
  2708. //----------------------------------------------------------------------
  2709. HRESULT CHTTPMailServer::HandlePutMessage(LPHTTPMAILRESPONSE pResponse)
  2710. {
  2711. HRESULT hr = S_OK;
  2712. if (!pResponse->fDone && m_op.pCallback)
  2713. {
  2714. m_op.pCallback->OnProgress(m_op.tyOperation,
  2715. pResponse->rPostInfo.cbCurrent,
  2716. pResponse->rPostInfo.cbTotal,
  2717. NULL);
  2718. }
  2719. if (pResponse->fDone)
  2720. {
  2721. Assert(NULL != pResponse->rPostInfo.pszLocation);
  2722. if (NULL == pResponse->rPostInfo.pszLocation)
  2723. {
  2724. hr = E_FAIL;
  2725. goto exit;
  2726. }
  2727. // assume ownership of the location url
  2728. m_op.pszDestUrl = pResponse->rPostInfo.pszLocation;
  2729. pResponse->rPostInfo.pszLocation = NULL;
  2730. }
  2731. exit:
  2732. return hr;
  2733. }
  2734. //----------------------------------------------------------------------
  2735. // CHTTPMailServer::AddPutMessage
  2736. //----------------------------------------------------------------------
  2737. HRESULT CHTTPMailServer::AddPutMessage()
  2738. {
  2739. HRESULT hr = S_OK;
  2740. IMessageFolder *pFolder = NULL;
  2741. MESSAGEID idMessage;
  2742. MESSAGEFLAGS dwFlags;
  2743. // adopt some of the flags of the message we are putting
  2744. dwFlags = m_op.dwMsgFlags & (ARF_READ | ARF_SIGNED | ARF_ENCRYPTED | ARF_HASATTACH | ARF_VOICEMAIL);
  2745. if (!!(m_op.dwMsgFlags & ARF_UNSENT) || FOLDER_DRAFT == m_tySpecialFolder)
  2746. dwFlags |= ARF_UNSENT;
  2747. IF_FAILEXIT(hr = m_pStore->OpenFolder(m_op.idFolder, NULL, NOFLAGS, &pFolder));
  2748. IF_FAILEXIT(hr = Http_AddMessageToFolder(pFolder, m_szAccountId, NULL, dwFlags, m_op.pszDestUrl, &idMessage));
  2749. IF_FAILEXIT(hr = Http_SetMessageStream(pFolder, idMessage, m_op.pMessageStream, NULL, TRUE));
  2750. m_op.idPutMessage = idMessage;
  2751. exit:
  2752. SafeRelease(pFolder);
  2753. return hr;
  2754. }
  2755. //----------------------------------------------------------------------
  2756. // CHTTPMailServer::HandleBatchCopyMoveMessages
  2757. //----------------------------------------------------------------------
  2758. HRESULT CHTTPMailServer::HandleBatchCopyMoveMessages(LPHTTPMAILRESPONSE pResponse)
  2759. {
  2760. HRESULT hr = S_OK;
  2761. CHAR szUrlComponent[MAX_PATH];
  2762. DWORD dwComponentBytes;
  2763. LPHTTPMAILBCOPYMOVE pCopyMove;
  2764. CSimpleString ss;
  2765. TPair<CSimpleString, MARKEDMESSAGE> *pFoundPair = NULL;
  2766. HLOCK hLockNotify = NULL;
  2767. BOOL fDeleteOriginal = !!(m_op.dwOptions & COPY_MESSAGE_MOVE);
  2768. // This forces all notifications to be queued (this is good since you do segmented deletes)
  2769. m_pFolder->LockNotify(0, &hLockNotify);
  2770. for (DWORD dw = 0; dw < pResponse->rBCopyMoveList.cBCopyMove; dw++)
  2771. {
  2772. pCopyMove = &pResponse->rBCopyMoveList.prgBCopyMove[dw];
  2773. if (FAILED(pCopyMove->hrResult))
  2774. {
  2775. if (IXP_E_HTTP_INSUFFICIENT_STORAGE == pCopyMove->hrResult)
  2776. m_op.dwCopyMoveErrorFlags |= HTTPCOPYMOVE_OUTOFSPACE;
  2777. else
  2778. m_op.dwCopyMoveErrorFlags |= HTTPCOPYMOVE_ERROR;
  2779. continue;
  2780. }
  2781. Assert(NULL != pCopyMove->pszHref);
  2782. if (pCopyMove->pszHref)
  2783. {
  2784. dwComponentBytes = ARRAYSIZE(szUrlComponent);
  2785. if (FAILED(Http_NameFromUrl(pCopyMove->pszHref, szUrlComponent, &dwComponentBytes)))
  2786. continue;
  2787. if (FAILED(ss.SetString(szUrlComponent)))
  2788. goto exit;
  2789. pFoundPair = m_op.pmapMessageId->Find(ss);
  2790. Assert(NULL != pFoundPair);
  2791. if (NULL == pFoundPair)
  2792. continue;
  2793. // move the message and, if the move succeeds, mark the success
  2794. if (SUCCEEDED(_CopyMoveLocalMessage(pFoundPair->m_value.idMessage, m_op.pMessageFolder, pCopyMove->pszLocation, fDeleteOriginal)))
  2795. pFoundPair->m_value.fMarked = TRUE;
  2796. }
  2797. }
  2798. exit:
  2799. m_pFolder->UnlockNotify(&hLockNotify);
  2800. m_op.lIndex += pResponse->rBCopyMoveList.cBCopyMove;
  2801. if (m_op.pCallback)
  2802. m_op.pCallback->OnProgress(m_op.tyOperation, m_op.lIndex + 1, m_op.pmapMessageId->GetLength(), NULL);
  2803. return hr;
  2804. }
  2805. //----------------------------------------------------------------------
  2806. // CHTTPMailServer::HandleCopyMessage
  2807. //----------------------------------------------------------------------
  2808. HRESULT CHTTPMailServer::HandleCopyMoveMessage(LPHTTPMAILRESPONSE pResponse)
  2809. {
  2810. HRESULT hr = S_OK;
  2811. BOOL fDeleteOriginal = !!(m_op.dwOptions & COPY_MESSAGE_MOVE);
  2812. hr = _CopyMoveLocalMessage(m_op.pIDList->prgidMsg[m_op.dwIndex - 1],
  2813. m_op.pMessageFolder,
  2814. pResponse->rCopyMoveInfo.pszLocation,
  2815. fDeleteOriginal);
  2816. return hr;
  2817. }
  2818. //----------------------------------------------------------------------
  2819. // CHTTPMailServer::_CopyMoveLocalMessage
  2820. //----------------------------------------------------------------------
  2821. HRESULT CHTTPMailServer::_CopyMoveLocalMessage(MESSAGEID idMessage,
  2822. IMessageFolder* pDestFolder,
  2823. LPSTR pszUrl,
  2824. BOOL fMoveSource)
  2825. {
  2826. HRESULT hr = S_OK;
  2827. MESSAGEINFO miSource, miDest;
  2828. char szUrlComponent[MAX_PATH];
  2829. DWORD dwUrlComponentLen = MAX_PATH;
  2830. IStream *pStream = NULL;
  2831. LPMESSAGEINFO pmiFreeSource = NULL;
  2832. MESSAGEIDLIST rIdList = { 1, 1, &idMessage };
  2833. ZeroMemory(&miDest, sizeof(MESSAGEINFO));
  2834. if (FAILED(hr = GetMessageInfo(m_pFolder, idMessage, &miSource)))
  2835. goto exit;
  2836. pmiFreeSource = &miSource;
  2837. // get the store to generate an id
  2838. if (FAILED(hr = pDestFolder->GenerateId((DWORD *)&miDest.idMessage)))
  2839. goto exit;
  2840. // if the response specified a destination, use it. otherwise, assume
  2841. // that the url component did not change
  2842. if (pszUrl)
  2843. {
  2844. if (FAILED(hr = Http_NameFromUrl(pszUrl, szUrlComponent, &dwUrlComponentLen)))
  2845. goto exit;
  2846. }
  2847. else if (miSource.pszUrlComponent)
  2848. {
  2849. StrCpyN(szUrlComponent, miSource.pszUrlComponent, ARRAYSIZE(szUrlComponent));
  2850. }
  2851. miDest.dwFlags = miSource.dwFlags;
  2852. miDest.dwFlags &= ~(ARF_HASBODY | ARF_DELETED_OFFLINE);
  2853. miDest.pszSubject = miSource.pszSubject;
  2854. miDest.pszNormalSubj = miSource.pszNormalSubj;
  2855. miDest.pszDisplayFrom = miSource.pszDisplayFrom;
  2856. miDest.ftReceived = miSource.ftReceived;
  2857. miDest.pszUrlComponent = szUrlComponent;
  2858. miDest.pszEmailTo = miSource.pszEmailTo;
  2859. // add it to the database
  2860. if (FAILED(hr = m_op.pMessageFolder->InsertRecord(&miDest)))
  2861. goto exit;
  2862. // normalize the result code
  2863. hr = S_OK;
  2864. if (0 != miSource.faStream)
  2865. {
  2866. FILEADDRESS faDst;
  2867. IStream *pStmDst;
  2868. Assert(!!(miSource.dwFlags & ARF_HASBODY));
  2869. if (FAILED(hr = m_pFolder->CopyStream(m_op.pMessageFolder, miSource.faStream, &faDst)))
  2870. goto exit;
  2871. if (FAILED(hr = m_op.pMessageFolder->OpenStream(ACCESS_READ, faDst, &pStmDst)))
  2872. goto exit;
  2873. if (FAILED(hr = m_op.pMessageFolder->SetMessageStream(miDest.idMessage, pStmDst)))
  2874. {
  2875. pStmDst->Release();
  2876. goto exit;
  2877. }
  2878. pStmDst->Release();
  2879. }
  2880. if (fMoveSource)
  2881. hr = m_pFolder->DeleteMessages(DELETE_MESSAGE_NOTRASHCAN | DELETE_MESSAGE_NOPROMPT, &rIdList, NULL, NULL);
  2882. exit:
  2883. SafeRelease(pStream);
  2884. if (NULL != pmiFreeSource)
  2885. m_pFolder->FreeRecord(pmiFreeSource);
  2886. return hr;
  2887. }
  2888. //----------------------------------------------------------------------
  2889. // CHTTPMailServer::_CopyMoveNextMessage
  2890. //----------------------------------------------------------------------
  2891. HRESULT CHTTPMailServer::_CopyMoveNextMessage(void)
  2892. {
  2893. HRESULT hr = S_OK;
  2894. MESSAGEINFO mi = {0};
  2895. MESSAGEINFO *pmiFree = NULL;
  2896. char szUrlComponent[MAX_PATH];
  2897. DWORD dwUrlComponentLen = MAX_PATH;
  2898. LPSTR pszSourceUrl = NULL;
  2899. LPSTR pszDestUrl = NULL;
  2900. // return success when the index meets the count
  2901. if (m_op.dwIndex == m_op.pIDList->cMsgs)
  2902. goto exit;
  2903. if (FAILED(hr = GetMessageInfo(m_pFolder, m_op.pIDList->prgidMsg[m_op.dwIndex], &mi)))
  2904. goto exit;
  2905. pmiFree = &mi;
  2906. ++m_op.dwIndex;
  2907. Assert(mi.pszUrlComponent);
  2908. if (NULL == mi.pszUrlComponent)
  2909. {
  2910. hr = ERROR_INTERNET_INVALID_URL;
  2911. goto exit;
  2912. }
  2913. // build the source url
  2914. if (FAILED(hr = _BuildMessageUrl(m_pszFolderUrl, mi.pszUrlComponent, &pszSourceUrl)))
  2915. goto exit;
  2916. // build the destination url
  2917. if (FAILED(hr = _BuildMessageUrl(m_op.pszDestFolderUrl, mi.pszUrlComponent, &pszDestUrl)))
  2918. goto exit;
  2919. if (!!(m_op.dwOptions & COPY_MESSAGE_MOVE))
  2920. hr = m_pTransport->CommandMOVE(pszSourceUrl, pszDestUrl, TRUE, 0);
  2921. else
  2922. hr = m_pTransport->CommandCOPY(pszSourceUrl, pszDestUrl, TRUE, 0);
  2923. if (SUCCEEDED(hr))
  2924. hr = E_PENDING;
  2925. exit:
  2926. if (NULL != pmiFree)
  2927. m_pFolder->FreeRecord(pmiFree);
  2928. SafeMemFree(pszSourceUrl);
  2929. SafeMemFree(pszDestUrl);
  2930. return hr;
  2931. }
  2932. //----------------------------------------------------------------------
  2933. // CHTTPMailServer::_DoCopyMoveMessages
  2934. //----------------------------------------------------------------------
  2935. HRESULT CHTTPMailServer::_DoCopyMoveMessages(STOREOPERATIONTYPE sot,
  2936. IMessageFolder *pDest,
  2937. COPYMESSAGEFLAGS dwOptions,
  2938. LPMESSAGEIDLIST pList,
  2939. IStoreCallback *pCallback)
  2940. {
  2941. HRESULT hr = S_OK;
  2942. AssertSingleThreaded;
  2943. Assert(NULL == pList || pList->cMsgs > 0);
  2944. Assert(SOT_INVALID == m_op.tyOperation);
  2945. Assert(NULL != m_pStore);
  2946. if ((NULL == pList) || (0 == pList->cMsgs) || (NULL == pDest) || (NULL == pCallback))
  2947. return E_INVALIDARG;
  2948. if (FAILED(hr = pDest->GetFolderId(&m_op.idFolder)))
  2949. goto exit;
  2950. if (FAILED(hr = CloneMessageIDList(pList, &m_op.pIDList)))
  2951. {
  2952. m_op.idFolder = FOLDERID_INVALID;
  2953. goto exit;
  2954. }
  2955. m_op.tyOperation = sot;
  2956. if (1 == pList->cMsgs)
  2957. {
  2958. m_op.pfnState = c_rgpfnCopyMoveMessage;
  2959. m_op.cState = ARRAYSIZE(c_rgpfnCopyMoveMessage);
  2960. }
  2961. else
  2962. {
  2963. m_op.pfnState = c_rgpfnBatchCopyMoveMessages;
  2964. m_op.cState = ARRAYSIZE(c_rgpfnBatchCopyMoveMessages);
  2965. }
  2966. m_op.dwOptions = dwOptions;
  2967. m_op.iState = 0;
  2968. m_op.pCallback = pCallback;
  2969. m_op.pCallback->AddRef();
  2970. m_op.pMessageFolder = pDest;
  2971. m_op.pMessageFolder->AddRef();
  2972. hr = _BeginDeferredOperation();
  2973. exit:
  2974. return hr;
  2975. }
  2976. //----------------------------------------------------------------------
  2977. // CHTTPMailServer::_LoadAccountInfo
  2978. //----------------------------------------------------------------------
  2979. HRESULT CHTTPMailServer::_LoadAccountInfo(IImnAccount *pAcct)
  2980. {
  2981. HRESULT hr = S_OK;
  2982. FOLDERINFO fi;
  2983. FOLDERINFO *pfiFree = NULL;;
  2984. Assert(NULL != pAcct);
  2985. Assert(FOLDERID_INVALID != m_idServer);
  2986. Assert(NULL != m_pStore);
  2987. Assert(NULL != g_pAcctMan);
  2988. // free data associated with the account. if we connected to
  2989. // a transport, and then disconnected, we might be reconnecting
  2990. // with stale data left around.
  2991. SafeMemFree(m_pszFldrLeafName);
  2992. IF_FAILEXIT(hr = m_pStore->GetFolderInfo(m_idServer, &fi));
  2993. pfiFree = &fi;
  2994. m_pszFldrLeafName = PszDupA(fi.pszName);
  2995. if (NULL == m_pszFldrLeafName)
  2996. {
  2997. hr = TraceResult(E_OUTOFMEMORY);
  2998. goto exit;
  2999. }
  3000. // failure of the account name is recoverable
  3001. pAcct->GetPropSz(AP_ACCOUNT_NAME, m_szAccountName, sizeof(m_szAccountName));
  3002. exit:
  3003. if (pfiFree)
  3004. m_pStore->FreeRecord(pfiFree);
  3005. return hr;
  3006. }
  3007. //----------------------------------------------------------------------
  3008. // CHTTPMailServer::_LoadTransport
  3009. //----------------------------------------------------------------------
  3010. HRESULT CHTTPMailServer::_LoadTransport(void)
  3011. {
  3012. HRESULT hr = S_OK;
  3013. char szLogFilePath[MAX_PATH];
  3014. char *pszLogFilePath = NULL;
  3015. LPSTR pszUserAgent = NULL;
  3016. Assert(NULL == m_pTransport);
  3017. // Create and initialize HTTPMail transport
  3018. hr = CoCreateInstance(CLSID_IHTTPMailTransport, NULL, CLSCTX_INPROC_SERVER, IID_IHTTPMailTransport, (LPVOID *)&m_pTransport);
  3019. if (FAILED(hr))
  3020. {
  3021. TraceResult(hr);
  3022. goto exit;
  3023. }
  3024. IF_FAILEXIT(hr = m_pTransport->QueryInterface(IID_IHTTPMailTransport2, (LPVOID*)&m_pTransport2));
  3025. // check if logging is enabled
  3026. if (DwGetOption(OPT_MAIL_LOGHTTPMAIL))
  3027. {
  3028. char szDirectory[MAX_PATH];
  3029. char szLogFileName[MAX_PATH];
  3030. DWORD cb;
  3031. *szDirectory = 0;
  3032. // get the log filename
  3033. cb = GetOption(OPT_MAIL_HTTPMAILLOGFILE, szLogFileName, sizeof(szLogFileName) / sizeof(TCHAR));
  3034. if (0 == cb)
  3035. {
  3036. // push the defaults into the registry
  3037. StrCpyN(szLogFileName, c_szDefaultHTTPMailLog, ARRAYSIZE(szLogFileName));
  3038. SetOption(OPT_MAIL_HTTPMAILLOGFILE,
  3039. (void *)c_szDefaultHTTPMailLog,
  3040. lstrlen(c_szDefaultHTTPMailLog) + sizeof(TCHAR),
  3041. NULL,
  3042. 0);
  3043. }
  3044. m_pStore->GetDirectory(szDirectory, ARRAYSIZE(szDirectory));
  3045. PathCombineA(szLogFilePath, szDirectory, szLogFileName);
  3046. pszLogFilePath = szLogFilePath;
  3047. }
  3048. pszUserAgent = GetOEUserAgentString();
  3049. if (FAILED(hr = m_pTransport->InitNew(pszUserAgent, pszLogFilePath, this)))
  3050. {
  3051. TraceResult(hr);
  3052. goto exit;
  3053. }
  3054. exit:
  3055. SafeMemFree(pszUserAgent);
  3056. return hr;
  3057. }
  3058. //----------------------------------------------------------------------
  3059. // CHTTPMailServer::_TranslateHTTPSpecialFolderType
  3060. //----------------------------------------------------------------------
  3061. SPECIALFOLDER CHTTPMailServer::_TranslateHTTPSpecialFolderType(HTTPMAILSPECIALFOLDER tySpecial)
  3062. {
  3063. SPECIALFOLDER tyOESpecial;
  3064. switch (tySpecial)
  3065. {
  3066. case HTTPMAIL_SF_INBOX:
  3067. tyOESpecial = FOLDER_INBOX;
  3068. break;
  3069. case HTTPMAIL_SF_DELETEDITEMS:
  3070. tyOESpecial = FOLDER_DELETED;
  3071. break;
  3072. case HTTPMAIL_SF_DRAFTS:
  3073. tyOESpecial = FOLDER_DRAFT;
  3074. break;
  3075. case HTTPMAIL_SF_OUTBOX:
  3076. tyOESpecial = FOLDER_OUTBOX;
  3077. break;
  3078. case HTTPMAIL_SF_SENTITEMS:
  3079. tyOESpecial = FOLDER_SENT;
  3080. break;
  3081. case HTTPMAIL_SF_MSNPROMO:
  3082. tyOESpecial = FOLDER_MSNPROMO;
  3083. break;
  3084. case HTTPMAIL_SF_BULKMAIL:
  3085. tyOESpecial = FOLDER_BULKMAIL;
  3086. break;
  3087. default:
  3088. tyOESpecial = FOLDER_NOTSPECIAL;
  3089. break;
  3090. }
  3091. return tyOESpecial;
  3092. }
  3093. //----------------------------------------------------------------------
  3094. // CHTTPMailServer::_LoadSpecialFolderName
  3095. //----------------------------------------------------------------------
  3096. BOOL CHTTPMailServer::_LoadSpecialFolderName(SPECIALFOLDER tySpecial,
  3097. LPSTR pszName,
  3098. DWORD cbBuffer)
  3099. {
  3100. BOOL fResult = TRUE;
  3101. UINT uID;
  3102. switch (tySpecial)
  3103. {
  3104. case FOLDER_INBOX:
  3105. uID = idsInbox;
  3106. break;
  3107. case FOLDER_DELETED:
  3108. uID = idsDeletedItems;
  3109. break;
  3110. case FOLDER_DRAFT:
  3111. uID = idsDraft;
  3112. break;
  3113. case FOLDER_OUTBOX:
  3114. uID = idsOutbox;
  3115. break;
  3116. case FOLDER_SENT:
  3117. uID = idsSentItems;
  3118. break;
  3119. case FOLDER_MSNPROMO:
  3120. uID = idsMsnPromo;
  3121. break;
  3122. case FOLDER_BULKMAIL:
  3123. uID = idsJunkFolderName;
  3124. break;
  3125. default:
  3126. fResult = FALSE;
  3127. break;
  3128. }
  3129. if (fResult && (0 == LoadString(g_hLocRes, uID, pszName, cbBuffer)))
  3130. fResult = FALSE;
  3131. return fResult;
  3132. }
  3133. //----------------------------------------------------------------------
  3134. // CHTTPMailServer::_CreateMessageIDMap
  3135. //----------------------------------------------------------------------
  3136. HRESULT CHTTPMailServer::_CreateMessageIDMap(TMap<CSimpleString, MARKEDMESSAGE> **ppMap)
  3137. {
  3138. HRESULT hr = S_OK;
  3139. TMap<CSimpleString, MARKEDMESSAGE> *pMap = NULL;
  3140. HROWSET hRowSet = NULL;
  3141. MESSAGEINFO mi;
  3142. CSimpleString ss;
  3143. MARKEDMESSAGE markedID = { 0, 0, FALSE };
  3144. if (NULL == m_pStore || NULL == ppMap)
  3145. return E_INVALIDARG;
  3146. *ppMap = NULL;
  3147. pMap = new TMap<CSimpleString, MARKEDMESSAGE>;
  3148. if (NULL == pMap)
  3149. {
  3150. hr = E_OUTOFMEMORY;
  3151. goto exit;
  3152. }
  3153. ZeroMemory(&mi, sizeof(MESSAGEINFO));
  3154. if (FAILED(hr = m_pFolder->CreateRowset(IINDEX_PRIMARY, NOFLAGS, &hRowSet)))
  3155. goto exit;
  3156. // iterate through the messages
  3157. while (S_OK == m_pFolder->QueryRowset(hRowSet, 1, (LPVOID *)&mi, NULL))
  3158. {
  3159. // add the message's info to the map
  3160. markedID.idMessage = mi.idMessage;
  3161. markedID.dwFlags = mi.dwFlags;
  3162. hr = ss.SetString(mi.pszUrlComponent);
  3163. if (FAILED(hr))
  3164. {
  3165. m_pFolder->FreeRecord(&mi);
  3166. goto exit;
  3167. }
  3168. hr = pMap->Add(ss, markedID);
  3169. // Free
  3170. m_pFolder->FreeRecord(&mi);
  3171. if (FAILED(hr))
  3172. goto exit;
  3173. }
  3174. // the map was built successfully
  3175. *ppMap = pMap;
  3176. pMap = NULL;
  3177. exit:
  3178. if (NULL != hRowSet)
  3179. m_pFolder->CloseRowset(&hRowSet);
  3180. if (NULL != pMap)
  3181. delete pMap;
  3182. return hr;
  3183. }
  3184. //----------------------------------------------------------------------
  3185. // CHTTPMailServer::_HrBuildMapAndTargets
  3186. //----------------------------------------------------------------------
  3187. HRESULT CHTTPMailServer::_HrBuildMapAndTargets(LPMESSAGEIDLIST pList,
  3188. HROWSET hRowSet,
  3189. LPADJUSTFLAGS pFlags,
  3190. SETMESSAGEFLAGSFLAGS dwFlags,
  3191. TMap<CSimpleString, MARKEDMESSAGE> **ppMap,
  3192. LPHTTPTARGETLIST *ppTargets)
  3193. {
  3194. HRESULT hr = S_OK;
  3195. TMap<CSimpleString, MARKEDMESSAGE> *pMap = NULL;
  3196. LPHTTPTARGETLIST pTargets = NULL;
  3197. MESSAGEINFO mi = { 0 };
  3198. LPMESSAGEINFO pmiFree = NULL;
  3199. CSimpleString ss;
  3200. MARKEDMESSAGE markedID = { 0, 0, FALSE };
  3201. BOOL fSkipRead = (pFlags && !!(pFlags->dwAdd & ARF_READ));
  3202. BOOL fSkipUnread = (pFlags && !!(pFlags->dwRemove & ARF_READ));
  3203. DWORD cMsgs;
  3204. DWORD dwIndex = 0;
  3205. if ((NULL == pList && NULL == hRowSet) || NULL == ppMap || NULL == ppTargets)
  3206. return E_INVALIDARG;
  3207. // expect either a list or a rowset, but not both
  3208. Assert(NULL == pList || NULL == hRowSet);
  3209. // if using a rowset, determine the rowcount
  3210. if (NULL != hRowSet)
  3211. {
  3212. IF_FAILEXIT(hr = m_pFolder->GetRecordCount(0, &cMsgs));
  3213. // seek the first row
  3214. IF_FAILEXIT(hr = m_pFolder->SeekRowset(hRowSet, SEEK_ROWSET_BEGIN, 0, NULL));
  3215. }
  3216. else
  3217. cMsgs = pList->cMsgs;
  3218. *ppMap = NULL;
  3219. *ppTargets = NULL;
  3220. pMap = new TMap<CSimpleString, MARKEDMESSAGE>;
  3221. if (NULL == pMap)
  3222. {
  3223. hr = TrapError(E_OUTOFMEMORY);
  3224. goto exit;
  3225. }
  3226. if (!MemAlloc((void **)&pTargets, sizeof(HTTPTARGETLIST)))
  3227. {
  3228. hr = TrapError(E_OUTOFMEMORY);
  3229. goto exit;
  3230. }
  3231. pTargets->cTarget = 0;
  3232. pTargets->prgTarget = NULL;
  3233. // allocate enough space for all of the targets
  3234. if (!MemAlloc((void **)&pTargets->prgTarget, sizeof(LPCSTR) * cMsgs))
  3235. {
  3236. hr = TrapError(E_OUTOFMEMORY);
  3237. goto exit;
  3238. }
  3239. ZeroMemory(pTargets->prgTarget, sizeof(LPCSTR) * cMsgs);
  3240. while (TRUE)
  3241. {
  3242. // fetch the next message
  3243. if (NULL != pList)
  3244. {
  3245. if (dwIndex == pList->cMsgs)
  3246. break;
  3247. hr = GetMessageInfo(m_pFolder, pList->prgidMsg[dwIndex++], &mi);
  3248. // if the record wasn't found, just skip it
  3249. if (DB_E_NOTFOUND == hr)
  3250. goto next;
  3251. if (FAILED(hr))
  3252. break;
  3253. }
  3254. else
  3255. {
  3256. // bail out if the number of targets is the same as the rowcount
  3257. // we expected. this will prevent us from overflowing the target
  3258. // array if the rowcount changes while we are building up our target
  3259. // list.
  3260. if (pTargets->cTarget == cMsgs)
  3261. break;
  3262. if (S_OK != m_pFolder->QueryRowset(hRowSet, 1, (LPVOID *)&mi, NULL))
  3263. break;
  3264. }
  3265. pmiFree = &mi;
  3266. // respect control flags, if they exist
  3267. if (0 == (dwFlags & SET_MESSAGE_FLAGS_FORCE) && ((fSkipRead && !!(mi.dwFlags & ARF_READ)) || (fSkipUnread && !(mi.dwFlags & ARF_READ))))
  3268. goto next;
  3269. Assert(NULL != mi.pszUrlComponent);
  3270. if (NULL == mi.pszUrlComponent)
  3271. {
  3272. hr = TrapError(ERROR_INTERNET_INVALID_URL);
  3273. goto exit;
  3274. }
  3275. // add the url component to the target list
  3276. pTargets->prgTarget[pTargets->cTarget] = PszDupA(mi.pszUrlComponent);
  3277. if (NULL == pTargets->prgTarget[pTargets->cTarget])
  3278. {
  3279. hr = TrapError(E_OUTOFMEMORY);
  3280. goto exit;
  3281. }
  3282. pTargets->cTarget++;
  3283. // add the url and the message id to the map
  3284. markedID.idMessage = mi.idMessage;
  3285. markedID.dwFlags = mi.dwFlags;
  3286. if (FAILED(hr = ss.SetString(mi.pszUrlComponent)))
  3287. goto exit;
  3288. if (FAILED(hr = pMap->Add(ss, markedID)))
  3289. goto exit;
  3290. next:
  3291. if (pmiFree)
  3292. {
  3293. m_pFolder->FreeRecord(pmiFree);
  3294. pmiFree = NULL;
  3295. }
  3296. hr = S_OK;
  3297. }
  3298. *ppMap = pMap;
  3299. pMap = NULL;
  3300. *ppTargets = pTargets;
  3301. pTargets = NULL;
  3302. exit:
  3303. if (pmiFree)
  3304. m_pFolder->FreeRecord(pmiFree);
  3305. if (pTargets)
  3306. Http_FreeTargetList(pTargets);
  3307. SafeDelete(pMap);
  3308. return hr;
  3309. }
  3310. //----------------------------------------------------------------------
  3311. // CHTTPMailServer::_FillStoreError
  3312. //----------------------------------------------------------------------
  3313. void CHTTPMailServer::_FillStoreError(LPSTOREERROR pErrorInfo,
  3314. IXPRESULT *pResult)
  3315. {
  3316. TraceCall("CHTTPMailServer::FillStoreError");
  3317. Assert(m_cRef >= 0); // Can be called during destruction
  3318. Assert(NULL != pErrorInfo);
  3319. //TODO: Fill in pszFolder
  3320. // Fill out the STOREERROR structure
  3321. ZeroMemory(pErrorInfo, sizeof(*pErrorInfo));
  3322. if (IXP_E_USER_CANCEL == pResult->hrResult)
  3323. pErrorInfo->hrResult = STORE_E_OPERATION_CANCELED;
  3324. else
  3325. pErrorInfo->hrResult = pResult->hrResult;
  3326. pErrorInfo->uiServerError = pResult->uiServerError;
  3327. pErrorInfo->hrServerError = pResult->hrServerError;
  3328. pErrorInfo->dwSocketError = pResult->dwSocketError;
  3329. pErrorInfo->pszProblem = (NULL != m_op.pszProblem) ? m_op.pszProblem : pResult->pszProblem;
  3330. pErrorInfo->pszDetails = pResult->pszResponse;
  3331. pErrorInfo->pszAccount = m_rInetServerInfo.szAccount;
  3332. pErrorInfo->pszServer = m_rInetServerInfo.szServerName;
  3333. pErrorInfo->pszFolder = NULL;
  3334. pErrorInfo->pszUserName = m_rInetServerInfo.szUserName;
  3335. pErrorInfo->pszProtocol = "HTTPMail";
  3336. pErrorInfo->pszConnectoid = m_rInetServerInfo.szConnectoid;
  3337. pErrorInfo->rasconntype = m_rInetServerInfo.rasconntype;
  3338. pErrorInfo->ixpType = IXP_HTTPMail;
  3339. pErrorInfo->dwPort = m_rInetServerInfo.dwPort;
  3340. pErrorInfo->fSSL = m_rInetServerInfo.fSSL;
  3341. pErrorInfo->fTrySicily = m_rInetServerInfo.fTrySicily;
  3342. pErrorInfo->dwFlags = 0;
  3343. }
  3344. STDMETHODIMP CHTTPMailServer::GetAdBarUrl(IStoreCallback *pCallback)
  3345. {
  3346. TraceCall("CHTTPMailServer::GetAdBarUrl");
  3347. AssertSingleThreaded;
  3348. Assert(NULL != pCallback);
  3349. Assert(SOT_INVALID == m_op.tyOperation);
  3350. Assert(NULL != m_pStore);
  3351. if (NULL == pCallback)
  3352. return E_INVALIDARG;
  3353. m_op.tyOperation = SOT_GET_ADURL;
  3354. m_op.iState = 0;
  3355. m_op.pfnState = c_rgpfnGetAdUrl;
  3356. m_op.cState = ARRAYSIZE(c_rgpfnGetAdUrl);
  3357. m_op.pCallback = pCallback;
  3358. m_op.pCallback->AddRef();
  3359. return _BeginDeferredOperation();
  3360. }
  3361. HRESULT CHTTPMailServer::GetAdBarUrlFromServer()
  3362. {
  3363. HRESULT hr = S_OK;
  3364. LPSTR pszUrl = NULL;
  3365. hr = m_pTransport->GetProperty(HTTPMAIL_PROP_ADBAR, &pszUrl);
  3366. if (hr == S_OK)
  3367. m_op.pszAdUrl = pszUrl;
  3368. return hr;
  3369. }
  3370. STDMETHODIMP CHTTPMailServer::GetMinPollingInterval(IStoreCallback *pCallback)
  3371. {
  3372. TraceCall("CHTTPMailServer::GetMinPollingInterval");
  3373. AssertSingleThreaded;
  3374. Assert(NULL != pCallback);
  3375. Assert(SOT_INVALID == m_op.tyOperation);
  3376. Assert(NULL != m_pStore);
  3377. if (NULL == pCallback)
  3378. return E_INVALIDARG;
  3379. m_op.tyOperation = SOT_GET_HTTP_MINPOLLINGINTERVAL;
  3380. m_op.iState = 0;
  3381. m_op.pfnState = c_rgpfnGetMinPollingInterval;
  3382. m_op.cState = ARRAYSIZE(c_rgpfnGetMinPollingInterval);
  3383. m_op.pCallback = pCallback;
  3384. m_op.pCallback->AddRef();
  3385. return _BeginDeferredOperation();
  3386. }
  3387. HRESULT CHTTPMailServer::GetMinPollingInterval()
  3388. {
  3389. DWORD dwDone = FALSE;
  3390. DWORD dwPollingInterval = 0;
  3391. HRESULT hr = S_OK;
  3392. hr = m_pTransport->GetPropertyDw(HTTPMAIL_PROP_MAXPOLLINGINTERVAL, &dwPollingInterval);
  3393. if (hr == S_OK)
  3394. m_op.dwMinPollingInterval = dwPollingInterval;
  3395. return hr;
  3396. }