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.

1157 lines
35 KiB

  1. // --------------------------------------------------------------------------------
  2. // h t t p t a s k . h
  3. // Copyright (c)1998 Microsoft Corporation, All Rights Reserved
  4. // Greg S. Friedman
  5. // --------------------------------------------------------------------------------
  6. #include "pch.hxx"
  7. #include "httptask.h"
  8. #include "taskutil.h"
  9. #include "acctcach.h"
  10. #include "xputil.h"
  11. #include "useragnt.h"
  12. #include "..\http\httputil.h"
  13. // --------------------------------------------------------------------------------
  14. // Data Types
  15. // --------------------------------------------------------------------------------
  16. typedef enum tagHTTPEVENTTYPE
  17. {
  18. EVENT_HTTPSEND
  19. } HTTPEVENTTYPE;
  20. #define CURRENTHTTPEVENT ((LPHTTPEVENTINFO)m_psaEvents->GetItemAt(m_iEvent))
  21. //----------------------------------------------------------------------
  22. // FreeNewMessageInfo
  23. //----------------------------------------------------------------------
  24. static void __cdecl _FreeHTTPEventInfo(LPVOID pei)
  25. {
  26. Assert(NULL != pei);
  27. SafeMemFree(pei);
  28. }
  29. // --------------------------------------------------------------------------------
  30. // CHTTPTask::CHTTPTask
  31. // --------------------------------------------------------------------------------
  32. CHTTPTask::CHTTPTask(void) :
  33. m_cRef(1),
  34. m_dwFlags(NOFLAGS),
  35. m_dwState(NOFLAGS),
  36. m_cbTotal(0),
  37. m_cbSent(0),
  38. m_cbStart(0),
  39. m_cCompleted(0),
  40. m_wProgress(0),
  41. m_pSpoolCtx(NULL),
  42. m_pAccount(NULL),
  43. m_pOutbox(NULL),
  44. m_pSentItems(NULL),
  45. m_psaEvents(NULL),
  46. m_iEvent(0),
  47. m_pszSubject(NULL),
  48. m_pBody(NULL),
  49. m_pTransport(NULL),
  50. m_pUI(NULL),
  51. m_idSendEvent(INVALID_EVENT),
  52. m_pszAccountId(NULL),
  53. m_pszSendMsgUrl(NULL)
  54. {
  55. InitializeCriticalSection(&m_cs);
  56. ZeroMemory(&m_rServer, sizeof(m_rServer));
  57. }
  58. // --------------------------------------------------------------------------------
  59. // CHTTPTask::~CHTTPTask
  60. // --------------------------------------------------------------------------------
  61. CHTTPTask::~CHTTPTask(void)
  62. {
  63. ZeroMemory(&m_rServer, sizeof(m_rServer)); // Done for security.
  64. _Reset();
  65. DeleteCriticalSection(&m_cs);
  66. }
  67. // --------------------------------------------------------------------------------
  68. // CHTTPTask::QueryInterface
  69. // --------------------------------------------------------------------------------
  70. STDMETHODIMP CHTTPTask::QueryInterface(REFIID riid, LPVOID *ppv)
  71. {
  72. // Locals
  73. HRESULT hr = S_OK;
  74. // check params
  75. if (ppv == NULL)
  76. return TrapError(E_INVALIDARG);
  77. // Thread Safety
  78. EnterCriticalSection(&m_cs);
  79. // Find IID
  80. if (IID_IUnknown == riid)
  81. *ppv = (IUnknown *)(ISpoolerTask *)this;
  82. else if (IID_ISpoolerTask == riid)
  83. *ppv = (ISpoolerTask *)this;
  84. else
  85. {
  86. *ppv = NULL;
  87. hr = TrapError(E_NOINTERFACE);
  88. goto exit;
  89. }
  90. // AddRef It
  91. ((IUnknown *)*ppv)->AddRef();
  92. exit:
  93. // Thread Safety
  94. LeaveCriticalSection(&m_cs);
  95. // Done
  96. return hr;
  97. }
  98. // --------------------------------------------------------------------------------
  99. // CHTTPTask::AddRef
  100. // --------------------------------------------------------------------------------
  101. STDMETHODIMP_(ULONG) CHTTPTask::AddRef(void)
  102. {
  103. return InterlockedIncrement(&m_cRef);
  104. }
  105. // --------------------------------------------------------------------------------
  106. // CHTTPTask::Release
  107. // --------------------------------------------------------------------------------
  108. STDMETHODIMP_(ULONG) CHTTPTask::Release(void)
  109. {
  110. LONG cRef = InterlockedDecrement(&m_cRef);
  111. if (0 == cRef)
  112. delete this;
  113. return (ULONG)cRef;
  114. }
  115. // ---------------------------------------------------------------------------
  116. // ISpoolerTask Methods
  117. // ---------------------------------------------------------------------------
  118. // --------------------------------------------------------------------------------
  119. // CHTTPTask::Init
  120. // --------------------------------------------------------------------------------
  121. STDMETHODIMP CHTTPTask::Init(DWORD dwFlags, ISpoolerBindContext *pBindCtx)
  122. {
  123. // Invalid Arg
  124. if (NULL == pBindCtx)
  125. return TrapError(E_INVALIDARG);
  126. // Thread Safety
  127. EnterCriticalSection(&m_cs);
  128. // Save the Activity Flags - DELIVER_xxx
  129. m_dwFlags = dwFlags;
  130. // Hold onto the bind context
  131. Assert(NULL == m_pSpoolCtx);
  132. m_pSpoolCtx = pBindCtx;
  133. m_pSpoolCtx->AddRef();
  134. // Thread Safety
  135. LeaveCriticalSection(&m_cs);
  136. // Done
  137. return S_OK;
  138. }
  139. // --------------------------------------------------------------------------------
  140. // CHTTPTask::BuildEvents
  141. // --------------------------------------------------------------------------------
  142. STDMETHODIMP CHTTPTask::BuildEvents(ISpoolerUI *pSpoolerUI,
  143. IImnAccount *pAccount,
  144. FOLDERID idFolder)
  145. {
  146. HRESULT hr = S_OK;
  147. HROWSET hRowset=NULL;
  148. MESSAGEINFO mi = {0};
  149. CHAR szAccount[CCHMAX_ACCOUNT_NAME];
  150. CHAR szAccountId[CCHMAX_ACCOUNT_NAME];
  151. CHAR szMessage[255];
  152. CHAR szRes[255];
  153. FOLDERINFO fi = {0};
  154. LPFOLDERINFO pfiFree = NULL;
  155. LPSTR pszUserAgent = GetOEUserAgentString();
  156. LPSTR pszCachedPass = NULL;
  157. FOLDERID idServer;
  158. // Invalid Arg
  159. if (NULL == pSpoolerUI || NULL == pAccount)
  160. return TrapError(E_INVALIDARG);
  161. // Thread Safety
  162. EnterCriticalSection(&m_cs);
  163. m_pUI = pSpoolerUI;
  164. m_pUI->AddRef();
  165. m_pAccount = pAccount;
  166. m_pAccount->AddRef();
  167. // Get the Account Name
  168. CHECKHR(hr = m_pAccount->GetPropSz(AP_ACCOUNT_NAME, szAccount, ARRAYSIZE(szAccount)));
  169. // Get the account ID
  170. CHECKHR(hr = m_pAccount->GetPropSz(AP_ACCOUNT_ID, szAccountId, ARRAYSIZE(szAccountId)));
  171. m_pszAccountId = PszDupA(szAccountId);
  172. // Get the outbox
  173. CHECKHR(hr = m_pSpoolCtx->BindToObject(IID_CLocalStoreOutbox, (LPVOID *)&m_pOutbox));
  174. // Get the sent items. Don't fail if it doesn't exist.
  175. if (DwGetOption(OPT_SAVESENTMSGS))
  176. {
  177. if (SUCCEEDED(g_pStore->FindServerId(m_pszAccountId, &idServer)))
  178. g_pStore->OpenSpecialFolder(idServer, NULL, FOLDER_SENT, &m_pSentItems);
  179. }
  180. // Create a Rowset
  181. CHECKHR(hr = m_pOutbox->CreateRowset(IINDEX_PRIMARY, NOFLAGS, &hRowset));
  182. // Loop
  183. while (S_OK == m_pOutbox->QueryRowset(hRowset, 1, (LPVOID *)&mi, NULL))
  184. {
  185. CHECKHR(hr = _HrAppendOutboxMessage(szAccount, &mi));
  186. // Free Current
  187. m_pOutbox->FreeRecord(&mi);
  188. }
  189. if (NULL == m_psaEvents || 0 == m_psaEvents->GetLength())
  190. goto exit;
  191. // create the transport object
  192. CHECKHR(hr = CoCreateInstance(CLSID_IHTTPMailTransport, NULL, CLSCTX_INPROC_SERVER, IID_IHTTPMailTransport, (LPVOID *)&m_pTransport));
  193. // Init the Transport
  194. CHECKHR(hr = m_pTransport->InitNew(pszUserAgent, NULL, this));
  195. // Fill an INETSERVER structure from the account object
  196. CHECKHR(hr = m_pTransport->InetServerFromAccount(m_pAccount, &m_rServer));
  197. // looked for a cached password and, if one exists, use it
  198. GetAccountPropStrA(m_pszAccountId, CAP_PASSWORD, &pszCachedPass);
  199. if (NULL != pszCachedPass)
  200. StrCpyN(m_rServer.szPassword, pszCachedPass, sizeof(m_rServer.szPassword));
  201. // connect to the server. the transport won't
  202. // actually connect until a command is issued
  203. CHECKHR(hr = m_pTransport->Connect(&m_rServer, TRUE, FALSE));
  204. LOADSTRING(IDS_SPS_SMTPEVENT, szRes);
  205. wnsprintf(szMessage, ARRAYSIZE(szMessage), szRes, m_psaEvents->GetLength(), m_rServer.szAccount);
  206. CHECKHR(hr = m_pSpoolCtx->RegisterEvent(szMessage, (ISpoolerTask *)this, EVENT_HTTPSEND, m_pAccount, &m_idSendEvent));
  207. // If this account is set to always prompt for password and password isn't
  208. // already cached, show UI so we can prompt user for password
  209. if (ISFLAGSET(m_rServer.dwFlags, ISF_ALWAYSPROMPTFORPASSWORD) && NULL == pszCachedPass)
  210. {
  211. m_pUI->ShowWindow(SW_SHOW);
  212. }
  213. exit:
  214. // Cleanup
  215. SafeMemFree(pszUserAgent);
  216. SafeMemFree(pszCachedPass);
  217. if (m_pOutbox)
  218. {
  219. m_pOutbox->CloseRowset(&hRowset);
  220. m_pOutbox->FreeRecord(&mi);
  221. }
  222. LeaveCriticalSection(&m_cs);
  223. return hr;
  224. }
  225. // --------------------------------------------------------------------------------
  226. // CHTTPTask::Execute
  227. // --------------------------------------------------------------------------------
  228. STDMETHODIMP CHTTPTask::Execute(EVENTID eid, DWORD_PTR dwTwinkie)
  229. {
  230. HRESULT hr = E_FAIL;
  231. // Thread Safety
  232. EnterCriticalSection(&m_cs);
  233. if (EVENT_HTTPSEND == dwTwinkie)
  234. hr = _HrExecuteSend(eid, dwTwinkie);
  235. // Thread Safety
  236. LeaveCriticalSection(&m_cs);
  237. // Done
  238. return hr;
  239. }
  240. // --------------------------------------------------------------------------------
  241. // CHTTPTask::CancelEvent
  242. // --------------------------------------------------------------------------------
  243. STDMETHODIMP CHTTPTask::CancelEvent(EVENTID eid, DWORD_PTR dwTwinkie)
  244. {
  245. return S_OK;
  246. }
  247. // --------------------------------------------------------------------------------
  248. // CHTTPTask::Cancel
  249. // --------------------------------------------------------------------------------
  250. STDMETHODIMP CHTTPTask::Cancel(void)
  251. {
  252. // Thread Safety
  253. EnterCriticalSection(&m_cs);
  254. m_dwState |= HTTPSTATE_CANCELED;
  255. // Simply drop the connection
  256. if (m_pTransport)
  257. m_pTransport->DropConnection();
  258. // Thread Safety
  259. LeaveCriticalSection(&m_cs);
  260. // Done
  261. return S_OK;
  262. }
  263. // --------------------------------------------------------------------------------
  264. // CHTTPTask::IsDialogMessage
  265. // --------------------------------------------------------------------------------
  266. STDMETHODIMP CHTTPTask::IsDialogMessage(LPMSG pMsg)
  267. {
  268. return S_FALSE;
  269. }
  270. // --------------------------------------------------------------------------------
  271. // CHTTPTask::OnFlagsChanged
  272. // --------------------------------------------------------------------------------
  273. STDMETHODIMP CHTTPTask::OnFlagsChanged(DWORD dwFlags)
  274. {
  275. return S_OK;
  276. }
  277. // --------------------------------------------------------------------------------
  278. // CHTTPTask::OnLogonPrompt
  279. // --------------------------------------------------------------------------------
  280. STDMETHODIMP CHTTPTask::OnLogonPrompt(
  281. LPINETSERVER pInetServer,
  282. IInternetTransport *pTransport)
  283. {
  284. HRESULT hr = S_OK;
  285. LPSTR pszCachedPass = NULL;
  286. EnterCriticalSection(&m_cs);
  287. // pull password out of the cache
  288. GetAccountPropStrA(m_pszAccountId, CAP_PASSWORD, &pszCachedPass);
  289. if (NULL != pszCachedPass && 0 != lstrcmp(pszCachedPass, pInetServer->szPassword))
  290. {
  291. StrCpyN(pInetServer->szPassword, pszCachedPass, ARRAYSIZE(pInetServer->szPassword));
  292. goto exit;
  293. }
  294. if (ISFLAGSET(m_dwFlags, DELIVER_NOUI))
  295. {
  296. hr = S_FALSE;
  297. goto exit;
  298. }
  299. hr = TaskUtil_OnLogonPrompt(m_pAccount, m_pUI, NULL, pInetServer, AP_HTTPMAIL_USERNAME,
  300. AP_HTTPMAIL_PASSWORD, AP_HTTPMAIL_PROMPT_PASSWORD, TRUE);
  301. // cache the password
  302. if (S_OK == hr)
  303. HrCacheAccountPropStrA(m_pszAccountId, CAP_PASSWORD, pInetServer->szPassword);
  304. exit:
  305. LeaveCriticalSection(&m_cs);
  306. SafeMemFree(pszCachedPass);
  307. return hr;
  308. }
  309. // --------------------------------------------------------------------------------
  310. // CHTTPTask::OnPrompt
  311. // --------------------------------------------------------------------------------
  312. STDMETHODIMP_(INT) CHTTPTask::OnPrompt(
  313. HRESULT hrError,
  314. LPCTSTR pszText,
  315. LPCTSTR pszCaption,
  316. UINT uType,
  317. IInternetTransport *pTransport)
  318. {
  319. return E_NOTIMPL;
  320. }
  321. // --------------------------------------------------------------------------------
  322. // CHTTPTask::OnStatus
  323. // --------------------------------------------------------------------------------
  324. STDMETHODIMP CHTTPTask::OnStatus(IXPSTATUS ixpstatus, IInternetTransport *pTransport)
  325. {
  326. // Locals
  327. EVENTCOMPLETEDSTATUS tyEventStatus = EVENT_SUCCEEDED;
  328. // Invalid State
  329. Assert(m_pUI && m_pSpoolCtx);
  330. if (!m_pUI || !m_pSpoolCtx)
  331. {
  332. return E_FAIL;
  333. }
  334. // Thread Safety
  335. EnterCriticalSection(&m_cs);
  336. // Feed the the IXP status to the UI object
  337. m_pUI->SetSpecificProgress(MAKEINTRESOURCE(XPUtil_StatusToString(ixpstatus)));
  338. // Disconnected
  339. if (ixpstatus == IXP_DISCONNECTED)
  340. {
  341. HRESULT hrDisconnect = _OnDisconnectComplete();
  342. // TODO: update progress state and deal with errors
  343. // Set the animation
  344. m_pUI->SetAnimation(idanOutbox, FALSE);
  345. if (!ISFLAGSET(m_dwState, HTTPSTATE_EVENTSUCCESS) || (NULL != m_cCompleted && m_cCompleted < m_psaEvents->GetLength()))
  346. {
  347. if (ISFLAGSET(m_dwState, HTTPSTATE_CANCELED))
  348. tyEventStatus = EVENT_CANCELED;
  349. else if (ISFLAGSET(m_dwState, HTTPSTATE_EVENTSUCCESS))
  350. tyEventStatus = EVENT_WARNINGS;
  351. else
  352. tyEventStatus = EVENT_FAILED;
  353. }
  354. // Result
  355. m_pSpoolCtx->Notify(DELIVERY_NOTIFY_RESULT, tyEventStatus);
  356. // Result
  357. m_pSpoolCtx->Notify(DELIVERY_NOTIFY_COMPLETE, 0);
  358. // Hands Off my callback
  359. SideAssert(m_pTransport->HandsOffCallback() == S_OK);
  360. // This task is complete
  361. m_pSpoolCtx->EventDone(m_idSendEvent, tyEventStatus);
  362. }
  363. LeaveCriticalSection(&m_cs);
  364. return S_OK;
  365. }
  366. // --------------------------------------------------------------------------------
  367. // CHTTPTask::OnError
  368. // --------------------------------------------------------------------------------
  369. STDMETHODIMP CHTTPTask::OnError(
  370. IXPSTATUS ixpstatus,
  371. LPIXPRESULT pIxpResult,
  372. IInternetTransport *pTransport)
  373. {
  374. return E_NOTIMPL;
  375. }
  376. // --------------------------------------------------------------------------------
  377. // CHTTPTask::OnProgress
  378. // --------------------------------------------------------------------------------
  379. STDMETHODIMP CHTTPTask::OnProgress(
  380. DWORD dwIncrement,
  381. DWORD dwCurrent,
  382. DWORD dwMaximum,
  383. IInternetTransport *pTransport)
  384. {
  385. return E_NOTIMPL;
  386. }
  387. // --------------------------------------------------------------------------------
  388. // CHTTPTask::OnCommand
  389. // --------------------------------------------------------------------------------
  390. STDMETHODIMP CHTTPTask::OnCommand(
  391. CMDTYPE cmdtype,
  392. LPSTR pszLine,
  393. HRESULT hrResponse,
  394. IInternetTransport *pTransport)
  395. {
  396. return E_NOTIMPL;
  397. }
  398. // --------------------------------------------------------------------------------
  399. // CHTTPTask::OnTimeout
  400. // --------------------------------------------------------------------------------
  401. STDMETHODIMP CHTTPTask::OnTimeout(
  402. DWORD *pdwTimeout,
  403. IInternetTransport *pTransport)
  404. {
  405. return E_NOTIMPL;
  406. }
  407. // --------------------------------------------------------------------------------
  408. // IHTTPMailCallback methods
  409. // --------------------------------------------------------------------------------
  410. // --------------------------------------------------------------------------------
  411. // CHTTPTask::OnResponse
  412. // --------------------------------------------------------------------------------
  413. STDMETHODIMP CHTTPTask::OnResponse(LPHTTPMAILRESPONSE pResponse)
  414. {
  415. HRESULT hr = S_OK;
  416. HRESULT hrCatch;
  417. // Thread Safety
  418. EnterCriticalSection(&m_cs);
  419. // if the send message url couldn't be retrieved, convert the error into
  420. // a more informative error code.
  421. if (SP_E_HTTP_SERVICEDOESNTWORK == pResponse->rIxpResult.hrResult)
  422. {
  423. _CatchResult(SP_E_HTTP_NOSENDMSGURL);
  424. goto exit;
  425. }
  426. // Handle the Error
  427. if (TASKRESULT_SUCCESS != _CatchResult(&pResponse->rIxpResult))
  428. goto exit;
  429. switch (pResponse->command)
  430. {
  431. case HTTPMAIL_GETPROP:
  432. if (SUCCEEDED(_HrAdoptSendMsgUrl(pResponse->rGetPropInfo.pszProp)))
  433. {
  434. pResponse->rGetPropInfo.pszProp = NULL;
  435. // build the message and post it
  436. hr = _HrPostCurrentMessage();
  437. }
  438. break;
  439. case HTTPMAIL_SENDMESSAGE:
  440. _UpdateSendMessageProgress(pResponse);
  441. if (pResponse->fDone)
  442. _CatchResult(_HrFinishCurrentEvent(S_OK, pResponse->rSendMessageInfo.pszLocation));
  443. break;
  444. default:
  445. Assert(FALSE);
  446. break;
  447. }
  448. exit:
  449. // Thread Safety
  450. LeaveCriticalSection(&m_cs);
  451. return hr;
  452. }
  453. // --------------------------------------------------------------------------------
  454. // CHTTPTask::GetParentWindow
  455. // --------------------------------------------------------------------------------
  456. STDMETHODIMP CHTTPTask::GetParentWindow(HWND *phwndParent)
  457. {
  458. return E_NOTIMPL;
  459. }
  460. // --------------------------------------------------------------------------------
  461. // Private Implementation
  462. // --------------------------------------------------------------------------------
  463. // --------------------------------------------------------------------------------
  464. // CHTTPTask::_Reset
  465. // --------------------------------------------------------------------------------
  466. void CHTTPTask::_Reset(void)
  467. {
  468. SafeRelease(m_pSpoolCtx);
  469. SafeRelease(m_pAccount);
  470. SafeRelease(m_pOutbox);
  471. SafeRelease(m_pSentItems);
  472. delete m_psaEvents;
  473. m_iEvent = 0;
  474. SafeMemFree(m_pszSubject);
  475. SafeRelease(m_pBody);
  476. SafeRelease(m_pTransport);
  477. SafeRelease(m_pUI);
  478. SafeMemFree(m_pszAccountId);
  479. SafeMemFree(m_pszSendMsgUrl);
  480. }
  481. // --------------------------------------------------------------------------------
  482. // CHTTPTask::_CatchResult
  483. // --------------------------------------------------------------------------------
  484. TASKRESULTTYPE CHTTPTask::_CatchResult(HRESULT hr)
  485. {
  486. // Locals
  487. IXPRESULT rResult;
  488. // Build an IXPRESULT
  489. ZeroMemory(&rResult, sizeof(rResult));
  490. rResult.hrResult = hr;
  491. // Get the HTTPMail Result Type
  492. return _CatchResult(&rResult);
  493. }
  494. // --------------------------------------------------------------------------------
  495. // CHTTPTask::_CatchResult
  496. // --------------------------------------------------------------------------------
  497. TASKRESULTTYPE CHTTPTask::_CatchResult(LPIXPRESULT pResult)
  498. {
  499. HWND hwndParent;
  500. TASKRESULTTYPE tyTaskResult = TASKRESULT_FAILURE;
  501. // If Succeeded
  502. if (SUCCEEDED(pResult->hrResult))
  503. return TASKRESULT_SUCCESS;
  504. // Get Window
  505. if (NULL == m_pUI || FAILED(m_pUI->GetWindow(&hwndParent)))
  506. hwndParent = NULL;
  507. // Process generic protocol error
  508. tyTaskResult = TaskUtil_FBaseTransportError(IXP_HTTPMail, m_idSendEvent, pResult, &m_rServer, m_pszSubject, m_pUI,
  509. !ISFLAGSET(m_dwFlags, DELIVER_NOUI), hwndParent);
  510. // Have a Transport
  511. if (m_pTransport)
  512. {
  513. // If Task Failure, drop the connection
  514. if (TASKRESULT_FAILURE == tyTaskResult)
  515. {
  516. // Roast the current connection
  517. m_pTransport->DropConnection();
  518. }
  519. // If Event Failure...
  520. else if (TASKRESULT_EVENTFAILED == tyTaskResult)
  521. {
  522. // Goto Next Event
  523. if (FAILED(_HrFinishCurrentEvent(pResult->hrResult, NULL)))
  524. {
  525. // Roast the current connection
  526. m_pTransport->DropConnection();
  527. }
  528. }
  529. }
  530. return tyTaskResult;
  531. }
  532. // --------------------------------------------------------------------------------
  533. // CHTTPTask::_HrAppendOutboxMessage
  534. // --------------------------------------------------------------------------------
  535. HRESULT CHTTPTask::_HrAppendOutboxMessage(LPCSTR pszAccount, LPMESSAGEINFO pmi)
  536. {
  537. HRESULT hr = S_OK;
  538. IImnAccount *pAccount = NULL;
  539. LPHTTPEVENTINFO pEvent = NULL;
  540. Assert(NULL != pszAccount && NULL != pmi);
  541. // handle empty account id
  542. if (NULL == pmi->pszAcctId || FAILED(g_pAcctMan->FindAccount(AP_ACCOUNT_ID, pmi->pszAcctId, &pAccount)))
  543. {
  544. // do some special junk with default accounts
  545. goto exit;
  546. }
  547. else if (lstrcmpi(pmi->pszAcctName, pszAccount) != 0)
  548. goto exit;
  549. if (NULL == m_psaEvents)
  550. CHECKHR(hr = CSortedArray::Create(NULL, _FreeHTTPEventInfo, &m_psaEvents));
  551. // build the event object and append it into the event array
  552. if (!MemAlloc((void **)&pEvent, sizeof(HTTPEVENTINFO)))
  553. {
  554. hr = TrapError(E_OUTOFMEMORY);
  555. goto exit;
  556. }
  557. CHECKHR(hr = m_psaEvents->Add(pEvent));
  558. pEvent->idMessage = pmi->idMessage;
  559. pEvent->fComplete = FALSE;
  560. m_cbTotal += (pmi->cbMessage + 175);
  561. pEvent->cbSentTotal = m_cbTotal; // running total
  562. pEvent = NULL;
  563. exit:
  564. SafeMemFree(pEvent);
  565. SafeRelease(pAccount);
  566. return hr;
  567. }
  568. // --------------------------------------------------------------------------------
  569. // CHTTPTask::_HrCreateSendProps
  570. // --------------------------------------------------------------------------------
  571. HRESULT CHTTPTask::_HrCreateSendProps(IMimeMessage *pMessage,
  572. LPSTR *ppszFrom,
  573. LPHTTPTARGETLIST *ppTargets)
  574. {
  575. HRESULT hr = S_OK;
  576. IMimeAddressTable *pAdrTable = NULL;
  577. IMimeEnumAddressTypes *pAdrEnum = NULL;
  578. ADDRESSPROPS rAddress;
  579. ULONG c;
  580. LPSTR pszFrom = NULL;
  581. LPSTR pszTemp = NULL;
  582. LPHTTPTARGETLIST pTargets = NULL;
  583. DWORD dwTargetCapacity = 0;
  584. Assert(NULL != ppszFrom && NULL != ppTargets);
  585. if (NULL == ppszFrom || NULL == ppTargets)
  586. return E_INVALIDARG;
  587. *ppszFrom = NULL;
  588. *ppTargets = NULL;
  589. // allocate a targetlist
  590. if (!MemAlloc((void **)&pTargets, sizeof(HTTPTARGETLIST)))
  591. {
  592. hr = TraceResult(E_OUTOFMEMORY);
  593. goto exit;
  594. }
  595. pTargets->cTarget = 0;
  596. pTargets->prgTarget = NULL;
  597. ZeroMemory(&rAddress, sizeof(rAddress));
  598. // Get the recipients...
  599. CHECKHR(hr = pMessage->GetAddressTable(&pAdrTable));
  600. // Get Enumerator
  601. CHECKHR(hr = pAdrTable->EnumTypes(IAT_KNOWN, IAP_ADRTYPE | IAP_EMAIL, &pAdrEnum));
  602. // Walk the enumerator
  603. while (SUCCEEDED(pAdrEnum->Next(1, &rAddress, &c)) && c == 1)
  604. {
  605. if (NULL != rAddress.pszEmail)
  606. {
  607. // Get Type
  608. if (ISFLAGSET(IAT_RECIPS, rAddress.dwAdrType))
  609. {
  610. // copy the address
  611. pszTemp = PszDupA(rAddress.pszEmail);
  612. if (NULL == pszTemp)
  613. {
  614. hr = TraceResult(E_OUTOFMEMORY);
  615. goto exit;
  616. }
  617. // add it to the collection of addresses we are building
  618. if (pTargets->cTarget == dwTargetCapacity)
  619. {
  620. if (!MemRealloc((void **)&pTargets->prgTarget, (dwTargetCapacity + 4) * sizeof(LPSTR)))
  621. {
  622. hr = TraceResult(E_OUTOFMEMORY);
  623. goto exit;
  624. }
  625. dwTargetCapacity += 4;
  626. }
  627. pTargets->prgTarget[pTargets->cTarget++] = pszTemp;
  628. pszTemp = NULL;
  629. }
  630. else if (NULL == pszFrom && IAT_FROM == rAddress.dwAdrType)
  631. {
  632. pszFrom = PszDupA(rAddress.pszEmail);
  633. if (NULL == pszFrom)
  634. {
  635. hr = TraceResult(E_OUTOFMEMORY);
  636. goto exit;
  637. }
  638. }
  639. }
  640. // Release
  641. g_pMoleAlloc->FreeAddressProps(&rAddress);
  642. }
  643. // success. transfer ownership of the params to the caller
  644. *ppszFrom = pszFrom;
  645. pszFrom = NULL;
  646. *ppTargets = pTargets;
  647. pTargets = NULL;
  648. exit:
  649. if (pTargets)
  650. Http_FreeTargetList(pTargets);
  651. SafeMemFree(pszTemp);
  652. SafeRelease(pAdrTable);
  653. SafeRelease(pAdrEnum);
  654. SafeMemFree(pszFrom);
  655. return hr;
  656. }
  657. // ------------------------------------------------------------------------------------
  658. // CHTTPTask::_HrOpenMessage
  659. // ------------------------------------------------------------------------------------
  660. HRESULT CHTTPTask::_HrOpenMessage(MESSAGEID idMessage, IMimeMessage **ppMessage)
  661. {
  662. // Locals
  663. HRESULT hr=S_OK;
  664. // Check Params
  665. Assert(ppMessage && m_pOutbox);
  666. // Init
  667. *ppMessage = NULL;
  668. // Stream in message
  669. CHECKHR(hr = m_pOutbox->OpenMessage(idMessage, OPEN_MESSAGE_SECURE, ppMessage, NOSTORECALLBACK));
  670. // remove an X-Unsent headers before sending
  671. (*ppMessage)->DeleteBodyProp(HBODY_ROOT, PIDTOSTR(PID_HDR_XUNSENT));
  672. exit:
  673. // Failure
  674. if (FAILED(hr))
  675. SafeRelease((*ppMessage));
  676. // Done
  677. return hr;
  678. }
  679. // --------------------------------------------------------------------------------
  680. // CHTTPTask::_HrPostCurrentMessage
  681. // --------------------------------------------------------------------------------
  682. HRESULT CHTTPTask::_HrPostCurrentMessage(void)
  683. {
  684. HRESULT hr = S_OK;
  685. IMimeMessage *pMessage = NULL;
  686. LPHTTPEVENTINFO pEvent = NULL;
  687. CHAR szRes[CCHMAX_RES];
  688. CHAR szMsg[CCHMAX_RES + CCHMAX_ACCOUNT_NAME];
  689. LPSTR pszFrom = NULL;
  690. LPHTTPTARGETLIST pTargets = NULL;
  691. Assert(NULL != m_psaEvents);
  692. Assert(m_iEvent <= m_psaEvents->GetLength());
  693. pEvent = CURRENTHTTPEVENT;
  694. Assert(NULL != pEvent);
  695. LOADSTRING(IDS_SPS_SMTPPROGRESS, szRes);
  696. wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, m_iEvent + 1, m_psaEvents->GetLength());
  697. // Set Specific Progress
  698. m_pUI->SetSpecificProgress(szMsg);
  699. // Open Store Message
  700. if (FAILED(_HrOpenMessage(pEvent->idMessage, &pMessage)))
  701. {
  702. hr = TrapError(SP_E_SMTP_CANTOPENMESSAGE);
  703. goto exit;
  704. }
  705. CHECKHR(hr = _HrCreateSendProps(pMessage, &pszFrom, &pTargets));
  706. CHECKHR(hr = pMessage->GetMessageSource(&m_pBody, 0));
  707. hr = m_pTransport->SendMessage(m_pszSendMsgUrl, pszFrom, pTargets, DwGetOption(OPT_SAVESENTMSGS), m_pBody, 0);
  708. exit:
  709. SafeRelease(pMessage);
  710. SafeMemFree(pszFrom);
  711. if (pTargets)
  712. Http_FreeTargetList(pTargets);
  713. return hr;
  714. }
  715. // --------------------------------------------------------------------------------
  716. // CHTTPTask::_HrExecuteSend
  717. // --------------------------------------------------------------------------------
  718. HRESULT CHTTPTask::_HrExecuteSend(EVENTID eid, DWORD_PTR dwTwinkie)
  719. {
  720. HRESULT hr = S_OK;
  721. LPSTR pszSendMsgUrl = NULL;
  722. CHAR szRes[CCHMAX_RES];
  723. CHAR szBuf[CCHMAX_RES + CCHMAX_SERVER_NAME];
  724. // Set the animation
  725. m_pUI->SetAnimation(idanOutbox, TRUE);
  726. // Setup Progress Meter
  727. m_pUI->SetProgressRange(100);
  728. // Connecting to ...
  729. LoadString(g_hLocRes, idsInetMailConnectingHost, szRes, ARRAYSIZE(szRes));
  730. wnsprintf(szBuf, ARRAYSIZE(szBuf), szRes, m_rServer.szAccount);
  731. m_pUI->SetGeneralProgress(szBuf);
  732. // Notify
  733. m_pSpoolCtx->Notify(DELIVERY_NOTIFY_CONNECTING, 0);
  734. Assert(NULL == m_pszSendMsgUrl);
  735. // look for the sendmsg url in the cache
  736. if (!GetAccountPropStrA(m_pszAccountId, CAP_HTTPMAILSENDMSG, &m_pszSendMsgUrl))
  737. {
  738. hr = m_pTransport->GetProperty(HTTPMAIL_PROP_SENDMSG, &pszSendMsgUrl);
  739. if (E_PENDING == hr)
  740. {
  741. hr = S_OK;
  742. goto exit;
  743. }
  744. CHECKHR(hr);
  745. CHECKHR(hr = _HrAdoptSendMsgUrl(pszSendMsgUrl));
  746. }
  747. Assert(NULL != m_pszSendMsgUrl);
  748. CHECKHR(hr = _HrPostCurrentMessage());
  749. exit:
  750. return hr;
  751. }
  752. // --------------------------------------------------------------------------------
  753. // CHTTPTask::_HrAdoptSendMsgUrl
  754. // --------------------------------------------------------------------------------
  755. HRESULT CHTTPTask::_HrAdoptSendMsgUrl(LPSTR pszSendMsgUrl)
  756. {
  757. Assert(NULL == m_pszSendMsgUrl);
  758. if (NULL == pszSendMsgUrl)
  759. return E_INVALIDARG;
  760. m_pszSendMsgUrl = pszSendMsgUrl ;
  761. // add it to the account data cache
  762. HrCacheAccountPropStrA(m_pszAccountId, CAP_HTTPMAILSENDMSG, m_pszSendMsgUrl);
  763. return S_OK;
  764. }
  765. // --------------------------------------------------------------------------------
  766. // CHTTPTask::_HrFinishCurrentEvent
  767. // --------------------------------------------------------------------------------
  768. HRESULT CHTTPTask::_HrFinishCurrentEvent(HRESULT hrResult, LPSTR pszLocationUrl)
  769. {
  770. // Locals
  771. HRESULT hr = S_OK;
  772. LPHTTPEVENTINFO pEvent;
  773. MESSAGEID idMessage;
  774. if (FAILED(hrResult))
  775. goto exit;
  776. // save in sent items
  777. if (m_pSentItems && m_pBody && pszLocationUrl)
  778. {
  779. // add the message to the sent items folder
  780. CHECKHR(hr = Http_AddMessageToFolder(m_pSentItems, m_pszAccountId, NULL, ARF_READ, pszLocationUrl, &idMessage));
  781. // write the message body out
  782. CHECKHR(hr = Http_SetMessageStream(m_pSentItems, idMessage, m_pBody, NULL, TRUE));
  783. }
  784. // Get the current http event
  785. pEvent = CURRENTHTTPEVENT;
  786. pEvent->fComplete = TRUE;
  787. m_dwState |= HTTPSTATE_EVENTSUCCESS;
  788. ++m_cCompleted;
  789. exit:
  790. // go to the next event
  791. hr = _HrStartNextEvent();
  792. return hr;
  793. }
  794. // --------------------------------------------------------------------------------
  795. // CHTTPTask::_HrStartNextEvent
  796. // --------------------------------------------------------------------------------
  797. HRESULT CHTTPTask::_HrStartNextEvent(void)
  798. {
  799. // Locals
  800. HRESULT hr = S_OK;
  801. // free the previous subject
  802. SafeMemFree(m_pszSubject);
  803. // free the previous body
  804. SafeRelease(m_pBody);
  805. // Fixup m_cbSent to be correct
  806. m_cbSent = (CURRENTHTTPEVENT)->cbSentTotal;
  807. m_cbStart = m_cbSent;
  808. // Are we done yet ?
  809. if (m_iEvent + 1 == m_psaEvents->GetLength())
  810. {
  811. // Update progress
  812. _DoProgress();
  813. // Disconnect from the server
  814. CHECKHR(hr = m_pTransport->Disconnect());
  815. }
  816. // otherwise, increment the event count and send the next message
  817. else
  818. {
  819. // Next Event
  820. m_iEvent++;
  821. // Update progress
  822. //_DoProgress();
  823. // Send Reset Command
  824. hr = _HrPostCurrentMessage();
  825. if (hr == E_PENDING)
  826. hr = S_OK;
  827. }
  828. exit:
  829. // Done
  830. return hr;
  831. }
  832. // --------------------------------------------------------------------------------
  833. // CHTTPTask::_OnDisconnectComplete
  834. // --------------------------------------------------------------------------------
  835. HRESULT CHTTPTask::_OnDisconnectComplete(void)
  836. {
  837. // Locals
  838. HRESULT hr = S_OK;
  839. LPDWORD prgdwIds = NULL;
  840. DWORD cIdsAlloc = 0;
  841. DWORD i;
  842. LPHTTPEVENTINFO pEvent;
  843. ADJUSTFLAGS Flags;
  844. DWORD cEvents;
  845. MESSAGEIDLIST rList;
  846. rList.cMsgs = 0;
  847. rList.prgidMsg = NULL;
  848. // Invalid State
  849. Assert(m_pOutbox);
  850. Assert(m_psaEvents);
  851. cEvents = m_psaEvents->GetLength();
  852. // Walk through the list of events
  853. for (i=0; i < cEvents; i++)
  854. {
  855. // Readability
  856. pEvent = (LPHTTPEVENTINFO)m_psaEvents->GetItemAt(i);
  857. // If this event was in the outbox
  858. if (0 != pEvent->idMessage && pEvent->fComplete)
  859. {
  860. // Insert into my array of message ids
  861. if (rList.cMsgs + 1 > cIdsAlloc)
  862. {
  863. // Realloc
  864. CHECKHR(hr = HrRealloc((LPVOID *)&rList.prgidMsg, sizeof(DWORD) * (cIdsAlloc + 10)));
  865. // Increment cIdsAlloc
  866. cIdsAlloc += 10;
  867. }
  868. // Set Message Id
  869. rList.prgidMsg[rList.cMsgs++] = pEvent->idMessage;
  870. }
  871. }
  872. if (rList.cMsgs)
  873. {
  874. Flags.dwAdd = ARF_READ;
  875. Flags.dwRemove = ARF_SUBMITTED | ARF_UNSENT;
  876. if (m_idSendEvent != INVALID_EVENT)
  877. {
  878. // Delete the messages.
  879. // Messages are never copied to the local outbox for httpmail
  880. CHECKHR(hr = m_pOutbox->DeleteMessages(DELETE_MESSAGE_NOTRASHCAN | DELETE_MESSAGE_NOPROMPT, &rList, NULL, NOSTORECALLBACK));
  881. }
  882. else
  883. {
  884. // Raid-7639: OE sends message over and over when runs out of disk space.
  885. m_pOutbox->SetMessageFlags(&rList, &Flags, NULL, NOSTORECALLBACK);
  886. }
  887. }
  888. exit:
  889. // Cleanup
  890. SafeMemFree(rList.prgidMsg);
  891. // Done
  892. return hr;
  893. }
  894. // --------------------------------------------------------------------------------
  895. // CHTTPTask::_UpdateSendMessageProgress
  896. // --------------------------------------------------------------------------------
  897. void CHTTPTask::_UpdateSendMessageProgress(LPHTTPMAILRESPONSE pResponse)
  898. {
  899. // the transport is attempting to resend the stream..
  900. // reset our progress indicator
  901. if (pResponse->rSendMessageInfo.fResend)
  902. {
  903. m_cbSent = m_cbStart;
  904. }
  905. else
  906. {
  907. // Increment Status
  908. m_cbSent += pResponse->rSendMessageInfo.cbIncrement;
  909. }
  910. // Do Progress
  911. _DoProgress();
  912. }
  913. // --------------------------------------------------------------------------------
  914. // CHTTPTask::_DoProgress
  915. // --------------------------------------------------------------------------------
  916. void CHTTPTask::_DoProgress(void)
  917. {
  918. // Locals
  919. WORD wProgress = 0;
  920. WORD wDelta;
  921. // Invalid Arg
  922. Assert(m_cbTotal > 0 && m_pUI);
  923. if (m_cbSent > 0)
  924. {
  925. // Compute Current Progress Index
  926. wProgress = (WORD)((m_cbSent * 100) / m_cbTotal);
  927. // Compute Delta
  928. wDelta = wProgress - m_wProgress;
  929. // Progress Delta
  930. if (wDelta > 0)
  931. {
  932. // Incremenet Progress
  933. m_pUI->IncrementProgress(wDelta);
  934. // Increment my wProgress
  935. m_wProgress += wDelta;
  936. // Don't go over 100 percent
  937. Assert(m_wProgress <= 100);
  938. }
  939. }
  940. else if (m_wProgress != 0)
  941. {
  942. m_pUI->SetProgressPosition(0);
  943. m_wProgress = 0;
  944. }
  945. }