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.

499 lines
16 KiB

  1. //***************************************************************************
  2. // IMAP4 Spooler Task Object
  3. // Written by Raymond Cheng, 6/27/97
  4. //***************************************************************************
  5. //---------------------------------------------------------------------------
  6. // Includes
  7. //---------------------------------------------------------------------------
  8. #include "pch.hxx"
  9. #include "resource.h"
  10. #include "imaptask.h"
  11. #include "imnact.h"
  12. #include "conman.h"
  13. #include "imapfmgr.h"
  14. #include "thormsgs.h"
  15. #include "imaputil.h"
  16. #include "xpcomm.h"
  17. #include "ourguid.h"
  18. //---------------------------------------------------------------------------
  19. // Functions
  20. //---------------------------------------------------------------------------
  21. //***************************************************************************
  22. // Function: CIMAPTask (Constructor)
  23. //***************************************************************************
  24. CIMAPTask::CIMAPTask(void)
  25. {
  26. m_lRefCount = 1;
  27. m_pBindContext = NULL;
  28. m_pSpoolerUI = NULL;
  29. m_szAccountName[0] = '\0';
  30. m_pszFolder = NULL;
  31. m_pIMAPFolderMgr = NULL;
  32. m_hwnd = NULL;
  33. m_CurrentEID = 0;
  34. m_fFailuresEncountered = FALSE;
  35. m_dwTotalTicks = 0;
  36. m_dwFlags = 0;
  37. } // CIMAPTask (constructor)
  38. //***************************************************************************
  39. // Function: ~CIMAPTask (Destructor)
  40. //***************************************************************************
  41. CIMAPTask::~CIMAPTask(void)
  42. {
  43. if (NULL != m_pIMAPFolderMgr) {
  44. m_pIMAPFolderMgr->Close();
  45. m_pIMAPFolderMgr->Release();
  46. }
  47. if (NULL != m_pSpoolerUI)
  48. m_pSpoolerUI->Release();
  49. if (NULL != m_pBindContext)
  50. m_pBindContext->Release();
  51. if (NULL != m_hwnd)
  52. DestroyWindow(m_hwnd);
  53. } // ~CIMAPTask (destructor)
  54. //***************************************************************************
  55. // Function: QueryInterface
  56. //
  57. // Purpose:
  58. // Read the Win32SDK OLE Programming References (Interfaces) about the
  59. // IUnknown::QueryInterface function for details. This function returns a
  60. // pointer to the requested interface.
  61. //
  62. // Arguments:
  63. // REFIID iid [in] - an IID identifying the interface to return.
  64. // void **ppvObject [out] - if successful, this function returns a pointer
  65. // to the requested interface in this argument.
  66. //
  67. // Returns:
  68. // HRESULT indicating success or failure.
  69. //***************************************************************************
  70. HRESULT STDMETHODCALLTYPE CIMAPTask::QueryInterface(REFIID iid, void **ppvObject)
  71. {
  72. HRESULT hrResult;
  73. Assert(m_lRefCount > 0);
  74. Assert(NULL != ppvObject);
  75. // Init variables, arguments
  76. hrResult = E_NOINTERFACE;
  77. if (NULL == ppvObject)
  78. goto exit;
  79. *ppvObject = NULL;
  80. // Find a ptr to the interface
  81. if (IID_IUnknown == iid) {
  82. *ppvObject = (IUnknown *) this;
  83. ((IUnknown *) this)->AddRef();
  84. }
  85. if (IID_ISpoolerTask == iid) {
  86. *ppvObject = (ISpoolerTask *) this;
  87. ((ISpoolerTask *) this)->AddRef();
  88. }
  89. // If we returned an interface, return success
  90. if (NULL != *ppvObject)
  91. hrResult = S_OK;
  92. exit:
  93. return hrResult;
  94. } // QueryInterface
  95. //***************************************************************************
  96. // Function: AddRef
  97. //
  98. // Purpose:
  99. // This function should be called whenever someone makes a copy of a
  100. // pointer to this object. It bumps the reference count so that we know
  101. // there is one more pointer to this object, and thus we need one more
  102. // release before we delete ourselves.
  103. //
  104. // Returns:
  105. // A ULONG representing the current reference count. Although technically
  106. // our reference count is signed, we should never return a negative number,
  107. // anyways.
  108. //***************************************************************************
  109. ULONG STDMETHODCALLTYPE CIMAPTask::AddRef(void)
  110. {
  111. Assert(m_lRefCount > 0);
  112. m_lRefCount += 1;
  113. DOUT ("CIMAPTask::AddRef, returned Ref Count=%ld", m_lRefCount);
  114. return m_lRefCount;
  115. } // AddRef
  116. //***************************************************************************
  117. // Function: Release
  118. //
  119. // Purpose:
  120. // This function should be called when a pointer to this object is to
  121. // go out of commission. It knocks the reference count down by one, and
  122. // automatically deletes the object if we see that nobody has a pointer
  123. // to this object.
  124. //
  125. // Returns:
  126. // A ULONG representing the current reference count. Although technically
  127. // our reference count is signed, we should never return a negative number,
  128. // anyways.
  129. //***************************************************************************
  130. ULONG STDMETHODCALLTYPE CIMAPTask::Release(void)
  131. {
  132. Assert(m_lRefCount > 0);
  133. m_lRefCount -= 1;
  134. DOUT("CIMAPTask::Release, returned Ref Count = %ld", m_lRefCount);
  135. if (0 == m_lRefCount) {
  136. delete this;
  137. return 0;
  138. }
  139. else
  140. return m_lRefCount;
  141. } // Release
  142. static const char c_szIMAPTask[] = "IMAP Task";
  143. //***************************************************************************
  144. // Function: Init
  145. // Purpose: ISpoolerTask implementation.
  146. //***************************************************************************
  147. HRESULT STDMETHODCALLTYPE CIMAPTask::Init(DWORD dwFlags,
  148. ISpoolerBindContext *pBindCtx)
  149. {
  150. WNDCLASSEX wc;
  151. HRESULT hrResult;
  152. Assert(m_lRefCount > 0);
  153. Assert(NULL != pBindCtx);
  154. // Initialize variables
  155. hrResult = S_OK;
  156. // Save pBindCtx to module var
  157. m_pBindContext = pBindCtx;
  158. pBindCtx->AddRef();
  159. m_dwFlags = dwFlags;
  160. // Create a hidden window to process WM_IMAP_* messages
  161. wc.cbSize = sizeof(WNDCLASSEX);
  162. if (!GetClassInfoEx(g_hInst, c_szIMAPTask, &wc)) {
  163. wc.style = 0;
  164. wc.lpfnWndProc = IMAPTaskWndProc;
  165. wc.cbClsExtra = 0;
  166. wc.cbWndExtra = 0;
  167. wc.hInstance = g_hInst;
  168. wc.hCursor = NULL;
  169. wc.hbrBackground = (HBRUSH) (COLOR_3DFACE + 1);
  170. wc.lpszMenuName = NULL;
  171. wc.lpszClassName = c_szIMAPTask;
  172. wc.hIcon = NULL;
  173. wc.hIconSm = NULL;
  174. RegisterClassEx(&wc);
  175. }
  176. m_hwnd = CreateWindow(c_szIMAPTask, NULL, WS_POPUP, 10, 10, 10, 10,
  177. GetDesktopWindow(), NULL, g_hInst, this);
  178. if (NULL == m_hwnd) {
  179. hrResult = E_OUTOFMEMORY;
  180. goto exit;
  181. }
  182. exit:
  183. return hrResult;
  184. } // Init
  185. //***************************************************************************
  186. // Function: BuildEvents
  187. // Purpose: ISpoolerTask implementation.
  188. // Arguments:
  189. // LPCTSTR pszFolder [in] - currently this argument is taken to mean the
  190. // currently selected IMAP folder. Set this argument to NULL if no
  191. // IMAP folder is currently selected. This argument is used to avoid
  192. // polling the currently selected folder for its unread count.
  193. //***************************************************************************
  194. HRESULT STDMETHODCALLTYPE CIMAPTask::BuildEvents(ISpoolerUI *pSpoolerUI,
  195. IImnAccount *pAccount,
  196. LPCTSTR pszFolder)
  197. {
  198. HRESULT hrResult;
  199. char szFmt[CCHMAX_STRINGRES], szEventDescription[CCHMAX_STRINGRES];
  200. EVENTID eidThrowaway;
  201. Assert(m_lRefCount > 0);
  202. Assert(NULL != pSpoolerUI);
  203. Assert(NULL != pAccount);
  204. // Copy spooler UI pointer
  205. m_pSpoolerUI = pSpoolerUI;
  206. pSpoolerUI->AddRef();
  207. // Find and save account name
  208. hrResult = pAccount->GetPropSz(AP_ACCOUNT_NAME, m_szAccountName,
  209. sizeof(m_szAccountName));
  210. if (FAILED(hrResult))
  211. goto exit;
  212. // Keep ptr to current folder name (we want to SKIP it during unread poll!)
  213. m_pszFolder = pszFolder;
  214. #ifndef WIN16 // No RAS support in Win16
  215. // Create and initialize CIMAPFolderMgr to poll unread
  216. hrResult = g_pConMan->CanConnect(m_szAccountName);
  217. if (FAILED(hrResult))
  218. goto exit;
  219. #endif
  220. m_pIMAPFolderMgr = new CIMAPFolderMgr(m_hwnd);
  221. if (NULL == m_pIMAPFolderMgr) {
  222. hrResult = E_OUTOFMEMORY;
  223. goto exit;
  224. }
  225. hrResult = m_pIMAPFolderMgr->HrInit(m_szAccountName, 'i', fCREATE_FLDR_CACHE);
  226. if (FAILED(hrResult))
  227. goto exit;
  228. m_pIMAPFolderMgr->SetOnlineOperation(TRUE);
  229. m_pIMAPFolderMgr->SetUIMode(!(m_dwFlags & DELIVER_BACKGROUND));
  230. // This CIMAPFolderMgr is ready. Register our one and only event
  231. LoadString(g_hLocRes, IDS_SPS_POP3CHECKING, szFmt, ARRAYSIZE(szFmt));
  232. wnsprintf(szEventDescription, ARRAYSIZE(szEventDescription), szFmt, m_szAccountName);
  233. hrResult = m_pBindContext->RegisterEvent(szEventDescription, this, NULL,
  234. pAccount, &eidThrowaway);
  235. if (SUCCEEDED(hrResult))
  236. TaskUtil_CheckForPasswordPrompt(pAccount, SRV_IMAP, m_pSpoolerUI);
  237. exit:
  238. return hrResult;
  239. } // BuildEvents
  240. //***************************************************************************
  241. // Function: Execute
  242. // Purpose: ISpoolerTask implementation.
  243. //***************************************************************************
  244. HRESULT STDMETHODCALLTYPE CIMAPTask::Execute(EVENTID eid, DWORD dwTwinkie)
  245. {
  246. HRESULT hrResult;
  247. char szFmt[CCHMAX_STRINGRES], szBuf[CCHMAX_STRINGRES];
  248. Assert(m_lRefCount > 0);
  249. Assert(NULL == dwTwinkie); // I'm not currently using this
  250. // Initialize progress indication
  251. m_pSpoolerUI->SetProgressRange(1);
  252. LoadString(g_hLocRes, IDS_SPS_POP3CHECKING, szFmt, ARRAYSIZE(szFmt));
  253. wnsprintf(szBuf, ARRAYSIZE(szBuf), szFmt, m_szAccountName);
  254. m_pSpoolerUI->SetGeneralProgress(szBuf);
  255. m_pSpoolerUI->SetAnimation(idanDownloadNews, TRUE);
  256. // Start the unread count poll
  257. Assert(NULL != m_pIMAPFolderMgr);
  258. hrResult = m_pIMAPFolderMgr->PollUnreadCounts(m_hwnd, m_pszFolder);
  259. if (FAILED(hrResult))
  260. goto exit;
  261. m_CurrentEID = eid;
  262. exit:
  263. return hrResult;
  264. } // Execute
  265. //***************************************************************************
  266. // Function: ShowProperties
  267. // Purpose: ISpoolerTask implementation.
  268. //***************************************************************************
  269. HRESULT STDMETHODCALLTYPE CIMAPTask::ShowProperties(HWND hwndParent,
  270. EVENTID eid,
  271. DWORD dwTwinkie)
  272. {
  273. Assert(m_lRefCount > 0);
  274. return E_NOTIMPL;
  275. } // ShowProperties
  276. //***************************************************************************
  277. // Function: GetExtendedDetails
  278. // Purpose: ISpoolerTask implementation.
  279. //***************************************************************************
  280. HRESULT STDMETHODCALLTYPE CIMAPTask::GetExtendedDetails(EVENTID eid,
  281. DWORD dwTwinkie,
  282. LPSTR *ppszDetails)
  283. {
  284. Assert(m_lRefCount > 0);
  285. return E_NOTIMPL;
  286. } // GetExtendedDetails
  287. //***************************************************************************
  288. // Function: Cancel
  289. // Purpose: ISpoolerTask implementation.
  290. //***************************************************************************
  291. HRESULT STDMETHODCALLTYPE CIMAPTask::Cancel(void)
  292. {
  293. Assert(m_lRefCount > 0);
  294. return m_pIMAPFolderMgr->Disconnect();
  295. } // Cancel
  296. //***************************************************************************
  297. // Function: IsDialogMessage
  298. // Purpose: ISpoolerTask implementation.
  299. //***************************************************************************
  300. HRESULT STDMETHODCALLTYPE CIMAPTask::IsDialogMessage(LPMSG pMsg)
  301. {
  302. Assert(m_lRefCount > 0);
  303. return S_FALSE;
  304. } // IsDialogMessage
  305. //***************************************************************************
  306. // Function: OnFlagsChanged
  307. // Purpose: ISpoolerTask implementation.
  308. //***************************************************************************
  309. HRESULT STDMETHODCALLTYPE CIMAPTask::OnFlagsChanged(DWORD dwFlags)
  310. {
  311. Assert(m_lRefCount > 0);
  312. m_dwFlags = dwFlags;
  313. if (m_pIMAPFolderMgr)
  314. m_pIMAPFolderMgr->SetUIMode(!(m_dwFlags & DELIVER_BACKGROUND));
  315. return S_OK;
  316. } // OnFlagsChanged
  317. //***************************************************************************
  318. // Function: IMAPTaskWndProc
  319. //
  320. // Purpose:
  321. // This function handles WM_IMAP_* messages which result from polling for
  322. // unread counts on the IMAP server. The various WM_IMAP_* messages are
  323. // translated into spooler UI events to inform the user of the progress of
  324. // the operation.
  325. //***************************************************************************
  326. LRESULT CALLBACK CIMAPTask::IMAPTaskWndProc(HWND hwnd, UINT uMsg,
  327. WPARAM wParam, LPARAM lParam)
  328. {
  329. CIMAPTask *pThis = (CIMAPTask *) GetProp(hwnd, _T("this"));
  330. switch (uMsg) {
  331. case WM_CREATE:
  332. pThis = (CIMAPTask *) ((LPCREATESTRUCT)lParam)->lpCreateParams;
  333. SetProp(hwnd, _T("this"), (LPVOID) pThis);
  334. return 0;
  335. case WM_IMAP_ERROR: {
  336. HRESULT hrResult;
  337. LPSTR pszErrorStr;
  338. pThis->m_fFailuresEncountered = TRUE;
  339. hrResult = ImapUtil_WMIMAPERRORToString(lParam, &pszErrorStr, NULL);
  340. if (FAILED(hrResult)) {
  341. AssertSz(FALSE, "Could not construct full error str for WM_IMAP_ERROR");
  342. pThis->m_pSpoolerUI->InsertError(pThis->m_CurrentEID,
  343. ((INETMAILERROR *)lParam)->pszMessage);
  344. }
  345. else {
  346. pThis->m_pSpoolerUI->InsertError(pThis->m_CurrentEID,
  347. pszErrorStr);
  348. MemFree(pszErrorStr);
  349. }
  350. return 0;
  351. } // case WM_IMAP_ERROR
  352. case WM_IMAP_SIMPLEERROR: {
  353. char sz[CCHMAX_STRINGRES];
  354. pThis->m_fFailuresEncountered = TRUE;
  355. Assert(0 == HIWORD(lParam)); // Can't handle two text strings
  356. LoadString(g_hLocRes, LOWORD(lParam), sz, ARRAYSIZE(sz));
  357. pThis->m_pSpoolerUI->InsertError(pThis->m_CurrentEID, sz);
  358. } // case WM_IMAP_SIMPLEERROR
  359. return 0;
  360. case WM_IMAP_POLLUNREAD_DONE: {
  361. HRESULT hrResult;
  362. EVENTCOMPLETEDSTATUS ecs;
  363. Assert((0 == wParam || 1 == wParam) && 0 == lParam);
  364. ecs = EVENT_SUCCEEDED; // Let's be optimistic
  365. if (pThis->m_fFailuresEncountered) {
  366. char sz[CCHMAX_STRINGRES], szFmt[CCHMAX_STRINGRES];
  367. LoadString(g_hLocRes, idsIMAPPollUnreadFailuresFmt, szFmt, ARRAYSIZE(szFmt));
  368. wnsprintf(sz, ARRAYSIZE(sz), szFmt, pThis->m_szAccountName);
  369. pThis->m_pSpoolerUI->InsertError(pThis->m_CurrentEID, sz);
  370. ecs = EVENT_WARNINGS;
  371. }
  372. if (0 == wParam)
  373. ecs = EVENT_FAILED;
  374. hrResult = pThis->m_pBindContext->EventDone(pThis->m_CurrentEID, ecs);
  375. Assert(SUCCEEDED(hrResult));
  376. return 0;
  377. } // case WM_IMAP_POLLUNREAD_DONE
  378. case WM_IMAP_POLLUNREAD_TICK:
  379. Assert(0 == lParam);
  380. if (0 == wParam)
  381. pThis->m_fFailuresEncountered = TRUE;
  382. else if (1 == wParam) {
  383. char sz[CCHMAX_STRINGRES], szFmt[CCHMAX_STRINGRES];
  384. LoadString(g_hLocRes, idsIMAPPollUnreadIMAP4Fmt, szFmt, ARRAYSIZE(szFmt));
  385. wnsprintf(sz, ARRAYSIZE(sz), szFmt, pThis->m_szAccountName);
  386. pThis->m_fFailuresEncountered = TRUE;
  387. pThis->m_pSpoolerUI->InsertError(pThis->m_CurrentEID, sz);
  388. }
  389. else {
  390. Assert(2 == wParam);
  391. if (pThis->m_dwTotalTicks > 0)
  392. pThis->m_pSpoolerUI->IncrementProgress(1);
  393. }
  394. return 0;
  395. case WM_IMAP_POLLUNREAD_TOTAL:
  396. Assert(0 == lParam);
  397. pThis->m_dwTotalTicks = wParam;
  398. pThis->m_pSpoolerUI->SetProgressRange(wParam);
  399. return 0;
  400. } // switch (uMsg)
  401. // If we reached this point, we didn't process the msg: DefWindowProc it
  402. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  403. } // IMAPTaskWndProc