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.

2207 lines
63 KiB

  1. // --------------------------------------------------------------------------------
  2. // Smtptask.cpp
  3. // Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  4. // Steven J. Bailey
  5. // --------------------------------------------------------------------------------
  6. #include "pch.hxx"
  7. #include "smtptask.h"
  8. #include "mimeutil.h"
  9. #include "goptions.h"
  10. #include "strconst.h"
  11. #include "xputil.h"
  12. #include "resource.h"
  13. #include "shlwapip.h"
  14. #include "spoolui.h"
  15. #include "thormsgs.h"
  16. #include "flagconv.h"
  17. #include "ourguid.h"
  18. #include "msgfldr.h"
  19. #include "storecb.h"
  20. #include "demand.h"
  21. #include "taskutil.h"
  22. // --------------------------------------------------------------------------------
  23. // Data Types
  24. // --------------------------------------------------------------------------------
  25. typedef enum tagSMTPEVENTTYPE
  26. {
  27. EVENT_SMTP,
  28. EVENT_IMAPUPLOAD
  29. } SMTPEVENTTYPE;
  30. // --------------------------------------------------------------------------------
  31. // CURRENTSMTPEVENT
  32. // --------------------------------------------------------------------------------
  33. #define CURRENTSMTPEVENT(_rTable) (&_rTable.prgEvent[_rTable.iEvent])
  34. // --------------------------------------------------------------------------------
  35. // CMessageIdStream::CMessageIdStream
  36. // --------------------------------------------------------------------------------
  37. CMessageIdStream::CMessageIdStream(IStream *pStream) : m_pStream(pStream)
  38. {
  39. // Reference count
  40. m_cRef = 1;
  41. // Addref the source stream
  42. m_pStream->AddRef();
  43. // Format the string
  44. ULONG cchPrefix = wnsprintf(m_szMessageId, ARRAYSIZE(m_szMessageId), "%s: ", STR_HDR_MESSAGEID);
  45. // Generate a message Id
  46. if (FAILED(MimeOleGenerateMID(m_szMessageId + cchPrefix, sizeof(m_szMessageId) - cchPrefix, FALSE)))
  47. {
  48. Assert(FALSE);
  49. *m_szMessageId = '\0';
  50. m_cchMessageId = 0;
  51. }
  52. // Otherwise, fixup the message id so that <mid>\r\n
  53. else
  54. {
  55. StrCatBuff(m_szMessageId, "\r\n", ARRAYSIZE(m_szMessageId));
  56. m_cchMessageId = lstrlen(m_szMessageId);
  57. }
  58. // Iniailize Index
  59. m_cbIndex = 0;
  60. }
  61. // --------------------------------------------------------------------------------
  62. // CMessageIdStream::Seek
  63. // --------------------------------------------------------------------------------
  64. STDMETHODIMP CMessageIdStream::Seek(LARGE_INTEGER liMove, DWORD dwOrigin, ULARGE_INTEGER *pulNew)
  65. {
  66. // Only supported case
  67. if (STREAM_SEEK_SET != dwOrigin && 0 != liMove.LowPart && 0 != liMove.HighPart && 0 != m_cbIndex)
  68. {
  69. Assert(FALSE);
  70. return E_NOTIMPL;
  71. }
  72. // Otheriwse, set new position
  73. else if (pulNew)
  74. {
  75. pulNew->HighPart = 0;
  76. pulNew->LowPart = 0;
  77. }
  78. // Done
  79. return S_OK;
  80. }
  81. // --------------------------------------------------------------------------------
  82. // CMessageIdStream::Read
  83. // --------------------------------------------------------------------------------
  84. STDMETHODIMP CMessageIdStream::Read(LPVOID pv, ULONG cbWanted, ULONG *pcbRead)
  85. {
  86. // Locals
  87. HRESULT hr=S_OK;
  88. // Reading from m_szMessageId ?
  89. if (m_cbIndex < m_cchMessageId)
  90. {
  91. // Compute amount I can read from m_cchMessageId
  92. ULONG cbReadMsgId = min(m_cchMessageId - m_cbIndex, cbWanted);
  93. // Init pcbRead
  94. if (pcbRead)
  95. *pcbRead = 0;
  96. // If we have some ?
  97. if (cbReadMsgId)
  98. {
  99. // Copy memory
  100. CopyMemory(pv, m_szMessageId + m_cbIndex, cbReadMsgId);
  101. // Increment index
  102. m_cbIndex += cbReadMsgId;
  103. }
  104. // If there is still some left to read...
  105. if (cbReadMsgId < cbWanted)
  106. hr = m_pStream->Read(((LPBYTE)pv + cbReadMsgId), cbWanted - cbReadMsgId, pcbRead);
  107. // Fixup pcbRead
  108. if (pcbRead)
  109. (*pcbRead) += cbReadMsgId;
  110. }
  111. // Otherwise, read from source stream
  112. else
  113. hr = m_pStream->Read(pv, cbWanted, pcbRead);
  114. // Done
  115. return hr;
  116. }
  117. // --------------------------------------------------------------------------------
  118. // CSmtpTask::CSmtpTask
  119. // --------------------------------------------------------------------------------
  120. CSmtpTask::CSmtpTask(void)
  121. {
  122. m_cRef = 1;
  123. m_dwFlags = 0;
  124. m_pSpoolCtx = NULL;
  125. m_pAccount = NULL;
  126. m_pTransport = NULL;
  127. m_pOutbox = NULL;
  128. m_pSentItems = NULL;
  129. m_cbTotal = 0;
  130. m_cbSent = 0;
  131. m_wProgress = 0;
  132. m_idEvent = INVALID_EVENT;
  133. m_idEventUpload = INVALID_EVENT;
  134. m_pUI = NULL;
  135. m_dwState = 0;
  136. m_pAdrEnum = NULL;
  137. m_hwndTimeout = NULL;
  138. m_pLogFile = NULL;
  139. ZeroMemory(&m_rServer, sizeof(INETSERVER));
  140. ZeroMemory(&m_rTable, sizeof(SMTPEVENTTABLE));
  141. ZeroMemory(&m_rList, sizeof(MESSAGEIDLIST));
  142. m_pCancel = NULL;
  143. m_tyOperation = SOT_INVALID;
  144. InitializeCriticalSection(&m_cs);
  145. }
  146. // --------------------------------------------------------------------------------
  147. // CSmtpTask::~CSmtpTask
  148. // --------------------------------------------------------------------------------
  149. CSmtpTask::~CSmtpTask(void)
  150. {
  151. // Reset the Object
  152. _ResetObject(TRUE);
  153. // Kill the critical section
  154. DeleteCriticalSection(&m_cs);
  155. }
  156. // --------------------------------------------------------------------------------
  157. // CSmtpTask::_ResetObject
  158. // --------------------------------------------------------------------------------
  159. void CSmtpTask::_ResetObject(BOOL fDeconstruct)
  160. {
  161. // Make sure the transport is disconnect
  162. if (m_pTransport)
  163. {
  164. m_pTransport->Release();
  165. m_pTransport = NULL;
  166. }
  167. // Release the Outbox
  168. SafeRelease(m_pAccount);
  169. SafeRelease(m_pOutbox);
  170. SafeRelease(m_pSentItems);
  171. SafeRelease(m_pAdrEnum);
  172. SafeRelease(m_pSpoolCtx);
  173. SafeRelease(m_pUI);
  174. SafeRelease(m_pLogFile);
  175. SafeRelease(m_pCancel);
  176. SafeMemFree(m_rList.prgidMsg);
  177. ZeroMemory(&m_rList, sizeof(MESSAGEIDLIST));
  178. // Free the event table elements
  179. _FreeEventTableElements();
  180. // Deconstructing
  181. if (fDeconstruct)
  182. {
  183. // Free Event Table
  184. SafeMemFree(m_rTable.prgEvent);
  185. }
  186. // Otherwise, reset some vars
  187. else
  188. {
  189. // Reset total byte count
  190. m_cbTotal = 0;
  191. m_idEvent = INVALID_EVENT;
  192. m_cbSent = 0;
  193. m_wProgress = 0;
  194. ZeroMemory(&m_rServer, sizeof(INETSERVER));
  195. }
  196. }
  197. // --------------------------------------------------------------------------------
  198. // CSmtpTask::Init
  199. // --------------------------------------------------------------------------------
  200. void CSmtpTask::_FreeEventTableElements(void)
  201. {
  202. // Loop the table of events
  203. for (ULONG i=0; i<m_rTable.cEvents; i++)
  204. {
  205. // Release the Message
  206. SafeRelease(m_rTable.prgEvent[i].pMessage);
  207. }
  208. // No Events
  209. m_rTable.cEvents = 0;
  210. }
  211. // --------------------------------------------------------------------------------
  212. // CSmtpTask::QueryInterface
  213. // --------------------------------------------------------------------------------
  214. STDMETHODIMP CSmtpTask::QueryInterface(REFIID riid, LPVOID *ppv)
  215. {
  216. // Locals
  217. HRESULT hr=S_OK;
  218. // check params
  219. if (ppv == NULL)
  220. return TrapError(E_INVALIDARG);
  221. // Thread Safety
  222. EnterCriticalSection(&m_cs);
  223. // Find IID
  224. if (IID_IUnknown == riid)
  225. *ppv = (IUnknown *)(ISpoolerTask *)this;
  226. else if (IID_ISpoolerTask == riid)
  227. *ppv = (ISpoolerTask *)this;
  228. else if (IID_ITimeoutCallback == riid)
  229. *ppv = (ITimeoutCallback *) this;
  230. else if (IID_ITransportCallbackService == riid)
  231. *ppv = (ITransportCallbackService *) this;
  232. else
  233. {
  234. *ppv = NULL;
  235. hr = TrapError(E_NOINTERFACE);
  236. goto exit;
  237. }
  238. // AddRef It
  239. ((IUnknown *)*ppv)->AddRef();
  240. exit:
  241. // Thread Safety
  242. LeaveCriticalSection(&m_cs);
  243. // Done
  244. return hr;
  245. }
  246. // --------------------------------------------------------------------------------
  247. // CSmtpTask::CSmtpTask
  248. // --------------------------------------------------------------------------------
  249. STDMETHODIMP_(ULONG) CSmtpTask::AddRef(void)
  250. {
  251. EnterCriticalSection(&m_cs);
  252. ULONG cRef = ++m_cRef;
  253. LeaveCriticalSection(&m_cs);
  254. return cRef;
  255. }
  256. // --------------------------------------------------------------------------------
  257. // CSmtpTask::CSmtpTask
  258. // --------------------------------------------------------------------------------
  259. STDMETHODIMP_(ULONG) CSmtpTask::Release(void)
  260. {
  261. EnterCriticalSection(&m_cs);
  262. ULONG cRef = --m_cRef;
  263. LeaveCriticalSection(&m_cs);
  264. if (0 != cRef)
  265. return cRef;
  266. delete this;
  267. return 0;
  268. }
  269. // --------------------------------------------------------------------------------
  270. // CSmtpTask::Init
  271. // --------------------------------------------------------------------------------
  272. STDMETHODIMP CSmtpTask::Init(DWORD dwFlags, ISpoolerBindContext *pBindCtx)
  273. {
  274. // Invalid Arg
  275. if (NULL == pBindCtx)
  276. return TrapError(E_INVALIDARG);
  277. // Thread Safety
  278. EnterCriticalSection(&m_cs);
  279. // Reset this object
  280. _ResetObject(FALSE);
  281. // Save the Activity Flags - DELIVER_xxx
  282. m_dwFlags = dwFlags;
  283. // Hold onto the bind context
  284. Assert(NULL == m_pSpoolCtx);
  285. m_pSpoolCtx = pBindCtx;
  286. m_pSpoolCtx->AddRef();
  287. // Thread Safety
  288. LeaveCriticalSection(&m_cs);
  289. // Done
  290. return S_OK;
  291. }
  292. // --------------------------------------------------------------------------------
  293. // CSmtpTask::BuildEvents
  294. // --------------------------------------------------------------------------------
  295. STDMETHODIMP CSmtpTask::BuildEvents(ISpoolerUI *pSpoolerUI, IImnAccount *pAccount, FOLDERID idFolder)
  296. {
  297. // Locals
  298. HRESULT hr=S_OK;
  299. DWORD fSplitMsgs;
  300. FOLDERINFO Folder;
  301. FOLDERID id;
  302. DWORD cbMaxPart;
  303. CHAR szRes[255];
  304. CHAR szMessage[255];
  305. CHAR szAccount[CCHMAX_ACCOUNT_NAME];
  306. CHAR szDefault[CCHMAX_ACCOUNT_NAME];
  307. MESSAGEINFO MsgInfo={0};
  308. HROWSET hRowset=NULL;
  309. // Invalid Arg
  310. if (NULL == pSpoolerUI || NULL == pAccount)
  311. return TrapError(E_INVALIDARG);
  312. // Thread Safety
  313. EnterCriticalSection(&m_cs);
  314. // Validate State
  315. Assert(NULL == m_pTransport && NULL == m_pAccount && NULL == m_pOutbox && 0 == m_rTable.cEvents);
  316. Assert(NULL == m_pSentItems);
  317. // Save the UI Object
  318. m_pUI = pSpoolerUI;
  319. m_pUI->AddRef();
  320. // Release current Account
  321. m_pAccount = pAccount;
  322. m_pAccount->AddRef();
  323. // Get the Account Name
  324. CHECKHR(hr = m_pAccount->GetPropSz(AP_ACCOUNT_NAME, szAccount, ARRAYSIZE(szAccount)));
  325. // Split Messages ?
  326. if (FAILED(m_pAccount->GetPropDw(AP_SMTP_SPLIT_MESSAGES, &fSplitMsgs)))
  327. fSplitMsgs = FALSE;
  328. // Split Size
  329. if (FAILED(m_pAccount->GetPropDw(AP_SMTP_SPLIT_SIZE, &cbMaxPart)))
  330. {
  331. fSplitMsgs = FALSE;
  332. cbMaxPart = 0;
  333. }
  334. // Else, convert cbMaxPart for kilobytes to bytes
  335. else
  336. cbMaxPart *= 1024;
  337. // Get the default Account
  338. if (SUCCEEDED(g_pAcctMan->GetDefaultAccountName(ACCT_MAIL, szDefault, ARRAYSIZE(szDefault))))
  339. {
  340. if (lstrcmpi(szDefault, szAccount) == 0)
  341. FLAGSET(m_dwState, SMTPSTATE_DEFAULT);
  342. }
  343. // Get the outbox
  344. CHECKHR(hr = m_pSpoolCtx->BindToObject(IID_CLocalStoreOutbox, (LPVOID *)&m_pOutbox));
  345. // Create a Rowset
  346. CHECKHR(hr = m_pOutbox->CreateRowset(IINDEX_PRIMARY, NOFLAGS, &hRowset));
  347. // Loop
  348. while (S_OK == m_pOutbox->QueryRowset(hRowset, 1, (LPVOID *)&MsgInfo, NULL))
  349. {
  350. // Process Store Header
  351. CHECKHR(hr = _HrAppendOutboxMessage(szAccount, &MsgInfo, fSplitMsgs, cbMaxPart));
  352. // Free Current
  353. m_pOutbox->FreeRecord(&MsgInfo);
  354. }
  355. // If no messages, were done
  356. if (0 == m_rTable.cEvents)
  357. goto exit;
  358. // Get a SMTP log file
  359. m_pSpoolCtx->BindToObject(IID_CSmtpLogFile, (LPVOID *)&m_pLogFile);
  360. // Format the string
  361. LOADSTRING(IDS_SPS_SMTPEVENT, szRes);
  362. // Build the message
  363. wnsprintf(szMessage, ARRAYSIZE(szMessage), szRes, m_rTable.cEvents, szAccount);
  364. // Register the event
  365. CHECKHR(hr = m_pSpoolCtx->RegisterEvent(szMessage, (ISpoolerTask *)this, EVENT_SMTP, m_pAccount, &m_idEvent));
  366. // Get SentItems
  367. if (DwGetOption(OPT_SAVESENTMSGS))
  368. {
  369. // Get Sent Items Folder
  370. CHECKHR(hr = TaskUtil_OpenSentItemsFolder(m_pAccount, &m_pSentItems));
  371. // Get the Folder Id
  372. m_pSentItems->GetFolderId(&id);
  373. // Get the folder information
  374. CHECKHR(hr = g_pStore->GetFolderInfo(id, &Folder));
  375. // If not a local folder, then we will need to do an upload
  376. if (Folder.tyFolder != FOLDER_LOCAL)
  377. {
  378. // Get event string
  379. LOADSTRING(IDS_SPS_MOVEEVENT, szRes);
  380. // Format the message
  381. wnsprintf(szMessage, ARRAYSIZE(szMessage), szRes, szAccount);
  382. // Register Upload Event
  383. CHECKHR(hr = m_pSpoolCtx->RegisterEvent(szMessage, (ISpoolerTask *)this, EVENT_IMAPUPLOAD, m_pAccount, &m_idEventUpload));
  384. }
  385. // Free the Record
  386. g_pStore->FreeRecord(&Folder);
  387. }
  388. exit:
  389. // Cleanup
  390. if (m_pOutbox)
  391. {
  392. m_pOutbox->CloseRowset(&hRowset);
  393. m_pOutbox->FreeRecord(&MsgInfo);
  394. }
  395. // Failure
  396. if (FAILED(hr))
  397. {
  398. _CatchResult(hr, IXP_SMTP);
  399. _ResetObject(FALSE);
  400. }
  401. // Thread Safety
  402. LeaveCriticalSection(&m_cs);
  403. // Done
  404. return hr;
  405. }
  406. // --------------------------------------------------------------------------------
  407. // CSmtpTask::_HrAppendEventTable
  408. // --------------------------------------------------------------------------------
  409. HRESULT CSmtpTask::_HrAppendEventTable(LPSMTPEVENTINFO *ppEvent)
  410. {
  411. // Locals
  412. HRESULT hr=S_OK;
  413. // Add an item to the event list
  414. if (m_rTable.cEvents + 1 > m_rTable.cAlloc)
  415. {
  416. // Realloc the table
  417. CHECKHR(hr = HrRealloc((LPVOID *)&m_rTable.prgEvent, sizeof(SMTPEVENTINFO) * (m_rTable.cAlloc + 10)));
  418. // Increment cAlloc
  419. m_rTable.cAlloc += 10;
  420. }
  421. // Readability
  422. *ppEvent = &m_rTable.prgEvent[m_rTable.cEvents];
  423. // ZeroInit
  424. ZeroMemory(*ppEvent, sizeof(SMTPEVENTINFO));
  425. exit:
  426. // Done
  427. return hr;
  428. }
  429. // --------------------------------------------------------------------------------
  430. // CSmtpTask::_HrAppendOutboxMessage
  431. // --------------------------------------------------------------------------------
  432. HRESULT CSmtpTask::_HrAppendOutboxMessage(LPCSTR pszAccount, LPMESSAGEINFO pMsgInfo,
  433. BOOL fSplitMsgs, DWORD cbMaxPart)
  434. {
  435. // Locals
  436. HRESULT hr=S_OK;
  437. LPSMTPEVENTINFO pEvent;
  438. IImnAccount *pAccount=NULL;
  439. // Invalid Arg
  440. Assert(pszAccount && pMsgInfo);
  441. // Has this message been submitted and is it a mail message
  442. if((pMsgInfo->dwFlags & (ARF_SUBMITTED | ARF_NEWSMSG)) != ARF_SUBMITTED)
  443. goto exit;
  444. // Empty Account Name
  445. if (NULL == pMsgInfo->pszAcctId || FAILED(g_pAcctMan->FindAccount(AP_ACCOUNT_ID, pMsgInfo->pszAcctId, &pAccount)))
  446. {
  447. // Not the Default Account
  448. if (!ISFLAGSET(m_dwState, SMTPSTATE_DEFAULT) || ISFLAGSET(m_dwFlags, DELIVER_NOUI))
  449. goto exit;
  450. // Have I asked the user if they want to use the default account
  451. if (!ISFLAGSET(m_dwState, SMTPSTATE_ASKEDDEFAULT))
  452. {
  453. // Get hwndParent
  454. HWND hwndParent;
  455. if (FAILED(m_pUI->GetWindow(&hwndParent)))
  456. hwndParent = NULL;
  457. // Message
  458. if (AthMessageBoxW(hwndParent, MAKEINTRESOURCEW(idsAthenaMail), MAKEINTRESOURCEW(IDS_SPS_SMTPUSEDEFAULT), NULL, MB_YESNO|MB_ICONEXCLAMATION ) == IDYES)
  459. FLAGSET(m_dwState, SMTPSTATE_USEDEFAULT);
  460. else
  461. goto exit;
  462. // I've Asked, don't ask again
  463. FLAGSET(m_dwState, SMTPSTATE_ASKEDDEFAULT);
  464. }
  465. // Not using default
  466. else if (!ISFLAGSET(m_dwState, SMTPSTATE_USEDEFAULT))
  467. goto exit;
  468. }
  469. // Use this account
  470. else if (lstrcmpi(pMsgInfo->pszAcctName, pszAccount) != 0)
  471. goto exit;
  472. // Split the Message ?
  473. if (TRUE == fSplitMsgs && pMsgInfo->cbMessage >= cbMaxPart)
  474. {
  475. // Make sure the total number of messages is less than 100
  476. if (100 <= (pMsgInfo->cbMessage / cbMaxPart))
  477. {
  478. HWND hwndParent;
  479. CHAR rgchBuff[CCHMAX_STRINGRES + 20];
  480. CHAR rgchRes[CCHMAX_STRINGRES];
  481. DWORD cbMaxPartCount;
  482. // Figure out the new message part size
  483. cbMaxPartCount = pMsgInfo->cbMessage / 100;
  484. // Round the new message part size to the
  485. // closest power of 2
  486. if (0x80000000 <= cbMaxPartCount)
  487. {
  488. // Can't round up any higher
  489. cbMaxPart = cbMaxPartCount;
  490. }
  491. else
  492. {
  493. cbMaxPart = 1;
  494. do
  495. {
  496. cbMaxPart *= 2;
  497. } while ( 0 != (cbMaxPartCount /= 2));
  498. }
  499. // Get the UI window
  500. if (FAILED(m_pUI->GetWindow(&hwndParent)))
  501. hwndParent = NULL;
  502. if (NULL == AthLoadString(idsErrTooManySplitMsgs, rgchRes, sizeof(rgchRes)))
  503. {
  504. hr = E_OUTOFMEMORY;
  505. goto exit;
  506. }
  507. // Display the warning string
  508. wnsprintf(rgchBuff, ARRAYSIZE(rgchBuff), rgchRes, cbMaxPart / 1024);
  509. if (AthMessageBox(hwndParent, MAKEINTRESOURCE(idsAthenaMail), rgchBuff, NULL, MB_YESNO|MB_ICONEXCLAMATION ) != IDYES)
  510. goto exit;
  511. }
  512. // Split and Add the message
  513. CHECKHR(hr = _HrAppendSplitMessage(pMsgInfo, cbMaxPart));
  514. }
  515. // Otherwise, simply add the message as normal
  516. else
  517. {
  518. // Append the Table
  519. CHECKHR(hr = _HrAppendEventTable(&pEvent));
  520. // Save the store message id
  521. pEvent->idMessage = pMsgInfo->idMessage;
  522. // Save Message Size + 100 which is the average MID that is added on
  523. pEvent->cbEvent = pMsgInfo->cbMessage;
  524. // Increment total send byte count
  525. m_cbTotal += pEvent->cbEvent;
  526. // Running Sent Total
  527. pEvent->cbSentTotal = m_cbTotal;
  528. // Increment Number of event
  529. m_rTable.cEvents++;
  530. }
  531. exit:
  532. // Cleanup
  533. SafeRelease(pAccount);
  534. // Done
  535. return hr;
  536. }
  537. // --------------------------------------------------------------------------------
  538. // CSmtpTask::_HrAppendSplitMessage
  539. // --------------------------------------------------------------------------------
  540. HRESULT CSmtpTask::_HrAppendSplitMessage(LPMESSAGEINFO pMsgInfo, DWORD cbMaxPart)
  541. {
  542. // Locals
  543. HRESULT hr=S_OK;
  544. ULONG c;
  545. ULONG iPart=1;
  546. ULONG cParts;
  547. IMimeMessage *pMessage=NULL;
  548. IMimeMessage *pMsgPart=NULL;
  549. IMimeMessageParts *pParts=NULL;
  550. IMimeEnumMessageParts *pEnum=NULL;
  551. LPSMTPEVENTINFO pEvent;
  552. // Invalid Arg
  553. Assert(pMsgInfo);
  554. // Lets open the message from the Outbox
  555. CHECKHR(hr = _HrOpenMessage(pMsgInfo->idMessage, &pMessage));
  556. // Split the message
  557. CHECKHR(hr = pMessage->SplitMessage(cbMaxPart, &pParts));
  558. // Get Total Parts
  559. CHECKHR(hr = pParts->CountParts(&cParts));
  560. // Walk the list of messages
  561. CHECKHR(hr = pParts->EnumParts(&pEnum));
  562. // Walk the parts and add them into the event list
  563. while(SUCCEEDED(pEnum->Next(1, &pMsgPart, &c)) && 1 == c)
  564. {
  565. // Append the Table
  566. CHECKHR(hr = _HrAppendEventTable(&pEvent));
  567. // Event Type
  568. FLAGSET(pEvent->dwFlags, SMTPEVENT_SPLITPART);
  569. // Split Information
  570. pEvent->iPart = iPart;
  571. pEvent->cParts = cParts;
  572. pEvent->cbParts = pMsgInfo->cbMessage;
  573. // Save the message part
  574. pEvent->pMessage = pMsgPart;
  575. pMsgPart = NULL;
  576. // Save Message Size
  577. pEvent->pMessage->GetMessageSize(&pEvent->cbEvent, 0);
  578. // Increment total send byte count
  579. m_cbTotal += pEvent->cbEvent;
  580. // Running Sent Total
  581. pEvent->cbSentTotal = m_cbTotal;
  582. // Increment Number of event
  583. m_rTable.cEvents++;
  584. // Increment iPart
  585. iPart++;
  586. }
  587. // Have the last split message free the header info
  588. pEvent->idMessage = pMsgInfo->idMessage;
  589. exit:
  590. // Cleanup
  591. SafeRelease(pMessage);
  592. SafeRelease(pParts);
  593. SafeRelease(pMsgPart);
  594. SafeRelease(pEnum);
  595. // Done
  596. return hr;
  597. }
  598. // ------------------------------------------------------------------------------------
  599. // CSmtpTask::_HrOpenMessage
  600. // ------------------------------------------------------------------------------------
  601. HRESULT CSmtpTask::_HrOpenMessage(MESSAGEID idMessage, IMimeMessage **ppMessage)
  602. {
  603. // Locals
  604. HRESULT hr=S_OK;
  605. // Check Params
  606. Assert(ppMessage && m_pOutbox);
  607. // Init
  608. *ppMessage = NULL;
  609. // Stream in message
  610. CHECKHR(hr = m_pOutbox->OpenMessage(idMessage, OPEN_MESSAGE_SECURE , ppMessage, NOSTORECALLBACK));
  611. // remove an X-Unsent headers before sending
  612. (*ppMessage)->DeleteBodyProp(HBODY_ROOT, PIDTOSTR(PID_HDR_XUNSENT));
  613. exit:
  614. // Failure
  615. if (FAILED(hr))
  616. SafeRelease((*ppMessage));
  617. // Done
  618. return hr;
  619. }
  620. // --------------------------------------------------------------------------------
  621. // CSmtpTask::Execute
  622. // --------------------------------------------------------------------------------
  623. STDMETHODIMP CSmtpTask::Execute(EVENTID eid, DWORD_PTR dwTwinkie)
  624. {
  625. HRESULT hr = E_FAIL;
  626. // Thread Safety
  627. EnterCriticalSection(&m_cs);
  628. // What is the event type
  629. if (EVENT_SMTP == dwTwinkie)
  630. {
  631. // Better not have a transport yet...
  632. Assert(NULL == m_pTransport);
  633. // Create the Transport Object
  634. CHECKHR(hr = CreateSMTPTransport(&m_pTransport));
  635. // Init the Transport
  636. CHECKHR(hr = m_pTransport->InitNew(NULL, (ISMTPCallback *)this));
  637. // Fill an INETSERVER structure from the account object
  638. CHECKHR(hr = m_pTransport->InetServerFromAccount(m_pAccount, &m_rServer));
  639. // Use IP Address for HELO command ?
  640. if (DwGetOption(OPT_SMTPUSEIPFORHELO))
  641. FLAGSET(m_rServer.dwFlags, ISF_SMTP_USEIPFORHELO);
  642. // If this account is set to always prompt for password and password isn't already cached, show UI so we can prompt user for password
  643. if (ISFLAGSET(m_rServer.dwFlags, ISF_ALWAYSPROMPTFORPASSWORD) && FAILED(GetPassword(m_rServer.dwPort, m_rServer.szServerName, m_rServer.szUserName, NULL, 0)))
  644. m_pUI->ShowWindow(SW_SHOW);
  645. // Execute SMTP Event
  646. hr = _ExecuteSMTP(eid, dwTwinkie);
  647. }
  648. // Otherwise, do IMAP Event
  649. else if (EVENT_IMAPUPLOAD == dwTwinkie)
  650. hr = _ExecuteUpload(eid, dwTwinkie);
  651. exit:
  652. // Thread Safety
  653. LeaveCriticalSection(&m_cs);
  654. // Done
  655. return hr;
  656. }
  657. STDMETHODIMP CSmtpTask::CancelEvent(EVENTID eid, DWORD_PTR dwTwinkie)
  658. {
  659. return(S_OK);
  660. }
  661. // --------------------------------------------------------------------------------
  662. // CSmtpTask::_ExecuteSMTP
  663. // --------------------------------------------------------------------------------
  664. HRESULT CSmtpTask::_ExecuteSMTP(EVENTID eid, DWORD_PTR dwTwinkie)
  665. {
  666. // Locals
  667. HRESULT hr=S_OK;
  668. CHAR szRes[CCHMAX_RES];
  669. CHAR szBuf[CCHMAX_RES + CCHMAX_SERVER_NAME];
  670. DWORD cb;
  671. // I only handle on event
  672. Assert(m_pAccount && m_idEvent == eid && m_pUI && m_pTransport && m_rTable.cEvents > 0);
  673. // Set the animation
  674. m_pUI->SetAnimation(idanOutbox, TRUE);
  675. // Setup Progress Meter
  676. m_pUI->SetProgressRange(100);
  677. // Connecting to ...
  678. LoadString(g_hLocRes, idsInetMailConnectingHost, szRes, ARRAYSIZE(szRes));
  679. wnsprintf(szBuf, ARRAYSIZE(szBuf), szRes, m_rServer.szAccount);
  680. m_pUI->SetGeneralProgress(szBuf);
  681. // Notify
  682. m_pSpoolCtx->Notify(DELIVERY_NOTIFY_CONNECTING, 0);
  683. // Connect
  684. CHECKHR(hr = m_pTransport->Connect(&m_rServer, TRUE, TRUE));
  685. exit:
  686. // Failure
  687. if (FAILED(hr))
  688. {
  689. FLAGSET(m_dwState, SMTPSTATE_EXECUTEFAILED);
  690. _CatchResult(hr, IXP_SMTP);
  691. // Hands Off my callback: otherwise we leak like a stuck pig
  692. SideAssert(m_pTransport->HandsOffCallback() == S_OK);
  693. }
  694. return hr;
  695. } // _ExecuteSMTP
  696. HRESULT CSmtpTask::_ExecuteUpload(EVENTID eid, DWORD_PTR dwTwinkie)
  697. {
  698. // Locals
  699. HRESULT hr=S_OK;
  700. ADJUSTFLAGS Flags;
  701. // I only handle on event
  702. Assert(m_pAccount && m_idEventUpload == eid && m_pUI && m_pTransport && m_rTable.cEvents > 0);
  703. // Invalid State
  704. Assert(m_pOutbox);
  705. Assert(m_pSentItems != NULL);
  706. // Are the Ids
  707. if (m_rList.cMsgs)
  708. {
  709. // Setup Flags
  710. Flags.dwAdd = ARF_READ;
  711. Flags.dwRemove = ARF_SUBMITTED | ARF_UNSENT;
  712. // Move the message from the sent items folder
  713. hr = m_pOutbox->CopyMessages(m_pSentItems, COPY_MESSAGE_MOVE, &m_rList, &Flags, NULL, this);
  714. Assert(FAILED(hr));
  715. if (hr == E_PENDING)
  716. {
  717. hr = S_OK;
  718. }
  719. else
  720. {
  721. IXPTYPE ixpType;
  722. FLAGSET(m_dwState, SMTPSTATE_EXECUTEFAILED);
  723. // Remap the Error Result
  724. hr = TrapError(SP_E_CANT_MOVETO_SENTITEMS);
  725. // Show an error in the spooler dialog
  726. ixpType = m_pTransport->GetIXPType();
  727. _CatchResult(hr, ixpType);
  728. }
  729. }
  730. else
  731. {
  732. hr = E_FAIL;
  733. }
  734. return hr;
  735. } // _ExecuteSMTP
  736. // --------------------------------------------------------------------------------
  737. // CSmtpTask::OnTimeout
  738. // --------------------------------------------------------------------------------
  739. STDMETHODIMP CSmtpTask::OnTimeout(DWORD *pdwTimeout, IInternetTransport *pTransport)
  740. {
  741. // Locals
  742. HRESULT hr=S_OK;
  743. // Thread Safety
  744. EnterCriticalSection(&m_cs);
  745. // Is there currently a timeout dialog
  746. if (m_hwndTimeout)
  747. {
  748. // Set foreground
  749. SetForegroundWindow(m_hwndTimeout);
  750. }
  751. else
  752. {
  753. // Not suppose to be showing UI ?
  754. if (ISFLAGSET(m_dwFlags, DELIVER_NOUI))
  755. {
  756. hr = S_FALSE;
  757. goto exit;
  758. }
  759. // Do Timeout Dialog
  760. m_hwndTimeout = TaskUtil_HwndOnTimeout(m_rServer.szServerName, m_rServer.szAccount, "SMTP", m_rServer.dwTimeout, (ITimeoutCallback *) this);
  761. // Couldn't create the dialog
  762. if (NULL == m_hwndTimeout)
  763. {
  764. hr = S_FALSE;
  765. goto exit;
  766. }
  767. }
  768. exit:
  769. // Thread Safety
  770. LeaveCriticalSection(&m_cs);
  771. // Always tell the transport to keep on trucking
  772. return hr;
  773. }
  774. // --------------------------------------------------------------------------------
  775. // CSmtpTask::OnLogonPrompt
  776. // --------------------------------------------------------------------------------
  777. STDMETHODIMP CSmtpTask::OnLogonPrompt(LPINETSERVER pInetServer, IInternetTransport *pTransport)
  778. {
  779. // Locals
  780. HRESULT hr=S_FALSE;
  781. SMTPAUTHTYPE authtype;
  782. char szPassword[CCHMAX_PASSWORD];
  783. // Check if we have a cached password that's different from current password
  784. hr = GetPassword(pInetServer->dwPort, pInetServer->szServerName, pInetServer->szUserName,
  785. szPassword, sizeof(szPassword));
  786. if (SUCCEEDED(hr) && 0 != lstrcmp(szPassword, pInetServer->szPassword))
  787. {
  788. StrCpyN(pInetServer->szPassword, szPassword, ARRAYSIZE(pInetServer->szPassword));
  789. ZeroMemory(szPassword, sizeof(szPassword)); // Done for security.
  790. return S_OK;
  791. }
  792. hr = S_FALSE; // Re-initialize
  793. // Thread Safety
  794. EnterCriticalSection(&m_cs);
  795. // NOERRORS...
  796. if (ISFLAGSET(m_dwFlags, DELIVER_NOUI))
  797. goto exit;
  798. // TaskUtil_OnLogonPrompt
  799. hr = TaskUtil_OnLogonPrompt(m_pAccount, m_pUI, NULL, pInetServer, AP_SMTP_USERNAME,
  800. AP_SMTP_PASSWORD, AP_SMTP_PROMPT_PASSWORD, FALSE);
  801. // Cache the password if the user slected ok
  802. if (S_OK == hr)
  803. {
  804. // Save the password
  805. SavePassword(pInetServer->dwPort, pInetServer->szServerName,
  806. pInetServer->szUserName, pInetServer->szPassword);
  807. // Lets switch the account to using the logon information...
  808. authtype = SMTP_AUTH_USE_SMTP_SETTINGS;
  809. m_pAccount->SetPropDw(AP_SMTP_USE_SICILY, (DWORD)authtype);
  810. // Save the changes
  811. m_pAccount->SaveChanges();
  812. }
  813. exit:
  814. // Thread Safety
  815. LeaveCriticalSection(&m_cs);
  816. ZeroMemory(szPassword, sizeof(szPassword)); // Done for security.
  817. // Done
  818. return hr;
  819. }
  820. // --------------------------------------------------------------------------------
  821. // CSmtpTask::OnPrompt
  822. // --------------------------------------------------------------------------------
  823. STDMETHODIMP_(INT) CSmtpTask::OnPrompt(HRESULT hrError, LPCTSTR pszText, LPCTSTR pszCaption, UINT uType, IInternetTransport *pTransport)
  824. {
  825. // Locals
  826. HWND hwnd;
  827. INT nAnswer;
  828. // Thread Safety
  829. EnterCriticalSection(&m_cs);
  830. // Raid 55082 - SPOOLER: SPA/SSL auth to NNTP does not display cert warning and fails.
  831. #if 0
  832. if (!!(m_dwFlags & (DELIVER_NOUI | DELIVER_BACKGROUND)))
  833. return(0);
  834. #endif
  835. // Invalid State
  836. Assert(m_pUI);
  837. // Get Window
  838. if (FAILED(m_pUI->GetWindow(&hwnd)))
  839. hwnd = NULL;
  840. // I assume this is a critical prompt, so I will not check for no UI mode
  841. nAnswer = MessageBox(hwnd, pszText, pszCaption, uType);
  842. // Thread Safety
  843. LeaveCriticalSection(&m_cs);
  844. // Done
  845. return nAnswer;
  846. }
  847. // --------------------------------------------------------------------------------
  848. // CSmtpTask::OnStatus
  849. // --------------------------------------------------------------------------------
  850. STDMETHODIMP CSmtpTask::OnStatus(IXPSTATUS ixpstatus, IInternetTransport *pTransport)
  851. {
  852. // Locals
  853. EVENTCOMPLETEDSTATUS tyEventStatus=EVENT_SUCCEEDED;
  854. // Invalid State
  855. Assert(m_pUI && m_pSpoolCtx);
  856. if (!m_pUI || !m_pSpoolCtx)
  857. {
  858. return E_FAIL;
  859. }
  860. // Thread Safety
  861. EnterCriticalSection(&m_cs);
  862. // Feed the the IXP status to the UI object
  863. m_pUI->SetSpecificProgress(MAKEINTRESOURCE(XPUtil_StatusToString(ixpstatus)));
  864. // Disconnected
  865. if (ixpstatus == IXP_DISCONNECTED)
  866. {
  867. // Kill the timeout dialog
  868. if (m_hwndTimeout)
  869. {
  870. DestroyWindow(m_hwndTimeout);
  871. m_hwndTimeout = NULL;
  872. }
  873. // _OnDisconnectComplete
  874. HRESULT hrDisconnect = _OnDisconnectComplete();
  875. // Reset the progress
  876. // m_pUI->SetProgressRange(100);
  877. // Set the animation
  878. m_pUI->SetAnimation(idanOutbox, FALSE);
  879. // Determine
  880. if (ISFLAGSET(m_dwState, SMTPSTATE_CANCELED))
  881. tyEventStatus = EVENT_CANCELED;
  882. else if (m_rTable.cCompleted == 0 && m_rTable.cEvents > 0)
  883. tyEventStatus = EVENT_FAILED;
  884. else if (m_rTable.cCompleted && m_rTable.cEvents && m_rTable.cCompleted < m_rTable.cEvents)
  885. tyEventStatus = EVENT_WARNINGS;
  886. else if (FAILED(hrDisconnect))
  887. tyEventStatus = EVENT_WARNINGS;
  888. // Result
  889. m_pSpoolCtx->Notify(DELIVERY_NOTIFY_RESULT, tyEventStatus);
  890. // Result
  891. m_pSpoolCtx->Notify(DELIVERY_NOTIFY_COMPLETE, 0);
  892. // Hands Off my callback
  893. if (m_pTransport)
  894. SideAssert(m_pTransport->HandsOffCallback() == S_OK);
  895. // This task is complete
  896. if (!ISFLAGSET(m_dwState, SMTPSTATE_EXECUTEFAILED))
  897. m_pSpoolCtx->EventDone(m_idEvent, tyEventStatus);
  898. }
  899. // Authorizing
  900. else if (ixpstatus == IXP_AUTHORIZING)
  901. m_pSpoolCtx->Notify(DELIVERY_NOTIFY_AUTHORIZING, 0);
  902. // Thread Safety
  903. LeaveCriticalSection(&m_cs);
  904. // Done
  905. return S_OK;
  906. }
  907. // --------------------------------------------------------------------------------
  908. // CSmtpTask::OnError
  909. // --------------------------------------------------------------------------------
  910. STDMETHODIMP CSmtpTask::OnError(IXPSTATUS ixpstatus, LPIXPRESULT pResult, IInternetTransport *pTransport)
  911. {
  912. INETSERVER rServer;
  913. HRESULT hrResult;
  914. // Thread Safety
  915. EnterCriticalSection(&m_cs);
  916. // Invalid State
  917. Assert(m_pUI);
  918. // Insert Error Into UI
  919. if (m_pTransport)
  920. {
  921. hrResult = pTransport->GetServerInfo(&rServer);
  922. if (FAILED(hrResult))
  923. CopyMemory(&rServer, &m_rServer, sizeof(rServer));
  924. }
  925. _CatchResult(pResult, &rServer, IXP_SMTP);
  926. // Thread Safety
  927. LeaveCriticalSection(&m_cs);
  928. // Done
  929. return S_OK;
  930. }
  931. // --------------------------------------------------------------------------------
  932. // CSmtpTask::OnCommand
  933. // --------------------------------------------------------------------------------
  934. STDMETHODIMP CSmtpTask::OnCommand(CMDTYPE cmdtype, LPSTR pszLine, HRESULT hrResponse, IInternetTransport *pTransport)
  935. {
  936. // Logging
  937. if (m_pLogFile && pszLine)
  938. {
  939. // Response
  940. if (CMD_RESP == cmdtype)
  941. m_pLogFile->WriteLog(LOGFILE_RX, pszLine);
  942. // Send
  943. else if (CMD_SEND == cmdtype)
  944. m_pLogFile->WriteLog(LOGFILE_TX, pszLine);
  945. }
  946. // Done
  947. return S_OK;
  948. }
  949. // --------------------------------------------------------------------------------
  950. // CSmtpTask::_CatchResult
  951. // --------------------------------------------------------------------------------
  952. TASKRESULTTYPE CSmtpTask::_CatchResult(HRESULT hr, IXPTYPE ixpType)
  953. {
  954. // Locals
  955. IXPRESULT rResult;
  956. // Build an IXPRESULT
  957. ZeroMemory(&rResult, sizeof(IXPRESULT));
  958. rResult.hrResult = hr;
  959. // Get the SMTP Result Type
  960. return _CatchResult(&rResult, &m_rServer, ixpType);
  961. }
  962. // --------------------------------------------------------------------------------
  963. // CSmtpTask::_CatchResult
  964. // --------------------------------------------------------------------------------
  965. TASKRESULTTYPE CSmtpTask::_CatchResult(LPIXPRESULT pResult, INETSERVER *pServer, IXPTYPE ixpType)
  966. {
  967. // Locals
  968. HWND hwndParent;
  969. TASKRESULTTYPE tyTaskResult=TASKRESULT_FAILURE;
  970. LPSTR pszSubject=NULL;
  971. // If Succeeded
  972. if (SUCCEEDED(pResult->hrResult))
  973. return TASKRESULT_SUCCESS;
  974. // Is there is a current event, get the subject
  975. if (m_rTable.prgEvent && m_rTable.prgEvent[m_rTable.iEvent].pMessage)
  976. {
  977. // Get the subject
  978. if (FAILED(MimeOleGetBodyPropA(m_rTable.prgEvent[m_rTable.iEvent].pMessage, HBODY_ROOT, PIDTOSTR(PID_HDR_SUBJECT), NOFLAGS, &pszSubject)))
  979. pszSubject = NULL;
  980. }
  981. // Get Window
  982. if (NULL == m_pUI || FAILED(m_pUI->GetWindow(&hwndParent)))
  983. hwndParent = NULL;
  984. // Process generic protocol errro
  985. tyTaskResult = TaskUtil_FBaseTransportError(ixpType, m_idEvent, pResult, pServer, pszSubject, m_pUI,
  986. !ISFLAGSET(m_dwFlags, DELIVER_NOUI), hwndParent);
  987. // Have a Transport
  988. if (m_pTransport)
  989. {
  990. // If Task Failure, drop the connection
  991. if (TASKRESULT_FAILURE == tyTaskResult)
  992. {
  993. // Roast the current connection
  994. m_pTransport->DropConnection();
  995. }
  996. // If Event Failure...
  997. else if (TASKRESULT_EVENTFAILED == tyTaskResult)
  998. {
  999. // Goto Next Event
  1000. if (FAILED(_HrFinishCurrentEvent(pResult->hrResult)))
  1001. {
  1002. // Roast the current connection
  1003. m_pTransport->DropConnection();
  1004. }
  1005. }
  1006. }
  1007. // Cleanup
  1008. SafeMemFree(pszSubject);
  1009. // Return Result
  1010. return tyTaskResult;
  1011. }
  1012. // --------------------------------------------------------------------------------
  1013. // CSmtpTask::_DoProgress
  1014. // --------------------------------------------------------------------------------
  1015. void CSmtpTask::_DoProgress(void)
  1016. {
  1017. // Locals
  1018. WORD wProgress;
  1019. WORD wDelta;
  1020. LPSMTPEVENTINFO pEvent;
  1021. // Invalid Arg
  1022. Assert(m_cbTotal > 0 && m_pUI);
  1023. // Compute Current Progress Index
  1024. wProgress = (WORD)((m_cbSent * 100) / m_cbTotal);
  1025. // Compute Delta
  1026. wDelta = wProgress - m_wProgress;
  1027. // Progress Delta
  1028. if (wDelta > 0)
  1029. {
  1030. // Incremenet Progress
  1031. m_pUI->IncrementProgress(wDelta);
  1032. // Increment my wProgress
  1033. m_wProgress += wDelta;
  1034. // Don't go over 100 percent
  1035. Assert(m_wProgress <= 100);
  1036. }
  1037. }
  1038. // --------------------------------------------------------------------------------
  1039. // CSmtpTask::OnResponse
  1040. // --------------------------------------------------------------------------------
  1041. STDMETHODIMP CSmtpTask::OnResponse(LPSMTPRESPONSE pResponse)
  1042. {
  1043. // Thread Safety
  1044. EnterCriticalSection(&m_cs);
  1045. if (pResponse)
  1046. {
  1047. // Handle the Error
  1048. if (TASKRESULT_SUCCESS != _CatchResult(&pResponse->rIxpResult, &m_rServer, IXP_SMTP))
  1049. goto exit;
  1050. // Handle Command Type
  1051. switch(pResponse->command)
  1052. {
  1053. case SMTP_CONNECTED:
  1054. // CommandRSET
  1055. _CatchResult(_HrOnConnected(), IXP_SMTP);
  1056. // Done
  1057. break;
  1058. case SMTP_RSET:
  1059. // Progress
  1060. _DoProgress();
  1061. // Send the current message
  1062. _CatchResult(_HrStartCurrentEvent(), IXP_SMTP);
  1063. // Done
  1064. break;
  1065. case SMTP_MAIL:
  1066. // Reset the address enumerator
  1067. Assert(m_pAdrEnum);
  1068. m_pAdrEnum->Reset();
  1069. // CommandRCPT
  1070. _CatchResult(_HrCommandRCPT(), IXP_SMTP);
  1071. // Done
  1072. break;
  1073. case SMTP_RCPT:
  1074. // CommandRCPT -> CommandDATA
  1075. _CatchResult(_HrCommandRCPT(), IXP_SMTP);
  1076. // Done
  1077. break;
  1078. case SMTP_DATA:
  1079. // Send the data stream
  1080. _CatchResult(_HrSendDataStream(), IXP_SMTP);
  1081. // Done
  1082. break;
  1083. case SMTP_SEND_STREAM:
  1084. // Increment Current Progress
  1085. _OnStreamProgress(&pResponse->rStreamInfo);
  1086. // Done
  1087. break;
  1088. case SMTP_DOT:
  1089. // Finish the Current Event
  1090. _CatchResult(_HrFinishCurrentEvent(S_OK), IXP_SMTP);
  1091. // Done
  1092. break;
  1093. }
  1094. }
  1095. exit:
  1096. // Thread Safety
  1097. LeaveCriticalSection(&m_cs);
  1098. // Done
  1099. return S_OK;
  1100. }
  1101. // --------------------------------------------------------------------------------
  1102. // CSmtpTask::_HrOnConnected
  1103. // --------------------------------------------------------------------------------
  1104. HRESULT CSmtpTask::_HrOnConnected(void)
  1105. {
  1106. // Locals
  1107. CHAR szRes[CCHMAX_RES];
  1108. CHAR szMsg[CCHMAX_RES+CCHMAX_RES];
  1109. // Progress
  1110. LOADSTRING(IDS_SPS_SMTPPROGGEN, szRes);
  1111. wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, m_rServer.szAccount);
  1112. // Set General Progress
  1113. m_pUI->SetGeneralProgress(szMsg);
  1114. // Progress
  1115. _DoProgress();
  1116. // Notify
  1117. m_pSpoolCtx->Notify(DELIVERY_NOTIFY_SENDING, 0);
  1118. // Send the current message
  1119. _CatchResult(_HrStartCurrentEvent(), IXP_SMTP);
  1120. // Done
  1121. return S_OK;
  1122. }
  1123. // --------------------------------------------------------------------------------
  1124. // CSmtpTask::_HrStartCurrentEvent
  1125. // --------------------------------------------------------------------------------
  1126. HRESULT CSmtpTask::_HrStartCurrentEvent(void)
  1127. {
  1128. // Locals
  1129. HRESULT hr=S_OK;
  1130. LPSMTPEVENTINFO pEvent;
  1131. IMimeAddressTable *pAddrTable=NULL;
  1132. CHAR szRes[CCHMAX_RES];
  1133. CHAR szMsg[CCHMAX_RES + CCHMAX_ACCOUNT_NAME];
  1134. // Invalid Arg
  1135. Assert(m_rTable.iEvent < m_rTable.cEvents);
  1136. // Get the current event
  1137. pEvent = CURRENTSMTPEVENT(m_rTable);
  1138. // Is this a partial message
  1139. if (ISFLAGSET(pEvent->dwFlags, SMTPEVENT_SPLITPART))
  1140. {
  1141. LOADSTRING(IDS_SPS_SMTPPROGRESS_SPLIT, szRes);
  1142. wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, m_rTable.iEvent + 1, m_rTable.cEvents, pEvent->iPart, pEvent->cParts);
  1143. }
  1144. // Otherwise
  1145. else
  1146. {
  1147. LOADSTRING(IDS_SPS_SMTPPROGRESS, szRes);
  1148. wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, m_rTable.iEvent + 1, m_rTable.cEvents);
  1149. }
  1150. // Set Specific Progress
  1151. m_pUI->SetSpecificProgress(szMsg);
  1152. // If mail is coming from the outbox
  1153. if (!ISFLAGSET(pEvent->dwFlags, SMTPEVENT_SPLITPART))
  1154. {
  1155. // Open Store Message
  1156. if (FAILED(_HrOpenMessage(pEvent->idMessage, &pEvent->pMessage)))
  1157. {
  1158. hr = TrapError(SP_E_SMTP_CANTOPENMESSAGE);
  1159. goto exit;
  1160. }
  1161. }
  1162. // We better have a message object at this point
  1163. else if (NULL == pEvent->pMessage)
  1164. {
  1165. Assert(FALSE);
  1166. hr = TrapError(E_FAIL);
  1167. goto exit;
  1168. }
  1169. // Catch Result
  1170. CHECKHR(hr = _HrCommandMAIL());
  1171. exit:
  1172. // Cleanup
  1173. SafeRelease(pAddrTable);
  1174. // Done
  1175. return hr;
  1176. }
  1177. // ------------------------------------------------------------------------------------
  1178. // CSmtpTask::_HrCommandMAIL
  1179. // ------------------------------------------------------------------------------------
  1180. HRESULT CSmtpTask::_HrCommandMAIL(void)
  1181. {
  1182. // Locals
  1183. HRESULT hr=S_OK;
  1184. HRESULT hrFind;
  1185. IMimeAddressTable *pAdrTable=NULL;
  1186. ADDRESSPROPS rAddress;
  1187. ULONG c;
  1188. LPSMTPEVENTINFO pEvent;
  1189. // Get the current smtp event
  1190. pEvent = CURRENTSMTPEVENT(m_rTable);
  1191. // Init
  1192. ZeroMemory(&rAddress, sizeof(ADDRESSPROPS));
  1193. // Check State
  1194. Assert(m_pTransport && pEvent->pMessage);
  1195. // Release Current Enumerator
  1196. SafeRelease(m_pAdrEnum);
  1197. // Get the Sender...
  1198. CHECKHR(hr = pEvent->pMessage->GetAddressTable(&pAdrTable));
  1199. // Get Enumerator
  1200. CHECKHR(hr = pAdrTable->EnumTypes(IAT_KNOWN, IAP_ADRTYPE | IAP_EMAIL, &m_pAdrEnum));
  1201. // Loop Enumerator
  1202. while (SUCCEEDED(m_pAdrEnum->Next(1, &rAddress, &c)) && c == 1)
  1203. {
  1204. // Not IAT_FROM
  1205. if (NULL == rAddress.pszEmail || IAT_FROM != rAddress.dwAdrType)
  1206. {
  1207. g_pMoleAlloc->FreeAddressProps(&rAddress);
  1208. continue;
  1209. }
  1210. // Send the command
  1211. CHECKHR(hr = m_pTransport->CommandMAIL(rAddress.pszEmail));
  1212. // Done
  1213. goto exit;
  1214. }
  1215. // No Sender
  1216. hr = TrapError(IXP_E_SMTP_NO_SENDER);
  1217. exit:
  1218. // Cleanup
  1219. SafeRelease(pAdrTable);
  1220. g_pMoleAlloc->FreeAddressProps(&rAddress);
  1221. // Done
  1222. return hr;
  1223. }
  1224. // ------------------------------------------------------------------------------------
  1225. // CSmtpTask::_HrCommandRCPT
  1226. // ------------------------------------------------------------------------------------
  1227. HRESULT CSmtpTask::_HrCommandRCPT(void)
  1228. {
  1229. // Locals
  1230. HRESULT hr=S_OK;
  1231. DWORD dwAdrType;
  1232. DWORD c;
  1233. LPSTR pszEmail=NULL;
  1234. ADDRESSPROPS rAddress;
  1235. LPSMTPEVENTINFO pEvent;
  1236. // Get the current smtp event
  1237. pEvent = CURRENTSMTPEVENT(m_rTable);
  1238. // Init
  1239. ZeroMemory(&rAddress, sizeof(ADDRESSPROPS));
  1240. // Check State
  1241. Assert(m_pAdrEnum && m_pTransport && pEvent->pMessage);
  1242. // Walk the enumerator for the next recipient
  1243. while (SUCCEEDED(m_pAdrEnum->Next(1, &rAddress, &c)) && c == 1)
  1244. {
  1245. // Get Type
  1246. if (rAddress.pszEmail && ISFLAGSET(IAT_RECIPS, rAddress.dwAdrType))
  1247. {
  1248. // Send the command
  1249. CHECKHR(hr = m_pTransport->CommandRCPT(rAddress.pszEmail));
  1250. // Count Recipients
  1251. pEvent->cRecipients++;
  1252. // Done
  1253. goto exit;
  1254. }
  1255. // Release
  1256. g_pMoleAlloc->FreeAddressProps(&rAddress);
  1257. }
  1258. // Release the Enumerator
  1259. SafeRelease(m_pAdrEnum);
  1260. // No Recipients
  1261. if (0 == pEvent->cRecipients)
  1262. {
  1263. hr = TrapError(IXP_E_SMTP_NO_RECIPIENTS);
  1264. goto exit;
  1265. }
  1266. // Send the Data Command
  1267. CHECKHR(hr = m_pTransport->CommandDATA());
  1268. exit:
  1269. // Cleanup
  1270. g_pMoleAlloc->FreeAddressProps(&rAddress);
  1271. // Done
  1272. return hr;
  1273. }
  1274. // --------------------------------------------------------------------------------
  1275. // CSmtpTask::_HrSendDataStream
  1276. // --------------------------------------------------------------------------------
  1277. HRESULT CSmtpTask::_HrSendDataStream(void)
  1278. {
  1279. // Locals
  1280. HRESULT hr=S_OK;
  1281. LPSTREAM pStream=NULL;
  1282. LPSTREAM pStmActual;
  1283. LPSTR pszBCC=NULL;
  1284. LPSTR pszTo=NULL;
  1285. LPSTR pszMessageId=NULL;
  1286. LPSMTPEVENTINFO pEvent;
  1287. CMessageIdStream *pStmWrapper=NULL;
  1288. // Get the current smtp event
  1289. pEvent = CURRENTSMTPEVENT(m_rTable);
  1290. // Check State
  1291. Assert(m_pTransport && pEvent->pMessage);
  1292. // See if BCC is set
  1293. if (SUCCEEDED(MimeOleGetBodyPropA(pEvent->pMessage, HBODY_ROOT, PIDTOSTR(PID_HDR_BCC), NOFLAGS, &pszBCC)))
  1294. {
  1295. // Locals
  1296. LPSTR pszToAppend=NULL;
  1297. // RAID-20750 - If the to line is not set, then we will set it to "Undisclosed Recipient"
  1298. // or the SMTP gateways will put the BCC into the to line.
  1299. if (FAILED(MimeOleGetBodyPropA(pEvent->pMessage, HBODY_ROOT, PIDTOSTR(PID_HDR_TO), NOFLAGS, &pszTo)))
  1300. {
  1301. // Raid-9691: We were just putting <Undiscolsed Recipient>, which was an illegal email address (bad for Exchange Server)
  1302. pszToAppend = "To: <Undisclosed-Recipient:;>\r\n";
  1303. }
  1304. // Raid-2705: If this fails, just get the message source
  1305. if (FAILED(MimeOleStripHeaders(pEvent->pMessage, HBODY_ROOT, STR_HDR_BCC, pszToAppend, &pStream)))
  1306. {
  1307. // Get Message Stream
  1308. CHECKHR(hr = pEvent->pMessage->GetMessageSource(&pStream, 0));
  1309. }
  1310. }
  1311. // Otherwise, just get the message source
  1312. else
  1313. {
  1314. // Get Message Stream
  1315. CHECKHR(hr = pEvent->pMessage->GetMessageSource(&pStream, 0));
  1316. }
  1317. // Lets see if the message has a message-id already
  1318. if (FAILED(MimeOleGetBodyPropA(pEvent->pMessage, HBODY_ROOT, PIDTOSTR(PID_HDR_MESSAGEID), NOFLAGS, &pszMessageId)))
  1319. {
  1320. // Create a wrapper for this stream that will output the messageid
  1321. CHECKALLOC(pStmWrapper = new CMessageIdStream(pStream));
  1322. // Adjust pEvent->cbEvent
  1323. pEvent->cbEvent += pStmWrapper->CchMessageId();
  1324. // Increment total
  1325. m_cbTotal += pStmWrapper->CchMessageId();
  1326. // Increment pEvent->cbSentTotal
  1327. pEvent->cbSentTotal += pStmWrapper->CchMessageId();
  1328. // Reset pStream
  1329. pStmActual = (IStream *)pStmWrapper;
  1330. }
  1331. else
  1332. pStmActual = pStream;
  1333. // Send the stream
  1334. CHECKHR(hr = m_pTransport->SendDataStream(pStmActual, pEvent->cbEvent));
  1335. exit:
  1336. // Cleanup
  1337. SafeRelease(pStream);
  1338. SafeRelease(pStmWrapper);
  1339. SafeMemFree(pszBCC);
  1340. SafeMemFree(pszTo);
  1341. SafeMemFree(pszMessageId);
  1342. // Done
  1343. return hr;
  1344. }
  1345. // --------------------------------------------------------------------------------
  1346. // CSmtpTask::_OnStreamProgress
  1347. // --------------------------------------------------------------------------------
  1348. void CSmtpTask::_OnStreamProgress(LPSMTPSTREAM pInfo)
  1349. {
  1350. // Locals
  1351. LPSMTPEVENTINFO pEvent;
  1352. // Get the current smtp event
  1353. pEvent = CURRENTSMTPEVENT(m_rTable);
  1354. // Increment Status
  1355. pEvent->cbEventSent += pInfo->cbIncrement;
  1356. Assert(pEvent->cbEventSent == pInfo->cbCurrent);
  1357. // Increment total sent
  1358. m_cbSent += pInfo->cbIncrement;
  1359. // Do Progress
  1360. _DoProgress();
  1361. }
  1362. // --------------------------------------------------------------------------------
  1363. // CSmtpTask::_HrFinishCurrentEvent
  1364. // --------------------------------------------------------------------------------
  1365. HRESULT CSmtpTask::_HrFinishCurrentEvent(HRESULT hrResult)
  1366. {
  1367. // Locals
  1368. HRESULT hr=S_OK;
  1369. LPSMTPEVENTINFO pEvent;
  1370. // Get the current smtp event
  1371. pEvent = CURRENTSMTPEVENT(m_rTable);
  1372. // Save the Event Result
  1373. pEvent->hrResult = hrResult;
  1374. // If the Event Failed...
  1375. if (FAILED(pEvent->hrResult))
  1376. {
  1377. // If this message was part of a split group, skip all pars in this group
  1378. if (ISFLAGSET(pEvent->dwFlags, SMTPEVENT_SPLITPART))
  1379. {
  1380. // Compute Next Event
  1381. ULONG iNextEvent = m_rTable.iEvent + (pEvent->cParts - pEvent->iPart) + 1;
  1382. // Increment to last part
  1383. while(m_rTable.iEvent < iNextEvent && m_rTable.iEvent < m_rTable.cEvents)
  1384. {
  1385. // Goto next event
  1386. m_rTable.iEvent++;
  1387. // Fail this event
  1388. _CatchResult(SP_E_SENDINGSPLITGROUP, IXP_SMTP);
  1389. // Fixup m_cbSent to be correct
  1390. m_cbSent = m_rTable.prgEvent[m_rTable.iEvent].cbSentTotal;
  1391. // Update progress
  1392. _DoProgress();
  1393. }
  1394. }
  1395. }
  1396. // Otherwise
  1397. else
  1398. {
  1399. // Mark the event as complete
  1400. FLAGSET(pEvent->dwFlags, SMTPEVENT_COMPLETE);
  1401. // Increment number of completed events
  1402. m_rTable.cCompleted++;
  1403. }
  1404. // Go to next message
  1405. CHECKHR(hr = _HrStartNextEvent());
  1406. exit:
  1407. // Done
  1408. return hr;
  1409. }
  1410. // --------------------------------------------------------------------------------
  1411. // CSmtpTask::_HrStartNextEvent
  1412. // --------------------------------------------------------------------------------
  1413. HRESULT CSmtpTask::_HrStartNextEvent(void)
  1414. {
  1415. // Locals
  1416. HRESULT hr=S_OK;
  1417. // Fixup m_cbSent to be correct
  1418. m_cbSent = m_rTable.prgEvent[m_rTable.iEvent].cbSentTotal;
  1419. // Are we done yet ?
  1420. if (m_rTable.iEvent + 1 == m_rTable.cEvents)
  1421. {
  1422. // Update progress
  1423. _DoProgress();
  1424. // Disconnect from the server
  1425. CHECKHR(hr = m_pTransport->Disconnect());
  1426. }
  1427. // Oterhwise, Increment Event and send rset
  1428. else
  1429. {
  1430. // Next Event
  1431. m_rTable.iEvent++;
  1432. // Update progress
  1433. _DoProgress();
  1434. // Send Reset Command
  1435. CHECKHR(hr = m_pTransport->CommandRSET());
  1436. }
  1437. exit:
  1438. // Done
  1439. return hr;
  1440. }
  1441. // --------------------------------------------------------------------------------
  1442. // CSmtpTask::_OnDisconnectComplete
  1443. // --------------------------------------------------------------------------------
  1444. HRESULT CSmtpTask::_OnDisconnectComplete(void)
  1445. {
  1446. // Locals
  1447. HRESULT hr=S_OK;
  1448. PDWORD_PTR prgdwIds=NULL;
  1449. DWORD cIds=0;
  1450. DWORD cIdsAlloc=0;
  1451. DWORD i;
  1452. LPSMTPEVENTINFO pEvent;
  1453. ADJUSTFLAGS Flags;
  1454. // Invalid State
  1455. Assert(m_pOutbox);
  1456. // Walk through the list of events
  1457. for (i=0; i<m_rTable.cEvents; i++)
  1458. {
  1459. // Readability
  1460. pEvent = &m_rTable.prgEvent[i];
  1461. // If this event was in the outbox
  1462. if (0 != pEvent->idMessage && ISFLAGSET(pEvent->dwFlags, SMTPEVENT_COMPLETE))
  1463. {
  1464. // Insert into my array of message ids
  1465. if (cIds + 1 > cIdsAlloc)
  1466. {
  1467. // Realloc
  1468. CHECKHR(hr = HrRealloc((LPVOID *)&prgdwIds, sizeof(DWORD) * (cIdsAlloc + 10)));
  1469. // Increment cIdsAlloc
  1470. cIdsAlloc += 10;
  1471. }
  1472. // Set Message Id
  1473. prgdwIds[cIds++] = (DWORD_PTR)pEvent->idMessage;
  1474. }
  1475. }
  1476. // Setup List
  1477. m_rList.cMsgs = cIds;
  1478. m_rList.prgidMsg = (LPMESSAGEID)prgdwIds;
  1479. prgdwIds = NULL;
  1480. if (m_rList.cMsgs)
  1481. {
  1482. Flags.dwAdd = ARF_READ;
  1483. Flags.dwRemove = ARF_SUBMITTED | ARF_UNSENT;
  1484. if (m_idEventUpload == INVALID_EVENT)
  1485. {
  1486. if (DwGetOption(OPT_SAVESENTMSGS))
  1487. {
  1488. Assert(m_pSentItems != NULL);
  1489. // Move the message from the sent items folder
  1490. CHECKHR(hr = m_pOutbox->CopyMessages(m_pSentItems, COPY_MESSAGE_MOVE, &m_rList, &Flags, NULL, NOSTORECALLBACK));
  1491. }
  1492. else
  1493. {
  1494. // Delete the messages
  1495. CHECKHR(hr = m_pOutbox->DeleteMessages(DELETE_MESSAGE_NOTRASHCAN | DELETE_MESSAGE_NOPROMPT, &m_rList, NULL, NOSTORECALLBACK));
  1496. }
  1497. }
  1498. else
  1499. {
  1500. // Raid-7639: OE sends message over and over when runs out of disk space.
  1501. m_pOutbox->SetMessageFlags(&m_rList, &Flags, NULL, NOSTORECALLBACK);
  1502. }
  1503. }
  1504. exit:
  1505. // Cleanup
  1506. SafeMemFree(prgdwIds);
  1507. // Done
  1508. return hr;
  1509. }
  1510. // --------------------------------------------------------------------------------
  1511. // CSmtpTask::Cancel
  1512. // --------------------------------------------------------------------------------
  1513. STDMETHODIMP CSmtpTask::Cancel(void)
  1514. {
  1515. // Thread Safety
  1516. EnterCriticalSection(&m_cs);
  1517. // Cancelled
  1518. FLAGSET(m_dwState, SMTPSTATE_CANCELED);
  1519. // Simply drop the connection
  1520. if (m_pTransport)
  1521. m_pTransport->DropConnection();
  1522. if (m_pCancel != NULL)
  1523. m_pCancel->Cancel(CT_ABORT);
  1524. // Thread Safety
  1525. LeaveCriticalSection(&m_cs);
  1526. // Done
  1527. return S_OK;
  1528. }
  1529. // --------------------------------------------------------------------------------
  1530. // CSmtpTask::OnTimeoutResponse
  1531. // --------------------------------------------------------------------------------
  1532. STDMETHODIMP CSmtpTask::OnTimeoutResponse(TIMEOUTRESPONSE eResponse)
  1533. {
  1534. // Thread Safety
  1535. EnterCriticalSection(&m_cs);
  1536. // Should have a handle to the timeout window
  1537. Assert(m_hwndTimeout);
  1538. // No timeout window handle
  1539. m_hwndTimeout = NULL;
  1540. // Stop ?
  1541. if (TIMEOUT_RESPONSE_STOP == eResponse)
  1542. {
  1543. // Cancelled
  1544. FLAGSET(m_dwState, SMTPSTATE_CANCELED);
  1545. // Report error and drop connection
  1546. _CatchResult(IXP_E_TIMEOUT, IXP_SMTP);
  1547. }
  1548. // Thread Safety
  1549. LeaveCriticalSection(&m_cs);
  1550. // Done
  1551. return S_OK;
  1552. }
  1553. // --------------------------------------------------------------------------------
  1554. // CSmtpTask::IsDialogMessage
  1555. // --------------------------------------------------------------------------------
  1556. STDMETHODIMP CSmtpTask::IsDialogMessage(LPMSG pMsg)
  1557. {
  1558. HRESULT hr=S_FALSE;
  1559. EnterCriticalSection(&m_cs);
  1560. if (m_hwndTimeout && IsWindow(m_hwndTimeout))
  1561. hr = (TRUE == ::IsDialogMessage(m_hwndTimeout, pMsg)) ? S_OK : S_FALSE;
  1562. LeaveCriticalSection(&m_cs);
  1563. return hr;
  1564. }
  1565. // --------------------------------------------------------------------------------
  1566. // CSmtpTask::OnFlagsChanged
  1567. // --------------------------------------------------------------------------------
  1568. STDMETHODIMP CSmtpTask::OnFlagsChanged(DWORD dwFlags)
  1569. {
  1570. EnterCriticalSection(&m_cs);
  1571. m_dwFlags = dwFlags;
  1572. LeaveCriticalSection(&m_cs);
  1573. return (S_OK);
  1574. }
  1575. STDMETHODIMP CSmtpTask::OnBegin(STOREOPERATIONTYPE tyOperation, STOREOPERATIONINFO *pOpInfo, IOperationCancel *pCancel)
  1576. {
  1577. char szRes[CCHMAX_STRINGRES], szBuf[CCHMAX_STRINGRES];
  1578. // Hold onto this
  1579. Assert(m_tyOperation == SOT_INVALID);
  1580. if (pCancel)
  1581. {
  1582. m_pCancel = pCancel;
  1583. m_pCancel->AddRef();
  1584. }
  1585. m_tyOperation = tyOperation;
  1586. // Set the animation
  1587. m_pUI->SetAnimation(idanOutbox, TRUE);
  1588. // Setup Progress Meter
  1589. m_pUI->SetProgressRange(100);
  1590. m_wProgress = 0;
  1591. LOADSTRING(IDS_SPS_MOVEPROGRESS, szRes);
  1592. wnsprintf(szBuf, ARRAYSIZE(szBuf), szRes, 1, m_rList.cMsgs);
  1593. m_pUI->SetSpecificProgress(szBuf);
  1594. // Party On
  1595. return(S_OK);
  1596. }
  1597. STDMETHODIMP CSmtpTask::OnProgress(STOREOPERATIONTYPE tyOperation, DWORD dwCurrent, DWORD dwMax, LPCSTR pszStatus)
  1598. {
  1599. char szRes[CCHMAX_STRINGRES], szBuf[CCHMAX_STRINGRES];
  1600. WORD wProgress, wDelta;
  1601. // NOTE: that you can get more than one type of value for tyOperation.
  1602. // Most likely, you will get SOT_CONNECTION_STATUS and then the
  1603. // operation that you might expect. See HotStore.idl and look for
  1604. // the STOREOPERATION enumeration type for more info.
  1605. if (tyOperation == SOT_CONNECTION_STATUS)
  1606. {
  1607. // Connecting to ...
  1608. LoadString(g_hLocRes, idsInetMailConnectingHost, szRes, ARRAYSIZE(szRes));
  1609. wnsprintf(szBuf, ARRAYSIZE(szBuf), szRes, m_rServer.szAccount);
  1610. m_pUI->SetGeneralProgress(szBuf);
  1611. }
  1612. else if (tyOperation == SOT_COPYMOVE_MESSAGE)
  1613. {
  1614. // Compute Current Progress Index
  1615. wProgress = (WORD)((dwCurrent * 100) / dwMax);
  1616. // Compute Delta
  1617. wDelta = wProgress - m_wProgress;
  1618. // Progress Delta
  1619. if (wDelta > 0)
  1620. {
  1621. // Incremenet Progress
  1622. m_pUI->IncrementProgress(wDelta);
  1623. // Increment my wProgress
  1624. m_wProgress += wDelta;
  1625. // Don't go over 100 percent
  1626. Assert(m_wProgress <= 100);
  1627. }
  1628. if (dwCurrent < dwMax)
  1629. {
  1630. LOADSTRING(IDS_SPS_MOVEPROGRESS, szRes);
  1631. wnsprintf(szBuf, ARRAYSIZE(szBuf), szRes, dwCurrent + 1, dwMax);
  1632. // Set Specific Progress
  1633. m_pUI->SetSpecificProgress(szBuf);
  1634. }
  1635. }
  1636. // Done
  1637. return(S_OK);
  1638. }
  1639. STDMETHODIMP CSmtpTask::OnTimeout(LPINETSERVER pServer, LPDWORD pdwTimeout, IXPTYPE ixpServerType)
  1640. {
  1641. // Is there currently a timeout dialog
  1642. if (m_hwndTimeout)
  1643. {
  1644. // Set foreground
  1645. SetForegroundWindow(m_hwndTimeout);
  1646. }
  1647. else
  1648. {
  1649. LPCSTR pszProtocol;
  1650. // Not suppose to be showing UI ?
  1651. if (ISFLAGSET(m_dwFlags, DELIVER_NOUI))
  1652. return(S_FALSE);
  1653. // Do Timeout Dialog
  1654. GetProtocolString(&pszProtocol, ixpServerType);
  1655. if (pServer)
  1656. {
  1657. m_hwndTimeout = TaskUtil_HwndOnTimeout(pServer->szServerName, pServer->szAccount,
  1658. pszProtocol, pServer->dwTimeout, (ITimeoutCallback *) this);
  1659. // Couldn't create the dialog
  1660. if (NULL == m_hwndTimeout)
  1661. return(S_FALSE);
  1662. }
  1663. }
  1664. return(S_OK);
  1665. }
  1666. STDMETHODIMP CSmtpTask::CanConnect(LPCSTR pszAccountId, DWORD dwFlags)
  1667. {
  1668. HWND hwnd;
  1669. BOOL fPrompt = TRUE;
  1670. if (m_pUI)
  1671. m_pUI->GetWindow(&hwnd);
  1672. else
  1673. hwnd = NULL;
  1674. // Call into general CanConnect Utility
  1675. if ((m_dwFlags & (DELIVER_NOUI | DELIVER_BACKGROUND)) || (dwFlags & CC_FLAG_DONTPROMPT))
  1676. fPrompt = FALSE;
  1677. return CallbackCanConnect(pszAccountId, hwnd, fPrompt);
  1678. }
  1679. STDMETHODIMP CSmtpTask::OnLogonPrompt(LPINETSERVER pServer, IXPTYPE ixpServerType)
  1680. {
  1681. HWND hwnd;
  1682. if (m_hwndTimeout)
  1683. {
  1684. DestroyWindow(m_hwndTimeout);
  1685. m_hwndTimeout = NULL;
  1686. }
  1687. if (!!(m_dwFlags & (DELIVER_NOUI | DELIVER_BACKGROUND)))
  1688. return(E_FAIL);
  1689. if (m_pUI)
  1690. m_pUI->GetWindow(&hwnd);
  1691. else
  1692. hwnd = NULL;
  1693. // Call into general OnLogonPrompt Utility
  1694. return CallbackOnLogonPrompt(hwnd, pServer, ixpServerType);
  1695. }
  1696. STDMETHODIMP CSmtpTask::OnComplete(STOREOPERATIONTYPE tyOperation, HRESULT hrComplete,
  1697. LPSTOREOPERATIONINFO pOpInfo, LPSTOREERROR pErrorInfo)
  1698. {
  1699. HRESULT hr;
  1700. char szRes[CCHMAX_STRINGRES], szBuf[CCHMAX_STRINGRES * 2], szSubject[64];
  1701. EVENTCOMPLETEDSTATUS tyEventStatus;
  1702. if (m_hwndTimeout)
  1703. {
  1704. DestroyWindow(m_hwndTimeout);
  1705. m_hwndTimeout = NULL;
  1706. }
  1707. IxpAssert(m_tyOperation != SOT_INVALID);
  1708. if (m_tyOperation != tyOperation)
  1709. return(S_OK);
  1710. Assert(tyOperation == SOT_COPYMOVE_MESSAGE);
  1711. // Figure out if we succeeded or failed
  1712. if (FAILED(hrComplete))
  1713. {
  1714. Assert(m_pUI);
  1715. if (NULL != pErrorInfo)
  1716. {
  1717. IXPRESULT ixpResult;
  1718. INETSERVER rServer;
  1719. char szProblem[CCHMAX_STRINGRES];
  1720. int iLen;
  1721. // Prepend sent items text error text to supplied problem
  1722. Assert(tyOperation == SOT_COPYMOVE_MESSAGE);
  1723. iLen = LoadString(g_hLocRes, IDS_SP_E_CANT_MOVETO_SENTITEMS, szProblem, sizeof(szProblem));
  1724. if (iLen < sizeof(szProblem) - 1)
  1725. {
  1726. szProblem[iLen] = ' ';
  1727. iLen += 1;
  1728. szProblem[iLen] = '\0';
  1729. }
  1730. if (NULL != pErrorInfo->pszProblem)
  1731. StrCpyN(szProblem + iLen, pErrorInfo->pszProblem, ARRAYSIZE(szProblem) - iLen);
  1732. TaskUtil_SplitStoreError(&ixpResult, &rServer, pErrorInfo);
  1733. ixpResult.pszProblem = szProblem;
  1734. _CatchResult(&ixpResult, &rServer, pErrorInfo->ixpType);
  1735. }
  1736. else
  1737. {
  1738. // Remap the Error Result
  1739. hr = TrapError(SP_E_CANT_MOVETO_SENTITEMS);
  1740. // Show an error in the spooler dialog
  1741. _CatchResult(hr, IXP_IMAP); // Without a STOREERROR, we just have to guess
  1742. }
  1743. }
  1744. m_pUI->SetAnimation(idanOutbox, FALSE);
  1745. if (ISFLAGSET(m_dwState, SMTPSTATE_CANCELED))
  1746. tyEventStatus = EVENT_CANCELED;
  1747. else if (SUCCEEDED(hrComplete))
  1748. tyEventStatus = EVENT_SUCCEEDED;
  1749. else
  1750. tyEventStatus = EVENT_FAILED;
  1751. // Result
  1752. m_pSpoolCtx->Notify(DELIVERY_NOTIFY_RESULT, tyEventStatus);
  1753. // Result
  1754. m_pSpoolCtx->Notify(DELIVERY_NOTIFY_COMPLETE, 0);
  1755. m_pSpoolCtx->EventDone(m_idEventUpload, tyEventStatus);
  1756. // Release your cancel object
  1757. SafeRelease(m_pCancel);
  1758. m_tyOperation = SOT_INVALID;
  1759. // Done
  1760. return(S_OK);
  1761. }
  1762. STDMETHODIMP CSmtpTask::OnPrompt(HRESULT hrError, LPCTSTR pszText, LPCTSTR pszCaption, UINT uType, INT *piUserResponse)
  1763. {
  1764. HWND hwnd;
  1765. // Close any timeout dialog, if present
  1766. if (m_hwndTimeout)
  1767. {
  1768. DestroyWindow(m_hwndTimeout);
  1769. m_hwndTimeout = NULL;
  1770. }
  1771. // Raid 55082 - SPOOLER: SPA/SSL auth to NNTP does not display cert warning and fails.
  1772. #if 0
  1773. if (!!(m_dwFlags & (DELIVER_NOUI | DELIVER_BACKGROUND)))
  1774. return(E_FAIL);
  1775. #endif
  1776. if (m_pUI)
  1777. m_pUI->GetWindow(&hwnd);
  1778. else
  1779. hwnd = NULL;
  1780. // Call into my swanky utility
  1781. return CallbackOnPrompt(hwnd, hrError, pszText, pszCaption, uType, piUserResponse);
  1782. }