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.

2341 lines
71 KiB

  1. // --------------------------------------------------------------------------------
  2. // Spengine.cpp
  3. // Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  4. // Steven J. Bailey
  5. // --------------------------------------------------------------------------------
  6. #include "pch.hxx"
  7. #include "spengine.h"
  8. #include "strconst.h"
  9. #include "spoolui.h"
  10. #include "thormsgs.h"
  11. #include "newstask.h"
  12. #include "goptions.h"
  13. #include "conman.h"
  14. #include "resource.h"
  15. #include "ontask.h"
  16. #include "smtptask.h"
  17. #include "pop3task.h"
  18. #include "instance.h"
  19. #include "shlwapip.h"
  20. #include "ourguid.h"
  21. #include "demand.h"
  22. #include "storutil.h"
  23. #include "msgfldr.h"
  24. #include "httptask.h"
  25. #include "watchtsk.h"
  26. #include "shared.h"
  27. #include "util.h"
  28. // --------------------------------------------------------------------------------
  29. // Globals
  30. // --------------------------------------------------------------------------------
  31. BOOL g_fCheckOutboxOnShutdown=FALSE;
  32. extern HANDLE hSmapiEvent; // Added for Bug# 62129 (v-snatar)
  33. // --------------------------------------------------------------------------------
  34. // ISSPOOLERTHREAD
  35. // --------------------------------------------------------------------------------
  36. #define ISSPOOLERTHREAD \
  37. (m_dwThreadId == GetCurrentThreadId())
  38. // --------------------------------------------------------------------------------
  39. // CSpoolerEngine::CSpoolerEngine
  40. // --------------------------------------------------------------------------------
  41. CSpoolerEngine::CSpoolerEngine(void)
  42. {
  43. m_cRef = 1;
  44. m_pUI = NULL;
  45. m_dwState = 0;
  46. m_dwFlags = 0;
  47. m_dwQueued = 0;
  48. m_pAcctMan = NULL;
  49. m_pUidlCache = NULL;
  50. m_hwndUI = NULL;
  51. m_pszAcctID = NULL;
  52. m_idFolder = FOLDERID_INVALID;
  53. m_dwThreadId = GetCurrentThreadId();
  54. m_hThread = GetCurrentThread();
  55. ZeroMemory(&m_rViewRegister, sizeof(VIEWREGISTER));
  56. ZeroMemory(&m_rEventTable, sizeof(SPOOLEREVENTTABLE));
  57. m_fBackgroundPollPending = FALSE;
  58. m_dwPollInterval = 0;
  59. m_cCurEvent = FALSE;
  60. m_hwndTray = NULL;
  61. m_fRasSpooled = FALSE;
  62. m_fOfflineWhenDone = FALSE;
  63. m_pPop3LogFile = NULL;
  64. m_pSmtpLogFile = NULL;
  65. m_fIDialed = FALSE;
  66. m_cSyncEvent = 0;
  67. m_fNoSyncEvent = FALSE;
  68. InitializeCriticalSection(&m_cs);
  69. }
  70. // --------------------------------------------------------------------------------
  71. // CSpoolerEngine::~CSpoolerEngine
  72. // --------------------------------------------------------------------------------
  73. CSpoolerEngine::~CSpoolerEngine(void)
  74. {
  75. Assert(m_rEventTable.prgEvents == NULL);
  76. Assert(ISSPOOLERTHREAD);
  77. if (g_pConMan)
  78. g_pConMan->Unadvise((IConnectionNotify *) this);
  79. OptionUnadvise(m_hwndUI);
  80. SafeRelease(m_pUI);
  81. SafeRelease(m_pAcctMan);
  82. SafeRelease(m_pUidlCache);
  83. SafeRelease(m_pSmtpLogFile);
  84. SafeRelease(m_pPop3LogFile);
  85. SafeMemFree(m_pszAcctID);
  86. ReleaseMem(m_rViewRegister.rghwndView);
  87. DeleteCriticalSection(&m_cs);
  88. }
  89. // --------------------------------------------------------------------------------
  90. // CSpoolerEngine::QueryInterface
  91. // --------------------------------------------------------------------------------
  92. STDMETHODIMP CSpoolerEngine::QueryInterface(REFIID riid, LPVOID *ppv)
  93. {
  94. // Locals
  95. HRESULT hr=S_OK;
  96. // check params
  97. if (ppv == NULL)
  98. return TrapError(E_INVALIDARG);
  99. // Thread Safety
  100. EnterCriticalSection(&m_cs);
  101. // Find IID
  102. if (IID_IUnknown == riid)
  103. *ppv = (IUnknown *)(ISpoolerEngine *)this;
  104. else if (IID_ISpoolerEngine == riid)
  105. *ppv = (ISpoolerEngine *)this;
  106. else if (IID_ISpoolerBindContext == riid)
  107. *ppv = (ISpoolerBindContext *)this;
  108. else
  109. {
  110. *ppv = NULL;
  111. hr = TrapError(E_NOINTERFACE);
  112. goto exit;
  113. }
  114. // AddRef It
  115. ((IUnknown *)*ppv)->AddRef();
  116. exit:
  117. // Thread Safety
  118. LeaveCriticalSection(&m_cs);
  119. // Done
  120. return hr;
  121. }
  122. // --------------------------------------------------------------------------------
  123. // CSpoolerEngine::AddRef
  124. // --------------------------------------------------------------------------------
  125. STDMETHODIMP_(ULONG) CSpoolerEngine::AddRef(void)
  126. {
  127. EnterCriticalSection(&m_cs);
  128. ULONG cRef = ++m_cRef;
  129. LeaveCriticalSection(&m_cs);
  130. return cRef;
  131. }
  132. // --------------------------------------------------------------------------------
  133. // CSpoolerEngine::Release
  134. // --------------------------------------------------------------------------------
  135. STDMETHODIMP_(ULONG) CSpoolerEngine::Release(void)
  136. {
  137. EnterCriticalSection(&m_cs);
  138. ULONG cRef = --m_cRef;
  139. LeaveCriticalSection(&m_cs);
  140. if (0 != cRef)
  141. return cRef;
  142. delete this;
  143. return 0;
  144. }
  145. // --------------------------------------------------------------------------------
  146. // CSpoolerEngine::Init
  147. // --------------------------------------------------------------------------------
  148. STDMETHODIMP CSpoolerEngine::Init(ISpoolerUI *pUI, BOOL fPoll)
  149. {
  150. // Locals
  151. HRESULT hr=S_OK;
  152. DWORD dw;
  153. // Thread Safety
  154. EnterCriticalSection(&m_cs);
  155. // Already Inited
  156. if (m_pAcctMan)
  157. {
  158. Assert(FALSE);
  159. goto exit;
  160. }
  161. // Create Default Spooler UI Object
  162. if (NULL == pUI)
  163. {
  164. // Create a Serdy UI object
  165. CHECKALLOC(m_pUI = (ISpoolerUI *)new CSpoolerDlg);
  166. // Create
  167. CHECKHR(hr = m_pUI->Init(GetDesktopWindow()));
  168. }
  169. // Otherwise, assume pUI
  170. else
  171. {
  172. m_pUI = pUI;
  173. m_pUI->AddRef();
  174. }
  175. // Register SpoolerBindContext with the UI object
  176. m_pUI->RegisterBindContext((ISpoolerBindContext *)this);
  177. // Get the window handle of the spooler UI
  178. m_pUI->GetWindow(&m_hwndUI);
  179. // Get Me An Account Manager
  180. Assert(NULL == m_pAcctMan);
  181. CHECKHR(hr = HrCreateAccountManager(&m_pAcctMan));
  182. // Advise on the connection status
  183. Assert(g_pConMan);
  184. g_pConMan->Advise((IConnectionNotify *) this);
  185. exit:
  186. // Thread Safety
  187. LeaveCriticalSection(&m_cs);
  188. // Done
  189. return hr;
  190. }
  191. HRESULT CSpoolerEngine::OnStartupFinished(void)
  192. {
  193. DWORD dw;
  194. // Start Polling...
  195. dw = DwGetOption(OPT_POLLFORMSGS);
  196. if (dw != OPTION_OFF)
  197. SetTimer(m_hwndUI, IMAIL_POOLFORMAIL, dw, NULL);
  198. // Advise Options
  199. OptionAdvise(m_hwndUI);
  200. return (S_OK);
  201. }
  202. // --------------------------------------------------------------------------------
  203. // CSpoolerEngine::StartDelivery
  204. // --------------------------------------------------------------------------------
  205. STDMETHODIMP CSpoolerEngine::StartDelivery(HWND hwnd, LPCSTR pszAcctID, FOLDERID idFolder, DWORD dwFlags)
  206. {
  207. // Locals
  208. HRESULT hr=S_OK;
  209. // No Flags
  210. if (0 == dwFlags || (DELIVER_SHOW != dwFlags && 0 == (dwFlags & ~DELIVER_COMMON_MASK)))
  211. return TrapError(E_INVALIDARG);
  212. // Check to see if we're working offline
  213. Assert(g_pConMan);
  214. if (DELIVER_SHOW != dwFlags && g_pConMan->IsGlobalOffline())
  215. {
  216. if (IDNO == AthMessageBoxW(hwnd, MAKEINTRESOURCEW(idsAthena), MAKEINTRESOURCEW(idsErrWorkingOffline),
  217. 0, MB_YESNO | MB_ICONEXCLAMATION ))
  218. {
  219. return (S_OK);
  220. }
  221. else
  222. {
  223. g_pConMan->SetGlobalOffline(FALSE);
  224. }
  225. }
  226. // Enter Critical Section
  227. EnterCriticalSection(&m_cs);
  228. // If were busy...
  229. if (!ISFLAGSET(m_dwState, SPSTATE_BUSY))
  230. {
  231. // Don't need this anymore
  232. SafeMemFree(m_pszAcctID);
  233. // Save the Account Name
  234. if (pszAcctID)
  235. CHECKALLOC(m_pszAcctID = PszDupA(pszAcctID));
  236. // Save the folder ID
  237. m_idFolder = idFolder;
  238. // Lets enter the busy state
  239. FLAGSET(m_dwState, SPSTATE_BUSY);
  240. }
  241. else
  242. FLAGSET(dwFlags, DELIVER_REFRESH);
  243. // Process the outbox
  244. Assert(m_hwndUI && IsWindow(m_hwndUI));
  245. PostMessage(m_hwndUI, IMAIL_DELIVERNOW, 0, dwFlags);
  246. exit:
  247. // Leave Critical Section
  248. LeaveCriticalSection(&m_cs);
  249. // Done
  250. return hr;
  251. }
  252. // --------------------------------------------------------------------------------
  253. // CSpoolerEngine::_HrStartDeliveryActual
  254. // --------------------------------------------------------------------------------
  255. HRESULT CSpoolerEngine::_HrStartDeliveryActual(DWORD dwFlags)
  256. {
  257. // Locals
  258. HRESULT hr=S_OK;
  259. IImnAccount *pAccount=NULL;
  260. ACCOUNTTABLE rTable;
  261. IImnEnumAccounts *pEnum=NULL;
  262. DWORD dw;
  263. ULONG c;
  264. MSG msg;
  265. ULONG iConnectoid;
  266. ULONG i;
  267. CHAR szConnectoid[CCHMAX_CONNECTOID];
  268. // Thread Safety
  269. EnterCriticalSection(&m_cs);
  270. // Init
  271. ZeroMemory(&rTable, sizeof(ACCOUNTTABLE));
  272. m_cSyncEvent = 0;
  273. m_fNoSyncEvent = FALSE;
  274. // If we are currently busy...
  275. if (ISFLAGSET(dwFlags, DELIVER_REFRESH))
  276. {
  277. // If we are currently with no UI, and new request is for ui
  278. if (ISFLAGSET(m_dwFlags, DELIVER_NOUI) && !ISFLAGSET(dwFlags, DELIVER_NOUI))
  279. FLAGCLEAR(m_dwFlags, DELIVER_NOUI);
  280. // If we are currently doing a background poll
  281. if (ISFLAGSET(m_dwFlags, DELIVER_BACKGROUND) && !ISFLAGSET(dwFlags, DELIVER_BACKGROUND))
  282. FLAGCLEAR(m_dwFlags, DELIVER_BACKGROUND);
  283. // If not running with now ui, set to foreground
  284. if (!ISFLAGSET(m_dwFlags, DELIVER_NOUI) && !ISFLAGSET(m_dwFlags, DELIVER_BACKGROUND))
  285. {
  286. m_pUI->ShowWindow(SW_SHOW);
  287. SetForegroundWindow(m_hwndUI);
  288. }
  289. // Should I queue an outbox delivery?
  290. if (0 == m_dwQueued && ISFLAGSET(dwFlags, DELIVER_QUEUE))
  291. {
  292. m_dwQueued = dwFlags;
  293. FLAGCLEAR(m_dwQueued, DELIVER_REFRESH);
  294. FLAGCLEAR(m_dwQueued, DELIVER_QUEUE);
  295. }
  296. // Done
  297. goto exit;
  298. }
  299. // Simply show the ui ?
  300. if (ISFLAGSET(dwFlags, DELIVER_SHOW))
  301. {
  302. m_pUI->ShowWindow(SW_SHOW);
  303. SetForegroundWindow(m_hwndUI);
  304. FLAGCLEAR(m_dwState, SPSTATE_BUSY);
  305. goto exit;
  306. }
  307. // Reset
  308. m_pUI->ClearEvents();
  309. m_pUI->SetTaskCounts(0, 0);
  310. m_pUI->StartDelivery();
  311. // Save these flags
  312. m_dwFlags = dwFlags;
  313. // Show the UI if necessary
  314. if (!ISFLAGSET(m_dwFlags, DELIVER_BACKGROUND))
  315. {
  316. m_pUI->ShowWindow(SW_SHOW);
  317. SetForegroundWindow(m_hwndUI);
  318. }
  319. else
  320. {
  321. // If the invoker called for background, but the UI is already visible,
  322. // then remove the flags
  323. if (IsWindowVisible(m_hwndUI))
  324. {
  325. FLAGCLEAR(m_dwFlags, DELIVER_BACKGROUND);
  326. FLAGCLEAR(m_dwFlags, DELIVER_NOUI);
  327. }
  328. }
  329. #if 0
  330. // Raid 43695: Spooler: News post with a CC causes an SMTP error
  331. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  332. {
  333. TranslateMessage(&msg);
  334. DispatchMessage(&msg);
  335. }
  336. #endif
  337. // Single Account Polling...
  338. if (m_pszAcctID)
  339. {
  340. // Add the Account into the Account Table
  341. CHECKHR(hr = _HrAppendAccountTable(&rTable, m_pszAcctID, ALL_ACCT_SERVERS));
  342. }
  343. // Otherwise, polling all accounts
  344. else
  345. {
  346. // Determine the types of servers we're going to queue up
  347. DWORD dwServers = 0, dw;
  348. if (m_dwFlags & DELIVER_SMTP_TYPE)
  349. dwServers |= SRV_SMTP;
  350. if (m_dwFlags & DELIVER_NEWS_TYPE && !(g_dwAthenaMode & MODE_MAILONLY))
  351. dwServers |= SRV_NNTP;
  352. if (m_dwFlags & DELIVER_HTTP_TYPE && !(g_dwAthenaMode & MODE_NEWSONLY))
  353. dwServers |= SRV_HTTPMAIL;
  354. if (m_dwFlags & DELIVER_IMAP_TYPE && !(g_dwAthenaMode & MODE_NEWSONLY))
  355. dwServers |= SRV_IMAP;
  356. if ((m_dwFlags & DELIVER_MAIL_RECV) && !(g_dwAthenaMode & MODE_NEWSONLY))
  357. dwServers |= SRV_POP3;
  358. // Enumerate the accounts
  359. CHECKHR(hr = m_pAcctMan->Enumerate(dwServers, &pEnum));
  360. // Sort by Account Name
  361. pEnum->SortByAccountName();
  362. // Add all the accounts into the Account Table
  363. while (SUCCEEDED(pEnum->GetNext(&pAccount)))
  364. {
  365. // Add Account Into the Account Table
  366. CHECKHR(hr = _HrAppendAccountTable(&rTable, pAccount, dwServers));
  367. // Release
  368. SafeRelease(pAccount);
  369. }
  370. }
  371. // No Accounts...
  372. if (0 == rTable.cAccounts)
  373. goto exit;
  374. // Sort the Account Table by Connnection Name
  375. if (rTable.cRasAccts)
  376. {
  377. Assert(rTable.prgRasAcct);
  378. _SortAccountTableByConnName(0, rTable.cRasAccts - 1, rTable.prgRasAcct);
  379. }
  380. m_fRasSpooled = FALSE;
  381. m_fIDialed = FALSE;
  382. // Raid-46334: MAIL: Time to build a Task List. First loop through the LAN list and build tasks from those accounts.
  383. for (dw = 0; dw < rTable.cLanAccts; dw++)
  384. {
  385. if (ISFLAGSET(rTable.prgLanAcct[dw].dwServers, SRV_POP3) ||
  386. ISFLAGSET(rTable.prgLanAcct[dw].dwServers, SRV_SMTP) ||
  387. ISFLAGSET(rTable.prgLanAcct[dw].dwServers, SRV_IMAP) ||
  388. ISFLAGSET(rTable.prgLanAcct[dw].dwServers, SRV_HTTPMAIL))
  389. {
  390. Assert(rTable.prgLanAcct[dw].pAccount);
  391. _HrCreateTaskObject(&(rTable.prgLanAcct[dw]));
  392. SafeRelease(rTable.prgLanAcct[dw].pAccount);
  393. }
  394. }
  395. // Raid-46334: NEWS: Time to build a Task List. First loop through the LAN/news list and build tasks from those accounts.
  396. for (dw = 0; dw < rTable.cLanAccts; dw++)
  397. {
  398. if (ISFLAGSET(rTable.prgLanAcct[dw].dwServers, SRV_NNTP))
  399. {
  400. Assert(rTable.prgLanAcct[dw].pAccount);
  401. _HrCreateTaskObject(&(rTable.prgLanAcct[dw]));
  402. SafeRelease(rTable.prgLanAcct[dw].pAccount);
  403. }
  404. else
  405. Assert(NULL == rTable.prgLanAcct[dw].pAccount);
  406. }
  407. // Now walk the list of RAS accounts and add those to the task list
  408. iConnectoid = 0;
  409. while(iConnectoid < rTable.cRasAccts)
  410. {
  411. // Indirect Sort
  412. i = rTable.prgRasAcct[iConnectoid].dwSort;
  413. // Save current connectoid
  414. StrCpyN(szConnectoid, rTable.prgRasAcct[i].szConnectoid, ARRAYSIZE(szConnectoid));
  415. // Insert Ras Accounts
  416. // TODO Add HTTP accounts to it too.
  417. _InsertRasAccounts(&rTable, szConnectoid, SRV_POP3 | SRV_SMTP | SRV_IMAP | SRV_HTTPMAIL);
  418. // Insert Ras Accounts
  419. _InsertRasAccounts(&rTable, szConnectoid, SRV_NNTP);
  420. // Move iConnectoid to next unique connectoid
  421. while(1)
  422. {
  423. // Increment iConnectoid
  424. iConnectoid++;
  425. // Done
  426. if (iConnectoid >= rTable.cRasAccts)
  427. break;
  428. // Indirect Sort
  429. i = rTable.prgRasAcct[iConnectoid].dwSort;
  430. // Next connectoid
  431. if (lstrcmpi(szConnectoid, rTable.prgRasAcct[i].szConnectoid) != 0)
  432. break;
  433. }
  434. }
  435. // Execute the first task
  436. m_cCurEvent = -1;
  437. m_fNoSyncEvent = (ISFLAGSET(m_dwFlags, DELIVER_OFFLINE_SYNC) && m_pszAcctID != NULL && m_cSyncEvent == 0);
  438. // Toggle Hangup When Done option
  439. m_pUI->ChangeHangupOption(m_fRasSpooled, DwGetOption(OPT_DIALUP_HANGUP_DONE));
  440. // $$HACK$$
  441. EnableWindow(GetDlgItem(m_hwndUI, IDC_SP_STOP), TRUE);
  442. // Notify
  443. Notify(DELIVERY_NOTIFY_STARTING, 0);
  444. // Start Next Task
  445. PostMessage(m_hwndUI, IMAIL_NEXTTASK, 0, 0);
  446. exit:
  447. // Failure
  448. if (FAILED(hr) || 0 == m_rEventTable.cEvents && !ISFLAGSET(dwFlags, DELIVER_SHOW))
  449. {
  450. // Not Busy
  451. FLAGCLEAR(m_dwState, SPSTATE_BUSY);
  452. // Forces a next task
  453. PostMessage(m_hwndUI, IMAIL_NEXTTASK, 0, 0);
  454. // No Flags
  455. m_dwFlags = 0;
  456. }
  457. // Cleanup
  458. SafeRelease(pEnum);
  459. SafeRelease(pAccount);
  460. SafeMemFree(m_pszAcctID);
  461. SafeMemFree(rTable.prgLanAcct);
  462. SafeMemFree(rTable.prgRasAcct);
  463. // Thread Safety
  464. LeaveCriticalSection(&m_cs);
  465. // Done
  466. return hr;
  467. }
  468. // --------------------------------------------------------------------------------
  469. // CSpoolerEngine::_InsertRasAccounts
  470. // --------------------------------------------------------------------------------
  471. void CSpoolerEngine::_InsertRasAccounts(LPACCOUNTTABLE pTable, LPCSTR pszConnectoid, DWORD dwSrvTypes)
  472. {
  473. // Locals
  474. ULONG j;
  475. ULONG i;
  476. // Loop through the ras accounts and insert account on szConnetoid that are mail accounts
  477. for (j=0; j<pTable->cRasAccts; j++)
  478. {
  479. // Indirect
  480. i = pTable->prgRasAcct[j].dwSort;
  481. // Is a mail account
  482. if (pTable->prgRasAcct[i].dwServers & dwSrvTypes)
  483. {
  484. // On this connectoid
  485. if (lstrcmpi(pszConnectoid, pTable->prgRasAcct[i].szConnectoid) == 0)
  486. {
  487. // We better have an account
  488. Assert(pTable->prgRasAcct[i].pAccount);
  489. // If dialog allowed or we can connect to the account
  490. if (0 == (m_dwFlags & DELIVER_NODIAL) || S_OK == g_pConMan->CanConnect(pTable->prgRasAcct[i].pAccount))
  491. {
  492. _HrCreateTaskObject(&(pTable->prgRasAcct[i]));
  493. }
  494. // Release the account, we've added it
  495. SafeRelease(pTable->prgRasAcct[i].pAccount);
  496. }
  497. }
  498. }
  499. }
  500. // --------------------------------------------------------------------------------
  501. // CSpoolerEngine::_SortAccountTableByConnName
  502. // --------------------------------------------------------------------------------
  503. void CSpoolerEngine::_SortAccountTableByConnName(LONG left, LONG right, LPSPOOLERACCOUNT prgRasAcct)
  504. {
  505. // Locals
  506. register long i, j;
  507. DWORD k, temp;
  508. i = left;
  509. j = right;
  510. k = prgRasAcct[(i + j) / 2].dwSort;
  511. do
  512. {
  513. while(lstrcmpiA(prgRasAcct[prgRasAcct[i].dwSort].szConnectoid, prgRasAcct[k].szConnectoid) < 0 && i < right)
  514. i++;
  515. while (lstrcmpiA(prgRasAcct[prgRasAcct[j].dwSort].szConnectoid, prgRasAcct[k].szConnectoid) > 0 && j > left)
  516. j--;
  517. if (i <= j)
  518. {
  519. temp = prgRasAcct[i].dwSort;
  520. prgRasAcct[i].dwSort = prgRasAcct[j].dwSort;
  521. prgRasAcct[j].dwSort = temp;
  522. i++; j--;
  523. }
  524. } while (i <= j);
  525. if (left < j)
  526. _SortAccountTableByConnName(left, j, prgRasAcct);
  527. if (i < right)
  528. _SortAccountTableByConnName(i, right, prgRasAcct);
  529. }
  530. // --------------------------------------------------------------------------------
  531. // CSpoolerEngine::_HrAppendAccountTable
  532. // --------------------------------------------------------------------------------
  533. HRESULT CSpoolerEngine::_HrAppendAccountTable(LPACCOUNTTABLE pTable, LPCSTR pszAcctID, DWORD dwServers)
  534. {
  535. // Locals
  536. HRESULT hr=S_OK;
  537. IImnAccount *pAccount=NULL;
  538. // Invalid Arg
  539. Assert(pTable && pszAcctID);
  540. // Does the Account Exist...
  541. CHECKHR(hr = m_pAcctMan->FindAccount(AP_ACCOUNT_ID, m_pszAcctID, &pAccount));
  542. // Actual Append
  543. CHECKHR(hr = _HrAppendAccountTable(pTable, pAccount, dwServers));
  544. exit:
  545. // Cleanup
  546. SafeRelease(pAccount);
  547. // Done
  548. return hr;
  549. }
  550. // --------------------------------------------------------------------------------
  551. // CSpoolerEngine::_HrAppendAccountTable
  552. // --------------------------------------------------------------------------------
  553. HRESULT CSpoolerEngine::_HrAppendAccountTable(LPACCOUNTTABLE pTable, IImnAccount *pAccount, DWORD dwServers)
  554. {
  555. // Locals
  556. HRESULT hr=S_OK;
  557. LPSPOOLERACCOUNT pSpoolAcct;
  558. DWORD dwConnType;
  559. CHAR szConnectoid[CCHMAX_CONNECTOID];
  560. // InvalidArg
  561. Assert(pTable && pAccount);
  562. // Init
  563. *szConnectoid = '\0';
  564. // Get the Account Connection Type
  565. if (FAILED(pAccount->GetPropDw(AP_RAS_CONNECTION_TYPE, &dwConnType)))
  566. {
  567. // Default to Manual Connection
  568. dwConnType = CONNECTION_TYPE_MANUAL;
  569. }
  570. // Otheriwse, get the connectoid if its a RAS connection
  571. //else if (CONNECTION_TYPE_RAS == dwConnType || CONNECTION_TYPE_INETSETTINGS == dwConnType)
  572. else if (CONNECTION_TYPE_RAS == dwConnType)
  573. {
  574. // AP_RAS_CONNECTOID
  575. if (FAILED(pAccount->GetPropSz(AP_RAS_CONNECTOID, szConnectoid, ARRAYSIZE(szConnectoid))))
  576. {
  577. // Default to Lan Connection
  578. dwConnType = CONNECTION_TYPE_MANUAL;
  579. }
  580. }
  581. else if (CONNECTION_TYPE_INETSETTINGS == dwConnType)
  582. {
  583. DWORD dwFlags;
  584. InternetGetConnectedStateExA(&dwFlags, szConnectoid, ARRAYSIZE(szConnectoid), 0);
  585. if (!!(dwFlags & INTERNET_CONNECTION_MODEM))
  586. {
  587. dwConnType = CONNECTION_TYPE_RAS;
  588. }
  589. else
  590. {
  591. dwConnType = CONNECTION_TYPE_LAN;
  592. }
  593. }
  594. // Which Table Should I insert into - LAN OR RAS
  595. if (CONNECTION_TYPE_RAS == dwConnType)
  596. {
  597. // Better have a Connectoid
  598. Assert(FIsEmptyA(szConnectoid) == FALSE);
  599. // Grow the Table
  600. if (pTable->cRasAccts + 1 > pTable->cRasAlloc)
  601. {
  602. // Temp
  603. LPSPOOLERACCOUNT pRealloc=pTable->prgRasAcct;
  604. // Realloc
  605. CHECKALLOC(pTable->prgRasAcct = (LPSPOOLERACCOUNT)g_pMalloc->Realloc((LPVOID)pRealloc, (pTable->cRasAlloc + 5) * sizeof(SPOOLERACCOUNT)));
  606. // Grow
  607. pTable->cRasAlloc += 5;
  608. }
  609. // Readability
  610. pSpoolAcct = &pTable->prgRasAcct[pTable->cRasAccts];
  611. }
  612. // Otherwise, LAN
  613. else
  614. {
  615. // Grow the Table
  616. if (pTable->cLanAccts + 1 > pTable->cLanAlloc)
  617. {
  618. // Temp
  619. LPSPOOLERACCOUNT pRealloc=pTable->prgLanAcct;
  620. // Realloc
  621. CHECKALLOC(pTable->prgLanAcct = (LPSPOOLERACCOUNT)g_pMalloc->Realloc((LPVOID)pRealloc, (pTable->cLanAlloc + 5) * sizeof(SPOOLERACCOUNT)));
  622. // Grow
  623. pTable->cLanAlloc += 5;
  624. }
  625. // Readability
  626. pSpoolAcct = &pTable->prgLanAcct[pTable->cLanAccts];
  627. }
  628. // Zero
  629. ZeroMemory(pSpoolAcct, sizeof(SPOOLERACCOUNT));
  630. // AddRef the Account
  631. pSpoolAcct->pAccount = pAccount;
  632. pSpoolAcct->pAccount->AddRef();
  633. // Get the servers supported by the account
  634. CHECKHR(hr = pAccount->GetServerTypes(&pSpoolAcct->dwServers));
  635. //Mask the servers returned by the acctman with the servers we want to spool
  636. pSpoolAcct->dwServers &= dwServers;
  637. /*
  638. if (pSpoolAcct->dwServers & (SRV_HTTPMAIL | SRV_IMAP))
  639. {
  640. //For each of these two servers, set the sync flags. See Bug# 51895
  641. m_dwFlags |= (DELIVER_NEWSIMAP_OFFLINE | DELIVER_NEWSIMAP_OFFLINE_FLAGS);
  642. }
  643. */
  644. // Save Connection Type
  645. pSpoolAcct->dwConnType = dwConnType;
  646. // Save Connectoid
  647. StrCpyN(pSpoolAcct->szConnectoid, szConnectoid, ARRAYSIZE(pSpoolAcct->szConnectoid));
  648. // Increment Count and set the sort index
  649. // if (CONNECTION_TYPE_RAS == dwConnType || dwConnType == CONNECTION_TYPE_INETSETTINGS)
  650. if (CONNECTION_TYPE_RAS == dwConnType)
  651. {
  652. pSpoolAcct->dwSort = pTable->cRasAccts;
  653. pTable->cRasAccts++;
  654. }
  655. else
  656. {
  657. pSpoolAcct->dwSort = pTable->cLanAccts;
  658. pTable->cLanAccts++;
  659. }
  660. // Total Acount
  661. pTable->cAccounts++;
  662. exit:
  663. // Done
  664. return hr;
  665. }
  666. // --------------------------------------------------------------------------------
  667. // CSpoolerEngine::Close
  668. // --------------------------------------------------------------------------------
  669. STDMETHODIMP CSpoolerEngine::Close(void)
  670. {
  671. // Locals
  672. HRESULT hr=S_OK;
  673. // Thread Safety
  674. EnterCriticalSection(&m_cs);
  675. _StopPolling();
  676. // Was I Threaded ?
  677. if (NULL != m_hThread)
  678. {
  679. hr = TrapError(E_FAIL);
  680. goto exit;
  681. }
  682. // Shutdown
  683. CHECKHR(hr = Shutdown());
  684. exit:
  685. // Thread Safety
  686. LeaveCriticalSection(&m_cs);
  687. // Done
  688. return hr;
  689. }
  690. // --------------------------------------------------------------------------------
  691. // CSpoolerEngine::Notify
  692. // --------------------------------------------------------------------------------
  693. STDMETHODIMP CSpoolerEngine::Notify(DELIVERYNOTIFYTYPE notify, LPARAM lParam)
  694. {
  695. // Locals
  696. ULONG i;
  697. // Enter it
  698. EnterCriticalSection(&m_cs);
  699. // Same thread we were created on...
  700. Assert(ISSPOOLERTHREAD);
  701. // Loop through registered views
  702. for (i=0; i<m_rViewRegister.cViewAlloc; i++)
  703. if (m_rViewRegister.rghwndView[i] != 0 && IsWindow(m_rViewRegister.rghwndView[i]))
  704. PostMessage(m_rViewRegister.rghwndView[i], MVM_SPOOLERDELIVERY, (WPARAM)notify, lParam);
  705. // Enter it
  706. LeaveCriticalSection(&m_cs);
  707. // Done
  708. return S_OK;
  709. }
  710. // --------------------------------------------------------------------------------
  711. // CSpoolerEngine::Advise
  712. // --------------------------------------------------------------------------------
  713. #define VIEW_TABLE_GROWSIZE 8
  714. STDMETHODIMP CSpoolerEngine::Advise(HWND hwndView, BOOL fRegister)
  715. {
  716. // Locals
  717. ULONG i;
  718. HRESULT hr=S_OK;
  719. // Enter it
  720. EnterCriticalSection(&m_cs);
  721. // If NULL view handle...
  722. if (!hwndView)
  723. {
  724. hr = TrapError(E_FAIL);
  725. goto exit;
  726. }
  727. // Are we registering the window
  728. if (fRegister)
  729. {
  730. // Do we need to grow the register array
  731. if (m_rViewRegister.cViewAlloc == m_rViewRegister.cView)
  732. {
  733. // Add some more
  734. m_rViewRegister.cViewAlloc += VIEW_TABLE_GROWSIZE;
  735. // Realloc the array
  736. if (!MemRealloc((LPVOID *)&m_rViewRegister.rghwndView, sizeof(HWND) * m_rViewRegister.cViewAlloc))
  737. {
  738. m_rViewRegister.cViewAlloc -= VIEW_TABLE_GROWSIZE;
  739. hr = TrapError(E_OUTOFMEMORY);
  740. goto exit;
  741. }
  742. // Zeroinit the new items
  743. ZeroMemory(&m_rViewRegister.rghwndView[m_rViewRegister.cView], sizeof(HWND) * (m_rViewRegister.cViewAlloc - m_rViewRegister.cView));
  744. }
  745. // Fill the first NULL item with the new view
  746. for (i=0; i<m_rViewRegister.cViewAlloc; i++)
  747. {
  748. // If empty, lets fill it
  749. if (!m_rViewRegister.rghwndView[i])
  750. {
  751. m_rViewRegister.rghwndView[i] = hwndView;
  752. m_rViewRegister.cView++;
  753. break;
  754. }
  755. }
  756. // Did we insert it ?
  757. AssertSz(i != m_rViewRegister.cViewAlloc, "didn't find a hole??");
  758. }
  759. // Otherwise, find and remove the view
  760. else
  761. {
  762. // Look for hwndView
  763. for (i=0; i<m_rViewRegister.cViewAlloc; i++)
  764. {
  765. // Is this it
  766. if (m_rViewRegister.rghwndView[i] == hwndView)
  767. {
  768. m_rViewRegister.rghwndView[i] = NULL;
  769. m_rViewRegister.cView--;
  770. break;
  771. }
  772. }
  773. }
  774. exit:
  775. // Leave CS
  776. LeaveCriticalSection(&m_cs);
  777. // If this is the first view to register, and there is a background poll pending, lets do it...
  778. if (fRegister && m_rViewRegister.cView == 1 && m_fBackgroundPollPending)
  779. {
  780. StartDelivery(NULL, NULL, FOLDERID_INVALID, DELIVER_BACKGROUND_POLL);
  781. m_fBackgroundPollPending = FALSE;
  782. }
  783. else if (m_rViewRegister.cView == 0)
  784. {
  785. // remove the notify icon if there aren't any views registered
  786. UpdateTrayIcon(TRAYICON_REMOVE);
  787. }
  788. // Done
  789. return hr;
  790. }
  791. // --------------------------------------------------------------------------------
  792. // CSpoolerEngine::UpdateTrayIcon
  793. // --------------------------------------------------------------------------------
  794. STDMETHODIMP CSpoolerEngine::UpdateTrayIcon(TRAYICONTYPE type)
  795. {
  796. // Locals
  797. NOTIFYICONDATA nid;
  798. HWND hwnd=NULL;
  799. ULONG i;
  800. // Enter it
  801. EnterCriticalSection(&m_cs);
  802. // Add the icon...
  803. if (TRAYICON_ADD == type)
  804. {
  805. // Loop through registered views
  806. for (i=0; i<m_rViewRegister.cViewAlloc; i++)
  807. {
  808. if (m_rViewRegister.rghwndView[i] && IsWindow(m_rViewRegister.rghwndView[i]))
  809. {
  810. hwnd = m_rViewRegister.rghwndView[i];
  811. break;
  812. }
  813. }
  814. // No window...
  815. if (hwnd == NULL)
  816. goto exit;
  817. }
  818. // Otherwise, if no notify window, were done
  819. else if (m_hwndTray == NULL)
  820. goto exit;
  821. // Set Tray Notify Icon Data
  822. nid.cbSize = sizeof(NOTIFYICONDATA);
  823. nid.uID = 0;
  824. nid.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE;
  825. nid.uCallbackMessage = MVM_NOTIFYICONEVENT;
  826. nid.hIcon = LoadIcon(g_hLocRes, MAKEINTRESOURCE(idiNewMailNotify));
  827. LoadString(g_hLocRes, idsNewMailNotify, nid.szTip, sizeof(nid.szTip));
  828. // Hmmm
  829. if (TRAYICON_REMOVE == type || (m_hwndTray != NULL && m_hwndTray != hwnd))
  830. {
  831. nid.hWnd = m_hwndTray;
  832. Shell_NotifyIcon(NIM_DELETE, &nid);
  833. m_hwndTray = NULL;
  834. }
  835. // Add
  836. if (TRAYICON_ADD == type)
  837. {
  838. nid.hWnd = hwnd;
  839. Shell_NotifyIcon(NIM_ADD, &nid);
  840. m_hwndTray = hwnd;
  841. }
  842. exit:
  843. // Leave CS
  844. LeaveCriticalSection(&m_cs);
  845. // Done
  846. return S_OK;
  847. }
  848. // --------------------------------------------------------------------------------
  849. // CSpoolerEngine::RegisterEvent
  850. // --------------------------------------------------------------------------------
  851. STDMETHODIMP CSpoolerEngine::RegisterEvent(LPCSTR pszDescription, ISpoolerTask *pTask,
  852. DWORD_PTR dwTwinkie, IImnAccount *pAccount,
  853. LPEVENTID peid)
  854. {
  855. HRESULT hr = S_OK;
  856. LPSPOOLEREVENT pEvent = NULL;
  857. LPWSTR pwszConn = NULL;
  858. WCHAR wsz[CCHMAX_STRINGRES];
  859. // Verify the input parameters
  860. if (FIsEmptyA(pszDescription) || pTask == NULL)
  861. return (E_INVALIDARG);
  862. EnterCriticalSection(&m_cs);
  863. // Grow the Table
  864. if (m_rEventTable.cEvents + 1 > m_rEventTable.cEventsAlloc)
  865. {
  866. // Temp
  867. LPSPOOLEREVENT pRealloc = m_rEventTable.prgEvents;
  868. // Realloc
  869. CHECKALLOC(m_rEventTable.prgEvents = (LPSPOOLEREVENT) g_pMalloc->Realloc((LPVOID)pRealloc, (m_rEventTable.cEventsAlloc + 5) * sizeof(SPOOLEREVENT)));
  870. // Grow
  871. m_rEventTable.cEventsAlloc += 5;
  872. }
  873. pEvent = &m_rEventTable.prgEvents[m_rEventTable.cEvents];
  874. // Insert the event
  875. pEvent->eid = m_rEventTable.cEvents;
  876. pEvent->pSpoolerTask = pTask;
  877. pEvent->pSpoolerTask->AddRef();
  878. pEvent->dwTwinkie = dwTwinkie;
  879. pEvent->pAccount = pAccount;
  880. pEvent->pAccount->AddRef();
  881. // Get the Account Connection Type
  882. if (FAILED(pAccount->GetPropDw(AP_RAS_CONNECTION_TYPE, &pEvent->dwConnType)))
  883. {
  884. // Default to Manual Connection
  885. pEvent->dwConnType = CONNECTION_TYPE_MANUAL;
  886. }
  887. // Otheriwse, get the connectoid if its a RAS connection
  888. //else if (CONNECTION_TYPE_RAS == pEvent->dwConnType || CONNECTION_TYPE_INETSETTINGS == pEvent->dwConnType)
  889. else if (CONNECTION_TYPE_RAS == pEvent->dwConnType)
  890. {
  891. // AP_RAS_CONNECTOID
  892. if (FAILED(pAccount->GetPropSz(AP_RAS_CONNECTOID, pEvent->szConnectoid, ARRAYSIZE(pEvent->szConnectoid))))
  893. {
  894. // Default to Lan Connection
  895. pEvent->dwConnType = CONNECTION_TYPE_MANUAL;
  896. }
  897. }
  898. else if (CONNECTION_TYPE_INETSETTINGS == pEvent->dwConnType)
  899. {
  900. DWORD dwFlags = 0;
  901. InternetGetConnectedStateExA(&dwFlags, pEvent->szConnectoid, ARRAYSIZE(pEvent->szConnectoid), 0);
  902. if (!!(dwFlags & INTERNET_CONNECTION_MODEM))
  903. {
  904. pEvent->dwConnType = CONNECTION_TYPE_RAS;
  905. }
  906. else
  907. {
  908. pEvent->dwConnType = CONNECTION_TYPE_LAN;
  909. }
  910. }
  911. // Get the connection name to put in the task list
  912. if (pEvent->dwConnType == CONNECTION_TYPE_LAN)
  913. {
  914. AthLoadStringW(idsConnectionLAN, wsz, ARRAYSIZE(wsz));
  915. pwszConn = wsz;
  916. }
  917. else if (pEvent->dwConnType == CONNECTION_TYPE_MANUAL)
  918. {
  919. AthLoadStringW(idsConnectionManual, wsz, ARRAYSIZE(wsz));
  920. pwszConn = wsz;
  921. m_fRasSpooled = TRUE;
  922. }
  923. else
  924. {
  925. IF_NULLEXIT(pwszConn = PszToUnicode(CP_ACP, pEvent->szConnectoid));
  926. m_fRasSpooled = TRUE;
  927. }
  928. // Add the event description to the UI
  929. if (m_pUI)
  930. {
  931. m_pUI->InsertEvent(m_rEventTable.prgEvents[m_rEventTable.cEvents].eid, pszDescription, pwszConn);
  932. m_pUI->SetTaskCounts(0, m_rEventTable.cEvents + 1);
  933. }
  934. // Check to see if the task cares about the event id
  935. if (peid)
  936. *peid = m_rEventTable.prgEvents[m_rEventTable.cEvents].eid;
  937. m_rEventTable.cEvents++;
  938. exit:
  939. if (pwszConn != wsz)
  940. MemFree(pwszConn);
  941. LeaveCriticalSection(&m_cs);
  942. return S_OK;
  943. }
  944. // --------------------------------------------------------------------------------
  945. // CSpoolerEngine::EventDone
  946. // --------------------------------------------------------------------------------
  947. STDMETHODIMP CSpoolerEngine::EventDone(EVENTID eid, EVENTCOMPLETEDSTATUS status)
  948. {
  949. LPSPOOLEREVENT pEvent;
  950. // Update the UI
  951. if (EVENT_SUCCEEDED == status)
  952. {
  953. m_rEventTable.cSucceeded++;
  954. m_pUI->SetTaskCounts(m_rEventTable.cSucceeded, m_rEventTable.cEvents);
  955. m_pUI->UpdateEventState(eid, IMAGE_CHECK, NULL, MAKEINTRESOURCE(idsStateCompleted));
  956. }
  957. else if (EVENT_WARNINGS == status)
  958. {
  959. m_pUI->UpdateEventState(eid, IMAGE_WARNING, NULL, MAKEINTRESOURCE(idsStateWarnings));
  960. }
  961. else if (EVENT_FAILED == status)
  962. {
  963. m_pUI->UpdateEventState(eid, IMAGE_ERROR, NULL, MAKEINTRESOURCE(idsStateFailed));
  964. }
  965. else if (EVENT_CANCELED == status)
  966. {
  967. m_pUI->UpdateEventState(eid, IMAGE_WARNING, NULL, MAKEINTRESOURCE(idsStateCanceled));
  968. }
  969. // When an event completes, we can move to the next item in the queue unless
  970. // we're done.
  971. if (!ISFLAGCLEAR(m_dwState, SPSTATE_CANCEL))
  972. {
  973. m_cCurEvent++;
  974. pEvent = &m_rEventTable.prgEvents[m_cCurEvent];
  975. for ( ; m_cCurEvent < m_rEventTable.cEvents; m_cCurEvent++, pEvent++)
  976. {
  977. pEvent->pSpoolerTask->CancelEvent(pEvent->eid, pEvent->dwTwinkie);
  978. }
  979. }
  980. // Next Task
  981. PostMessage(m_hwndUI, IMAIL_NEXTTASK, 0, 0);
  982. return S_OK;
  983. }
  984. // --------------------------------------------------------------------------------
  985. // CSpoolerEngine::_OpenMailLogFile
  986. // --------------------------------------------------------------------------------
  987. HRESULT CSpoolerEngine::_OpenMailLogFile(DWORD dwOptionId, LPCSTR pszPrefix,
  988. LPCSTR pszFileName, ILogFile **ppLogFile)
  989. {
  990. // Locals
  991. HRESULT hr=S_OK;
  992. CHAR szLogFile[MAX_PATH];
  993. CHAR szDirectory[MAX_PATH];
  994. DWORD dw;
  995. // Invalid Args
  996. Assert(pszPrefix && ppLogFile);
  997. // Log file path
  998. dw = GetOption(dwOptionId, szLogFile, ARRAYSIZE(szLogFile));
  999. // If we found a filepath and the file exists
  1000. if (0 == dw || FALSE == PathFileExists(szLogFile))
  1001. {
  1002. // Get the Store Root Directory
  1003. GetStoreRootDirectory(szDirectory, ARRAYSIZE(szDirectory));
  1004. // Ends with a backslash ?
  1005. IF_FAILEXIT(hr = MakeFilePath(szDirectory, pszFileName, c_szEmpty, szLogFile, ARRAYSIZE(szLogFile)));
  1006. // Reset the Option
  1007. SetOption(dwOptionId, szLogFile, lstrlen(szLogFile) + 1, NULL, 0);
  1008. }
  1009. // Create the log file
  1010. IF_FAILEXIT(hr = CreateLogFile(g_hInst, szLogFile, pszPrefix, DONT_TRUNCATE, ppLogFile,
  1011. FILE_SHARE_READ | FILE_SHARE_WRITE));
  1012. exit:
  1013. // Done
  1014. return(hr);
  1015. }
  1016. // --------------------------------------------------------------------------------
  1017. // CSpoolerEngine::BindToObject
  1018. // --------------------------------------------------------------------------------
  1019. STDMETHODIMP CSpoolerEngine::BindToObject(REFIID riid, void **ppvObject)
  1020. {
  1021. // Locals
  1022. HRESULT hr=S_OK;
  1023. // Invalid Arg
  1024. if (NULL == ppvObject)
  1025. return TrapError(E_INVALIDARG);
  1026. // Thread Safety
  1027. EnterCriticalSection(&m_cs);
  1028. // IID_ISpoolerBindContext
  1029. if (IID_ISpoolerBindContext == riid)
  1030. *ppvObject = (ISpoolerBindContext *)this;
  1031. // IID_CUidlCache
  1032. else if (IID_CUidlCache == riid)
  1033. {
  1034. // Doesn't Exist
  1035. if (NULL == m_pUidlCache)
  1036. {
  1037. // Open the Cache
  1038. CHECKHR(hr = OpenUidlCache(&m_pUidlCache));
  1039. }
  1040. // AddRef it
  1041. m_pUidlCache->AddRef();
  1042. // Return It
  1043. *ppvObject = (IDatabase *)m_pUidlCache;
  1044. }
  1045. // IImnAccountManager
  1046. else if (IID_IImnAccountManager == riid)
  1047. {
  1048. // Doesn't Exist
  1049. if (NULL == m_pAcctMan)
  1050. {
  1051. AssertSz(FALSE, "The Account Manager Could Not Be Created.");
  1052. hr = TrapError(E_FAIL);
  1053. goto exit;
  1054. }
  1055. // AddRef It
  1056. m_pAcctMan->AddRef();
  1057. // Return It
  1058. *ppvObject = (IImnAccountManager *)m_pAcctMan;
  1059. }
  1060. // ISpoolerUI
  1061. else if (IID_ISpoolerUI == riid)
  1062. {
  1063. // Doesn't Exist
  1064. if (NULL == m_pUI)
  1065. {
  1066. AssertSz(FALSE, "The Spooler UI Object Could Not Be Created.");
  1067. hr = TrapError(E_FAIL);
  1068. goto exit;
  1069. }
  1070. // AddRef It
  1071. m_pUI->AddRef();
  1072. // Return It
  1073. *ppvObject = (ISpoolerUI *)m_pUI;
  1074. }
  1075. // IID_CLocalStoreDeleted
  1076. else if (IID_CLocalStoreDeleted == riid)
  1077. {
  1078. // Open Special Folder
  1079. CHECKHR(hr = g_pStore->OpenSpecialFolder(FOLDERID_LOCAL_STORE, NULL, FOLDER_DELETED, (IMessageFolder **)ppvObject));
  1080. }
  1081. // IID_CLocalStoreInbox
  1082. else if (IID_CLocalStoreInbox == riid)
  1083. {
  1084. // Open Special Folder
  1085. CHECKHR(hr = g_pStore->OpenSpecialFolder(FOLDERID_LOCAL_STORE, NULL, FOLDER_INBOX, (IMessageFolder **)ppvObject));
  1086. }
  1087. // IID_CLocalStoreOutbox
  1088. else if (IID_CLocalStoreOutbox == riid)
  1089. {
  1090. // Open Special Folder
  1091. CHECKHR(hr = g_pStore->OpenSpecialFolder(FOLDERID_LOCAL_STORE, NULL, FOLDER_OUTBOX, (IMessageFolder **)ppvObject));
  1092. }
  1093. // IID_CLocalStoreSentItems
  1094. else if (IID_CLocalStoreSentItems == riid)
  1095. {
  1096. // Open Special Folder
  1097. CHECKHR(hr = g_pStore->OpenSpecialFolder(FOLDERID_LOCAL_STORE, NULL, FOLDER_SENT, (IMessageFolder **)ppvObject));
  1098. }
  1099. // IID_CPop3LogFile
  1100. else if (IID_CPop3LogFile == riid)
  1101. {
  1102. // Create logging objects
  1103. if (!DwGetOption(OPT_MAILLOG))
  1104. {
  1105. hr = TrapError(E_FAIL);
  1106. goto exit;
  1107. }
  1108. // Do I have the logfile yet ?
  1109. if (NULL == m_pPop3LogFile)
  1110. {
  1111. // Open the log file
  1112. CHECKHR(hr = _OpenMailLogFile(OPT_MAILPOP3LOGFILE, "POP3", c_szDefaultPop3Log, &m_pPop3LogFile));
  1113. }
  1114. // AddRef It
  1115. m_pPop3LogFile->AddRef();
  1116. // Return It
  1117. *ppvObject = (ILogFile *)m_pPop3LogFile;
  1118. }
  1119. // IID_CSmtpLogFile
  1120. else if (IID_CSmtpLogFile == riid)
  1121. {
  1122. // Create logging objects
  1123. if (!DwGetOption(OPT_MAILLOG))
  1124. {
  1125. hr = TrapError(E_FAIL);
  1126. goto exit;
  1127. }
  1128. // Do I have the logfile yet ?
  1129. if (NULL == m_pSmtpLogFile)
  1130. {
  1131. // Open the log file
  1132. CHECKHR(hr = _OpenMailLogFile(OPT_MAILSMTPLOGFILE, "SMTP", c_szDefaultSmtpLog, &m_pSmtpLogFile));
  1133. }
  1134. // AddRef It
  1135. m_pSmtpLogFile->AddRef();
  1136. // Return It
  1137. *ppvObject = (ILogFile *)m_pSmtpLogFile;
  1138. }
  1139. // E_NOTINTERFACE
  1140. else
  1141. {
  1142. hr = TrapError(E_NOINTERFACE);
  1143. goto exit;
  1144. }
  1145. exit:
  1146. // Thread Safety
  1147. LeaveCriticalSection(&m_cs);
  1148. // Done
  1149. return hr;
  1150. }
  1151. // --------------------------------------------------------------------------------
  1152. // CSpoolerEngine::TaskFromEventId
  1153. // --------------------------------------------------------------------------------
  1154. STDMETHODIMP CSpoolerEngine::TaskFromEventId(EVENTID eid, ISpoolerTask *ppTask)
  1155. {
  1156. return S_OK;
  1157. }
  1158. // --------------------------------------------------------------------------------
  1159. // CSpoolerEngine::Cancel
  1160. // --------------------------------------------------------------------------------
  1161. STDMETHODIMP CSpoolerEngine::Cancel(void)
  1162. {
  1163. EnterCriticalSection(&m_cs);
  1164. if (ISFLAGSET(m_dwState, SPSTATE_BUSY))
  1165. {
  1166. Assert(m_rEventTable.cEvents && m_rEventTable.prgEvents);
  1167. FLAGSET(m_dwState, SPSTATE_CANCEL);
  1168. if (m_rEventTable.prgEvents && m_rEventTable.prgEvents[m_cCurEvent].pSpoolerTask)
  1169. m_rEventTable.prgEvents[m_cCurEvent].pSpoolerTask->Cancel();
  1170. }
  1171. LeaveCriticalSection(&m_cs);
  1172. return S_OK;
  1173. }
  1174. // --------------------------------------------------------------------------------
  1175. // CSpoolerEngine::GetThreadInfo
  1176. // --------------------------------------------------------------------------------
  1177. STDMETHODIMP CSpoolerEngine::GetThreadInfo(LPDWORD pdwThreadId, HTHREAD* phThread)
  1178. {
  1179. // Invalid Arg
  1180. if (NULL == pdwThreadId || NULL == phThread)
  1181. return TrapError(E_INVALIDARG);
  1182. // Thread Safety
  1183. EnterCriticalSection(&m_cs);
  1184. // Return It
  1185. *pdwThreadId = m_dwThreadId;
  1186. *phThread = m_hThread;
  1187. // Thread Safety
  1188. LeaveCriticalSection(&m_cs);
  1189. // Done
  1190. return S_OK;
  1191. }
  1192. // --------------------------------------------------------------------------------
  1193. // CSpoolerEngine::QueryEndSession
  1194. // --------------------------------------------------------------------------------
  1195. STDMETHODIMP_(LRESULT) CSpoolerEngine::QueryEndSession(WPARAM wParam, LPARAM lParam)
  1196. {
  1197. if (ISFLAGSET(m_dwState, SPSTATE_BUSY))
  1198. {
  1199. if (AthMessageBoxW(NULL, MAKEINTRESOURCEW(idsAthenaMail), MAKEINTRESOURCEW(idsAbortDownload), NULL, MB_YESNO|MB_ICONEXCLAMATION ) == IDNO)
  1200. return FALSE;
  1201. }
  1202. Cancel();
  1203. return TRUE;
  1204. }
  1205. // --------------------------------------------------------------------------------
  1206. // CSpoolerEngine::Shutdown
  1207. // --------------------------------------------------------------------------------
  1208. HRESULT CSpoolerEngine::Shutdown(void)
  1209. {
  1210. // Thread Safety
  1211. EnterCriticalSection(&m_cs);
  1212. // Better shutdown on the same thread we started on
  1213. Assert(ISSPOOLERTHREAD);
  1214. // Stop Polling
  1215. _StopPolling();
  1216. // Are we currently busy
  1217. _ShutdownTasks();
  1218. // If we're executing, then we need to stop and release all the tasks
  1219. for (UINT i = 0; i < m_rEventTable.cEvents; i++)
  1220. {
  1221. SafeRelease(m_rEventTable.prgEvents[i].pSpoolerTask);
  1222. SafeRelease(m_rEventTable.prgEvents[i].pAccount);
  1223. }
  1224. // Release Objects
  1225. SafeRelease(m_pUI);
  1226. SafeRelease(m_pAcctMan);
  1227. SafeRelease(m_pUidlCache);
  1228. SafeMemFree(m_pszAcctID);
  1229. // Thread Safety
  1230. LeaveCriticalSection(&m_cs);
  1231. // Done
  1232. return S_OK;
  1233. }
  1234. // --------------------------------------------------------------------------------
  1235. // CSpoolerEngine::Shutdown
  1236. // --------------------------------------------------------------------------------
  1237. void CSpoolerEngine::_ShutdownTasks(void)
  1238. {
  1239. // Locals
  1240. HRESULT hr=S_OK;
  1241. MSG msg;
  1242. BOOL fFlushOutbox=FALSE;
  1243. IMessageFolder *pOutbox=NULL;
  1244. int ResId;
  1245. BOOL fOffline = FALSE;
  1246. // Clear queued events
  1247. m_dwQueued = 0;
  1248. // Check for unsent mail
  1249. if (g_fCheckOutboxOnShutdown)
  1250. {
  1251. // Open the Outbox
  1252. if (SUCCEEDED(BindToObject(IID_CLocalStoreOutbox, (LPVOID *)&pOutbox)))
  1253. {
  1254. // Locals
  1255. HROWSET hRowset=NULL;
  1256. MESSAGEINFO MsgInfo={0};
  1257. // Create a Rowset
  1258. if (SUCCEEDED(pOutbox->CreateRowset(IINDEX_PRIMARY, NOFLAGS, &hRowset)))
  1259. {
  1260. // While
  1261. while (S_OK == pOutbox->QueryRowset(hRowset, 1, (LPVOID *)&MsgInfo, NULL))
  1262. {
  1263. // Has this message been submitted and is it a mail message
  1264. if (((MsgInfo.dwFlags & (ARF_SUBMITTED | ARF_NEWSMSG)) == ARF_SUBMITTED) &&
  1265. (!ISFLAGSET(m_dwState, SPSTATE_BUSY)))
  1266. {
  1267. fOffline = g_pConMan->IsGlobalOffline();
  1268. if (fOffline)
  1269. ResId = idsWarnUnsentMailOffline;
  1270. else
  1271. ResId = idsWarnUnsentMail;
  1272. // Prompt to flush the outbox
  1273. if (AthMessageBoxW(NULL, MAKEINTRESOURCEW(idsAthenaMail), MAKEINTRESOURCEW(ResId), NULL, MB_YESNO|MB_ICONEXCLAMATION ) == IDYES)
  1274. {
  1275. // Go online
  1276. if (fOffline)
  1277. g_pConMan->SetGlobalOffline(FALSE);
  1278. // Flush on exit
  1279. fFlushOutbox = TRUE;
  1280. }
  1281. // Done
  1282. break;
  1283. }
  1284. // Free MsgInfo
  1285. pOutbox->FreeRecord(&MsgInfo);
  1286. }
  1287. // Free MsgInfo
  1288. pOutbox->FreeRecord(&MsgInfo);
  1289. // Close the Rowset
  1290. pOutbox->CloseRowset(&hRowset);
  1291. }
  1292. }
  1293. }
  1294. // Release outbox
  1295. SafeRelease(pOutbox);
  1296. // Set Shutdown state
  1297. FLAGSET(m_dwState, SPSTATE_SHUTDOWN);
  1298. // If not busy now, start the flush
  1299. if (!ISFLAGSET(m_dwState, SPSTATE_BUSY))
  1300. {
  1301. // Flush the Outbox
  1302. if (fFlushOutbox)
  1303. {
  1304. // No need to flush again
  1305. fFlushOutbox = FALSE;
  1306. // Start the delivery
  1307. _HrStartDeliveryActual(DELIVER_SEND | DELIVER_SMTP_TYPE | DELIVER_HTTP_TYPE );
  1308. // We are busy
  1309. FLAGSET(m_dwState, SPSTATE_BUSY);
  1310. }
  1311. // Otheriwse, were done...
  1312. else
  1313. goto exit;
  1314. }
  1315. // We must wait for current cycle to finish
  1316. if (ISFLAGSET(m_dwState, SPSTATE_BUSY))
  1317. {
  1318. // Lets show progress...
  1319. FLAGCLEAR(m_dwFlags, DELIVER_NOUI | DELIVER_BACKGROUND);
  1320. // Show the ui object
  1321. m_pUI->ShowWindow(SW_SHOW);
  1322. SetForegroundWindow(m_hwndUI);
  1323. // Here's a nice hack to disable the Hide button
  1324. EnableWindow(GetDlgItem(m_hwndUI, IDC_SP_MINIMIZE), FALSE);
  1325. // Set focus on the dialog
  1326. SetFocus(m_hwndUI);
  1327. // Set the focus onto the Stop Button
  1328. SetFocus(GetDlgItem(m_hwndUI, IDC_SP_STOP));
  1329. // Pump messages until current cycle is complete
  1330. while(GetMessage(&msg, NULL, 0, 0))
  1331. {
  1332. // Give the message to the UI object
  1333. if (m_pUI->IsDialogMessage(&msg) == S_FALSE && IsDialogMessage(&msg) == S_FALSE)
  1334. {
  1335. TranslateMessage(&msg);
  1336. DispatchMessage(&msg);
  1337. }
  1338. // If no cycle, were done
  1339. if (!ISFLAGSET(m_dwState, SPSTATE_BUSY))
  1340. {
  1341. // Do the Outbox
  1342. if (fFlushOutbox)
  1343. {
  1344. // Were the errors...
  1345. if (S_OK == m_pUI->AreThereErrors())
  1346. {
  1347. // Errors were encountered during the last Delivery Cycle. Would you still like to send the messages that are in your Outbox?
  1348. if (AthMessageBoxW(NULL, MAKEINTRESOURCEW(idsAthenaMail), MAKEINTRESOURCEW(idsWarnErrorUnsentMail), NULL, MB_YESNO | MB_ICONEXCLAMATION ) == IDNO)
  1349. break;
  1350. }
  1351. // No need to flush again
  1352. fFlushOutbox = FALSE;
  1353. // Start the delivery
  1354. _HrStartDeliveryActual(DELIVER_SEND | DELIVER_SMTP_TYPE | DELIVER_HTTP_TYPE );
  1355. // We are busy
  1356. FLAGSET(m_dwState, SPSTATE_BUSY);
  1357. }
  1358. else
  1359. break;
  1360. }
  1361. }
  1362. }
  1363. // Were the errors...
  1364. if (S_OK == m_pUI->AreThereErrors() && !g_pInstance->SwitchingUsers())
  1365. {
  1366. // Tell the ui to go into Shutdown Mode
  1367. m_pUI->Shutdown();
  1368. // Show the ui object
  1369. m_pUI->ShowWindow(SW_SHOW);
  1370. SetForegroundWindow(m_hwndUI);
  1371. // We are busy
  1372. FLAGCLEAR(m_dwState, SPSTATE_UISHUTDOWN);
  1373. // Set the focus onto the Stop Button
  1374. SetFocus(GetDlgItem(m_hwndUI, IDC_SP_MINIMIZE));
  1375. // Pump messages until current cycle is complete
  1376. while(GetMessage(&msg, NULL, 0, 0))
  1377. {
  1378. // Give the message to the UI object
  1379. if (m_pUI->IsDialogMessage(&msg) == S_FALSE && IsDialogMessage(&msg) == S_FALSE)
  1380. {
  1381. TranslateMessage(&msg);
  1382. DispatchMessage(&msg);
  1383. }
  1384. // User Pressed close yet ?
  1385. if (ISFLAGSET(m_dwState, SPSTATE_UISHUTDOWN))
  1386. break;
  1387. }
  1388. }
  1389. exit:
  1390. // Cleanup
  1391. SafeRelease(pOutbox);
  1392. // Done
  1393. return;
  1394. }
  1395. // --------------------------------------------------------------------------------
  1396. // CSpoolerEngine::UIShutdown
  1397. // --------------------------------------------------------------------------------
  1398. STDMETHODIMP CSpoolerEngine::UIShutdown(void)
  1399. {
  1400. EnterCriticalSection(&m_cs);
  1401. FLAGSET(m_dwState, SPSTATE_UISHUTDOWN);
  1402. LeaveCriticalSection(&m_cs);
  1403. return S_OK;
  1404. }
  1405. // --------------------------------------------------------------------------------
  1406. // CSpoolerEngine::PumpMessages
  1407. // --------------------------------------------------------------------------------
  1408. STDMETHODIMP CSpoolerEngine::PumpMessages(void)
  1409. {
  1410. // Locals
  1411. MSG msg;
  1412. BOOL fQuit=FALSE;
  1413. // Thread Safety
  1414. EnterCriticalSection(&m_cs);
  1415. // Pump messages until current cycle is complete
  1416. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  1417. {
  1418. // WM_QUIT
  1419. if (WM_QUIT == msg.message)
  1420. {
  1421. // Make a note that a quit was received
  1422. fQuit = TRUE;
  1423. // If not running with now ui, set to foreground
  1424. if (FALSE == IsWindowVisible(m_hwndUI))
  1425. {
  1426. m_pUI->ShowWindow(SW_SHOW);
  1427. SetForegroundWindow(m_hwndUI);
  1428. }
  1429. }
  1430. // Give the message to the UI object
  1431. if (m_pUI->IsDialogMessage(&msg) == S_FALSE && IsDialogMessage(&msg) == S_FALSE)
  1432. {
  1433. TranslateMessage(&msg);
  1434. DispatchMessage(&msg);
  1435. }
  1436. }
  1437. // Repost the quit message
  1438. if (fQuit)
  1439. PostThreadMessage(m_dwThreadId, WM_QUIT, 0, 0);
  1440. // Thread Safety
  1441. LeaveCriticalSection(&m_cs);
  1442. // Done
  1443. return S_OK;
  1444. }
  1445. // --------------------------------------------------------------------------------
  1446. // CSpoolerEngine::OnWindowMessage - S_OK (I Handled the message)
  1447. // --------------------------------------------------------------------------------
  1448. STDMETHODIMP CSpoolerEngine::OnWindowMessage(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1449. {
  1450. // Locals
  1451. HRESULT hr=S_OK;
  1452. DWORD dw;
  1453. // Thread Safety
  1454. EnterCriticalSection(&m_cs);
  1455. // Handle the window message
  1456. switch(uMsg)
  1457. {
  1458. case IMAIL_DELIVERNOW:
  1459. _HrStartDeliveryActual((DWORD)lParam);
  1460. break;
  1461. case IMAIL_NEXTTASK:
  1462. _HrStartNextEvent();
  1463. break;
  1464. case WM_TIMER:
  1465. if (wParam == IMAIL_POOLFORMAIL)
  1466. {
  1467. KillTimer(hwnd, IMAIL_POOLFORMAIL);
  1468. _DoBackgroundPoll();
  1469. }
  1470. break;
  1471. case CM_OPTIONADVISE:
  1472. // Check to see if the polling option changed
  1473. if (wParam == OPT_POLLFORMSGS)
  1474. {
  1475. dw = DwGetOption(OPT_POLLFORMSGS);
  1476. if (dw != OPTION_OFF)
  1477. {
  1478. if (dw != m_dwPollInterval)
  1479. {
  1480. KillTimer(hwnd, IMAIL_POOLFORMAIL);
  1481. SetTimer(hwnd, IMAIL_POOLFORMAIL, dw, NULL);
  1482. m_dwPollInterval = dw;
  1483. }
  1484. }
  1485. else
  1486. {
  1487. KillTimer(hwnd, IMAIL_POOLFORMAIL);
  1488. m_dwPollInterval = 0;
  1489. }
  1490. }
  1491. // Check to see if the hang up option changed
  1492. if (wParam == OPT_DIALUP_HANGUP_DONE)
  1493. {
  1494. dw = DwGetOption(OPT_DIALUP_HANGUP_DONE);
  1495. m_pUI->ChangeHangupOption(m_fRasSpooled, dw);
  1496. }
  1497. break;
  1498. default:
  1499. hr = S_FALSE;
  1500. break;
  1501. }
  1502. // Thread Safety
  1503. LeaveCriticalSection(&m_cs);
  1504. // Done
  1505. return hr;
  1506. }
  1507. HRESULT CSpoolerEngine::_HrCreateTaskObject(LPSPOOLERACCOUNT pSpoolerAcct)
  1508. {
  1509. DWORD cEvents, cEventsT;
  1510. HRESULT hr=S_OK;
  1511. // Let's try pumping messages to see if this get's any smoother
  1512. MSG msg;
  1513. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  1514. {
  1515. // Give the message to the UI object
  1516. if (m_pUI->IsDialogMessage(&msg) == S_FALSE)
  1517. {
  1518. TranslateMessage(&msg);
  1519. DispatchMessage(&msg);
  1520. }
  1521. }
  1522. // Create the appropriate task object. Start with SMTP
  1523. if (pSpoolerAcct->dwServers & SRV_SMTP && m_dwFlags & DELIVER_SEND)
  1524. {
  1525. CSmtpTask *pSmtpTask = new CSmtpTask();
  1526. if (pSmtpTask)
  1527. {
  1528. // Initialize the news task
  1529. if (SUCCEEDED(hr = pSmtpTask->Init(m_dwFlags, (ISpoolerBindContext *) this)))
  1530. {
  1531. // Tell the task to build it's event list
  1532. hr = pSmtpTask->BuildEvents(m_pUI, pSpoolerAcct->pAccount, 0);
  1533. }
  1534. pSmtpTask->Release();
  1535. }
  1536. }
  1537. // HTTPMail Servers
  1538. if ((!!(pSpoolerAcct->dwServers & SRV_HTTPMAIL)) && (!!(m_dwFlags & (DELIVER_SEND | DELIVER_POLL))))
  1539. {
  1540. /* DWORD dw;
  1541. if (SUCCEEDED(pSpoolerAcct->pAccount->GetPropDw(AP_HTTPMAIL_DOMAIN_MSN, &dw)) && dw)
  1542. {
  1543. if(HideHotmail())
  1544. return(hr);
  1545. }
  1546. */
  1547. CHTTPTask *pHTTPTask = new CHTTPTask();
  1548. if (pHTTPTask)
  1549. {
  1550. // initialize the http mail task
  1551. if (SUCCEEDED(hr = pHTTPTask->Init(m_dwFlags, (ISpoolerBindContext *)this)))
  1552. hr = pHTTPTask->BuildEvents(m_pUI, pSpoolerAcct->pAccount, 0);
  1553. pHTTPTask->Release();
  1554. }
  1555. }
  1556. // POP3 Servers
  1557. if (pSpoolerAcct->dwServers & SRV_POP3 && m_dwFlags & DELIVER_MAIL_RECV)
  1558. {
  1559. // Skipping Marked Pop3 Accounts
  1560. DWORD dw=FALSE;
  1561. if (ISFLAGSET(m_dwFlags, DELIVER_NOSKIP) || FAILED(pSpoolerAcct->pAccount->GetPropDw(AP_POP3_SKIP, &dw)) || FALSE == dw)
  1562. {
  1563. CPop3Task *pPop3Task = new CPop3Task();
  1564. if (pPop3Task)
  1565. {
  1566. // Initialize the news task
  1567. if (SUCCEEDED(hr = pPop3Task->Init(m_dwFlags, (ISpoolerBindContext *) this)))
  1568. {
  1569. // Tell the task to build it's event list
  1570. hr = pPop3Task->BuildEvents(m_pUI, pSpoolerAcct->pAccount, 0);
  1571. }
  1572. pPop3Task->Release();
  1573. }
  1574. }
  1575. }
  1576. // Servers that support offline sync
  1577. if ((pSpoolerAcct->dwServers & (SRV_NNTP | SRV_IMAP | SRV_HTTPMAIL)))
  1578. {
  1579. if (!!((DELIVER_POLL | DELIVER_SEND) & m_dwFlags))
  1580. {
  1581. CNewsTask *pNewsTask = new CNewsTask();
  1582. if (pNewsTask)
  1583. {
  1584. // Initialize the news task
  1585. if (SUCCEEDED(hr = pNewsTask->Init(m_dwFlags, (ISpoolerBindContext *) this)))
  1586. {
  1587. // Tell the task to build it's event list
  1588. hr = pNewsTask->BuildEvents(m_pUI, pSpoolerAcct->pAccount, 0);
  1589. }
  1590. pNewsTask->Release();
  1591. }
  1592. }
  1593. if ((m_dwFlags & DELIVER_WATCH) && !(m_dwFlags & DELIVER_NO_NEWSPOLL)
  1594. && (pSpoolerAcct->dwServers & SRV_NNTP))
  1595. {
  1596. CWatchTask *pWatchTask = new CWatchTask();
  1597. if (pWatchTask)
  1598. {
  1599. if (SUCCEEDED(hr = pWatchTask->Init(m_dwFlags, (ISpoolerBindContext *) this)))
  1600. {
  1601. hr = pWatchTask->BuildEvents(m_pUI, pSpoolerAcct->pAccount, m_idFolder);
  1602. }
  1603. pWatchTask->Release();
  1604. }
  1605. }
  1606. cEvents = m_rEventTable.cEvents;
  1607. if (m_dwFlags & DELIVER_OFFLINE_FLAGS)
  1608. {
  1609. COfflineTask *pOfflineTask = new COfflineTask();
  1610. if (pOfflineTask)
  1611. {
  1612. // Initialize the offline task
  1613. if (SUCCEEDED(hr = pOfflineTask->Init(m_dwFlags, (ISpoolerBindContext *) this)))
  1614. {
  1615. // Tell the task to build it's event list
  1616. hr = pOfflineTask->BuildEvents(m_pUI, pSpoolerAcct->pAccount, m_idFolder);
  1617. }
  1618. pOfflineTask->Release();
  1619. }
  1620. }
  1621. cEventsT = m_rEventTable.cEvents;
  1622. m_cSyncEvent += (cEventsT - cEvents);
  1623. }
  1624. return (hr);
  1625. }
  1626. STDMETHODIMP CSpoolerEngine::IsDialogMessage(LPMSG pMsg)
  1627. {
  1628. HRESULT hr=S_FALSE;
  1629. EnterCriticalSection(&m_cs);
  1630. if (ISFLAGSET(m_dwState, SPSTATE_BUSY) && (LONG)m_cCurEvent >= 0 && m_cCurEvent < m_rEventTable.cEvents && m_rEventTable.prgEvents[m_cCurEvent].pSpoolerTask)
  1631. hr = m_rEventTable.prgEvents[m_cCurEvent].pSpoolerTask->IsDialogMessage(pMsg);
  1632. LeaveCriticalSection(&m_cs);
  1633. return hr;
  1634. }
  1635. HRESULT CSpoolerEngine::_HrStartNextEvent(void)
  1636. {
  1637. HRESULT hr = S_OK;
  1638. TCHAR szRes[CCHMAX_STRINGRES], szBuf[CCHMAX_STRINGRES];
  1639. TCHAR szBuf2[CCHMAX_CONNECTOID + 2];
  1640. EnterCriticalSection(&m_cs);
  1641. // RAID-30804 Release the current task. This makes sure that objects like the pop3 object
  1642. // release it's locks on the store.
  1643. if ((LONG)m_cCurEvent >= 0 && m_cCurEvent < m_rEventTable.cEvents)
  1644. {
  1645. SafeRelease(m_rEventTable.prgEvents[m_cCurEvent].pSpoolerTask);
  1646. }
  1647. // Advance to the next event
  1648. m_cCurEvent++;
  1649. // Check to see if that pushes us over the edge
  1650. if (m_cCurEvent >= m_rEventTable.cEvents)
  1651. {
  1652. _HrGoIdle();
  1653. }
  1654. else
  1655. {
  1656. LPSPOOLEREVENT pEvent = &m_rEventTable.prgEvents[m_cCurEvent];
  1657. // Check to see if we need to connect first
  1658. if (pEvent->dwConnType == CONNECTION_TYPE_RAS)
  1659. {
  1660. // Check to see if we need to connect
  1661. if (m_cCurEvent == 0 || (0 != lstrcmpi(pEvent->szConnectoid, m_rEventTable.prgEvents[m_cCurEvent - 1].szConnectoid)) || S_OK != g_pConMan->CanConnect(pEvent->szConnectoid))
  1662. {
  1663. hr = _HrDoRasConnect(pEvent);
  1664. if (hr == HR_E_OFFLINE || hr == HR_E_USER_CANCEL_CONNECT || hr == HR_E_DIALING_INPROGRESS)
  1665. {
  1666. for (m_cCurEvent; m_cCurEvent < m_rEventTable.cEvents; m_cCurEvent++)
  1667. {
  1668. // Mark the event as cancelled
  1669. m_pUI->UpdateEventState(m_cCurEvent, IMAGE_WARNING, NULL, MAKEINTRESOURCE(idsStateCanceled));
  1670. //This is a hack to not show errors. In this case we just want to behave as though this
  1671. //operation succeeded.
  1672. m_rEventTable.cSucceeded++;
  1673. // Check to see if we've found a different connection yet
  1674. if ((m_cCurEvent == m_rEventTable.cEvents - 1) ||
  1675. 0 != lstrcmpi(m_rEventTable.prgEvents[m_cCurEvent].szConnectoid, m_rEventTable.prgEvents[m_cCurEvent + 1].szConnectoid))
  1676. break;
  1677. }
  1678. }
  1679. else
  1680. if (FAILED(hr))
  1681. {
  1682. // We need to mark all the events for this connection as failed as
  1683. // well.
  1684. for (m_cCurEvent; m_cCurEvent < m_rEventTable.cEvents; m_cCurEvent++)
  1685. {
  1686. // Mark the event as failed
  1687. m_pUI->UpdateEventState(m_cCurEvent, IMAGE_ERROR, NULL, MAKEINTRESOURCE(idsStateFailed));
  1688. // Check to see if we've found a different connection yet
  1689. if ((m_cCurEvent == m_rEventTable.cEvents - 1) ||
  1690. 0 != lstrcmpi(m_rEventTable.prgEvents[m_cCurEvent].szConnectoid, m_rEventTable.prgEvents[m_cCurEvent + 1].szConnectoid))
  1691. break;
  1692. }
  1693. // Insert an error for this failure
  1694. AthLoadString(idsRasErrorGeneralWithName, szRes, ARRAYSIZE(szRes));
  1695. wnsprintf(szBuf, ARRAYSIZE(szBuf), szRes, PszEscapeMenuStringA(m_rEventTable.prgEvents[m_cCurEvent].szConnectoid, szBuf2, ARRAYSIZE(szBuf2)));
  1696. m_pUI->InsertError(m_cCurEvent, szBuf);
  1697. hr = E_FAIL;
  1698. }
  1699. if (hr != S_OK)
  1700. {
  1701. // Move on to the next task
  1702. PostMessage(m_hwndUI, IMAIL_NEXTTASK, 0, 0);
  1703. goto exit;
  1704. }
  1705. }
  1706. }
  1707. if (FAILED(pEvent->pSpoolerTask->Execute(pEvent->eid, pEvent->dwTwinkie)))
  1708. {
  1709. m_pUI->UpdateEventState(pEvent->eid, IMAGE_ERROR, NULL, MAKEINTRESOURCE(idsStateFailed));
  1710. PostMessage(m_hwndUI, IMAIL_NEXTTASK, 0, 0);
  1711. }
  1712. else
  1713. m_pUI->UpdateEventState(pEvent->eid, IMAGE_EXECUTE, NULL, MAKEINTRESOURCE(idsStateExecuting));
  1714. }
  1715. exit:
  1716. LeaveCriticalSection(&m_cs);
  1717. //return (S_OK);
  1718. return hr;
  1719. }
  1720. HRESULT CSpoolerEngine::_HrDoRasConnect(const LPSPOOLEREVENT pEvent)
  1721. {
  1722. HRESULT hr;
  1723. HWND hwndParent = m_hwndUI;
  1724. // Check to see if we already can connect
  1725. hr = g_pConMan->CanConnect(pEvent->pAccount);
  1726. if (S_OK == hr)
  1727. return (S_OK);
  1728. // Check to see if we're allowed to dial
  1729. if (m_dwFlags & DELIVER_NODIAL)
  1730. return (E_FAIL);
  1731. if (m_dwFlags & DELIVER_DIAL_ALWAYS)
  1732. {
  1733. if (hr == HR_E_OFFLINE)
  1734. {
  1735. g_pConMan->SetGlobalOffline(FALSE);
  1736. m_fOfflineWhenDone = TRUE;
  1737. }
  1738. }
  1739. // Check to see if the parent window exists and is visible
  1740. if (!IsWindow(hwndParent) || !IsWindowVisible(hwndParent))
  1741. {
  1742. // Parent the UI to the browser window
  1743. hwndParent = FindWindowEx(NULL, NULL, c_szBrowserWndClass, 0);
  1744. }
  1745. // Try to connect
  1746. hr = g_pConMan->Connect(pEvent->pAccount, hwndParent, TRUE);
  1747. if (S_OK == hr)
  1748. {
  1749. m_fIDialed = TRUE;
  1750. return S_OK;
  1751. }
  1752. else
  1753. return hr;
  1754. }
  1755. HRESULT CSpoolerEngine::_HrGoIdle(void)
  1756. {
  1757. EnterCriticalSection(&m_cs);
  1758. // We need to hangup every time to be compatible with OE4. Bug# 75222
  1759. if (m_fRasSpooled && g_pConMan)
  1760. {
  1761. if (!!DwGetOption(OPT_DIALUP_HANGUP_DONE))
  1762. {
  1763. g_pConMan->Disconnect(m_hwndUI, FALSE, FALSE, FALSE);
  1764. }
  1765. }
  1766. // Check to see if we need to go offline now
  1767. // I'm disabling this for bug #17578.
  1768. if (m_fOfflineWhenDone)
  1769. {
  1770. g_pConMan->SetGlobalOffline(TRUE);
  1771. m_fOfflineWhenDone = FALSE;
  1772. }
  1773. // Tell the UI to idle
  1774. if (ISFLAGSET(m_dwState, SPSTATE_CANCEL))
  1775. m_pUI->GoIdle(m_dwState, ISFLAGSET(m_dwState, SPSTATE_SHUTDOWN), FALSE);
  1776. else
  1777. m_pUI->GoIdle(m_rEventTable.cSucceeded != m_rEventTable.cEvents, ISFLAGSET(m_dwState, SPSTATE_SHUTDOWN),
  1778. m_fNoSyncEvent && 0 == (m_dwFlags & DELIVER_BACKGROUND));
  1779. // If we're running background and there was errors, then we should show the UI
  1780. if (m_dwFlags & DELIVER_BACKGROUND && !(m_dwFlags & DELIVER_NOUI) &&
  1781. m_rEventTable.cSucceeded != m_rEventTable.cEvents)
  1782. {
  1783. m_pUI->ShowWindow(SW_SHOW);
  1784. SetForegroundWindow(m_hwndUI);
  1785. }
  1786. // Free the event table
  1787. for (UINT i = 0; i < m_rEventTable.cEvents; i++)
  1788. {
  1789. SafeRelease(m_rEventTable.prgEvents[i].pSpoolerTask);
  1790. SafeRelease(m_rEventTable.prgEvents[i].pAccount);
  1791. }
  1792. SafeMemFree(m_rEventTable.prgEvents);
  1793. ZeroMemory(&m_rEventTable, sizeof(SPOOLEREVENTTABLE));
  1794. // Leave the busy state
  1795. FLAGCLEAR(m_dwState, SPSTATE_CANCEL);
  1796. FLAGCLEAR(m_dwState, SPSTATE_BUSY);
  1797. // Notify
  1798. Notify(DELIVERY_NOTIFY_ALLDONE, 0);
  1799. // Is Something Queued, and the current poll was a success ?
  1800. if (!ISFLAGSET(m_dwState, SPSTATE_SHUTDOWN))
  1801. {
  1802. if (m_rEventTable.cSucceeded == m_rEventTable.cEvents && m_dwQueued)
  1803. StartDelivery(NULL, NULL, FOLDERID_INVALID, m_dwQueued);
  1804. else
  1805. _StartPolling();
  1806. }
  1807. // Nothing is queued now
  1808. m_dwQueued = 0;
  1809. // Thread Safety
  1810. LeaveCriticalSection(&m_cs);
  1811. // Added Bug# 62129 (v-snatar)
  1812. SetEvent(hSmapiEvent);
  1813. return (S_OK);
  1814. }
  1815. // ------------------------------------------------------------------------------------
  1816. // CSpoolerEngine::_DoBackgroundPoll
  1817. // ------------------------------------------------------------------------------------
  1818. void CSpoolerEngine::_DoBackgroundPoll(void)
  1819. {
  1820. BOOL fFound = FALSE;
  1821. ULONG i;
  1822. DWORD dw;
  1823. DWORD dwFlags = 0;
  1824. dw = DwGetOption(OPT_DIAL_DURING_POLL);
  1825. switch (dw)
  1826. {
  1827. case DIAL_ALWAYS:
  1828. {
  1829. //connect always
  1830. if (g_pConMan && g_pConMan->IsGlobalOffline())
  1831. {
  1832. g_pConMan->SetGlobalOffline(FALSE);
  1833. m_fOfflineWhenDone = TRUE;
  1834. }
  1835. dwFlags = DELIVER_BACKGROUND_POLL_DIAL_ALWAYS;
  1836. break;
  1837. }
  1838. case DIAL_IF_NOT_OFFLINE:
  1839. case DO_NOT_DIAL:
  1840. {
  1841. if (g_pConMan && g_pConMan->IsGlobalOffline())
  1842. {
  1843. _StartPolling();
  1844. return;
  1845. }
  1846. if (dw == DIAL_IF_NOT_OFFLINE)
  1847. {
  1848. dwFlags = DELIVER_BACKGROUND_POLL_DIAL;
  1849. }
  1850. else
  1851. {
  1852. dwFlags = DELIVER_BACKGROUND_POLL;
  1853. }
  1854. break;
  1855. }
  1856. default:
  1857. dwFlags = DELIVER_BACKGROUND_POLL_DIAL_ALWAYS;
  1858. }
  1859. //We need this flag to tell the spooler that this polling is triggered by the timer.
  1860. //In this case the spooler hangs up the phone if it dialed, irrespective of the option OPT_HANGUP_WHEN_DONE
  1861. dwFlags |= DELIVER_AT_INTERVALS | DELIVER_OFFLINE_FLAGS;
  1862. // Same thread we were created on...
  1863. Assert(ISSPOOLERTHREAD);
  1864. EnterCriticalSection(&m_cs);
  1865. // Are there any registered views...
  1866. for (i = 0; i < m_rViewRegister.cViewAlloc; i++)
  1867. {
  1868. // Is there a view handle
  1869. if (m_rViewRegister.rghwndView[i] && IsWindow(m_rViewRegister.rghwndView[i]))
  1870. {
  1871. fFound=TRUE;
  1872. break;
  1873. }
  1874. }
  1875. LeaveCriticalSection(&m_cs);
  1876. // If at least one view is registered we poll, otherwise we wait
  1877. if (fFound)
  1878. {
  1879. StartDelivery(NULL, NULL, FOLDERID_INVALID, dwFlags);
  1880. }
  1881. else
  1882. m_fBackgroundPollPending = TRUE;
  1883. }
  1884. void CSpoolerEngine::_StartPolling(void)
  1885. {
  1886. DWORD dw = DwGetOption(OPT_POLLFORMSGS);
  1887. if (dw != OPTION_OFF)
  1888. {
  1889. KillTimer(m_hwndUI, IMAIL_POOLFORMAIL);
  1890. SetTimer(m_hwndUI, IMAIL_POOLFORMAIL, dw, NULL);
  1891. }
  1892. }
  1893. void CSpoolerEngine::_StopPolling(void)
  1894. {
  1895. KillTimer(m_hwndUI, IMAIL_POOLFORMAIL);
  1896. }
  1897. STDMETHODIMP CSpoolerEngine::OnUIChange(BOOL fVisible)
  1898. {
  1899. EnterCriticalSection(&m_cs);
  1900. // Check to see if we need to notify the tasks
  1901. if (ISFLAGSET(m_dwState, SPSTATE_BUSY))
  1902. {
  1903. // Check to see if our flags are up to date
  1904. if (fVisible)
  1905. {
  1906. FLAGCLEAR(m_dwFlags, DELIVER_NOUI);
  1907. FLAGCLEAR(m_dwFlags, DELIVER_BACKGROUND);
  1908. }
  1909. else
  1910. {
  1911. FLAGSET(m_dwFlags, DELIVER_BACKGROUND);
  1912. }
  1913. for (UINT i = m_cCurEvent; i < m_rEventTable.cEvents; i++)
  1914. {
  1915. if (m_rEventTable.prgEvents[i].pSpoolerTask)
  1916. {
  1917. m_rEventTable.prgEvents[i].pSpoolerTask->OnFlagsChanged(m_dwFlags);
  1918. }
  1919. }
  1920. }
  1921. LeaveCriticalSection(&m_cs);
  1922. return (S_OK);
  1923. }
  1924. STDMETHODIMP CSpoolerEngine::OnConnectionNotify(CONNNOTIFY nCode, LPVOID pvData,
  1925. CConnectionManager *pConMan)
  1926. {
  1927. // If we're not busy, and the user has background polling turned on, then
  1928. // we should fire a poll right now
  1929. /* Bug# 75222
  1930. if (nCode == CONNNOTIFY_CONNECTED && OPTION_OFF != DwGetOption(OPT_POLLFORMSGS))
  1931. {
  1932. if (!ISFLAGSET(m_dwState, SPSTATE_BUSY))
  1933. {
  1934. SendMessage(m_hwndUI, WM_TIMER, IMAIL_POOLFORMAIL, 0);
  1935. }
  1936. }
  1937. */
  1938. // If the user just chose "Work Offline", then we cancel anything that's in progress
  1939. if (nCode == CONNNOTIFY_WORKOFFLINE && !!pvData)
  1940. {
  1941. if (ISFLAGSET(m_dwState, SPSTATE_BUSY))
  1942. {
  1943. Cancel();
  1944. }
  1945. }
  1946. return (S_OK);
  1947. }