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.

1768 lines
48 KiB

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Copyright (C) 1993-1998 Microsoft Corporation. All Rights Reserved.
  3. //
  4. // MODULE: newstask.cpp
  5. //
  6. // PURPOSE: Implements a task object to take care of news posts.
  7. //
  8. #include "pch.hxx"
  9. #include "resource.h"
  10. #include "imagelst.h"
  11. #include "storfldr.h"
  12. #include "mimeutil.h"
  13. #include "newstask.h"
  14. #include "goptions.h"
  15. #include "thormsgs.h"
  16. #include "spoolui.h"
  17. #include "xputil.h"
  18. #include "ourguid.h"
  19. #include "demand.h"
  20. #include "msgfldr.h"
  21. #include "taskutil.h"
  22. #include <storsync.h>
  23. #include <ntverp.h>
  24. ASSERTDATA
  25. const static char c_szThis[] = "this";
  26. static const PFNSTATEFUNC g_rgpfnState[NTS_MAX] =
  27. {
  28. NULL, // Idle
  29. NULL, // Connecting
  30. &CNewsTask::Post_Init,
  31. &CNewsTask::Post_NextMsg,
  32. NULL, // Post_OnResp
  33. &CNewsTask::Post_Dispose,
  34. &CNewsTask::Post_Done,
  35. &CNewsTask::NewMsg_Init,
  36. &CNewsTask::NewMsg_NextGroup,
  37. NULL, // NewMsg_OnResp
  38. &CNewsTask::NewMsg_HttpSyncStore,
  39. NULL, // NewMsg_OnHttpResp
  40. &CNewsTask::NewMsg_Done
  41. };
  42. static const TCHAR c_szXNewsReader[] = "Microsoft Outlook Express " VER_PRODUCTVERSION_STRING;
  43. //
  44. // FUNCTION: CNewsTask::CNewsTask()
  45. //
  46. // PURPOSE: Initializes the member variables of the object.
  47. //
  48. CNewsTask::CNewsTask()
  49. {
  50. m_cRef = 1;
  51. m_fInited = FALSE;
  52. m_dwFlags = 0;
  53. m_state = NTS_IDLE;
  54. m_eidCur = 0;
  55. m_pInfo = NULL;
  56. m_fConnectFailed = FALSE;
  57. m_szAccount[0] = 0;
  58. m_szAccountId[0] = 0;
  59. m_idAccount = FOLDERID_INVALID;
  60. m_pAccount = NULL;
  61. m_cEvents = 0;
  62. m_fCancel = FALSE;
  63. m_pBindCtx = NULL;
  64. m_pUI = NULL;
  65. m_pServer = NULL;
  66. m_pOutbox = NULL;
  67. m_pSent = NULL;
  68. m_hwnd = 0;
  69. m_cMsgsPost = 0;
  70. m_cCurPost = 0;
  71. m_cFailed = 0;
  72. m_cCurParts = 0;
  73. m_cPartsCompleted = 0;
  74. m_fPartFailed = FALSE;
  75. m_rgMsgInfo = NULL;
  76. m_pSplitInfo = NULL;
  77. m_cGroups = 0;
  78. m_cCurGroup = -1;
  79. m_rgidGroups = NULL;
  80. m_dwNewInboxMsgs = 0;
  81. m_pCancel = NULL;
  82. m_hTimeout = NULL;
  83. m_tyOperation = SOT_INVALID;
  84. }
  85. //
  86. // FUNCTION: CNewsTask::~CNewsTask()
  87. //
  88. // PURPOSE: Frees any resources allocated during the life of the class.
  89. //
  90. CNewsTask::~CNewsTask()
  91. {
  92. DestroyWindow(m_hwnd);
  93. FreeSplitInfo();
  94. SafeMemFree(m_pInfo);
  95. SafeRelease(m_pBindCtx);
  96. SafeRelease(m_pUI);
  97. SafeRelease(m_pAccount);
  98. if (m_pServer)
  99. {
  100. m_pServer->Close(MSGSVRF_HANDS_OFF_SERVER);
  101. m_pServer->Release();
  102. }
  103. Assert(NULL == m_pOutbox);
  104. Assert(NULL == m_pSent);
  105. SafeMemFree(m_rgMsgInfo);
  106. CallbackCloseTimeout(&m_hTimeout);
  107. SafeRelease(m_pCancel);
  108. }
  109. HRESULT CNewsTask::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
  110. {
  111. if (NULL == *ppvObj)
  112. return (E_INVALIDARG);
  113. *ppvObj = NULL;
  114. if (IsEqualIID(riid, IID_IUnknown))
  115. *ppvObj = (LPVOID)(ISpoolerTask *) this;
  116. else if (IsEqualIID(riid, IID_ISpoolerTask))
  117. *ppvObj = (LPVOID)(ISpoolerTask *) this;
  118. else if (IsEqualIID(riid, IID_IStoreCallback))
  119. *ppvObj = (LPVOID)(IStoreCallback *) this;
  120. else if (IsEqualIID(riid, IID_ITimeoutCallback))
  121. *ppvObj = (LPVOID)(ITimeoutCallback *) this;
  122. if (NULL == *ppvObj)
  123. return (E_NOINTERFACE);
  124. AddRef();
  125. return (S_OK);
  126. }
  127. ULONG CNewsTask::AddRef(void)
  128. {
  129. ULONG cRefT;
  130. cRefT = ++m_cRef;
  131. return (cRefT);
  132. }
  133. ULONG CNewsTask::Release(void)
  134. {
  135. ULONG cRefT;
  136. cRefT = --m_cRef;
  137. if (0 == cRefT)
  138. delete this;
  139. return (cRefT);
  140. }
  141. static const char c_szNewsTask[] = "News Task";
  142. //
  143. // FUNCTION: CNewsTask::Init()
  144. //
  145. // PURPOSE: Called by the spooler engine to tell us what type of task to
  146. // execute and to provide us with a pointer to our bind context.
  147. //
  148. // PARAMETERS:
  149. // <in> dwFlags - Flags to tell us what types of things to do
  150. // <in> pBindCtx - Pointer to the bind context interface we are to use
  151. //
  152. // RETURN VALUE:
  153. // E_INVALIDARG
  154. // SP_E_ALREADYINITIALIZED
  155. // S_OK
  156. // E_OUTOFMEMORY
  157. //
  158. HRESULT CNewsTask::Init(DWORD dwFlags, ISpoolerBindContext *pBindCtx)
  159. {
  160. HRESULT hr = S_OK;
  161. // Validate the arguments
  162. if (NULL == pBindCtx)
  163. return (E_INVALIDARG);
  164. // Check to see if we've been initialzed already
  165. if (m_fInited)
  166. {
  167. hr = SP_E_ALREADYINITIALIZED;
  168. goto exit;
  169. }
  170. // Copy the flags
  171. m_dwFlags = dwFlags;
  172. // Copy the bind context pointer
  173. m_pBindCtx = pBindCtx;
  174. m_pBindCtx->AddRef();
  175. // Create the window
  176. WNDCLASSEX wc;
  177. wc.cbSize = sizeof(WNDCLASSEX);
  178. if (!GetClassInfoEx(g_hInst, c_szNewsTask, &wc))
  179. {
  180. wc.style = 0;
  181. wc.lpfnWndProc = TaskWndProc;
  182. wc.cbClsExtra = 0;
  183. wc.cbWndExtra = 0;
  184. wc.hInstance = g_hInst;
  185. wc.hCursor = NULL;
  186. wc.hbrBackground = (HBRUSH) (COLOR_3DFACE + 1);
  187. wc.lpszMenuName = NULL;
  188. wc.lpszClassName = c_szNewsTask;
  189. wc.hIcon = NULL;
  190. wc.hIconSm = NULL;
  191. RegisterClassEx(&wc);
  192. }
  193. m_hwnd = CreateWindow(c_szNewsTask, NULL, WS_POPUP, 10, 10, 10, 10,
  194. GetDesktopWindow(), NULL, g_hInst, this);
  195. if (!m_hwnd)
  196. {
  197. hr = E_OUTOFMEMORY;
  198. goto exit;
  199. }
  200. m_fInited = TRUE;
  201. exit:
  202. return (hr);
  203. }
  204. //
  205. // FUNCTION: CNewsTask::BuildEvents()
  206. //
  207. // PURPOSE: This method is called by the spooler engine telling us to create
  208. // and event list for the account specified.
  209. //
  210. // PARAMETERS:
  211. // <in> pAccount - Account object to build the event list for
  212. //
  213. // RETURN VALUE:
  214. // SP_E_UNINITALIZED
  215. // E_INVALIDARG
  216. // S_OK
  217. //
  218. HRESULT CNewsTask::BuildEvents(ISpoolerUI *pSpoolerUI, IImnAccount *pAccount, FOLDERID idFolder)
  219. {
  220. HRESULT hr;
  221. BOOL fIMAP;
  222. BOOL fHttp;
  223. FOLDERINFO fiFolderInfo;
  224. DWORD dw = 0;
  225. ULARGE_INTEGER uhLastFileTime64 = {0};
  226. ULARGE_INTEGER uhCurFileTime64 = {0};
  227. ULARGE_INTEGER uhMinPollingInterval64 = {0};
  228. FILETIME CurFileTime = {0};
  229. DWORD cb = 0;
  230. Assert(pAccount != NULL);
  231. Assert(pSpoolerUI != NULL);
  232. Assert(m_fInited);
  233. m_pAccount = pAccount;
  234. m_pAccount->AddRef();
  235. // Get the account name from the account object
  236. if (FAILED(hr = pAccount->GetPropSz(AP_ACCOUNT_NAME, m_szAccount, ARRAYSIZE(m_szAccount))))
  237. return(hr);
  238. // Get the account name from the account object
  239. if (FAILED(hr = pAccount->GetPropSz(AP_ACCOUNT_ID, m_szAccountId, ARRAYSIZE(m_szAccountId))))
  240. return(hr);
  241. if (FAILED(hr = g_pStore->FindServerId(m_szAccountId, &m_idAccount)))
  242. return(hr);
  243. // Copy the UI object
  244. m_pUI = pSpoolerUI;
  245. m_pUI->AddRef();
  246. // Create the server object
  247. hr = g_pStore->GetFolderInfo(m_idAccount, &fiFolderInfo);
  248. if (FAILED(hr))
  249. return(hr);
  250. fIMAP = (fiFolderInfo.tyFolder == FOLDER_IMAP);
  251. fHttp = (fiFolderInfo.tyFolder == FOLDER_HTTPMAIL);
  252. hr = CreateMessageServerType(fiFolderInfo.tyFolder, &m_pServer);
  253. g_pStore->FreeRecord(&fiFolderInfo);
  254. if (FAILED(hr))
  255. return(hr);
  256. hr = m_pServer->Initialize(g_pLocalStore, m_idAccount, NULL, FOLDERID_INVALID);
  257. if (FAILED(hr))
  258. return(hr);
  259. if (!fIMAP & !fHttp)
  260. {
  261. // Add posts to upload
  262. if (DELIVER_SEND & m_dwFlags)
  263. InsertOutbox(m_szAccountId, pAccount);
  264. }
  265. if (fHttp)
  266. {
  267. if (!!(m_dwFlags & DELIVER_AT_INTERVALS))
  268. {
  269. //If this is background polling make sure that HTTP's maxpolling interval has elapsed before
  270. //polling again.
  271. cb = sizeof(uhMinPollingInterval64);
  272. IF_FAILEXIT(hr = pAccount->GetProp(AP_HTTPMAIL_MINPOLLINGINTERVAL, (LPBYTE)&uhMinPollingInterval64, &cb));
  273. cb = sizeof(uhLastFileTime64);
  274. IF_FAILEXIT(hr = pAccount->GetProp(AP_HTTPMAIL_LASTPOLLEDTIME, (LPBYTE)&uhLastFileTime64, &cb));
  275. GetSystemTimeAsFileTime(&CurFileTime);
  276. uhCurFileTime64.QuadPart = CurFileTime.dwHighDateTime;
  277. uhCurFileTime64.QuadPart = uhCurFileTime64.QuadPart << 32;
  278. uhCurFileTime64.QuadPart += CurFileTime.dwLowDateTime;
  279. //We do not want to do background polling if the last time we polled this http mail
  280. //account was less than maximum polling interval specified by the server.
  281. //We should only poll if the time elapsed is greater than or equal to the max polling interval
  282. if ((uhCurFileTime64.QuadPart - uhLastFileTime64.QuadPart) < uhMinPollingInterval64.QuadPart)
  283. {
  284. goto exit;
  285. }
  286. //Mark the last polled time.
  287. hr = pAccount->SetProp(AP_HTTPMAIL_LASTPOLLEDTIME, (LPBYTE)&uhCurFileTime64, sizeof(uhCurFileTime64));
  288. }
  289. }
  290. // Check for new msgs
  291. if ((DELIVER_POLL & m_dwFlags) && (fIMAP || fHttp || !(m_dwFlags & DELIVER_NO_NEWSPOLL)))
  292. {
  293. if (ISFLAGSET(m_dwFlags, DELIVER_NOSKIP) ||
  294. (!fIMAP && !fHttp && (FAILED(pAccount->GetPropDw(AP_NNTP_POLL, &dw)) || dw != 0)) ||
  295. (fIMAP && (FAILED(pAccount->GetPropDw(AP_IMAP_POLL, &dw)) || dw != 0)) ||
  296. (fHttp && (FAILED(pAccount->GetPropDw(AP_HTTPMAIL_POLL, &dw)) || dw != 0)))
  297. {
  298. InsertNewMsgs(m_szAccountId, pAccount, fHttp);
  299. }
  300. }
  301. exit:
  302. return (hr);
  303. }
  304. //
  305. // FUNCTION: CNewsTask::Execute()
  306. //
  307. // PURPOSE: This signals our task to start executing an event.
  308. //
  309. // PARAMETERS:
  310. // <in> pSpoolerUI - Pointer of the UI object we'll display progress through
  311. // <in> eid - ID of the event to execute
  312. // <in> dwTwinkie - Our extra information we associated with the event
  313. //
  314. // RETURN VALUE:
  315. // SP_E_EXECUTING
  316. // S_OK
  317. // E_INVALIDARG
  318. // SP_E_UNINITIALIZED
  319. //
  320. HRESULT CNewsTask::Execute(EVENTID eid, DWORD_PTR dwTwinkie)
  321. {
  322. TCHAR szRes[CCHMAX_STRINGRES], szBuf[CCHMAX_STRINGRES];
  323. // Make sure we're already idle
  324. Assert(m_state == NTS_IDLE);
  325. // Make sure we're initialized
  326. Assert(m_fInited);
  327. // Copy the event id and event info
  328. m_eidCur = eid;
  329. m_pInfo = (EVENTINFO *) dwTwinkie;
  330. // Update the event UI to an executing state
  331. Assert(m_pUI);
  332. m_pUI->SetProgressRange(1);
  333. // Set up the progress
  334. AthLoadString(idsInetMailConnectingHost, szRes, ARRAYSIZE(szRes));
  335. wnsprintf(szBuf, ARRAYSIZE(szBuf), szRes, m_szAccount);
  336. m_pUI->SetGeneralProgress(szBuf);
  337. m_pUI->SetAnimation(idanDownloadNews, TRUE);
  338. // Depending on the type of event, set the state machine info
  339. switch (((EVENTINFO*) dwTwinkie)->type)
  340. {
  341. case EVENT_OUTBOX:
  342. m_state = NTS_POST_INIT;
  343. break;
  344. case EVENT_NEWMSGS:
  345. m_state = NTS_NEWMSG_INIT;
  346. break;
  347. }
  348. PostMessage(m_hwnd, NTM_NEXTSTATE, 0, 0);
  349. return(S_OK);
  350. }
  351. HRESULT CNewsTask::CancelEvent(EVENTID eid, DWORD_PTR dwTwinkie)
  352. {
  353. // Make sure we're initialized
  354. Assert(m_fInited);
  355. Assert(dwTwinkie != 0);
  356. MemFree((EVENTINFO *)dwTwinkie);
  357. return(S_OK);
  358. }
  359. //
  360. // FUNCTION: CNewsTask::ShowProperties
  361. //
  362. // PURPOSE: <???>
  363. //
  364. // PARAMETERS:
  365. // <???>
  366. //
  367. // RETURN VALUE:
  368. // <???>
  369. //
  370. // COMMENTS:
  371. // <???>
  372. //
  373. HRESULT CNewsTask::ShowProperties(HWND hwndParent, EVENTID eid, DWORD_PTR dwTwinkie)
  374. {
  375. return (E_NOTIMPL);
  376. }
  377. //
  378. // FUNCTION: CNewsTask::GetExtendedDetails
  379. //
  380. // PURPOSE: <???>
  381. //
  382. // PARAMETERS:
  383. // <???>
  384. //
  385. // RETURN VALUE:
  386. // <???>
  387. //
  388. // COMMENTS:
  389. // <???>
  390. //
  391. HRESULT CNewsTask::GetExtendedDetails(EVENTID eid, DWORD_PTR dwTwinkie,
  392. LPSTR *ppszDetails)
  393. {
  394. return (E_NOTIMPL);
  395. }
  396. //
  397. // FUNCTION: CNewsTask::Cancel
  398. //
  399. // PURPOSE: <???>
  400. //
  401. // PARAMETERS:
  402. // <???>
  403. //
  404. // RETURN VALUE:
  405. // <???>
  406. //
  407. // COMMENTS:
  408. // <???>
  409. //
  410. HRESULT CNewsTask::Cancel(void)
  411. {
  412. // this can happen if user cancels out of connect dlg
  413. if (m_state == NTS_IDLE)
  414. return(S_OK);
  415. // Drop the server connection
  416. if (m_pServer)
  417. m_pServer->Close(MSGSVRF_DROP_CONNECTION);
  418. m_fCancel = TRUE;
  419. if (m_pInfo->type == EVENT_OUTBOX)
  420. m_state = NTS_POST_END;
  421. else
  422. m_state = NTS_NEWMSG_END;
  423. PostMessage(m_hwnd, NTM_NEXTSTATE, 0, 0);
  424. return (S_OK);
  425. }
  426. //
  427. // FUNCTION: CNewsTask::InsertOutbox()
  428. //
  429. // PURPOSE: Checks the outbox for news posts destine for this news account.
  430. //
  431. // PARAMETERS:
  432. // <in> pszAcctId - ID of the account to check the outbox for.
  433. //
  434. // RETURN VALUE:
  435. // E_UNEXECTED
  436. // E_OUTOFMEMORY
  437. // S_OK
  438. //
  439. HRESULT CNewsTask::InsertOutbox(LPTSTR pszAcctId, IImnAccount *pAccount)
  440. {
  441. HRESULT hr = S_OK;
  442. IMessageFolder *pOutbox = NULL;
  443. MESSAGEINFO MsgInfo={0};
  444. HROWSET hRowset=NULL;
  445. // Get the outbox
  446. if (FAILED(hr = m_pBindCtx->BindToObject(IID_CLocalStoreOutbox, (LPVOID *) &pOutbox)))
  447. goto exit;
  448. // Loop through the outbox looking for posts to this server
  449. m_cMsgsPost = 0;
  450. // Create a Rowset
  451. if (FAILED(hr = pOutbox->CreateRowset(IINDEX_PRIMARY, 0, &hRowset)))
  452. goto exit;
  453. // Get the first message
  454. while (S_OK == pOutbox->QueryRowset(hRowset, 1, (void **)&MsgInfo, NULL))
  455. {
  456. // Has this message been submitted and is it a news message?
  457. if ((MsgInfo.dwFlags & (ARF_SUBMITTED | ARF_NEWSMSG)) == (ARF_SUBMITTED | ARF_NEWSMSG))
  458. {
  459. // Is the account the same as the account we're looking for
  460. if (MsgInfo.pszAcctId && 0 == lstrcmpi(MsgInfo.pszAcctId, pszAcctId))
  461. m_cMsgsPost++;
  462. }
  463. // Free the header info
  464. pOutbox->FreeRecord(&MsgInfo);
  465. }
  466. // Release Lock
  467. pOutbox->CloseRowset(&hRowset);
  468. // Good to go
  469. hr = S_OK;
  470. // If there were any messages then add the event
  471. if (m_cMsgsPost)
  472. {
  473. EVENTINFO *pei = NULL;
  474. TCHAR szRes[CCHMAX_STRINGRES], szBuf[CCHMAX_STRINGRES];
  475. EVENTID eid;
  476. // Allocate a structure to set as our cookie
  477. if (!MemAlloc((LPVOID*) &pei, sizeof(EVENTINFO)))
  478. {
  479. hr = E_OUTOFMEMORY;
  480. goto exit;
  481. }
  482. // Fill out the event info
  483. pei->szGroup[0] = 0;
  484. pei->type = EVENT_OUTBOX;
  485. // Create the event description
  486. AthLoadString(idsNewsTaskPost, szRes, ARRAYSIZE(szRes));
  487. wnsprintf(szBuf, ARRAYSIZE(szBuf), szRes, m_cMsgsPost, m_szAccount);
  488. // Insert the event into the spooler
  489. hr = m_pBindCtx->RegisterEvent(szBuf, this, (DWORD_PTR) pei, pAccount, &eid);
  490. if (FAILED(hr))
  491. goto exit;
  492. m_cEvents++;
  493. } // if (m_cMsgsPost)
  494. exit:
  495. // Release Lock
  496. if (pOutbox)
  497. pOutbox->CloseRowset(&hRowset);
  498. SafeRelease(pOutbox);
  499. return (hr);
  500. }
  501. //
  502. // FUNCTION: CNewsTask::TaskWndProc()
  503. //
  504. // PURPOSE: Hidden window that processes messages for this task.
  505. //
  506. LRESULT CALLBACK CNewsTask::TaskWndProc(HWND hwnd, UINT uMsg, WPARAM wParam,
  507. LPARAM lParam)
  508. {
  509. CNewsTask *pThis = (CNewsTask *) GetProp(hwnd, c_szThis);
  510. switch (uMsg)
  511. {
  512. case WM_CREATE:
  513. {
  514. LPCREATESTRUCT pcs = (LPCREATESTRUCT) lParam;
  515. pThis = (CNewsTask *) pcs->lpCreateParams;
  516. SetProp(hwnd, c_szThis, (LPVOID) pThis);
  517. return (0);
  518. }
  519. case NTM_NEXTSTATE:
  520. if (pThis)
  521. {
  522. pThis->AddRef();
  523. pThis->NextState();
  524. pThis->Release();
  525. }
  526. return (0);
  527. case WM_DESTROY:
  528. RemoveProp(hwnd, c_szThis);
  529. break;
  530. }
  531. return (DefWindowProc(hwnd, uMsg, wParam, lParam));
  532. }
  533. //
  534. // FUNCTION: CNewsTask::Post_Init()
  535. //
  536. // PURPOSE: Called when we're in a NTS_POST_INIT state. The task is
  537. // initialized to execute the posting event.
  538. //
  539. // RETURN VALUE:
  540. // E_OUTOFMEMORY
  541. // E_UNEXPECTED
  542. // S_OK
  543. //
  544. HRESULT CNewsTask::Post_Init(void)
  545. {
  546. HRESULT hr = S_OK;
  547. DWORD dwCur = 0;
  548. MESSAGEINFO MsgInfo={0};
  549. HROWSET hRowset=NULL;
  550. BOOL fInserted = FALSE;
  551. TCHAR *pszAcctName = NULL;
  552. // Open the outbox
  553. Assert(m_pBindCtx);
  554. if (FAILED(hr = m_pBindCtx->BindToObject(IID_CLocalStoreOutbox, (LPVOID *) &m_pOutbox)))
  555. goto exit;
  556. Assert(m_pSent == NULL);
  557. // If we use sent items, get that pointer too
  558. if (DwGetOption(OPT_SAVESENTMSGS))
  559. {
  560. if (FAILED(hr = TaskUtil_OpenSentItemsFolder(m_pAccount, &m_pSent)))
  561. goto exit;
  562. Assert(m_pSent != NULL);
  563. }
  564. // Allocate an array of header pointers for the messages we're going to post
  565. if (!MemAlloc((LPVOID*) &m_rgMsgInfo, m_cMsgsPost * sizeof(MESSAGEINFO)))
  566. {
  567. hr = E_OUTOFMEMORY;
  568. goto exit;
  569. }
  570. // Zero out the array
  571. ZeroMemory(m_rgMsgInfo, m_cMsgsPost * sizeof(MESSAGEINFO));
  572. // Create Rowset
  573. if (FAILED(hr = m_pOutbox->CreateRowset(IINDEX_PRIMARY, 0, &hRowset)))
  574. goto exit;
  575. // While we have stuff
  576. while (S_OK == m_pOutbox->QueryRowset(hRowset, 1, (void **)&MsgInfo, NULL))
  577. {
  578. // Has this message been submitted and is it a news message?
  579. if ((MsgInfo.dwFlags & (ARF_SUBMITTED | ARF_NEWSMSG)) == (ARF_SUBMITTED | ARF_NEWSMSG))
  580. {
  581. // Is the account the same as the account we're looking for
  582. if (MsgInfo.pszAcctId && 0 == lstrcmpi(MsgInfo.pszAcctId, m_szAccountId))
  583. {
  584. if (NULL == pszAcctName && MsgInfo.pszAcctName)
  585. pszAcctName = PszDup(MsgInfo.pszAcctName);
  586. CopyMemory(&m_rgMsgInfo[dwCur++], &MsgInfo, sizeof(MESSAGEINFO));
  587. ZeroMemory(&MsgInfo, sizeof(MESSAGEINFO));
  588. }
  589. }
  590. if (dwCur >= (DWORD)m_cMsgsPost)
  591. {
  592. Assert(0);
  593. break;
  594. }
  595. // Free the header info
  596. m_pOutbox->FreeRecord(&MsgInfo);
  597. }
  598. // Release Lock
  599. m_pOutbox->CloseRowset(&hRowset);
  600. // Good to go
  601. hr = S_OK;
  602. //Assert(dwCur);
  603. // Update the UI to an executing state
  604. Assert(m_pUI);
  605. // Set up the progress
  606. TCHAR szRes[CCHMAX_STRINGRES], szBuf[CCHMAX_STRINGRES];
  607. AthLoadString(idsProgDLPostTo, szRes, ARRAYSIZE(szRes));
  608. wnsprintf(szBuf, ARRAYSIZE(szBuf), szRes, (LPTSTR) pszAcctName ? pszAcctName : "");
  609. Assert(m_pUI);
  610. m_pUI->SetGeneralProgress(szBuf);
  611. m_pUI->SetProgressRange((WORD) m_cMsgsPost);
  612. m_pUI->SetAnimation(idanOutbox, TRUE);
  613. m_pBindCtx->Notify(DELIVERY_NOTIFY_SENDING_NEWS, 0);
  614. // Reset the counter to post the first message
  615. m_cCurPost = -1;
  616. m_cFailed = 0;
  617. m_state = NTS_POST_NEXT;
  618. exit:
  619. SafeMemFree(pszAcctName);
  620. if (m_pOutbox)
  621. m_pOutbox->CloseRowset(&hRowset);
  622. // If something failed, then update the UI
  623. if (FAILED(hr))
  624. {
  625. m_pUI->InsertError(m_eidCur, MAKEINTRESOURCE(idshrCantOpenOutbox));
  626. m_cFailed = m_cMsgsPost;
  627. // Move to a terminating state
  628. m_state = NTS_POST_END;
  629. }
  630. PostMessage(m_hwnd, NTM_NEXTSTATE, 0, 0);
  631. return (hr);
  632. }
  633. void CNewsTask::FreeSplitInfo()
  634. {
  635. if (m_pSplitInfo != NULL)
  636. {
  637. if (m_pSplitInfo->pEnumParts != NULL)
  638. m_pSplitInfo->pEnumParts->Release();
  639. if (m_pSplitInfo->pMsgParts != NULL)
  640. m_pSplitInfo->pMsgParts->Release();
  641. MemFree(m_pSplitInfo);
  642. m_pSplitInfo = NULL;
  643. }
  644. }
  645. HRESULT CNewsTask::Post_NextPart(void)
  646. {
  647. LPMIMEMESSAGE pMsgSplit;
  648. HRESULT hr;
  649. LPSTREAM pStream;
  650. LPMESSAGEINFO pInfo;
  651. DWORD dwLines;
  652. char rgch[12];
  653. PROPVARIANT rUserData;
  654. Assert(m_pSplitInfo->pEnumParts != NULL);
  655. pInfo = &m_rgMsgInfo[m_cCurPost];
  656. hr = m_pSplitInfo->pEnumParts->Next(1, &pMsgSplit, NULL);
  657. if (hr == S_OK)
  658. {
  659. Assert(pMsgSplit);
  660. rUserData.vt = VT_LPSTR;
  661. rUserData.pszVal = (LPSTR)pInfo->pszAcctName;
  662. pMsgSplit->SetProp(STR_ATT_ACCOUNTNAME, 0, &rUserData);
  663. rUserData.pszVal = pInfo->pszAcctId;;
  664. pMsgSplit->SetProp(PIDTOSTR(PID_ATT_ACCOUNTID), 0, &rUserData);
  665. // since this is a new message it doesn't have a line
  666. // count yet, so we need to do it before we stick it
  667. // in the outbox
  668. HrComputeLineCount(pMsgSplit, &dwLines);
  669. wnsprintf(rgch, ARRAYSIZE(rgch), "%d", dwLines);
  670. MimeOleSetBodyPropA(pMsgSplit, HBODY_ROOT, PIDTOSTR(PID_HDR_LINES), NOFLAGS, rgch);
  671. MimeOleSetBodyPropA(pMsgSplit, HBODY_ROOT, PIDTOSTR(PID_HDR_XNEWSRDR), NOFLAGS, c_szXNewsReader);
  672. // Final Parameter: fSaveChange = TRUE since messsage is dirty
  673. hr = pMsgSplit->GetMessageSource(&pStream, 0);
  674. if (SUCCEEDED(hr) && pStream != NULL)
  675. {
  676. hr = m_pServer->PutMessage(m_pSplitInfo->idFolder, pInfo->dwFlags, &pInfo->ftReceived, pStream, this);
  677. m_cCurParts++;
  678. pStream->Release();
  679. }
  680. pMsgSplit->Release();
  681. }
  682. return(hr);
  683. }
  684. //
  685. // FUNCTION: CNewsTask::Post_NextMsg()
  686. //
  687. // PURPOSE: Posts the next message in our outbox.
  688. //
  689. // RETURN VALUE:
  690. // <???>
  691. //
  692. HRESULT CNewsTask::Post_NextMsg(void)
  693. {
  694. LPMESSAGEINFO pInfo;
  695. FOLDERID idFolder;
  696. char szRes[CCHMAX_STRINGRES], szBuf[CCHMAX_STRINGRES];
  697. DWORD dw, cbSize, cbMaxSendMsgSize;
  698. IImnAccount *pAcct;
  699. LPMIMEMESSAGE pMsg = 0;
  700. HRESULT hr = S_OK;
  701. IStream *pStream = NULL;
  702. if (m_pSplitInfo != NULL)
  703. {
  704. hr = Post_NextPart();
  705. Assert(hr != S_OK);
  706. if (hr == E_PENDING)
  707. {
  708. m_state = NTS_POST_RESP;
  709. return(S_OK);
  710. }
  711. FreeSplitInfo();
  712. if (FAILED(hr))
  713. {
  714. m_cFailed++;
  715. m_fPartFailed = TRUE;
  716. }
  717. Assert(m_pUI);
  718. m_pUI->IncrementProgress(1);
  719. PostMessage(m_hwnd, NTM_NEXTSTATE, 0, 0);
  720. return(S_OK);
  721. }
  722. m_cCurPost++;
  723. m_cCurParts = 0;
  724. m_cPartsCompleted = 0;
  725. m_fPartFailed = FALSE;
  726. // Check to see if we're already done
  727. if (m_cCurPost >= m_cMsgsPost)
  728. {
  729. // If so, move to a cleanup state
  730. m_state = NTS_POST_END;
  731. PostMessage(m_hwnd, NTM_NEXTSTATE, 0, 0);
  732. return(S_OK);
  733. }
  734. // Update the progress UI
  735. AthLoadString(idsProgDLPost, szRes, ARRAYSIZE(szRes));
  736. wnsprintf(szBuf, ARRAYSIZE(szBuf), szRes, m_cCurPost + 1, m_cMsgsPost);
  737. Assert(m_pUI);
  738. m_pUI->SetSpecificProgress(szBuf);
  739. pInfo = &m_rgMsgInfo[m_cCurPost];
  740. // Load the message stream from the store
  741. if (SUCCEEDED(hr = m_pOutbox->OpenMessage(pInfo->idMessage, OPEN_MESSAGE_SECURE, &pMsg, this)))
  742. {
  743. hr = g_pAcctMan->FindAccount(AP_ACCOUNT_ID, pInfo->pszAcctId, &pAcct);
  744. if (SUCCEEDED(hr))
  745. {
  746. hr = g_pStore->FindServerId(pInfo->pszAcctId, &idFolder);
  747. if (SUCCEEDED(hr))
  748. {
  749. if (SUCCEEDED(pAcct->GetPropDw(AP_NNTP_SPLIT_MESSAGES, &dw)) &&
  750. dw != 0 &&
  751. SUCCEEDED(pAcct->GetPropDw(AP_NNTP_SPLIT_SIZE, &dw)))
  752. {
  753. cbMaxSendMsgSize = dw;
  754. }
  755. else
  756. {
  757. cbMaxSendMsgSize = 0xffffffff;
  758. }
  759. SideAssert(pMsg->GetMessageSize(&cbSize, 0)==S_OK);
  760. if (cbSize < (cbMaxSendMsgSize * 1024))
  761. {
  762. hr = pMsg->GetMessageSource(&pStream, 0);
  763. if (SUCCEEDED(hr) && pStream != NULL)
  764. {
  765. hr = m_pServer->PutMessage(idFolder,
  766. pInfo->dwFlags,
  767. &pInfo->ftReceived,
  768. pStream,
  769. this);
  770. m_cCurParts ++;
  771. pStream->Release();
  772. }
  773. }
  774. else
  775. {
  776. Assert(m_pSplitInfo == NULL);
  777. if (!MemAlloc((void **)&m_pSplitInfo, sizeof(SPLITMSGINFO)))
  778. {
  779. hr = E_OUTOFMEMORY;
  780. }
  781. else
  782. {
  783. ZeroMemory(m_pSplitInfo, sizeof(SPLITMSGINFO));
  784. m_pSplitInfo->idFolder = idFolder;
  785. hr = pMsg->SplitMessage(cbMaxSendMsgSize * 1024, &m_pSplitInfo->pMsgParts);
  786. if (hr == S_OK)
  787. {
  788. hr = m_pSplitInfo->pMsgParts->EnumParts(&m_pSplitInfo->pEnumParts);
  789. if (hr == S_OK)
  790. {
  791. hr = Post_NextPart();
  792. }
  793. }
  794. if (hr != E_PENDING)
  795. FreeSplitInfo();
  796. }
  797. }
  798. }
  799. pAcct->Release();
  800. }
  801. if (hr == E_PENDING)
  802. {
  803. m_state = NTS_POST_RESP;
  804. hr = S_OK;
  805. goto exit;
  806. }
  807. }
  808. // If we get here, something failed.
  809. m_cFailed++;
  810. Assert(m_pUI);
  811. m_pUI->IncrementProgress(1);
  812. PostMessage(m_hwnd, NTM_NEXTSTATE, 0, 0);
  813. exit:
  814. SafeRelease(pMsg);
  815. return (hr);
  816. }
  817. HRESULT CNewsTask::Post_Dispose()
  818. {
  819. HRESULT hr;
  820. hr = DisposeOfPosting(m_rgMsgInfo[m_cCurPost].idMessage);
  821. if (hr == E_PENDING)
  822. return(S_OK);
  823. // TODO: handle error
  824. // Update the progress bar
  825. Assert(m_pUI);
  826. m_pUI->IncrementProgress(1);
  827. // Move on to the next post
  828. m_state = NTS_POST_NEXT;
  829. PostMessage(m_hwnd, NTM_NEXTSTATE, 0, 0);
  830. return(hr);
  831. }
  832. //
  833. // FUNCTION: CNewsTask::Post_Done()
  834. //
  835. // PURPOSE: Allows the posting event to clean up and finalize the UI.
  836. //
  837. // RETURN VALUE:
  838. // S_OK
  839. //
  840. HRESULT CNewsTask::Post_Done(void)
  841. {
  842. // Free the header array
  843. if (m_rgMsgInfo && m_cMsgsPost)
  844. {
  845. for (LONG i=0; i<m_cMsgsPost; i++)
  846. m_pOutbox->FreeRecord(&m_rgMsgInfo[i]);
  847. MemFree(m_rgMsgInfo);
  848. }
  849. // Free the folder pointers we're hanging on to
  850. SafeRelease(m_pOutbox);
  851. SafeRelease(m_pSent);
  852. // Tell the spooler we're done
  853. Assert(m_pBindCtx);
  854. m_pBindCtx->Notify(DELIVERY_NOTIFY_COMPLETE, m_dwNewInboxMsgs);
  855. if (m_fCancel)
  856. {
  857. m_pBindCtx->EventDone(m_eidCur, EVENT_CANCELED);
  858. m_fCancel = FALSE;
  859. }
  860. else if (m_cFailed == m_cMsgsPost)
  861. m_pBindCtx->EventDone(m_eidCur, EVENT_FAILED);
  862. else if (m_cFailed == 0)
  863. m_pBindCtx->EventDone(m_eidCur, EVENT_SUCCEEDED);
  864. else
  865. m_pBindCtx->EventDone(m_eidCur, EVENT_WARNINGS);
  866. m_cMsgsPost = 0;
  867. m_cCurPost = 0;
  868. m_cFailed = 0;
  869. m_rgMsgInfo = NULL;
  870. SafeMemFree(m_pInfo);
  871. m_eidCur = 0;
  872. m_cEvents--;
  873. if (m_cEvents == 0 && m_pServer)
  874. m_pServer->Close(MSGSVRF_DROP_CONNECTION);
  875. m_state = NTS_IDLE;
  876. return (S_OK);
  877. }
  878. HRESULT CNewsTask::DisposeOfPosting(MESSAGEID dwMsgID)
  879. {
  880. MESSAGEIDLIST MsgIdList;
  881. ADJUSTFLAGS AdjustFlags;
  882. HRESULT hrResult = E_FAIL;
  883. MsgIdList.cAllocated = 0;
  884. MsgIdList.cMsgs = 1;
  885. MsgIdList.prgidMsg = &dwMsgID;
  886. if (DwGetOption(OPT_SAVESENTMSGS))
  887. {
  888. // If we've reached this point, it's time to try local Sent Items folder
  889. Assert(m_pSent != NULL);
  890. // change msg flags first, so if copy fails, the user doesn't get
  891. // messed up by us posting the message every time they do a send
  892. AdjustFlags.dwRemove = ARF_SUBMITTED | ARF_UNSENT;
  893. AdjustFlags.dwAdd = ARF_READ;
  894. hrResult = m_pOutbox->SetMessageFlags(&MsgIdList, &AdjustFlags, NULL, NULL);
  895. Assert(hrResult != E_PENDING);
  896. if (SUCCEEDED(hrResult))
  897. hrResult = m_pOutbox->CopyMessages(m_pSent, COPY_MESSAGE_MOVE, &MsgIdList, NULL, NULL, this);
  898. }
  899. else
  900. {
  901. // If we've reached this point, it's time to delete the message from the Outbox
  902. hrResult = m_pOutbox->DeleteMessages(DELETE_MESSAGE_NOTRASHCAN | DELETE_MESSAGE_NOPROMPT, &MsgIdList, NULL, this);
  903. }
  904. return hrResult;
  905. }
  906. //
  907. // FUNCTION: CNewsTask::NextState()
  908. //
  909. // PURPOSE: Executes the function for the current state
  910. //
  911. void CNewsTask::NextState(void)
  912. {
  913. if (NULL != g_rgpfnState[m_state])
  914. (this->*(g_rgpfnState[m_state]))();
  915. }
  916. HRESULT CNewsTask::InsertNewMsgs(LPSTR pszAccountId, IImnAccount *pAccount, BOOL fHttp)
  917. {
  918. HRESULT hr = S_OK;
  919. ULONG cSub = 0;
  920. IEnumerateFolders *pEnum = NULL;
  921. if (fHttp)
  922. m_cGroups = 1;
  923. else
  924. {
  925. // Load the sublist for this server
  926. Assert(m_idAccount != FOLDERID_INVALID);
  927. hr = g_pStore->EnumChildren(m_idAccount, TRUE, &pEnum);
  928. if (FAILED(hr))
  929. goto exit;
  930. hr = pEnum->Count(&cSub);
  931. if (FAILED(hr))
  932. goto exit;
  933. m_cGroups = (int)cSub;
  934. }
  935. // If there were any groups then add the event
  936. if (m_cGroups)
  937. {
  938. EVENTINFO *pei;
  939. char szRes[CCHMAX_STRINGRES], szBuf[CCHMAX_STRINGRES];
  940. EVENTID eid;
  941. // Allocate a structure to set as our cookie
  942. if (!MemAlloc((LPVOID*) &pei, sizeof(EVENTINFO)))
  943. {
  944. hr = E_OUTOFMEMORY;
  945. goto exit;
  946. }
  947. // Fill out the event info
  948. pei->szGroup[0] = 0;
  949. pei->type = EVENT_NEWMSGS;
  950. // Create the event description
  951. AthLoadString(idsCheckNewMsgsServer, szRes, ARRAYSIZE(szRes));
  952. wnsprintf(szBuf, ARRAYSIZE(szBuf), szRes, m_szAccount);
  953. // Insert the event into the spooler
  954. hr = m_pBindCtx->RegisterEvent(szBuf, this, (DWORD_PTR) pei, pAccount, &eid);
  955. m_cEvents++;
  956. }
  957. exit:
  958. SafeRelease(pEnum);
  959. return (hr);
  960. }
  961. HRESULT CNewsTask::NewMsg_InitHttp(void)
  962. {
  963. HRESULT hr = S_OK;
  964. // Set up the progress
  965. TCHAR szRes[CCHMAX_STRINGRES], szBuf[CCHMAX_STRINGRES];
  966. AthLoadString(IDS_SPS_POP3CHECKING, szRes, ARRAYSIZE(szRes));
  967. wnsprintf(szBuf, ARRAYSIZE(szBuf), szRes, (LPTSTR) m_szAccount);
  968. Assert(m_pUI);
  969. m_pUI->SetGeneralProgress(szBuf);
  970. m_pUI->SetProgressRange(1);
  971. m_pUI->SetAnimation(idanInbox, TRUE);
  972. m_pBindCtx->Notify(DELIVERY_NOTIFY_CHECKING, 0);
  973. // set the to generate correct success/failure message
  974. m_cGroups = 1;
  975. m_state = NTS_NEWMSG_HTTPSYNCSTORE;
  976. return hr;
  977. }
  978. HRESULT CNewsTask::NewMsg_Init(void)
  979. {
  980. const BOOL fDONT_INCLUDE_PARENT = FALSE;
  981. const BOOL fSUBSCRIBED_ONLY = TRUE;
  982. FOLDERINFO FolderInfo = {0};
  983. HRESULT hr = S_OK;
  984. DWORD dwAllocated;
  985. DWORD dwUsed;
  986. BOOL fImap = FALSE;
  987. DWORD dwIncludeAll = 0;
  988. DWORD dwDone = FALSE;
  989. Assert(m_idAccount != FOLDERID_INVALID);
  990. if (SUCCEEDED(g_pStore->GetFolderInfo(m_idAccount, &FolderInfo)))
  991. {
  992. // httpmail updates folder counts differently
  993. if (FOLDER_HTTPMAIL == FolderInfo.tyFolder)
  994. {
  995. g_pStore->FreeRecord(&FolderInfo);
  996. IF_FAILEXIT(hr = m_pAccount->GetPropDw(AP_HTTPMAIL_GOTPOLLINGINTERVAL, &dwDone));
  997. if (!dwDone)
  998. {
  999. //We need to get the polling interval from the server
  1000. //This is an asynchrnous call. The value gets updated in OnComplete.
  1001. //Meanwhile we go ahead and poll for new messages
  1002. hr = m_pServer->GetMinPollingInterval((IStoreCallback*)this);
  1003. }
  1004. hr = NewMsg_InitHttp();
  1005. goto exit;
  1006. }
  1007. fImap = (FolderInfo.tyFolder == FOLDER_IMAP);
  1008. if (fImap)
  1009. {
  1010. if (FAILED(hr = m_pAccount->GetPropDw(AP_IMAP_POLL_ALL_FOLDERS, &dwIncludeAll)))
  1011. {
  1012. dwIncludeAll = 0;
  1013. }
  1014. }
  1015. g_pStore->FreeRecord(&FolderInfo);
  1016. }
  1017. if (fImap && (!dwIncludeAll))
  1018. {
  1019. dwUsed = 0;
  1020. if (FAILED(GetInboxId(g_pStore, m_idAccount, &m_rgidGroups, &dwUsed)))
  1021. goto exit;
  1022. }
  1023. else
  1024. {
  1025. // Get an array of all subscribed folders
  1026. hr = FlattenHierarchy(g_pStore, m_idAccount, fDONT_INCLUDE_PARENT,
  1027. fSUBSCRIBED_ONLY, &m_rgidGroups, &dwAllocated, &dwUsed);
  1028. if (FAILED(hr))
  1029. {
  1030. TraceResult(hr);
  1031. goto exit;
  1032. }
  1033. }
  1034. m_cGroups = dwUsed;
  1035. // Set up the progress
  1036. TCHAR szRes[CCHMAX_STRINGRES], szBuf[CCHMAX_STRINGRES];
  1037. AthLoadString(IDS_SPS_POP3CHECKING, szRes, ARRAYSIZE(szRes));
  1038. wnsprintf(szBuf, ARRAYSIZE(szBuf), szRes, (LPTSTR) m_szAccount);
  1039. Assert(m_pUI);
  1040. m_pUI->SetGeneralProgress(szBuf);
  1041. m_pUI->SetProgressRange((WORD) m_cGroups);
  1042. if (fImap)
  1043. {
  1044. m_pUI->SetAnimation(idanInbox, TRUE);
  1045. m_pBindCtx->Notify(DELIVERY_NOTIFY_CHECKING, 0);
  1046. }
  1047. else
  1048. {
  1049. m_pUI->SetAnimation(idanDownloadNews, TRUE);
  1050. m_pBindCtx->Notify(DELIVERY_NOTIFY_CHECKING_NEWS, 0);
  1051. }
  1052. // Reset the counters for the first group
  1053. m_cCurGroup = -1;
  1054. m_cFailed = 0;
  1055. m_state = NTS_NEWMSG_NEXTGROUP;
  1056. exit:
  1057. // If something failed, update the UI
  1058. if (FAILED(hr))
  1059. {
  1060. m_pUI->InsertError(m_eidCur, MAKEINTRESOURCE(idsErrNewMsgsFailed));
  1061. m_cFailed = m_cGroups;
  1062. // Move to a terminating state
  1063. m_state = NTS_NEWMSG_END;
  1064. }
  1065. PostMessage(m_hwnd, NTM_NEXTSTATE, 0, 0);
  1066. return (hr);
  1067. }
  1068. HRESULT CNewsTask::NewMsg_NextGroup(void)
  1069. {
  1070. HRESULT hr = E_FAIL;
  1071. do
  1072. {
  1073. FOLDERINFO info;
  1074. // Keep looping until we find a folder that's selectable and exists
  1075. m_cCurGroup++;
  1076. // Check to see if we're already done
  1077. if (m_cCurGroup >= m_cGroups)
  1078. {
  1079. m_state = NTS_NEWMSG_END;
  1080. hr = S_OK;
  1081. PostMessage(m_hwnd, NTM_NEXTSTATE, 0, 0);
  1082. break;
  1083. }
  1084. if (SUCCEEDED(hr = g_pStore->GetFolderInfo(m_rgidGroups[m_cCurGroup], &info)))
  1085. {
  1086. if (0 == (info.dwFlags & (FOLDER_NOSELECT | FOLDER_NONEXISTENT)))
  1087. {
  1088. // Update the progress UI
  1089. TCHAR szRes[CCHMAX_STRINGRES], szBuf[CCHMAX_STRINGRES];
  1090. AthLoadString(idsLogCheckingNewMessages, szRes, ARRAYSIZE(szRes));
  1091. wnsprintf(szBuf, ARRAYSIZE(szBuf), szRes, info.pszName);
  1092. g_pStore->FreeRecord(&info);
  1093. Assert(m_pUI);
  1094. m_pUI->SetSpecificProgress(szBuf);
  1095. // Send the group command to the server
  1096. if (E_PENDING == (hr = m_pServer->GetFolderCounts(m_rgidGroups[m_cCurGroup], (IStoreCallback *)this)))
  1097. {
  1098. m_state = NTS_NEWMSG_RESP;
  1099. hr = S_OK;
  1100. }
  1101. break;
  1102. }
  1103. else
  1104. {
  1105. g_pStore->FreeRecord(&info);
  1106. }
  1107. }
  1108. } while (1);
  1109. if (FAILED(hr))
  1110. {
  1111. // If we get here, something failed
  1112. m_cFailed++;
  1113. Assert(m_pUI);
  1114. m_pUI->IncrementProgress(1);
  1115. PostMessage(m_hwnd, NTM_NEXTSTATE, 0, 0);
  1116. }
  1117. return (hr);
  1118. }
  1119. HRESULT CNewsTask::NewMsg_HttpSyncStore(void)
  1120. {
  1121. HRESULT hr = S_OK;
  1122. // send the command to the server
  1123. hr = m_pServer->SynchronizeStore(FOLDERID_INVALID, NOFLAGS, (IStoreCallback *)this);
  1124. if (E_PENDING == hr)
  1125. {
  1126. m_state = NTS_NEWMSG_HTTPRESP;
  1127. hr = S_OK;
  1128. }
  1129. return hr;
  1130. }
  1131. HRESULT CNewsTask::NewMsg_Done(void)
  1132. {
  1133. HRESULT hr = S_OK;
  1134. // Free the group array
  1135. if (m_rgidGroups)
  1136. {
  1137. MemFree(m_rgidGroups);
  1138. m_rgidGroups = NULL;
  1139. }
  1140. SafeMemFree(m_pInfo);
  1141. // Tell the spooler we're done
  1142. Assert(m_pBindCtx);
  1143. m_pBindCtx->Notify(DELIVERY_NOTIFY_COMPLETE, m_dwNewInboxMsgs);
  1144. if (m_fCancel)
  1145. {
  1146. m_pBindCtx->EventDone(m_eidCur, EVENT_CANCELED);
  1147. m_fCancel = FALSE;
  1148. }
  1149. else if (m_cFailed == m_cGroups)
  1150. m_pBindCtx->EventDone(m_eidCur, EVENT_FAILED);
  1151. else if (m_cFailed == 0)
  1152. m_pBindCtx->EventDone(m_eidCur, EVENT_SUCCEEDED);
  1153. else
  1154. m_pBindCtx->EventDone(m_eidCur, EVENT_WARNINGS);
  1155. m_cGroups = 0;
  1156. m_cCurGroup = 0;
  1157. m_cFailed = 0;
  1158. m_dwNewInboxMsgs = 0;
  1159. m_eidCur = 0;
  1160. m_cEvents--;
  1161. if (m_cEvents == 0 && m_pServer)
  1162. m_pServer->Close(MSGSVRF_DROP_CONNECTION);
  1163. m_state = NTS_IDLE;
  1164. return (S_OK);
  1165. }
  1166. // --------------------------------------------------------------------------------
  1167. // CNewsTask::IsDialogMessage
  1168. // --------------------------------------------------------------------------------
  1169. STDMETHODIMP CNewsTask::IsDialogMessage(LPMSG pMsg)
  1170. {
  1171. return S_FALSE;
  1172. }
  1173. STDMETHODIMP CNewsTask::OnFlagsChanged(DWORD dwFlags)
  1174. {
  1175. m_dwFlags = dwFlags;
  1176. return (S_OK);
  1177. }
  1178. STDMETHODIMP CNewsTask::OnBegin(STOREOPERATIONTYPE tyOperation, STOREOPERATIONINFO *pOpInfo, IOperationCancel *pCancel)
  1179. {
  1180. // Hold onto this
  1181. Assert(m_tyOperation == SOT_INVALID);
  1182. if (pCancel)
  1183. {
  1184. m_pCancel = pCancel;
  1185. m_pCancel->AddRef();
  1186. }
  1187. m_tyOperation = tyOperation;
  1188. // Party On
  1189. return(S_OK);
  1190. }
  1191. STDMETHODIMP CNewsTask::OnProgress(STOREOPERATIONTYPE tyOperation, DWORD dwCurrent, DWORD dwMax, LPCSTR pszStatus)
  1192. {
  1193. // Close any timeout dialog, if present
  1194. CallbackCloseTimeout(&m_hTimeout);
  1195. // NOTE: that you can get more than one type of value for tyOperation.
  1196. // Most likely, you will get SOT_CONNECTION_STATUS and then the
  1197. // operation that you might expect. See HotStore.idl and look for
  1198. // the STOREOPERATION enumeration type for more info.
  1199. switch (tyOperation)
  1200. {
  1201. case SOT_NEW_MAIL_NOTIFICATION:
  1202. m_dwNewInboxMsgs = dwCurrent;
  1203. break;
  1204. }
  1205. // Done
  1206. return(S_OK);
  1207. }
  1208. STDMETHODIMP CNewsTask::OnTimeout(LPINETSERVER pServer, LPDWORD pdwTimeout, IXPTYPE ixpServerType)
  1209. {
  1210. if (!!(m_dwFlags & (DELIVER_NOUI | DELIVER_BACKGROUND)))
  1211. return(E_FAIL);
  1212. // Display a timeout dialog
  1213. return CallbackOnTimeout(pServer, ixpServerType, *pdwTimeout, (ITimeoutCallback *)this, &m_hTimeout);
  1214. }
  1215. STDMETHODIMP CNewsTask::CanConnect(LPCSTR pszAccountId, DWORD dwFlags)
  1216. {
  1217. HWND hwnd;
  1218. BOOL fPrompt = TRUE;
  1219. if (m_pUI)
  1220. m_pUI->GetWindow(&hwnd);
  1221. else
  1222. hwnd = NULL;
  1223. // Call into general CanConnect Utility
  1224. if ((m_dwFlags & (DELIVER_NOUI | DELIVER_BACKGROUND)) || (dwFlags & CC_FLAG_DONTPROMPT))
  1225. fPrompt = FALSE;
  1226. return CallbackCanConnect(pszAccountId, hwnd, fPrompt);
  1227. }
  1228. STDMETHODIMP CNewsTask::OnLogonPrompt(LPINETSERVER pServer, IXPTYPE ixpServerType)
  1229. {
  1230. HWND hwnd;
  1231. // Close any timeout dialog, if present
  1232. CallbackCloseTimeout(&m_hTimeout);
  1233. if (!!(m_dwFlags & (DELIVER_NOUI | DELIVER_BACKGROUND)) &&
  1234. !(ISFLAGSET(pServer->dwFlags, ISF_ALWAYSPROMPTFORPASSWORD) &&
  1235. '\0' == pServer->szPassword[0]))
  1236. return(S_FALSE);
  1237. if (m_pUI)
  1238. m_pUI->GetWindow(&hwnd);
  1239. else
  1240. hwnd = NULL;
  1241. // Call into general OnLogonPrompt Utility
  1242. return CallbackOnLogonPrompt(hwnd, pServer, ixpServerType);
  1243. }
  1244. STDMETHODIMP CNewsTask::OnComplete(STOREOPERATIONTYPE tyOperation, HRESULT hrComplete,
  1245. LPSTOREOPERATIONINFO pOpInfo, LPSTOREERROR pErrorInfo)
  1246. {
  1247. char szRes[CCHMAX_STRINGRES], szBuf[CCHMAX_STRINGRES * 2], szSubject[64];
  1248. NEWSTASKSTATE ntsNextState = NTS_MAX;
  1249. LPSTR pszSubject = NULL;
  1250. LPSTR pszOpDescription = NULL;
  1251. BOOL fInsertError = FALSE;
  1252. // Close any timeout dialog, if present
  1253. CallbackCloseTimeout(&m_hTimeout);
  1254. IxpAssert(m_tyOperation != SOT_INVALID);
  1255. if (m_tyOperation != tyOperation)
  1256. return(S_OK);
  1257. switch (tyOperation)
  1258. {
  1259. case SOT_PUT_MESSAGE:
  1260. m_cPartsCompleted ++;
  1261. // Figure out if we succeeded or failed
  1262. if (FAILED(hrComplete))
  1263. {
  1264. if (!m_fPartFailed )
  1265. {
  1266. Assert(m_pUI);
  1267. // Set us up to display the error
  1268. pszOpDescription = MAKEINTRESOURCE(idsNewsTaskPostError);
  1269. pszSubject = m_rgMsgInfo[m_cCurPost].pszSubject;
  1270. if (pszSubject == NULL || *pszSubject == 0)
  1271. {
  1272. AthLoadString(idsNoSubject, szSubject, ARRAYSIZE(szSubject));
  1273. pszSubject = szSubject;
  1274. }
  1275. fInsertError = TRUE;
  1276. m_cFailed++;
  1277. m_fPartFailed = TRUE;
  1278. }
  1279. }
  1280. if (m_cPartsCompleted == m_cCurParts)
  1281. {
  1282. if (m_fPartFailed)
  1283. {
  1284. // Update the progress bar
  1285. Assert(m_pUI);
  1286. m_pUI->IncrementProgress(1);
  1287. // Move on to the next post
  1288. ntsNextState = NTS_POST_NEXT;
  1289. }
  1290. else
  1291. {
  1292. ntsNextState = NTS_POST_DISPOSE;
  1293. }
  1294. }
  1295. break; // case SOT_PUT_MESSAGE
  1296. case SOT_UPDATE_FOLDER:
  1297. if (FAILED(hrComplete))
  1298. {
  1299. FOLDERINFO fiFolderInfo;
  1300. Assert(m_pUI);
  1301. LoadString(g_hLocRes, idsUnreadCountPollErrorFmt, szRes, sizeof(szRes));
  1302. if (SUCCEEDED(g_pStore->GetFolderInfo(m_rgidGroups[m_cCurGroup], &fiFolderInfo)))
  1303. {
  1304. wnsprintf(szBuf, ARRAYSIZE(szBuf), szRes, fiFolderInfo.pszName);
  1305. g_pStore->FreeRecord(&fiFolderInfo);
  1306. }
  1307. else
  1308. {
  1309. LoadString(g_hLocRes, idsUnknown, szSubject, sizeof(szSubject));
  1310. wnsprintf(szBuf, ARRAYSIZE(szBuf), szRes, szSubject);
  1311. }
  1312. pszOpDescription = szBuf;
  1313. fInsertError = TRUE;
  1314. m_cFailed++;
  1315. }
  1316. // Update the progress bar
  1317. m_pUI->IncrementProgress(1);
  1318. // Move on to the next group
  1319. ntsNextState = NTS_NEWMSG_NEXTGROUP;
  1320. break; // case SOT_UPDATE_FOLDER
  1321. case SOT_SYNCING_STORE:
  1322. if (( IXP_E_HTTP_NOT_MODIFIED != hrComplete) && (FAILED(hrComplete)))
  1323. {
  1324. LoadString(g_hLocRes, idsHttpPollFailed, szBuf, sizeof(szBuf));
  1325. pszOpDescription = szBuf;
  1326. fInsertError = TRUE;
  1327. m_cFailed++;
  1328. }
  1329. // update the progress bar
  1330. m_pUI->IncrementProgress(1);
  1331. // we're done
  1332. ntsNextState = NTS_NEWMSG_END;
  1333. break; // case SOT_SYNCING_STORE
  1334. case SOT_COPYMOVE_MESSAGE:
  1335. // Update the progress bar
  1336. Assert(m_pUI);
  1337. m_pUI->IncrementProgress(1);
  1338. // Move on to the next post
  1339. ntsNextState = NTS_POST_NEXT;
  1340. if (FAILED(hrComplete))
  1341. {
  1342. Assert(m_pUI);
  1343. pszOpDescription = MAKEINTRESOURCE(IDS_SP_E_CANT_MOVETO_SENTITEMS);
  1344. fInsertError = TRUE;
  1345. }
  1346. break; // case SOT_COPYMOVE_MESSAGE
  1347. case SOT_GET_HTTP_MINPOLLINGINTERVAL:
  1348. if (SUCCEEDED(hrComplete) && pOpInfo)
  1349. {
  1350. ULARGE_INTEGER uhMinPollingInterval64 = {0};
  1351. //Convert it to seconds.
  1352. uhMinPollingInterval64.QuadPart = pOpInfo->dwMinPollingInterval * 60;
  1353. //FILETIME is intervals of 100 nano seconds. Need to convert to 100 nanoseconds
  1354. uhMinPollingInterval64.QuadPart *= HUNDRED_NANOSECONDS;
  1355. m_pAccount->SetProp(AP_HTTPMAIL_MINPOLLINGINTERVAL, (LPBYTE)&uhMinPollingInterval64, sizeof(uhMinPollingInterval64));
  1356. m_pAccount->SetPropDw(AP_HTTPMAIL_GOTPOLLINGINTERVAL, TRUE);
  1357. break;
  1358. }
  1359. default:
  1360. if (IXP_E_HTTP_NOT_MODIFIED == hrComplete)
  1361. {
  1362. hrComplete = S_OK;
  1363. fInsertError = FALSE;
  1364. }
  1365. else
  1366. {
  1367. if (FAILED(hrComplete))
  1368. {
  1369. Assert(m_pUI);
  1370. pszOpDescription = MAKEINTRESOURCE(idsGenericError);
  1371. fInsertError = TRUE;
  1372. m_cFailed++;
  1373. }
  1374. }
  1375. break; // default case
  1376. } // switch
  1377. if (fInsertError && NULL != pErrorInfo)
  1378. {
  1379. Assert(pErrorInfo->hrResult == hrComplete); // These two should not be different
  1380. TaskUtil_InsertTransportError(ISFLAGCLEAR(m_dwFlags, DELIVER_NOUI), m_pUI, m_eidCur,
  1381. pErrorInfo, pszOpDescription, pszSubject);
  1382. }
  1383. // Move on to next state
  1384. if (IXP_E_USER_CANCEL == hrComplete)
  1385. {
  1386. // User cancelled logon prompt, so just abort everything
  1387. Cancel();
  1388. }
  1389. else if (NTS_MAX != ntsNextState)
  1390. {
  1391. m_state = ntsNextState;
  1392. PostMessage(m_hwnd, NTM_NEXTSTATE, 0, 0);
  1393. }
  1394. // Release your cancel object
  1395. SafeRelease(m_pCancel);
  1396. m_tyOperation = SOT_INVALID;
  1397. // Done
  1398. return(S_OK);
  1399. }
  1400. STDMETHODIMP CNewsTask::OnPrompt(HRESULT hrError, LPCTSTR pszText, LPCTSTR pszCaption, UINT uType, INT *piUserResponse)
  1401. {
  1402. HWND hwnd;
  1403. // Close any timeout dialog, if present
  1404. CallbackCloseTimeout(&m_hTimeout);
  1405. // Raid 55082 - SPOOLER: SPA/SSL auth to NNTP does not display cert warning and fails.
  1406. #if 0
  1407. if (!!(m_dwFlags & (DELIVER_NOUI | DELIVER_BACKGROUND)))
  1408. return(E_FAIL);
  1409. #endif
  1410. if (m_pUI)
  1411. m_pUI->GetWindow(&hwnd);
  1412. else
  1413. hwnd = NULL;
  1414. // Call into my swanky utility
  1415. return CallbackOnPrompt(hwnd, hrError, pszText, pszCaption, uType, piUserResponse);
  1416. }
  1417. STDMETHODIMP CNewsTask::OnTimeoutResponse(TIMEOUTRESPONSE eResponse)
  1418. {
  1419. // Call into general timeout response utility
  1420. return CallbackOnTimeoutResponse(eResponse, m_pCancel, &m_hTimeout);
  1421. }
  1422. STDMETHODIMP CNewsTask::GetParentWindow(DWORD dwReserved, HWND *phwndParent)
  1423. {
  1424. HRESULT hr;
  1425. if (!!(m_dwFlags & (DELIVER_NOUI | DELIVER_BACKGROUND)))
  1426. return(E_FAIL);
  1427. if (m_pUI)
  1428. {
  1429. hr = m_pUI->GetWindow(phwndParent);
  1430. }
  1431. else
  1432. {
  1433. *phwndParent = NULL;
  1434. hr = E_FAIL;
  1435. }
  1436. return(hr);
  1437. }