//*************************************************************************** // IMAP4 Spooler Task Object // Written by Raymond Cheng, 6/27/97 //*************************************************************************** //--------------------------------------------------------------------------- // Includes //--------------------------------------------------------------------------- #include "pch.hxx" #include "resource.h" #include "imaptask.h" #include "imnact.h" #include "conman.h" #include "imapfmgr.h" #include "thormsgs.h" #include "imaputil.h" #include "xpcomm.h" #include "ourguid.h" //--------------------------------------------------------------------------- // Functions //--------------------------------------------------------------------------- //*************************************************************************** // Function: CIMAPTask (Constructor) //*************************************************************************** CIMAPTask::CIMAPTask(void) { m_lRefCount = 1; m_pBindContext = NULL; m_pSpoolerUI = NULL; m_szAccountName[0] = '\0'; m_pszFolder = NULL; m_pIMAPFolderMgr = NULL; m_hwnd = NULL; m_CurrentEID = 0; m_fFailuresEncountered = FALSE; m_dwTotalTicks = 0; m_dwFlags = 0; } // CIMAPTask (constructor) //*************************************************************************** // Function: ~CIMAPTask (Destructor) //*************************************************************************** CIMAPTask::~CIMAPTask(void) { if (NULL != m_pIMAPFolderMgr) { m_pIMAPFolderMgr->Close(); m_pIMAPFolderMgr->Release(); } if (NULL != m_pSpoolerUI) m_pSpoolerUI->Release(); if (NULL != m_pBindContext) m_pBindContext->Release(); if (NULL != m_hwnd) DestroyWindow(m_hwnd); } // ~CIMAPTask (destructor) //*************************************************************************** // Function: QueryInterface // // Purpose: // Read the Win32SDK OLE Programming References (Interfaces) about the // IUnknown::QueryInterface function for details. This function returns a // pointer to the requested interface. // // Arguments: // REFIID iid [in] - an IID identifying the interface to return. // void **ppvObject [out] - if successful, this function returns a pointer // to the requested interface in this argument. // // Returns: // HRESULT indicating success or failure. //*************************************************************************** HRESULT STDMETHODCALLTYPE CIMAPTask::QueryInterface(REFIID iid, void **ppvObject) { HRESULT hrResult; Assert(m_lRefCount > 0); Assert(NULL != ppvObject); // Init variables, arguments hrResult = E_NOINTERFACE; if (NULL == ppvObject) goto exit; *ppvObject = NULL; // Find a ptr to the interface if (IID_IUnknown == iid) { *ppvObject = (IUnknown *) this; ((IUnknown *) this)->AddRef(); } if (IID_ISpoolerTask == iid) { *ppvObject = (ISpoolerTask *) this; ((ISpoolerTask *) this)->AddRef(); } // If we returned an interface, return success if (NULL != *ppvObject) hrResult = S_OK; exit: return hrResult; } // QueryInterface //*************************************************************************** // Function: AddRef // // Purpose: // This function should be called whenever someone makes a copy of a // pointer to this object. It bumps the reference count so that we know // there is one more pointer to this object, and thus we need one more // release before we delete ourselves. // // Returns: // A ULONG representing the current reference count. Although technically // our reference count is signed, we should never return a negative number, // anyways. //*************************************************************************** ULONG STDMETHODCALLTYPE CIMAPTask::AddRef(void) { Assert(m_lRefCount > 0); m_lRefCount += 1; DOUT ("CIMAPTask::AddRef, returned Ref Count=%ld", m_lRefCount); return m_lRefCount; } // AddRef //*************************************************************************** // Function: Release // // Purpose: // This function should be called when a pointer to this object is to // go out of commission. It knocks the reference count down by one, and // automatically deletes the object if we see that nobody has a pointer // to this object. // // Returns: // A ULONG representing the current reference count. Although technically // our reference count is signed, we should never return a negative number, // anyways. //*************************************************************************** ULONG STDMETHODCALLTYPE CIMAPTask::Release(void) { Assert(m_lRefCount > 0); m_lRefCount -= 1; DOUT("CIMAPTask::Release, returned Ref Count = %ld", m_lRefCount); if (0 == m_lRefCount) { delete this; return 0; } else return m_lRefCount; } // Release static const char c_szIMAPTask[] = "IMAP Task"; //*************************************************************************** // Function: Init // Purpose: ISpoolerTask implementation. //*************************************************************************** HRESULT STDMETHODCALLTYPE CIMAPTask::Init(DWORD dwFlags, ISpoolerBindContext *pBindCtx) { WNDCLASSEX wc; HRESULT hrResult; Assert(m_lRefCount > 0); Assert(NULL != pBindCtx); // Initialize variables hrResult = S_OK; // Save pBindCtx to module var m_pBindContext = pBindCtx; pBindCtx->AddRef(); m_dwFlags = dwFlags; // Create a hidden window to process WM_IMAP_* messages wc.cbSize = sizeof(WNDCLASSEX); if (!GetClassInfoEx(g_hInst, c_szIMAPTask, &wc)) { wc.style = 0; wc.lpfnWndProc = IMAPTaskWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = g_hInst; wc.hCursor = NULL; wc.hbrBackground = (HBRUSH) (COLOR_3DFACE + 1); wc.lpszMenuName = NULL; wc.lpszClassName = c_szIMAPTask; wc.hIcon = NULL; wc.hIconSm = NULL; RegisterClassEx(&wc); } m_hwnd = CreateWindow(c_szIMAPTask, NULL, WS_POPUP, 10, 10, 10, 10, GetDesktopWindow(), NULL, g_hInst, this); if (NULL == m_hwnd) { hrResult = E_OUTOFMEMORY; goto exit; } exit: return hrResult; } // Init //*************************************************************************** // Function: BuildEvents // Purpose: ISpoolerTask implementation. // Arguments: // LPCTSTR pszFolder [in] - currently this argument is taken to mean the // currently selected IMAP folder. Set this argument to NULL if no // IMAP folder is currently selected. This argument is used to avoid // polling the currently selected folder for its unread count. //*************************************************************************** HRESULT STDMETHODCALLTYPE CIMAPTask::BuildEvents(ISpoolerUI *pSpoolerUI, IImnAccount *pAccount, LPCTSTR pszFolder) { HRESULT hrResult; char szFmt[CCHMAX_STRINGRES], szEventDescription[CCHMAX_STRINGRES]; EVENTID eidThrowaway; Assert(m_lRefCount > 0); Assert(NULL != pSpoolerUI); Assert(NULL != pAccount); // Copy spooler UI pointer m_pSpoolerUI = pSpoolerUI; pSpoolerUI->AddRef(); // Find and save account name hrResult = pAccount->GetPropSz(AP_ACCOUNT_NAME, m_szAccountName, sizeof(m_szAccountName)); if (FAILED(hrResult)) goto exit; // Keep ptr to current folder name (we want to SKIP it during unread poll!) m_pszFolder = pszFolder; #ifndef WIN16 // No RAS support in Win16 // Create and initialize CIMAPFolderMgr to poll unread hrResult = g_pConMan->CanConnect(m_szAccountName); if (FAILED(hrResult)) goto exit; #endif m_pIMAPFolderMgr = new CIMAPFolderMgr(m_hwnd); if (NULL == m_pIMAPFolderMgr) { hrResult = E_OUTOFMEMORY; goto exit; } hrResult = m_pIMAPFolderMgr->HrInit(m_szAccountName, 'i', fCREATE_FLDR_CACHE); if (FAILED(hrResult)) goto exit; m_pIMAPFolderMgr->SetOnlineOperation(TRUE); m_pIMAPFolderMgr->SetUIMode(!(m_dwFlags & DELIVER_BACKGROUND)); // This CIMAPFolderMgr is ready. Register our one and only event LoadString(g_hLocRes, IDS_SPS_POP3CHECKING, szFmt, ARRAYSIZE(szFmt)); wnsprintf(szEventDescription, ARRAYSIZE(szEventDescription), szFmt, m_szAccountName); hrResult = m_pBindContext->RegisterEvent(szEventDescription, this, NULL, pAccount, &eidThrowaway); if (SUCCEEDED(hrResult)) TaskUtil_CheckForPasswordPrompt(pAccount, SRV_IMAP, m_pSpoolerUI); exit: return hrResult; } // BuildEvents //*************************************************************************** // Function: Execute // Purpose: ISpoolerTask implementation. //*************************************************************************** HRESULT STDMETHODCALLTYPE CIMAPTask::Execute(EVENTID eid, DWORD dwTwinkie) { HRESULT hrResult; char szFmt[CCHMAX_STRINGRES], szBuf[CCHMAX_STRINGRES]; Assert(m_lRefCount > 0); Assert(NULL == dwTwinkie); // I'm not currently using this // Initialize progress indication m_pSpoolerUI->SetProgressRange(1); LoadString(g_hLocRes, IDS_SPS_POP3CHECKING, szFmt, ARRAYSIZE(szFmt)); wnsprintf(szBuf, ARRAYSIZE(szBuf), szFmt, m_szAccountName); m_pSpoolerUI->SetGeneralProgress(szBuf); m_pSpoolerUI->SetAnimation(idanDownloadNews, TRUE); // Start the unread count poll Assert(NULL != m_pIMAPFolderMgr); hrResult = m_pIMAPFolderMgr->PollUnreadCounts(m_hwnd, m_pszFolder); if (FAILED(hrResult)) goto exit; m_CurrentEID = eid; exit: return hrResult; } // Execute //*************************************************************************** // Function: ShowProperties // Purpose: ISpoolerTask implementation. //*************************************************************************** HRESULT STDMETHODCALLTYPE CIMAPTask::ShowProperties(HWND hwndParent, EVENTID eid, DWORD dwTwinkie) { Assert(m_lRefCount > 0); return E_NOTIMPL; } // ShowProperties //*************************************************************************** // Function: GetExtendedDetails // Purpose: ISpoolerTask implementation. //*************************************************************************** HRESULT STDMETHODCALLTYPE CIMAPTask::GetExtendedDetails(EVENTID eid, DWORD dwTwinkie, LPSTR *ppszDetails) { Assert(m_lRefCount > 0); return E_NOTIMPL; } // GetExtendedDetails //*************************************************************************** // Function: Cancel // Purpose: ISpoolerTask implementation. //*************************************************************************** HRESULT STDMETHODCALLTYPE CIMAPTask::Cancel(void) { Assert(m_lRefCount > 0); return m_pIMAPFolderMgr->Disconnect(); } // Cancel //*************************************************************************** // Function: IsDialogMessage // Purpose: ISpoolerTask implementation. //*************************************************************************** HRESULT STDMETHODCALLTYPE CIMAPTask::IsDialogMessage(LPMSG pMsg) { Assert(m_lRefCount > 0); return S_FALSE; } // IsDialogMessage //*************************************************************************** // Function: OnFlagsChanged // Purpose: ISpoolerTask implementation. //*************************************************************************** HRESULT STDMETHODCALLTYPE CIMAPTask::OnFlagsChanged(DWORD dwFlags) { Assert(m_lRefCount > 0); m_dwFlags = dwFlags; if (m_pIMAPFolderMgr) m_pIMAPFolderMgr->SetUIMode(!(m_dwFlags & DELIVER_BACKGROUND)); return S_OK; } // OnFlagsChanged //*************************************************************************** // Function: IMAPTaskWndProc // // Purpose: // This function handles WM_IMAP_* messages which result from polling for // unread counts on the IMAP server. The various WM_IMAP_* messages are // translated into spooler UI events to inform the user of the progress of // the operation. //*************************************************************************** LRESULT CALLBACK CIMAPTask::IMAPTaskWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CIMAPTask *pThis = (CIMAPTask *) GetProp(hwnd, _T("this")); switch (uMsg) { case WM_CREATE: pThis = (CIMAPTask *) ((LPCREATESTRUCT)lParam)->lpCreateParams; SetProp(hwnd, _T("this"), (LPVOID) pThis); return 0; case WM_IMAP_ERROR: { HRESULT hrResult; LPSTR pszErrorStr; pThis->m_fFailuresEncountered = TRUE; hrResult = ImapUtil_WMIMAPERRORToString(lParam, &pszErrorStr, NULL); if (FAILED(hrResult)) { AssertSz(FALSE, "Could not construct full error str for WM_IMAP_ERROR"); pThis->m_pSpoolerUI->InsertError(pThis->m_CurrentEID, ((INETMAILERROR *)lParam)->pszMessage); } else { pThis->m_pSpoolerUI->InsertError(pThis->m_CurrentEID, pszErrorStr); MemFree(pszErrorStr); } return 0; } // case WM_IMAP_ERROR case WM_IMAP_SIMPLEERROR: { char sz[CCHMAX_STRINGRES]; pThis->m_fFailuresEncountered = TRUE; Assert(0 == HIWORD(lParam)); // Can't handle two text strings LoadString(g_hLocRes, LOWORD(lParam), sz, ARRAYSIZE(sz)); pThis->m_pSpoolerUI->InsertError(pThis->m_CurrentEID, sz); } // case WM_IMAP_SIMPLEERROR return 0; case WM_IMAP_POLLUNREAD_DONE: { HRESULT hrResult; EVENTCOMPLETEDSTATUS ecs; Assert((0 == wParam || 1 == wParam) && 0 == lParam); ecs = EVENT_SUCCEEDED; // Let's be optimistic if (pThis->m_fFailuresEncountered) { char sz[CCHMAX_STRINGRES], szFmt[CCHMAX_STRINGRES]; LoadString(g_hLocRes, idsIMAPPollUnreadFailuresFmt, szFmt, ARRAYSIZE(szFmt)); wnsprintf(sz, ARRAYSIZE(sz), szFmt, pThis->m_szAccountName); pThis->m_pSpoolerUI->InsertError(pThis->m_CurrentEID, sz); ecs = EVENT_WARNINGS; } if (0 == wParam) ecs = EVENT_FAILED; hrResult = pThis->m_pBindContext->EventDone(pThis->m_CurrentEID, ecs); Assert(SUCCEEDED(hrResult)); return 0; } // case WM_IMAP_POLLUNREAD_DONE case WM_IMAP_POLLUNREAD_TICK: Assert(0 == lParam); if (0 == wParam) pThis->m_fFailuresEncountered = TRUE; else if (1 == wParam) { char sz[CCHMAX_STRINGRES], szFmt[CCHMAX_STRINGRES]; LoadString(g_hLocRes, idsIMAPPollUnreadIMAP4Fmt, szFmt, ARRAYSIZE(szFmt)); wnsprintf(sz, ARRAYSIZE(sz), szFmt, pThis->m_szAccountName); pThis->m_fFailuresEncountered = TRUE; pThis->m_pSpoolerUI->InsertError(pThis->m_CurrentEID, sz); } else { Assert(2 == wParam); if (pThis->m_dwTotalTicks > 0) pThis->m_pSpoolerUI->IncrementProgress(1); } return 0; case WM_IMAP_POLLUNREAD_TOTAL: Assert(0 == lParam); pThis->m_dwTotalTicks = wParam; pThis->m_pSpoolerUI->SetProgressRange(wParam); return 0; } // switch (uMsg) // If we reached this point, we didn't process the msg: DefWindowProc it return DefWindowProc(hwnd, uMsg, wParam, lParam); } // IMAPTaskWndProc