// -------------------------------------------------------------------------------- // Pop3task.cpp // Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved // Steven J. Bailey // -------------------------------------------------------------------------------- #include "pch.hxx" #include "pop3task.h" #include "resource.h" #include "xputil.h" #include "goptions.h" #include "strconst.h" #include "mimeutil.h" #include "shlwapi.h" #include "shlwapip.h" #include "options.h" #include "xpcomm.h" #include "ourguid.h" #include "msgfldr.h" #include "storecb.h" #include "mailutil.h" #include "ruleutil.h" #include "demand.h" // -------------------------------------------------------------------------------- // Debug Modifiers // -------------------------------------------------------------------------------- #ifdef DEBUG BOOL g_fUidlByTop = FALSE; BOOL g_fFailTopCommand = FALSE; LONG g_ulFailNumber=-1; #endif // -------------------------------------------------------------------------------- // ISLASTPOPID // -------------------------------------------------------------------------------- #define ISLASTPOPID(_dwPopId) \ (_dwPopId == m_rTable.cItems) // -------------------------------------------------------------------------------- // ISVALIDPOPID // -------------------------------------------------------------------------------- #define ISVALIDPOPID(_dwPopId) \ (_dwPopId - 1 < m_rTable.cItems) // -------------------------------------------------------------------------------- // ITEMFROMPOPID // -------------------------------------------------------------------------------- #define ITEMFROMPOPID(_dwPopId) \ (&m_rTable.prgItem[_dwPopId - 1]) // -------------------------------------------------------------------------------- // CPop3Task::CPop3Task // -------------------------------------------------------------------------------- CPop3Task::CPop3Task(void) { m_cRef = 1; m_dwFlags = 0; m_dwState = 0; m_dwExpireDays = 0; m_pSpoolCtx = NULL; m_pAccount = NULL; m_pTransport = NULL; m_pUI = NULL; m_pIExecRules = NULL; m_pIRuleSender = NULL; m_pIRuleJunk = NULL; m_pInbox = NULL; m_pOutbox = NULL; m_eidEvent = 0; m_pUidlCache = NULL; m_uidlsupport = UIDL_SUPPORT_NONE; m_dwProgressMax = 0; m_dwProgressCur = 0; m_wProgress = 0; m_eidEvent = 0; m_hrResult = S_OK; m_pStream = NULL; m_state = POP3STATE_NONE; m_hwndTimeout = NULL; m_pLogFile = NULL; m_pSmartLog = NULL; *m_szAccountId = '\0'; ZeroMemory(&m_rMetrics, sizeof(POP3METRICS)); ZeroMemory(&m_rFolder, sizeof(POP3FOLDERINFO)); ZeroMemory(&m_rTable, sizeof(POP3ITEMTABLE)); ZeroMemory(&m_rServer, sizeof(INETSERVER)); InitializeCriticalSection(&m_cs); } // -------------------------------------------------------------------------------- // CPop3Task::~CPop3Task // -------------------------------------------------------------------------------- CPop3Task::~CPop3Task(void) { ZeroMemory(&m_rServer, sizeof(m_rServer)); // Done for security. // Reset the Object _ResetObject(TRUE); // Kill the critical section DeleteCriticalSection(&m_cs); } // -------------------------------------------------------------------------------- // CPop3Task::_ResetObject // -------------------------------------------------------------------------------- void CPop3Task::_ResetObject(BOOL fDeconstruct) { // Release Folder Objects _ReleaseFolderObjects(); // Make sure the transport is disconnect if (m_pTransport) { m_pTransport->Release(); m_pTransport = NULL; } // Release the Outbox SafeRelease(m_pAccount); SafeRelease(m_pInbox); SafeRelease(m_pOutbox); SafeRelease(m_pIExecRules); SafeRelease(m_pIRuleSender); SafeRelease(m_pIRuleJunk); SafeRelease(m_pSpoolCtx); SafeRelease(m_pUI); SafeRelease(m_pUidlCache); SafeRelease(m_pStream); SafeRelease(m_pLogFile); // Kill the log file _FreeSmartLog(); // Free the event table elements _FreeItemTableElements(); // Deconstructing if (fDeconstruct) { // Free Event Table SafeMemFree(m_rTable.prgItem); } // Otherwise, reset some vars else { // Reset total byte count m_dwFlags = 0; m_dwState = 0; m_dwExpireDays = 0; m_eidEvent = 0; m_wProgress = 0; m_uidlsupport = UIDL_SUPPORT_NONE; m_state = POP3STATE_NONE; ZeroMemory(&m_rFolder, sizeof(POP3FOLDERINFO)); ZeroMemory(&m_rMetrics, sizeof(POP3METRICS)); ZeroMemory(&m_rServer, sizeof(INETSERVER)); } } // -------------------------------------------------------------------------------- // CPop3Task::_ReleaseFolderObjects // -------------------------------------------------------------------------------- void CPop3Task::_ReleaseFolderObjects(void) { // m_rFolder should have been release _CloseFolder(); // Force Inbox Rules to release folder objects if (m_pIExecRules) { m_pIExecRules->ReleaseObjects(); } // Download only locks the inbox SafeRelease(m_pInbox); } // -------------------------------------------------------------------------------- // CPop3Task::_FreeItemTableElements // -------------------------------------------------------------------------------- void CPop3Task::_FreeItemTableElements(void) { // Loop the table of events for (ULONG i=0; iAddRef(); exit: // Thread Safety LeaveCriticalSection(&m_cs); // Done return hr; } // -------------------------------------------------------------------------------- // CPop3Task::CPop3Task // -------------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CPop3Task::AddRef(void) { EnterCriticalSection(&m_cs); ULONG cRef = ++m_cRef; LeaveCriticalSection(&m_cs); return cRef; } // -------------------------------------------------------------------------------- // CPop3Task::CPop3Task // -------------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CPop3Task::Release(void) { EnterCriticalSection(&m_cs); ULONG cRef = --m_cRef; LeaveCriticalSection(&m_cs); if (0 != cRef) return cRef; delete this; return 0; } // -------------------------------------------------------------------------------- // CPop3Task::Init // -------------------------------------------------------------------------------- STDMETHODIMP CPop3Task::Init(DWORD dwFlags, ISpoolerBindContext *pBindCtx) { // Invalid Arg if (NULL == pBindCtx) return TrapError(E_INVALIDARG); // Thread Safety EnterCriticalSection(&m_cs); // Reset this object _ResetObject(FALSE); // Save the Activity Flags - DELIVER_xxx m_dwFlags = dwFlags; // Hold onto the bind context Assert(NULL == m_pSpoolCtx); m_pSpoolCtx = pBindCtx; m_pSpoolCtx->AddRef(); // Thread Safety LeaveCriticalSection(&m_cs); // Done return S_OK; } // -------------------------------------------------------------------------------- // CPop3Task::BuildEvents // -------------------------------------------------------------------------------- STDMETHODIMP CPop3Task::BuildEvents(ISpoolerUI *pSpoolerUI, IImnAccount *pAccount, FOLDERID idFolder) { // Locals HRESULT hr=S_OK; DWORD dw; CHAR szAccountName[CCHMAX_ACCOUNT_NAME]; CHAR szRes[CCHMAX_RES]; CHAR szMessage[CCHMAX_RES + CCHMAX_ACCOUNT_NAME]; LPSTR pszLogFile=NULL; DWORD dwState; PROPVARIANT propvar = {0}; // Invalid Arg if (NULL == pSpoolerUI || NULL == pAccount) return TrapError(E_INVALIDARG); // Thread Safety EnterCriticalSection(&m_cs); // Validate State Assert(NULL == m_pTransport && NULL == m_pAccount && NULL == m_pInbox && 0 == m_rTable.cItems); // Save the UI Object m_pUI = pSpoolerUI; m_pUI->AddRef(); // Release current Account m_pAccount = pAccount; m_pAccount->AddRef(); // Leave mail on server if (SUCCEEDED(m_pAccount->GetPropDw(AP_POP3_LEAVE_ON_SERVER, &dw)) && TRUE == dw) FLAGSET(m_dwState, POP3STATE_LEAVEONSERVER); // Delete Expire if (SUCCEEDED(m_pAccount->GetPropDw(AP_POP3_REMOVE_EXPIRED, &dw)) && TRUE == dw) FLAGSET(m_dwState, POP3STATE_DELETEEXPIRED); // Days to Expire if (FAILED(m_pAccount->GetPropDw(AP_POP3_EXPIRE_DAYS, &m_dwExpireDays))) m_dwExpireDays = 5; // Delete From Server when deleted from Deleted Items Folder... if (SUCCEEDED(m_pAccount->GetPropDw(AP_POP3_REMOVE_DELETED, &dw)) && TRUE == dw) FLAGSET(m_dwState, POP3STATE_SYNCDELETED); // Get the inbox rules object Assert(g_pRulesMan); CHECKHR(hr = g_pRulesMan->ExecRules(EXECF_ALL, RULE_TYPE_MAIL, &m_pIExecRules)); // Get the block sender rule Assert(NULL == m_pIRuleSender); (VOID) g_pRulesMan->GetRule(RULEID_SENDERS, RULE_TYPE_MAIL, 0, &m_pIRuleSender); // Only use it if it there and enabled if (NULL != m_pIRuleSender) { if (FAILED(m_pIRuleSender->GetProp(RULE_PROP_DISABLED, 0, &propvar))) { m_pIRuleSender->Release(); m_pIRuleSender = NULL; } else { Assert(VT_BOOL == propvar.vt); if (FALSE != propvar.boolVal) { m_pIRuleSender->Release(); m_pIRuleSender = NULL; } PropVariantClear(&propvar); } } Assert(NULL == m_pIRuleJunk); (VOID) g_pRulesMan->GetRule(RULEID_JUNK, RULE_TYPE_MAIL, 0, &m_pIRuleJunk); // Only use it if it enabled if (NULL != m_pIRuleJunk) { if (FAILED(m_pIRuleJunk->GetProp(RULE_PROP_DISABLED, 0, &propvar))) { m_pIRuleJunk->Release(); m_pIRuleJunk = NULL; } else { Assert(VT_BOOL == propvar.vt); if (FALSE != propvar.boolVal) { m_pIRuleJunk->Release(); m_pIRuleJunk = NULL; } PropVariantClear(&propvar); } } // Predownload rules CHECKHR(hr = m_pIExecRules->GetState(&dwState)); // Do we have server actions to do? if (0 != (dwState & ACT_STATE_SERVER)) FLAGSET(m_dwState, POP3STATE_PDR); // No Post Download Rules if ((0 == (dwState & (ACT_STATE_LOCAL|CRIT_STATE_ALL))) && (NULL == m_pIRuleSender) && (NULL == m_pIRuleJunk)) FLAGSET(m_dwState, POP3STATE_NOPOSTRULES); // No Body Rules if ((ISFLAGSET(dwState, CRIT_STATE_ALL)) || (NULL != m_pIRuleJunk)) FLAGSET(m_dwState, POP3STATE_BODYRULES); // Get the outbox CHECKHR(hr = m_pSpoolCtx->BindToObject(IID_CLocalStoreOutbox, (LPVOID *)&m_pOutbox)); // Get a pop3 log file m_pSpoolCtx->BindToObject(IID_CPop3LogFile, (LPVOID *)&m_pLogFile); // Get Account Id CHECKHR(hr = m_pAccount->GetPropSz(AP_ACCOUNT_NAME, szAccountName, ARRAYSIZE(szAccountName))); // Register Event - Get new messages from '%s'. LOADSTRING(IDS_SPS_POP3EVENT, szRes); // Format the String wnsprintf(szMessage, ARRAYSIZE(szMessage), szRes, szAccountName); // Register for the event... CHECKHR(hr = m_pSpoolCtx->RegisterEvent(szMessage, (ISpoolerTask *)this, POP3EVENT_DOWNLOADMAIL, m_pAccount, &m_eidEvent)); exit: // Failure if (FAILED(hr)) { _CatchResult(hr); _ResetObject(FALSE); } // Thread Safety LeaveCriticalSection(&m_cs); // Done return hr; } // -------------------------------------------------------------------------------- // CPop3Task::_DoSmartLog // -------------------------------------------------------------------------------- void CPop3Task::_DoSmartLog(IMimeMessage *pMessage) { // Don't make the function call if this is null... Assert(m_pSmartLog && m_pSmartLog->pStmFile && m_pSmartLog->pszProperty && m_pSmartLog->pszValue && pMessage); // Do a query property... if (lstrcmpi("all", m_pSmartLog->pszProperty) == 0 || S_OK == pMessage->QueryProp(m_pSmartLog->pszProperty, m_pSmartLog->pszValue, TRUE, FALSE)) { // Locals LPSTR psz=NULL; PROPVARIANT rVariant; IStream *pStream=NULL; // Get IAT_FROM if (FAILED(pMessage->GetAddressFormat(IAT_FROM, AFT_DISPLAY_BOTH, &psz))) { // Try IAT_SENDER pMessage->GetAddressFormat(IAT_SENDER, AFT_DISPLAY_BOTH, &psz); } // Write the Sender if (psz) { // Write It SideAssert(SUCCEEDED(m_pSmartLog->pStmFile->Write(psz, lstrlen(psz), NULL))); // Free psz SafeMemFree(psz); } // Otherwise, write Unknown else { CHAR sz[255]; LoadString(g_hLocRes, idsUnknown, sz, ARRAYSIZE(sz)); SideAssert(SUCCEEDED(m_pSmartLog->pStmFile->Write(sz, lstrlen(sz), NULL))); } // Write a tab SideAssert(SUCCEEDED(m_pSmartLog->pStmFile->Write("\t", 1, NULL))); // Get IAT_CC if (SUCCEEDED(pMessage->GetAddressFormat(IAT_CC, AFT_DISPLAY_BOTH, &psz))) { // Write It SideAssert(SUCCEEDED(m_pSmartLog->pStmFile->Write(psz, lstrlen(psz), NULL))); // Free psz SafeMemFree(psz); } // Write a tab SideAssert(SUCCEEDED(m_pSmartLog->pStmFile->Write("\t", 1, NULL))); // Lets write the X-Mailer just to be a nice guy rVariant.vt = VT_LPSTR; if (SUCCEEDED(pMessage->GetProp(PIDTOSTR(PID_HDR_XMAILER), 0, &rVariant))) { // Write It SideAssert(SUCCEEDED(m_pSmartLog->pStmFile->Write(rVariant.pszVal, lstrlen(rVariant.pszVal), NULL))); // Free psz SafeMemFree(rVariant.pszVal); } // Write a tab SideAssert(SUCCEEDED(m_pSmartLog->pStmFile->Write("\t", 1, NULL))); // Lets write the X-MimeOLE just to be a nice guy rVariant.vt = VT_LPSTR; if (SUCCEEDED(pMessage->GetProp("X-MimeOLE", 0, &rVariant))) { // Write It SideAssert(SUCCEEDED(m_pSmartLog->pStmFile->Write(rVariant.pszVal, lstrlen(rVariant.pszVal), NULL))); // Free psz SafeMemFree(rVariant.pszVal); } // Write a tab SideAssert(SUCCEEDED(m_pSmartLog->pStmFile->Write("\t", 1, NULL))); // Lets write the Subject just to be a nice guy rVariant.vt = VT_LPSTR; if (SUCCEEDED(pMessage->GetProp(PIDTOSTR(PID_HDR_DATE), 0, &rVariant))) { // Write It SideAssert(SUCCEEDED(m_pSmartLog->pStmFile->Write(rVariant.pszVal, lstrlen(rVariant.pszVal), NULL))); // Free psz SafeMemFree(rVariant.pszVal); } // Write a tab SideAssert(SUCCEEDED(m_pSmartLog->pStmFile->Write("\t", 1, NULL))); // Lets write the Subject just to be a nice guy rVariant.vt = VT_LPSTR; if (SUCCEEDED(pMessage->GetProp(PIDTOSTR(PID_HDR_SUBJECT), 0, &rVariant))) { // Write It SideAssert(SUCCEEDED(m_pSmartLog->pStmFile->Write(rVariant.pszVal, lstrlen(rVariant.pszVal), NULL))); // Free psz SafeMemFree(rVariant.pszVal); } // Write a tab SideAssert(SUCCEEDED(m_pSmartLog->pStmFile->Write("\t", 1, NULL))); // Write the first line of the message body if (FAILED(pMessage->GetTextBody(TXT_PLAIN, IET_DECODED, &pStream, NULL))) { // Try to get the HTML body if (FAILED(pMessage->GetTextBody(TXT_HTML, IET_DECODED, &pStream, NULL))) pStream = NULL; } // Did we find a stream if (pStream) { // Locals BYTE rgBuffer[1048]; ULONG cbRead; ULONG i; ULONG cGood=0; // Read a buffer if (SUCCEEDED(pStream->Read(rgBuffer, sizeof(rgBuffer), &cbRead))) { // Write until we hit a \r or \n for (i=0; i 3) break; // Otherwise, continue... else { rgBuffer[i] = ' '; cGood = 0; continue; } } // Replace Tabs with spaces so that it doesn't mess up tab delimited file if ('\t' == rgBuffer[i]) rgBuffer[i] = ' '; // If not a space if (FALSE == FIsSpaceA((LPSTR)(rgBuffer + i))) cGood++; } // Write the character m_pSmartLog->pStmFile->Write(rgBuffer, ((i > 0) ? i - 1 : i), NULL); } // Free psz SafeRelease(pStream); } // Write a tab SideAssert(SUCCEEDED(m_pSmartLog->pStmFile->Write(g_szCRLF, lstrlen(g_szCRLF), NULL))); } } // -------------------------------------------------------------------------------- // CPop3Task::_FreeSmartLog // -------------------------------------------------------------------------------- void CPop3Task::_FreeSmartLog(void) { if (m_pSmartLog) { SafeMemFree(m_pSmartLog->pszAccount); SafeMemFree(m_pSmartLog->pszProperty); SafeMemFree(m_pSmartLog->pszValue); SafeMemFree(m_pSmartLog->pszLogFile); SafeRelease(m_pSmartLog->pStmFile); g_pMalloc->Free(m_pSmartLog); m_pSmartLog = NULL; } } // -------------------------------------------------------------------------------- // CPop3Task::_ReadSmartLogEntry // -------------------------------------------------------------------------------- HRESULT CPop3Task::_ReadSmartLogEntry(HKEY hKey, LPCSTR pszKey, LPSTR *ppszValue) { // Locals HRESULT hr=S_OK; ULONG cb; // Read the pszKey if (RegQueryValueEx(hKey, pszKey, NULL, NULL, NULL, &cb) != ERROR_SUCCESS) { hr = E_FAIL; goto exit; } // Allocate cb++; CHECKALLOC(*ppszValue = PszAllocA(cb)); // Read the pszKey if (RegQueryValueEx(hKey, pszKey, NULL, NULL, (LPBYTE)*ppszValue, &cb) != ERROR_SUCCESS) { hr = E_FAIL; goto exit; } exit: // Done return hr; } // -------------------------------------------------------------------------------- // CPop3Task::_InitializeSmartLog // -------------------------------------------------------------------------------- HRESULT CPop3Task::_InitializeSmartLog(void) { // Locals HRESULT hr=S_OK; HKEY hKey=NULL; ULARGE_INTEGER uliPos = {0,0}; LARGE_INTEGER liOrigin = {0,0}; // Get Advanced Logging Information if (AthUserOpenKey(c_szRegPathSmartLog, KEY_ALL_ACCESS, &hKey) != ERROR_SUCCESS) { hr = E_FAIL; goto exit; } // Allocate smart log CHECKALLOC(m_pSmartLog = (LPSMARTLOGINFO)g_pMalloc->Alloc(sizeof(SMARTLOGINFO))); // Zero Init ZeroMemory(m_pSmartLog, sizeof(SMARTLOGINFO)); // Read the Account CHECKHR(hr = _ReadSmartLogEntry(hKey, "Account", &m_pSmartLog->pszAccount)); // Read the Property CHECKHR(hr = _ReadSmartLogEntry(hKey, "Property", &m_pSmartLog->pszProperty)); // Read the ContainsValue CHECKHR(hr = _ReadSmartLogEntry(hKey, "ContainsValue", &m_pSmartLog->pszValue)); // Read the LogFile CHECKHR(hr = _ReadSmartLogEntry(hKey, "LogFile", &m_pSmartLog->pszLogFile)); // Open the logfile CHECKHR(hr = OpenFileStream(m_pSmartLog->pszLogFile, OPEN_ALWAYS, GENERIC_WRITE | GENERIC_READ, &m_pSmartLog->pStmFile)); // Seek to the end CHECKHR(hr = m_pSmartLog->pStmFile->Seek(liOrigin, STREAM_SEEK_END, &uliPos)); exit: // Failure if (FAILED(hr)) _FreeSmartLog(); // Cleanup if (hKey) RegCloseKey(hKey); // Done return hr; } // -------------------------------------------------------------------------------- // CPop3Task::Execute // -------------------------------------------------------------------------------- STDMETHODIMP CPop3Task::Execute(EVENTID eid, DWORD_PTR dwTwinkie) { // Locals HRESULT hr=S_OK; CHAR szRes[CCHMAX_RES]; CHAR szBuf[CCHMAX_RES + CCHMAX_SERVER_NAME]; DWORD cb; // Thread Safety EnterCriticalSection(&m_cs); // Check State Assert(eid == m_eidEvent && m_pAccount && m_pUI); // Create the Transport Object CHECKHR(hr = CreatePOP3Transport(&m_pTransport)); // Init the Transport CHECKHR(hr = m_pTransport->InitNew(NULL, (IPOP3Callback *)this)); // Fill an INETSERVER structure from the account object CHECKHR(hr = m_pTransport->InetServerFromAccount(m_pAccount, &m_rServer)); // Get Account Id CHECKHR(hr = m_pAccount->GetPropSz(AP_ACCOUNT_ID, m_szAccountId, ARRAYSIZE(m_szAccountId))); // Always connect using the most recently supplied password from the user hr = GetPassword(m_rServer.dwPort, m_rServer.szServerName, m_rServer.szUserName, m_rServer.szPassword, sizeof(m_rServer.szPassword)); // If this account is set to always prompt for password and password isn't // already cached, show UI so we can prompt user for password if (m_pUI && ISFLAGSET(m_rServer.dwFlags, ISF_ALWAYSPROMPTFORPASSWORD) && FAILED(hr)) { m_pUI->ShowWindow(SW_SHOW); } // Get Smart Logging INformation _InitializeSmartLog(); // Set the animation m_pUI->SetAnimation(idanInbox, TRUE); // Setup Progress Meter m_pUI->SetProgressRange(100); // Connecting to ... LoadString(g_hLocRes, idsInetMailConnectingHost, szRes, ARRAYSIZE(szRes)); wnsprintf(szBuf, ARRAYSIZE(szBuf), szRes, m_rServer.szAccount); m_pUI->SetGeneralProgress(szBuf); // Notify m_pSpoolCtx->Notify(DELIVERY_NOTIFY_CONNECTING, 0); // Connect CHECKHR(hr = m_pTransport->Connect(&m_rServer, TRUE, TRUE)); exit: // Failure if (FAILED(hr)) { FLAGSET(m_dwState, POP3STATE_EXECUTEFAILED); _CatchResult(hr); // Tell the transport to release my callback: otherwise I leak SideAssert(m_pTransport->HandsOffCallback() == S_OK); } // Thread Safety LeaveCriticalSection(&m_cs); // Done return hr; } STDMETHODIMP CPop3Task::CancelEvent(EVENTID eid, DWORD_PTR dwTwinkie) { return(S_OK); } // -------------------------------------------------------------------------------- // CPop3Task::OnTimeout // -------------------------------------------------------------------------------- STDMETHODIMP CPop3Task::OnTimeout(DWORD *pdwTimeout, IInternetTransport *pTransport) { // Locals HRESULT hr=S_OK; // Thread Safety EnterCriticalSection(&m_cs); // Is there currently a timeout dialog if (m_hwndTimeout) { // Set foreground SetForegroundWindow(m_hwndTimeout); } else { // Not suppose to be showing UI ? if (ISFLAGSET(m_dwFlags, DELIVER_NOUI)) { hr = S_FALSE; goto exit; } // Do Timeout Dialog m_hwndTimeout = TaskUtil_HwndOnTimeout(m_rServer.szServerName, m_rServer.szAccount, "POP3", m_rServer.dwTimeout, (ITimeoutCallback *) this); // Couldn't create the dialog if (NULL == m_hwndTimeout) { hr = S_FALSE; goto exit; } } exit: // Thread Safety LeaveCriticalSection(&m_cs); // Always tell the transport to keep on trucking return hr; } // -------------------------------------------------------------------------------- // CPop3Task::OnLogonPrompt // -------------------------------------------------------------------------------- STDMETHODIMP CPop3Task::OnLogonPrompt(LPINETSERVER pInetServer, IInternetTransport *pTransport) { // Locals HRESULT hr=S_FALSE; char szPassword[CCHMAX_PASSWORD]; // Check if we have a cached password that's different from current password hr = GetPassword(pInetServer->dwPort, pInetServer->szServerName, pInetServer->szUserName, szPassword, sizeof(szPassword)); if (SUCCEEDED(hr) && 0 != lstrcmp(szPassword, pInetServer->szPassword)) { StrCpyN(pInetServer->szPassword, szPassword, ARRAYSIZE(pInetServer->szPassword)); ZeroMemory(szPassword, sizeof(szPassword)); // Done for security. return S_OK; } hr = S_FALSE; // Re-initialize // Thread Safety EnterCriticalSection(&m_cs); // NOERRORS... if (ISFLAGSET(m_dwFlags, DELIVER_NOUI)) goto exit; // TaskUtil_OnLogonPrompt hr = TaskUtil_OnLogonPrompt(m_pAccount, m_pUI, NULL, pInetServer, AP_POP3_USERNAME, AP_POP3_PASSWORD, AP_POP3_PROMPT_PASSWORD, TRUE); // Cache the password for this session if (S_OK == hr) SavePassword(pInetServer->dwPort, pInetServer->szServerName, pInetServer->szUserName, pInetServer->szPassword); exit: // Thread Safety LeaveCriticalSection(&m_cs); ZeroMemory(szPassword, sizeof(szPassword)); // Done for security. // Done return hr; } // -------------------------------------------------------------------------------- // CPop3Task::OnPrompt // -------------------------------------------------------------------------------- STDMETHODIMP_(INT) CPop3Task::OnPrompt(HRESULT hrError, LPCTSTR pszText, LPCTSTR pszCaption, UINT uType, IInternetTransport *pTransport) { // Locals HWND hwnd; INT nAnswer; // Thread Safety EnterCriticalSection(&m_cs); // Invalid State Assert(m_pUI); // Get Window if (FAILED(m_pUI->GetWindow(&hwnd))) hwnd = NULL; // I assume this is a critical prompt, so I will not check for no UI mode nAnswer = MessageBox(hwnd, pszText, pszCaption, uType); // Thread Safety LeaveCriticalSection(&m_cs); // Done return nAnswer; } // -------------------------------------------------------------------------------- // CPop3Task::OnError // -------------------------------------------------------------------------------- STDMETHODIMP CPop3Task::OnError(IXPSTATUS ixpstatus, LPIXPRESULT pResult, IInternetTransport *pTransport) { // Thread Safety EnterCriticalSection(&m_cs); // Invalid State Assert(m_pUI); // Insert Error Into UI _CatchResult(POP3_NONE, pResult); // Thread Safety LeaveCriticalSection(&m_cs); // Done return S_OK; } // -------------------------------------------------------------------------------- // CPop3Task::OnCommand // -------------------------------------------------------------------------------- STDMETHODIMP CPop3Task::OnCommand(CMDTYPE cmdtype, LPSTR pszLine, HRESULT hrResponse, IInternetTransport *pTransport) { // Logging if (m_pLogFile && pszLine) { // Response if (CMD_RESP == cmdtype) m_pLogFile->WriteLog(LOGFILE_RX, pszLine); // Send else if (CMD_SEND == cmdtype) m_pLogFile->WriteLog(LOGFILE_TX, pszLine); } // Done return S_OK; } // -------------------------------------------------------------------------------- // CPop3Task::_CatchResult // -------------------------------------------------------------------------------- TASKRESULTTYPE CPop3Task::_CatchResult(HRESULT hr) { // Locals IXPRESULT rResult; // Build an IXPRESULT ZeroMemory(&rResult, sizeof(IXPRESULT)); rResult.hrResult = hr; // Get the SMTP Result Type return _CatchResult(POP3_NONE, &rResult); } // -------------------------------------------------------------------------------- // CPop3Task::_CatchResult // -------------------------------------------------------------------------------- TASKRESULTTYPE CPop3Task::_CatchResult(POP3COMMAND command, LPIXPRESULT pResult) { // Locals HWND hwndParent; TASKRESULTTYPE tyTaskResult=TASKRESULT_FAILURE; // If Succeeded if (SUCCEEDED(pResult->hrResult)) return TASKRESULT_SUCCESS; // Get Window if (FAILED(m_pUI->GetWindow(&hwndParent))) hwndParent = NULL; // Process generic protocol errro tyTaskResult = TaskUtil_FBaseTransportError(IXP_POP3, m_eidEvent, pResult, &m_rServer, NULL, m_pUI, !ISFLAGSET(m_dwFlags, DELIVER_NOUI), hwndParent); // Save Result m_hrResult = pResult->hrResult; // If Task Failure, drop the connection if (NULL != m_pTransport) m_pTransport->DropConnection(); // Return Result return tyTaskResult; } // -------------------------------------------------------------------------------- // CPop3Task::OnStatus // -------------------------------------------------------------------------------- STDMETHODIMP CPop3Task::OnStatus(IXPSTATUS ixpstatus, IInternetTransport *pTransport) { // Locals EVENTCOMPLETEDSTATUS tyEventStatus=EVENT_SUCCEEDED; // Invalid State Assert(m_pUI && m_pSpoolCtx); if (!m_pUI || !m_pSpoolCtx) { return E_FAIL; } // Thread Safety EnterCriticalSection(&m_cs); // Feed the the IXP status to the UI object m_pUI->SetSpecificProgress(MAKEINTRESOURCE(XPUtil_StatusToString(ixpstatus))); // Disconnected if (ixpstatus == IXP_DISCONNECTED) { // Locals BOOL fWarning=FALSE; // Note that OnDisconnect was called FLAGSET(m_dwState, POP3STATE_ONDISCONNECT); // If a UIDL Sync is in progress, then return now... if (POP3STATE_UIDLSYNC == m_state) goto exit; // Kill the timeout dialog if (m_hwndTimeout) { DestroyWindow(m_hwndTimeout); m_hwndTimeout = NULL; } // Cache Cleanup _CleanupUidlCache(); // Reset the progress // m_pUI->SetProgressRange(100); // State m_state = POP3STATE_NONE; // Set the animation m_pUI->SetAnimation(idanInbox, FALSE); // Infinite Loop if (m_rMetrics.cInfiniteLoopAutoGens) { // Load the Warning CHAR szRes[CCHMAX_RES]; LOADSTRING(idsReplyForwardLoop, szRes); // Format the Error CHAR szMsg[CCHMAX_RES + CCHMAX_ACCOUNT_NAME + CCHMAX_SERVER_NAME + CCHMAX_RES]; wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, m_rMetrics.cInfiniteLoopAutoGens, m_rServer.szAccount, m_rServer.szServerName); // Insert the warning m_pUI->InsertError(m_eidEvent, szMsg); // Warning fWarning = TRUE; } // Nothing to download if (ISFLAGSET(m_dwState, POP3STATE_CANCELPENDING)) tyEventStatus = EVENT_CANCELED; else if (FAILED(m_hrResult) || (m_rMetrics.cDownloaded == 0 && m_rMetrics.cDownload > 0)) tyEventStatus = EVENT_FAILED; else if (!ISFLAGSET(m_dwState, POP3STATE_LOGONSUCCESS)) tyEventStatus = EVENT_WARNINGS; else if (m_rMetrics.cDownloaded && m_rMetrics.cDownload && m_rMetrics.cDownloaded < m_rMetrics.cDownload) tyEventStatus = EVENT_WARNINGS; else if (fWarning) tyEventStatus = EVENT_WARNINGS; // Result m_pSpoolCtx->Notify(DELIVERY_NOTIFY_RESULT, tyEventStatus); // Success and messages were downloaded if (EVENT_FAILED != tyEventStatus && m_rMetrics.cDownloaded && m_rMetrics.cPartials) { // Sitch Partials _HrStitchPartials(); } // Notify m_pSpoolCtx->Notify(DELIVERY_NOTIFY_COMPLETE, m_rMetrics.cDownloaded); // Tell the transport to release my callback SideAssert(m_pTransport->HandsOffCallback() == S_OK); // This task is complete if (!ISFLAGSET(m_dwState, POP3STATE_EXECUTEFAILED)) m_pSpoolCtx->EventDone(m_eidEvent, tyEventStatus); } // Authorizing else if (ixpstatus == IXP_AUTHORIZING) m_pSpoolCtx->Notify(DELIVERY_NOTIFY_AUTHORIZING, 0); exit: // Thread Safety LeaveCriticalSection(&m_cs); // Done return S_OK; } // -------------------------------------------------------------------------------- // CPop3Task::_CleanupUidlCache // -------------------------------------------------------------------------------- void CPop3Task::_CleanupUidlCache(void) { // Locals ULONG i; UIDLRECORD UidlInfo={0}; LPPOP3ITEM pItem; // No Cache Objects if (NULL == m_pUidlCache) return; // Count the number of messages we will have to get a top for for (i=0; idwFlags, POP3ITEM_DELETED) && ISFLAGSET(pItem->dwFlags, POP3ITEM_DELETECACHEDUIDL)) { // No UIDL if (pItem->pszUidl) { // Set Search Info UidlInfo.pszUidl = pItem->pszUidl; UidlInfo.pszServer = m_rServer.szServerName; UidlInfo.pszAccountId = m_szAccountId; // Set Props on the cached uidl message m_pUidlCache->DeleteRecord(&UidlInfo); } } } // Remove all traces of if the account from the uid cache if (ISFLAGSET(m_dwState, POP3STATE_CLEANUPCACHE)) { // Locaks HROWSET hRowset=NULL; // Create a rowset if (SUCCEEDED(m_pUidlCache->CreateRowset(IINDEX_PRIMARY, NOFLAGS, &hRowset))) { // Delete Enumeration while (S_OK == m_pUidlCache->QueryRowset(hRowset, 1, (LPVOID *)&UidlInfo, NULL)) { // Delete this puppy ? if (lstrcmpi(UidlInfo.pszServer, m_rServer.szServerName) == 0 && UidlInfo.pszAccountId != NULL && lstrcmpi(UidlInfo.pszAccountId, m_szAccountId) == 0) { // Delete this record m_pUidlCache->DeleteRecord(&UidlInfo); } // Free m_pUidlCache->FreeRecord(&UidlInfo); } // Purge everthing that matches this m_pUidlCache->CloseRowset(&hRowset); } } } // -------------------------------------------------------------------------------- // CPop3Task::OnResponse // -------------------------------------------------------------------------------- STDMETHODIMP CPop3Task::OnResponse(LPPOP3RESPONSE pResponse) { // Thread Safety EnterCriticalSection(&m_cs); // Testing UIDL Command if (m_uidlsupport == UIDL_SUPPORT_TESTING_UIDL_COMMAND && POP3_UIDL == pResponse->command) { #ifdef DEBUG pResponse->rIxpResult.hrResult = g_fUidlByTop ? E_FAIL : pResponse->rIxpResult.hrResult; #endif // Failure ? if (FAILED(pResponse->rIxpResult.hrResult)) { // Set Specific Progress //CHAR szRes[CCHMAX_RES]; //LOADSTRING(IDS_SPS_POP3UIDL_UIDL, szRes); //m_pUI->SetSpecificProgress(szRes); // Try to top command _CatchResult(m_pTransport->CommandTOP(POP3CMD_GET_POPID, 1, 0)); // Testing by top command m_uidlsupport = UIDL_SUPPORT_TESTING_TOP_COMMAND; } // Otherwise else { // State m_state = POP3STATE_GETTINGUIDLS; // Using the UIDL command m_uidlsupport = UIDL_SUPPORT_USE_UIDL_COMMAND; // Set Specific Progress //CHAR szRes[CCHMAX_RES]; //LOADSTRING(IDS_SPS_POP3UIDL_UIDL, szRes); //m_pUI->SetSpecificProgress(szRes); // Issue full UIDL command _CatchResult(m_pTransport->CommandUIDL(POP3CMD_GET_ALL, 0)); } // Done goto exit; } // Testing Top Command else if (m_uidlsupport == UIDL_SUPPORT_TESTING_TOP_COMMAND && POP3_TOP == pResponse->command) { #ifdef DEBUG pResponse->rIxpResult.hrResult = g_fFailTopCommand ? E_FAIL : pResponse->rIxpResult.hrResult; #endif // Failure ? if (FAILED(pResponse->rIxpResult.hrResult)) { // Disable the leave on server option in the account m_pAccount->SetPropDw(AP_POP3_LEAVE_ON_SERVER, FALSE); // Save the Changed m_pAccount->SaveChanges(); // Failure _CatchResult(SP_E_CANTLEAVEONSERVER); // Done goto exit; } // Using the UIDL command else { // State m_state = POP3STATE_GETTINGUIDLS; // Set this and fall through to the switch... m_uidlsupport = UIDL_SUPPORT_USE_TOP_COMMAND; } } #ifdef DEBUG if (POP3_RETR == pResponse->command && TRUE == pResponse->fDone && (ULONG)g_ulFailNumber == pResponse->rRetrInfo.dwPopId) pResponse->rIxpResult.hrResult = E_FAIL; #endif // If Succeeded if (FAILED(pResponse->rIxpResult.hrResult)) { // Get Window HWND hwndParent; if (FAILED(m_pUI->GetWindow(&hwndParent))) hwndParent = NULL; // Dont drop if working on POP3_PASS or POP3_USER if (POP3_PASS == pResponse->command || POP3_USER == pResponse->command) { // Log an Error ? If the user's password is not empty or they have fSavePassword enabled TaskUtil_FBaseTransportError(IXP_POP3, m_eidEvent, &pResponse->rIxpResult, &m_rServer, NULL, m_pUI, !ISFLAGSET(m_dwFlags, DELIVER_NOUI), hwndParent); // Done goto exit; } // Command base Failure else if (POP3_RETR == pResponse->command) { // Message Number %d could not be retrieved." CHAR szRes[CCHMAX_RES]; LoadString(g_hLocRes, IDS_SP_E_RETRFAILED, szRes, ARRAYSIZE(szRes)); // Format the Error CHAR szMsg[CCHMAX_RES + CCHMAX_RES]; wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, pResponse->rRetrInfo.dwPopId); // Fill the IXPRESULT IXPRESULT rResult; CopyMemory(&rResult, &pResponse->rIxpResult, sizeof(IXPRESULT)); rResult.pszProblem = szMsg; rResult.hrResult = SP_E_POP3_RETR; // Insert the Error TaskUtil_FBaseTransportError(IXP_POP3, m_eidEvent, &rResult, &m_rServer, NULL, m_pUI, !ISFLAGSET(m_dwFlags, DELIVER_NOUI), hwndParent); // Close Current Folder _CloseFolder(); // Retrieve the next message _CatchResult(_HrRetrieveNextMessage(pResponse->rRetrInfo.dwPopId)); // Done goto exit; } // Default Error Handler else if (TASKRESULT_SUCCESS != _CatchResult(pResponse->command, &pResponse->rIxpResult)) goto exit; } // Handle Command Type switch(pResponse->command) { case POP3_CONNECTED: // Notify m_pSpoolCtx->Notify(DELIVERY_NOTIFY_CHECKING, 0); // Logon Success FLAGSET(m_dwState, POP3STATE_LOGONSUCCESS); // Issue the STAT command _CatchResult(m_pTransport->CommandSTAT()); break; case POP3_STAT: // Process the StatCommand _CatchResult(_HrOnStatResponse(pResponse)); break; case POP3_LIST: // Process the List Command _CatchResult(_HrOnListResponse(pResponse)); break; case POP3_UIDL: // Process the Uidl Command _CatchResult(_HrOnUidlResponse(pResponse)); break; case POP3_TOP: // Process the Top Command _CatchResult(_HrOnTopResponse(pResponse)); break; case POP3_RETR: // Process Retreive Response _CatchResult(_HrOnRetrResponse(pResponse)); break; case POP3_DELE: // Process Delete Response _CatchResult(_HrDeleteNextMessage(pResponse->dwPopId)); break; } exit: // Thread Safety LeaveCriticalSection(&m_cs); // Done return S_OK; } // -------------------------------------------------------------------------------- // CPop3Task::_HrLockUidlCache // -------------------------------------------------------------------------------- HRESULT CPop3Task::_HrLockUidlCache(void) { // Locals HRESULT hr=S_OK; // No Cache yet ? if (NULL == m_pUidlCache) { // Lets the the UID Cache CHECKHR(hr = m_pSpoolCtx->BindToObject(IID_CUidlCache, (LPVOID *)&m_pUidlCache)); } exit: // Done return hr; } // -------------------------------------------------------------------------------- // CPop3Task::_HrOnStatResponse // -------------------------------------------------------------------------------- HRESULT CPop3Task::_HrOnStatResponse(LPPOP3RESPONSE pResponse) { // Locals HRESULT hr=S_OK; CHAR szRes[CCHMAX_RES]; CHAR szSize[CCHMAX_RES]; CHAR szMsg[CCHMAX_RES + CCHMAX_ACCOUNT_NAME + CCHMAX_RES]; BOOL fFound; // Progress LOADSTRING(IDS_SPS_POP3CHECKING, szRes); wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, m_rServer.szAccount); m_pUI->SetGeneralProgress(szMsg); // Update Event Status LOADSTRING(IDS_SPS_POP3TOTAL, szRes); StrFormatByteSizeA(pResponse->rStatInfo.cbMessages, szSize, ARRAYSIZE(szSize)); wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, m_rServer.szAccount, pResponse->rStatInfo.cMessages, szSize); m_pUI->UpdateEventState(m_eidEvent, -1, szMsg, NULL); // No New Messages ? if (0 == pResponse->rStatInfo.cMessages) { m_pTransport->Disconnect(); goto exit; } // Save total byte count m_rMetrics.cbTotal = pResponse->rStatInfo.cbMessages; // Assume no clean cache FLAGCLEAR(m_dwState, POP3STATE_CLEANUPCACHE); // If Leave on Server, return TRUE if (ISFLAGSET(m_dwState, POP3STATE_LEAVEONSERVER)) { // Lock the tree CHECKHR(hr = _HrLockUidlCache()); // We will need to get the uidls FLAGSET(m_dwState, POP3STATE_GETUIDLS); } // Okay, we may still need to get the uidls if else { // Locals UIDLRECORD UidlInfo={0}; HROWSET hRowset=NULL; // Lock the tree CHECKHR(hr = _HrLockUidlCache()); // Create a Rowset CHECKHR(hr = m_pUidlCache->CreateRowset(IINDEX_PRIMARY, NOFLAGS, &hRowset)); // Delete Enumeration while (S_OK == m_pUidlCache->QueryRowset(hRowset, 1, (LPVOID *)&UidlInfo, NULL)) { // Delete this puppy ? if (lstrcmpi(UidlInfo.pszServer, m_rServer.szServerName) == 0 && UidlInfo.pszAccountId != NULL && lstrcmpi(UidlInfo.pszAccountId, m_szAccountId) == 0) { // Get Uidls from the server FLAGSET(m_dwState, POP3STATE_GETUIDLS); // Cleanup the uidl cache when complete FLAGSET(m_dwState, POP3STATE_CLEANUPCACHE); // Free m_pUidlCache->FreeRecord(&UidlInfo); // Done break; } // Free m_pUidlCache->FreeRecord(&UidlInfo); } // Purge everthing that matches this m_pUidlCache->CloseRowset(&hRowset); } // Allocate the Item Table CHECKALLOC(m_rTable.prgItem = (LPPOP3ITEM)g_pMalloc->Alloc(sizeof(POP3ITEM) * pResponse->rStatInfo.cMessages)); // Set Counts m_rTable.cAlloc = m_rTable.cItems = pResponse->rStatInfo.cMessages; // Zeroinit Array ZeroMemory(m_rTable.prgItem, sizeof(POP3ITEM) * pResponse->rStatInfo.cMessages); // Initialize Progress m_dwProgressMax = m_rTable.cItems; // If we need to get the UIDL list, lets test for it... if (ISFLAGSET(m_dwState, POP3STATE_GETUIDLS)) m_dwProgressMax += (m_rTable.cItems * 4); // Otherwise else { // Release the Uidl Cache Lock SafeRelease(m_pUidlCache); } // Progress Current m_dwProgressCur = 0; // Predownload rules increases mprogress if (ISFLAGSET(m_dwState, POP3STATE_PDR)) m_dwProgressMax += m_rTable.cItems; // Set Specific Progress LOADSTRING(IDS_SPS_POP3STAT, szRes); m_pUI->SetSpecificProgress(szRes); // Set the uidl command to see if the user supports it CHECKHR(hr = m_pTransport->CommandLIST(POP3CMD_GET_ALL, 0)); exit: // Done return hr; } // -------------------------------------------------------------------------------- // CPop3Task::_HrOnTopResponse // -------------------------------------------------------------------------------- HRESULT CPop3Task::_HrOnTopResponse(LPPOP3RESPONSE pResponse) { // Locals HRESULT hr=S_OK; DWORD dwPopId=pResponse->rTopInfo.dwPopId; LPPOP3ITEM pItem; IMimePropertySet *pHeader=NULL; CHAR szRes[CCHMAX_RES]; CHAR szMsg[CCHMAX_RES+CCHMAX_RES]; // Validate the Item Assert(ISVALIDPOPID(dwPopId)); // Get the current item pItem = ITEMFROMPOPID(dwPopId); // We should assume that were downloading this item at this point Assert(ISFLAGSET(pItem->dwFlags, POP3ITEM_DOWNLOAD)); // No stream yet ? if (NULL == m_pStream) { // Create a Stream CHECKHR(hr = MimeOleCreateVirtualStream(&m_pStream)); } // If this infor is valid if (TRUE == pResponse->fValidInfo) { // Write the data into the stream CHECKHR(hr = m_pStream->Write(pResponse->rTopInfo.pszLines, pResponse->rTopInfo.cbLines, NULL)); } // Is the command done ? if (TRUE == pResponse->fDone) { // Commit the stream CHECKHR(hr = m_pStream->Commit(STGC_DEFAULT)); // Getting UIDL if (POP3STATE_GETTINGUIDLS == m_state) { // Better not have a uidl yet Assert(NULL == pItem->pszUidl); // Increment Progress m_dwProgressCur+=2; // Set Specific Progress //LOADSTRING(IDS_SPS_POP3UIDL_TOP, szRes); //wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, dwPopId, m_rTable.cItems); //m_pUI->SetSpecificProgress(szMsg); // Get Uidl From HeaderStream CHECKHR(hr = _HrGetUidlFromHeaderStream(m_pStream, &pItem->pszUidl, &pHeader)); } // Otherwise, just increment one else m_dwProgressCur++; // Show Progress _DoProgress(); // If we plan on downloading this thing if (ISFLAGSET(pItem->dwFlags, POP3ITEM_DOWNLOAD) && ISFLAGSET(m_dwState, POP3STATE_PDR)) { // Check Inbox Rule for this item _ComputeItemInboxRule(pItem, m_pStream, pHeader, NULL, TRUE); } // Release the current stream SafeRelease(m_pStream); // Totally Done ? if (ISLASTPOPID(dwPopId)) { // Start the download process CHECKHR(hr = _HrStartDownloading()); } // Otherwise, lets get the top of the next item else if (POP3STATE_GETTINGUIDLS == m_state) { // Next Top CHECKHR(hr = m_pTransport->CommandTOP(POP3CMD_GET_POPID, dwPopId + 1, 0)); } // Otherwise, find next message marked for download to check against predownload rules else { // NextTopForInboxRule CHECKHR(hr = _HrNextTopForInboxRule(dwPopId)); } } exit: // Cleanup SafeRelease(pHeader); // Done return hr; } // -------------------------------------------------------------------------------- // CPop3Task::_HrOnUidlResponse // -------------------------------------------------------------------------------- HRESULT CPop3Task::_HrOnUidlResponse(LPPOP3RESPONSE pResponse) { // Locals HRESULT hr=S_OK; DWORD dwPopId=pResponse->rUidlInfo.dwPopId; LPPOP3ITEM pItem; CHAR szRes[CCHMAX_RES]; CHAR szMsg[CCHMAX_RES + CCHMAX_RES]; // Is the command done ? if (TRUE == pResponse->fDone) { // If there are pre-download rules that are not size only, get all the tops if (ISFLAGSET(m_dwState, POP3STATE_PDR)) { // Clear the state m_state = POP3STATE_NONE; // NextTopForInboxRule CHECKHR(hr = _HrStartServerSideRules()); } // Otherwise, do the list command else { // Start the download process CHECKHR(hr = _HrStartDownloading()); } } // Otherwise else { // Make Sure PopId is on current iitem Assert(ISVALIDPOPID(dwPopId) && pResponse->rUidlInfo.pszUidl); // Get Current Item pItem = ITEMFROMPOPID(dwPopId); // Duplicate the Uidl CHECKALLOC(pItem->pszUidl = PszDupA(pResponse->rUidlInfo.pszUidl)); // Increment Progress m_dwProgressCur+=1; // Do progress _DoProgress(); } exit: // Done return hr; } // -------------------------------------------------------------------------------- // CPop3Task::_HrOnListResponse // -------------------------------------------------------------------------------- HRESULT CPop3Task::_HrOnListResponse(LPPOP3RESPONSE pResponse) { // Locals HRESULT hr=S_OK; DWORD dwPopId=pResponse->rListInfo.dwPopId; LPPOP3ITEM pItem; // Is the command done ? if (TRUE == pResponse->fDone) { // If we need to get the UIDL list, lets test for it... if (ISFLAGSET(m_dwState, POP3STATE_GETUIDLS)) { // Set the uidl command to see if the user supports it CHECKHR(hr = m_pTransport->CommandUIDL(POP3CMD_GET_POPID, 1)); // Set State m_uidlsupport = UIDL_SUPPORT_TESTING_UIDL_COMMAND; } // Otherwise else { // Predownload rules increases mprogress if (ISFLAGSET(m_dwState, POP3STATE_PDR)) { // Clear the state m_state = POP3STATE_NONE; // NextTopForInboxRule CHECKHR(hr = _HrStartServerSideRules()); } // Otherwise, do the list command else { // Start the download process CHECKHR(hr = _HrStartDownloading()); } } } // Otherwise else { // Make Sure PopId is on current iitem if(!ISVALIDPOPID(dwPopId)) return(E_FAIL); // Get Current Item pItem = ITEMFROMPOPID(dwPopId); // Duplicate the Uidl pItem->cbSize = pResponse->rListInfo.cbSize; // Assume we will download it FLAGSET(pItem->dwFlags, POP3ITEM_DOWNLOAD | POP3ITEM_DELETEOFFSERVER); // Increment Progress m_dwProgressCur++; // Do progress _DoProgress(); // This yields so that other threads can execute //Sleep(0); } exit: // Done return hr; } // -------------------------------------------------------------------------------- // CPop3Task::_HrStartDownloading // -------------------------------------------------------------------------------- HRESULT CPop3Task::_HrStartDownloading(void) { // Locals HRESULT hr=S_OK; ULONG i; CHAR szRes[CCHMAX_RES]; CHAR szSize1[CCHMAX_RES]; CHAR szSize2[CCHMAX_RES]; CHAR szMsg[CCHMAX_RES + CCHMAX_ACCOUNT_NAME + CCHMAX_RES]; // State Assert(m_rMetrics.cLeftByRule == 0 && m_rMetrics.cDownload == 0 && m_rMetrics.cDelete == 0 && m_rMetrics.cbDownload == 0); // If we got uidls, then lets do the cache compare lookup if (!ISFLAGSET(m_dwState, POP3STATE_PDR) && ISFLAGSET(m_dwState, POP3STATE_GETUIDLS)) { // Returns FALSE if user cancel CHECKHR(hr = _HrDoUidlSynchronize()); } // Compute number of new messages to download for (i=0; iUpdateEventState(m_eidEvent, -1, szMsg, NULL); // New Messages ? if (m_rMetrics.cDownload > 0) { // Setup Progress m_rMetrics.iCurrent = 0; m_wProgress = 0; m_dwProgressCur = 0; m_dwProgressMax = m_rMetrics.cbDownload; m_pUI->SetProgressRange(100); m_rMetrics.cLeftByRule = 0; // Notify m_pSpoolCtx->Notify(DELIVERY_NOTIFY_RECEIVING, 0); // State m_state = POP3STATE_DOWNLOADING; // Open the Inbox Assert(NULL == m_pInbox); CHECKHR(hr = m_pSpoolCtx->BindToObject(IID_CLocalStoreInbox, (LPVOID *)&m_pInbox)); // Download the Next Message CHECKHR(hr = _HrRetrieveNextMessage(0)); } // Otherwise if cDelete else if (m_rMetrics.cDelete > 0) { // Delete the Next Message CHECKHR(hr = _HrStartDeleteCycle()); } // Otherwise, disconnect else { // Disconnect CHECKHR(hr = m_pTransport->Disconnect()); } exit: // Done return hr; } // -------------------------------------------------------------------------------- // CPop3Task::_DoProgress // -------------------------------------------------------------------------------- void CPop3Task::_DoProgress(void) { // Compute Current Progress Index WORD wProgress; if (m_dwProgressMax > 0) wProgress = (WORD)((m_dwProgressCur * 100) / m_dwProgressMax); else wProgress = 0; // Only if greater than if (wProgress > m_wProgress) { // Compute Delta WORD wDelta = wProgress - m_wProgress; // Progress Delta if (wDelta > 0) { // Incremenet Progress m_pUI->IncrementProgress(wDelta); // Increment my wProgress m_wProgress += wDelta; // Don't go above 100 if (m_wProgress > 100) m_wProgress = 100; } } } // -------------------------------------------------------------------------------- // CPop3Task::_HrGetUidlFromHeaderStream // -------------------------------------------------------------------------------- HRESULT CPop3Task::_HrGetUidlFromHeaderStream(IStream *pStream, LPSTR *ppszUidl, IMimePropertySet **ppHeader) { // Locals HRESULT hr=S_OK; IMimePropertySet *pHeader=NULL; // Invalid Arg Assert(pStream && ppszUidl); // Init *ppszUidl = NULL; *ppHeader = NULL; // Rewind Header Stream CHECKHR(hr = HrRewindStream(pStream)); // Load the header CHECKHR(hr = MimeOleCreatePropertySet(NULL, &pHeader)); // Load the header CHECKHR(hr = pHeader->Load(pStream)); // Get the message Id... if (FAILED(MimeOleGetPropA(pHeader, PIDTOSTR(PID_HDR_MESSAGEID), NOFLAGS, ppszUidl))) { // Try to use the received headers... MimeOleGetPropA(pHeader, PIDTOSTR(PID_HDR_RECEIVED), NOFLAGS, ppszUidl); } // Returen the Header ? *ppHeader = pHeader; pHeader = NULL; exit: // Release the text stream SafeRelease(pHeader); // Done return hr; } // -------------------------------------------------------------------------------- // CPop3Task::_HrDoUidlSynchronize // -------------------------------------------------------------------------------- HRESULT CPop3Task::_HrDoUidlSynchronize(void) { // Locals HRESULT hr=S_OK; LPPOP3ITEM pItem; ULONG i,j; #ifdef DEBUG DWORD dwTick = GetTickCount(); #endif // Uidl Sync m_state = POP3STATE_UIDLSYNC; // Compute number of new messages to download for (i=0,j=0; i= 10) { //Sleep(0); m_pSpoolCtx->PumpMessages(); j = 0; } // Cancel if (ISFLAGSET(m_dwState, POP3STATE_CANCELPENDING)) { // Change State m_state = POP3STATE_NONE; // Drop the connection if (m_pTransport) m_pTransport->DropConnection(); // User Cancel hr = IXP_E_USER_CANCEL; // Done break; } // OnDisconnect has been called if (ISFLAGSET(m_dwState, POP3STATE_ONDISCONNECT)) { // Change State m_state = POP3STATE_NONE; // Fake the call to OnStatus OnStatus(IXP_DISCONNECTED, NULL); // Done break; } } // Uidl Sync m_state = POP3STATE_NONE; // Cool tracing #ifdef DEBUG DebugTrace("CPop3Task::_HrDoUidlSynchronize took %d Milli-Seconds\n", GetTickCount() - dwTick); #endif // DEBUG // Done return hr; } // -------------------------------------------------------------------------------- // CPop3Task::_GetItemFlagsFromUidl // -------------------------------------------------------------------------------- void CPop3Task::_GetItemFlagsFromUidl(LPPOP3ITEM pItem) { // Locals UIDLRECORD rUidlInfo={0}; // Invalid Arg Assert(pItem && m_pUidlCache); // If we are already not going to download this item, then return if (!ISFLAGSET(pItem->dwFlags, POP3ITEM_DOWNLOAD)) return; // If there is no UIDL, we will download it... if (NULL == pItem->pszUidl || '\0' == *pItem->pszUidl) return; // If not leaving on server, mark for delete if (ISFLAGSET(m_dwState, POP3STATE_LEAVEONSERVER)) FLAGCLEAR(pItem->dwFlags, POP3ITEM_DELETEOFFSERVER); // Set Search Info rUidlInfo.pszUidl = pItem->pszUidl; rUidlInfo.pszServer = m_rServer.szServerName; rUidlInfo.pszAccountId = m_szAccountId; // This yields so that other threads can execute //Sleep(0); // Exist - if not, lets download it... if (DB_S_NOTFOUND == m_pUidlCache->FindRecord(IINDEX_PRIMARY, COLUMNS_ALL, &rUidlInfo, NULL)) { if (ISFLAGSET(m_dwState, POP3STATE_LEAVEONSERVER)) FLAGSET(pItem->dwFlags, POP3ITEM_CACHEUIDL); return; } // Don't download it again FLAGCLEAR(pItem->dwFlags, POP3ITEM_DOWNLOAD | POP3ITEM_DELETEOFFSERVER); // If the message has been download, lets decide if we should delete it if (rUidlInfo.fDownloaded) { // Expired or deleted from client, or remove when deleted from delete items folder. if (!ISFLAGSET(m_dwState, POP3STATE_LEAVEONSERVER) || _FUidlExpired(&rUidlInfo) || (ISFLAGSET(m_dwState, POP3STATE_SYNCDELETED) && rUidlInfo.fDeleted)) { FLAGSET(pItem->dwFlags, POP3ITEM_DELETECACHEDUIDL); FLAGSET(pItem->dwFlags, POP3ITEM_DELETEOFFSERVER); } } // Free The Dude m_pUidlCache->FreeRecord(&rUidlInfo); } // ------------------------------------------------------------------------------------ // CPop3Task::_FUidlExpired // ------------------------------------------------------------------------------------ BOOL CPop3Task::_FUidlExpired(LPUIDLRECORD pUidlInfo) { // Locals SYSTEMTIME st; FILETIME ft; ULONG ulSeconds; // If not expiring, return FALSE if (!ISFLAGSET(m_dwState, POP3STATE_DELETEEXPIRED)) return FALSE; // Get Current Time GetSystemTime(&st); SystemTimeToFileTime(&st, &ft); // Convert st to seconds since Jan 1, 1996 ulSeconds = UlDateDiff(&pUidlInfo->ftDownload, &ft); // Greater than expire days if ((ulSeconds / SECONDS_INA_DAY) >= m_dwExpireDays) return TRUE; // Done return FALSE; } // ------------------------------------------------------------------------------------ // CPop3Task::_ComputeItemInboxRule // ------------------------------------------------------------------------------------ void CPop3Task::_ComputeItemInboxRule(LPPOP3ITEM pItem, LPSTREAM pStream, IMimePropertySet *pHeaderIn, IMimeMessage * pIMMsg, BOOL fServerRules) { // Locals HRESULT hr=S_OK; IMimePropertySet *pHeader=NULL; ACT_ITEM *pActions=NULL; ULONG cActions=0; // We should not have checked the inbox rule for this item yet Assert(m_pIExecRules && pItem && (pStream || pHeaderIn || pIMMsg)); Assert(ISFLAGSET(pItem->dwFlags, POP3ITEM_DOWNLOAD) && !ISFLAGSET(pItem->dwFlags, POP3ITEM_CHECKEDINBOXRULE)); // We've checked this inbox rule FLAGSET(pItem->dwFlags, POP3ITEM_CHECKEDINBOXRULE); // Assume we don't find an inbox rule for this item FLAGCLEAR(pItem->dwFlags, POP3ITEM_HASINBOXRULE); // Header was passed in ? if (pHeaderIn) { pHeader = pHeaderIn; pHeader->AddRef(); } // Do we already have a Mime message? else if (pIMMsg) { CHECKHR(hr = pIMMsg->BindToObject(HBODY_ROOT, IID_IMimePropertySet, (LPVOID *)&pHeader)); } // Otherwise, load the stream in to a header else { // Rewind Header Stream CHECKHR(hr = HrRewindStream(pStream)); // Load the header CHECKHR(hr = MimeOleCreatePropertySet(NULL, &pHeader)); // Load the header CHECKHR(hr = pHeader->Load(pStream)); } // Check the inbox rule // If we have pre-download rules, if ((FALSE != fServerRules) && ISFLAGSET(m_dwState, POP3STATE_PDR)) { // Check to see if we have any actions hr = m_pIExecRules->ExecuteRules(ERF_ONLYSERVER | ERF_SKIPPARTIALS, m_szAccountId, NULL, NULL, pHeader, NULL, pItem->cbSize, &pActions, &cActions); // If we don't have any actions, or // this isn't a server side rule if ((S_OK != hr) || ((ACT_TYPE_DONTDOWNLOAD != pActions[0].type) && (ACT_TYPE_DELETESERVER != pActions[0].type))) { // Make sure we can check rules again FLAGCLEAR(pItem->dwFlags, POP3ITEM_CHECKEDINBOXRULE); hr = S_FALSE; } else { // _OnKnownRuleActions _OnKnownRuleActions(pItem, pActions, cActions, fServerRules); } } // If we don't have pre-download rules, then check rules normally. else { hr = S_FALSE; // Do block sender first if (m_pIRuleSender) { hr = m_pIRuleSender->Evaluate(m_szAccountId, NULL, NULL, pHeader, pIMMsg, pItem->cbSize, &pActions, &cActions); } // If we aren't blocking the sender if (S_OK != hr) { hr = m_pIExecRules->ExecuteRules(ERF_SKIPPARTIALS, m_szAccountId, NULL, NULL, pHeader, pIMMsg, pItem->cbSize, &pActions, &cActions); } // If we don't have a rule match if ((S_OK != hr) && (NULL != m_pIRuleJunk)) { hr = m_pIRuleJunk->Evaluate(m_szAccountId, NULL, NULL, pHeader, pIMMsg, pItem->cbSize, &pActions, &cActions); } // Did we have some actions to perform... if (S_OK == hr) { // This item has an inbox rule FLAGSET(pItem->dwFlags, POP3ITEM_HASINBOXRULE); // Save off the actions list pItem->pActList = pActions; pActions = NULL; pItem->cActList = cActions; } } exit: // Cleanup RuleUtil_HrFreeActionsItem(pActions, cActions); SafeMemFree(pActions); SafeRelease(pHeader); // Done return; } // ------------------------------------------------------------------------------------ // CPop3Task::_OnKnownRuleActions // ------------------------------------------------------------------------------------ void CPop3Task::_OnKnownRuleActions(LPPOP3ITEM pItem, ACT_ITEM * pActions, ULONG cActions, BOOL fServerRules) { // This item has an inbox rule FLAGSET(pItem->dwFlags, POP3ITEM_HASINBOXRULE); // If Action is to delete off sever if ((FALSE != fServerRules) && (1 == cActions)) { if (ACT_TYPE_DELETESERVER == pActions->type) { // Don't Cache the UIDL FLAGCLEAR(pItem->dwFlags, POP3ITEM_DELETECACHEDUIDL | POP3ITEM_CACHEUIDL | POP3ITEM_DOWNLOAD); // Delete off the server FLAGSET(pItem->dwFlags, POP3ITEM_DELETEOFFSERVER | POP3ITEM_DELEBYRULE); } // Otherwise, don't download the message else if (ACT_TYPE_DONTDOWNLOAD == pActions->type) { // Download It and Don't download it and delete it FLAGCLEAR(pItem->dwFlags, POP3ITEM_DOWNLOAD | POP3ITEM_DELETEOFFSERVER); // Set the Flag FLAGSET(pItem->dwFlags, POP3ITEM_LEFTBYRULE); } } } // ------------------------------------------------------------------------------------ // CPop3Task::_HrStartServerSideRules // ------------------------------------------------------------------------------------ HRESULT CPop3Task::_HrStartServerSideRules(void) { // Locals HRESULT hr=S_OK; ULONG i; // If we got uidls, then lets do the cache compare lookup if (ISFLAGSET(m_dwState, POP3STATE_GETUIDLS)) { // Returns FALSE if user cancel CHECKHR(hr = _HrDoUidlSynchronize()); } // Check State m_rMetrics.cTopMsgs = 0; m_rMetrics.iCurrent = 0; // Count the number of messages we will have to get a top for for (i=0; iSetSpecificProgress(szMsg); // Loop until we find the next message that we are downloading while(1) { // Incremenet dwPopIdCurrent dwPopIdCurrent++; // Last PopId, start the download if (dwPopIdCurrent > m_rTable.cItems) { // Start the download process CHECKHR(hr = _HrStartDownloading()); // Done break; } // If we are still downloading this item if (ISFLAGSET(m_rTable.prgItem[dwPopIdCurrent - 1].dwFlags, POP3ITEM_DOWNLOAD)) { // Try to top command CHECKHR(hr = m_pTransport->CommandTOP(POP3CMD_GET_POPID, dwPopIdCurrent, 0)); // Done break; } } exit: // Done return hr; } // ------------------------------------------------------------------------------------ // CPop3Task::_HrRetrieveNextMessage // ------------------------------------------------------------------------------------ HRESULT CPop3Task::_HrRetrieveNextMessage(DWORD dwPopIdCurrent) { // Locals HRESULT hr=S_OK; CHAR szRes[CCHMAX_RES]; CHAR szMsg[CCHMAX_RES + CCHMAX_RES]; LPPOP3ITEM pItem; // Cancel Pending... if (ISFLAGSET(m_dwState, POP3STATE_CANCELPENDING)) { // Start the Delete Cycle CHECKHR(hr = _HrStartDeleteCycle()); // Done goto exit; } // Adjust progress if (dwPopIdCurrent > 0) { // Get current item pItem = ITEMFROMPOPID(dwPopIdCurrent); Assert(ISFLAGSET(pItem->dwFlags, POP3ITEM_DOWNLOAD)); // Adjust progress Cur m_dwProgressCur = pItem->dwProgressCur; // Do progress _DoProgress(); } // Loop until we find the next message that we are downloading while(1) { // Incremenet dwPopIdCurrent dwPopIdCurrent++; // Last PopId, start the download if (dwPopIdCurrent > m_rTable.cItems) { // Start the download process CHECKHR(hr = _HrStartDeleteCycle()); // Done break; } // Readability pItem = ITEMFROMPOPID(dwPopIdCurrent); // Download this message ? if (ISFLAGSET(pItem->dwFlags, POP3ITEM_DOWNLOAD)) { // Increment m_rMetrics.iCurrent m_rMetrics.iCurrent++; // Status LOADSTRING(idsInetMailRecvStatus, szRes); wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, m_rMetrics.iCurrent, m_rMetrics.cDownload); m_pUI->SetSpecificProgress(szMsg); // Retrieve this item CHECKHR(hr = m_pTransport->CommandRETR(POP3CMD_GET_POPID, dwPopIdCurrent)); // Done break; } // Count Number of items left by rule else if (ISFLAGSET(pItem->dwFlags, POP3ITEM_LEFTBYRULE)) m_rMetrics.cLeftByRule++; } exit: // Done return hr; } // ------------------------------------------------------------------------------------ // CPop3Task::_HrOnRetrResponse // ------------------------------------------------------------------------------------ HRESULT CPop3Task::_HrOnRetrResponse(LPPOP3RESPONSE pResponse) { // Locals HRESULT hr=S_OK; DWORD dwPopId=pResponse->rRetrInfo.dwPopId; LPPOP3ITEM pItem; // Get Current Item pItem = ITEMFROMPOPID(dwPopId); // Validate the item Assert(ISFLAGSET(pItem->dwFlags, POP3ITEM_DOWNLOAD)); // Valid info if (TRUE == pResponse->fValidInfo) { // Progress... m_dwProgressCur += pResponse->rRetrInfo.cbLines; // Don't let progress grow beyond what we estimated the ceiling for this message if (m_dwProgressCur > pItem->dwProgressCur) m_dwProgressCur = pItem->dwProgressCur; // Show Progress _DoProgress(); // Do we have a destination yet ? if (ISFLAGSET(pItem->dwFlags, POP3ITEM_DESTINATIONKNOWN)) { // We better have a stream Assert(m_rFolder.pStream && m_rFolder.pFolder); // Simply write the data CHECKHR(hr = m_rFolder.pStream->Write(pResponse->rRetrInfo.pszLines, pResponse->rRetrInfo.cbLines, NULL)); } // Otherwise else { // If there are no inbox rules if (ISFLAGSET(m_dwState, POP3STATE_NOPOSTRULES)) { // Use the Inbox CHECKHR(hr = _HrOpenFolder(m_pInbox)); // Destination is known FLAGSET(pItem->dwFlags, POP3ITEM_DESTINATIONKNOWN); // Simply write the data CHECKHR(hr = m_rFolder.pStream->Write(pResponse->rRetrInfo.pszLines, pResponse->rRetrInfo.cbLines, NULL)); } // else if we have only body rules... else if (ISFLAGSET(m_dwState, POP3STATE_BODYRULES)) { // No stream yet ? if (NULL == m_pStream) { // Create a Stream CHECKHR(hr = MimeOleCreateVirtualStream(&m_pStream)); } // Simply write the data CHECKHR(hr = m_pStream->Write(pResponse->rRetrInfo.pszLines, pResponse->rRetrInfo.cbLines, NULL)); } // Otherwise... else { // Have I checked the inbox rule for this item yet ? if (!ISFLAGSET(pItem->dwFlags, POP3ITEM_CHECKEDINBOXRULE)) { // No stream yet ? if (NULL == m_pStream) { // Create a Stream CHECKHR(hr = MimeOleCreateVirtualStream(&m_pStream)); } // Simply write the data CHECKHR(hr = m_pStream->Write(pResponse->rRetrInfo.pszLines, pResponse->rRetrInfo.cbLines, NULL)); // If I have the header, check the inbox rule if (TRUE == pResponse->rRetrInfo.fHeader) { // Commit the stream CHECKHR(hr = m_pStream->Commit(STGC_DEFAULT)); // Check Inbox Rule for this item _ComputeItemInboxRule(pItem, m_pStream, NULL, NULL, FALSE); } } // Have I checked the inbox rule for this item yet ? if (ISFLAGSET(pItem->dwFlags, POP3ITEM_CHECKEDINBOXRULE)) { // Locals IMessageFolder *pFolder; // We must have the header IxpAssert(pResponse->rRetrInfo.fHeader); // Did we find an Inbox Rule if (ISFLAGSET(pItem->dwFlags, POP3ITEM_HASINBOXRULE) && S_OK == _GetMoveFolder(pItem, &pFolder)) { // Use the Inbox CHECKHR(hr = _HrOpenFolder(pFolder)); } // No Move To, just use the inbox else { // Use the Inbox CHECKHR(hr = _HrOpenFolder(m_pInbox)); } // Destination is known FLAGSET(pItem->dwFlags, POP3ITEM_DESTINATIONKNOWN); // If m_pStream, then copy this to the folder if (m_pStream) { // Rewind the stream CHECKHR(hr = HrRewindStream(m_pStream)); // Copy this stream to the folder CHECKHR(hr = HrCopyStream(m_pStream, m_rFolder.pStream, NULL)); // Relase m_pStream SafeRelease(m_pStream); } // Otherwise, store the data into the folder else { IxpAssert(FALSE); // Simply write the data CHECKHR(hr = m_rFolder.pStream->Write(pResponse->rRetrInfo.pszLines, pResponse->rRetrInfo.cbLines, NULL)); } } } } } // Done ? if (TRUE == pResponse->fDone) { // Finish this message download CHECKHR(hr = _HrFinishMessageDownload(dwPopId)); } exit: // Done return hr; } // ------------------------------------------------------------------------------------ // CPop3Task::_HrFinishMessageDownload // ------------------------------------------------------------------------------------ HRESULT CPop3Task::_HrFinishMessageDownload(DWORD dwPopId) { // Locals HRESULT hr=S_OK; IMimeMessage *pMessage=NULL; PROPVARIANT rUserData; LPPOP3ITEM pItem; SYSTEMTIME st; UIDLRECORD rUidlInfo={0}; MESSAGEID idMessage; DWORD dwMsgFlags; IMessageFolder *pFolder; ULONG ulIndex = 0; IStream * pIStm = NULL; BOOL fDelete=FALSE; // Get Current Item pItem = ITEMFROMPOPID(dwPopId); // Create a New Mail Message CHECKHR(hr = HrCreateMessage(&pMessage)); // Has Body rules if (ISFLAGSET(m_dwState, POP3STATE_BODYRULES)) { // I should not have checked for a rule yet IxpAssert(!ISFLAGSET(pItem->dwFlags, POP3ITEM_CHECKEDINBOXRULE) && !ISFLAGSET(pItem->dwFlags, POP3ITEM_HASINBOXRULE)); // Better have a current folder Assert(m_pStream); // Check Params CHECKHR(hr = m_pStream->Commit(STGC_DEFAULT)); pIStm = m_pStream; } else { // Better have a current folder Assert(m_rFolder.pStream); // Check Params CHECKHR(hr = m_rFolder.pStream->Commit(STGC_DEFAULT)); // Change the Lock Type CHECKHR(hr = m_rFolder.pFolder->ChangeStreamLock(m_rFolder.pStream, ACCESS_READ)); pIStm = m_rFolder.pStream; } // Rewind CHECKHR(hr = HrRewindStream(pIStm)); // Stream in CHECKHR(hr = pMessage->Load(pIStm)); // Count Partials if (S_OK == pMessage->IsContentType(HBODY_ROOT, STR_CNT_MESSAGE, STR_SUB_PARTIAL)) m_rMetrics.cPartials++; // Save Server rUserData.vt = VT_LPSTR; rUserData.pszVal = m_rServer.szServerName; pMessage->SetProp(PIDTOSTR(PID_ATT_SERVER), NOFLAGS, &rUserData); // Save Account Name rUserData.vt = VT_LPSTR; rUserData.pszVal = m_rServer.szAccount; pMessage->SetProp(STR_ATT_ACCOUNTNAME, NOFLAGS, &rUserData); // Save Account Name rUserData.vt = VT_LPSTR; rUserData.pszVal = m_szAccountId; pMessage->SetProp(PIDTOSTR(PID_ATT_ACCOUNTID), NOFLAGS, &rUserData); // Save UIDL if (pItem->pszUidl) { rUserData.vt = VT_LPSTR; rUserData.pszVal = pItem->pszUidl; pMessage->SetProp(PIDTOSTR(PID_ATT_UIDL), NOFLAGS, &rUserData); } // Save User Name rUserData.vt = VT_LPSTR; rUserData.pszVal = m_rServer.szUserName; pMessage->SetProp(PIDTOSTR(PID_ATT_USERNAME), NOFLAGS, &rUserData); // Initialize dwMsgFlags dwMsgFlags = ARF_RECEIVED; // Has Body rules if (ISFLAGSET(m_dwState, POP3STATE_BODYRULES)) { // I should not have checked for a rule yet IxpAssert(!ISFLAGSET(pItem->dwFlags, POP3ITEM_CHECKEDINBOXRULE) && !ISFLAGSET(pItem->dwFlags, POP3ITEM_HASINBOXRULE)); // Compute the inbox rule _ComputeItemInboxRule(pItem, NULL, NULL, pMessage, FALSE); // Did we find an Inbox Rule if (ISFLAGCLEAR(pItem->dwFlags, POP3ITEM_HASINBOXRULE) || (S_OK != _GetMoveFolder(pItem, &pFolder))) { pFolder = m_pInbox; } // Destination is known FLAGSET(pItem->dwFlags, POP3ITEM_DESTINATIONKNOWN); } else { pFolder = m_rFolder.pFolder; } // Store the message into the folder IF_FAILEXIT(hr = pFolder->SaveMessage(&idMessage, SAVE_MESSAGE_GENID, dwMsgFlags, pIStm, pMessage, NOSTORECALLBACK)); // Success m_rFolder.fCommitted = TRUE; // This message was successfully downloaded FLAGSET(pItem->dwFlags, POP3ITEM_DOWNLOADED); // Do PostDownloadRule _DoPostDownloadActions(pItem, idMessage, pFolder, pMessage, &fDelete); // Release Folder Object SafeRelease(m_rFolder.pStream); // Relase m_pStream SafeRelease(m_pStream); // Release the Folder SafeRelease(m_rFolder.pFolder); // Clear the folder infor Struct ZeroMemory(&m_rFolder, sizeof(POP3FOLDERINFO)); // If going to delete it... if (fDelete) { // Mark it for deletion FLAGSET(pItem->dwFlags, POP3ITEM_DELETEOFFSERVER); // We will store its uidl, but lets delete it later FLAGSET(pItem->dwFlags, POP3ITEM_DELETECACHEDUIDL); } // Cached the UIDL for this message ? if (ISFLAGSET(pItem->dwFlags, POP3ITEM_CACHEUIDL)) { // Should have a pszUidl Assert(pItem->pszUidl && m_pUidlCache); // Don't fault if (pItem->pszUidl) { // Set Key GetSystemTime(&st); SystemTimeToFileTime(&st, &rUidlInfo.ftDownload); rUidlInfo.fDownloaded = TRUE; rUidlInfo.fDeleted = FALSE; rUidlInfo.pszUidl = pItem->pszUidl; rUidlInfo.pszServer = m_rServer.szServerName; rUidlInfo.pszAccountId = m_szAccountId; // Set Propgs m_pUidlCache->InsertRecord(&rUidlInfo); } } // Successful download m_rMetrics.cDownloaded++; // Do smart log if (m_pSmartLog && (lstrcmpi(m_pSmartLog->pszAccount, m_rServer.szAccount) == 0 || lstrcmpi("All", m_pSmartLog->pszAccount) == 0)) _DoSmartLog(pMessage); // Retrieve the next message CHECKHR(hr = _HrRetrieveNextMessage(dwPopId)); exit: // Cleanup SafeRelease(pMessage); // Done return hr; } // ------------------------------------------------------------------------------------ // CPop3Task::_DoPostDownloadActions // ------------------------------------------------------------------------------------ void CPop3Task::_DoPostDownloadActions(LPPOP3ITEM pItem, MESSAGEID idMessage, IMessageFolder *pFolder, IMimeMessage *pMessage, BOOL *pfDeleteOffServer) { // Locals HRESULT hr; MESSAGEINFO Message = {0}; HWND hwnd = NULL; // Finish Applying the inbox rules if (!ISFLAGSET(pItem->dwFlags, POP3ITEM_HASINBOXRULE)) { goto exit; } // Get Window if (FAILED(m_pUI->GetWindow(&hwnd))) hwnd = NULL; // Set the Id Message.idMessage = idMessage; // Get the message hr = pFolder->FindRecord(IINDEX_PRIMARY, COLUMNS_ALL, &Message, NULL); if (FAILED(hr) || DB_S_NOTFOUND == hr) { goto exit; } if (FAILED(RuleUtil_HrApplyActions(hwnd, m_pIExecRules, &Message, pFolder, pMessage, 0, pItem->pActList, pItem->cActList, &(m_rMetrics.cInfiniteLoopAutoGens), pfDeleteOffServer))) { goto exit; } exit: // Free if (NULL != pFolder) { pFolder->FreeRecord(&Message); } // Done return; } // ------------------------------------------------------------------------------------ // CPop3Task::_HrOpenFolder // ------------------------------------------------------------------------------------ HRESULT CPop3Task::_HrOpenFolder(IMessageFolder *pFolder) { // Locals HRESULT hr=S_OK; // Current folder better be empty Assert(NULL == m_rFolder.pFolder && NULL == m_rFolder.pStream && 0 == m_rFolder.faStream); // Bad Arguments if (NULL == pFolder) { Assert(FALSE); return TrapError(E_INVALIDARG); } // Save the folder m_rFolder.pFolder = pFolder; // AddRef m_rFolder.pFolder->AddRef(); // Get a stream from the CHECKHR(hr = m_rFolder.pFolder->CreateStream(&m_rFolder.faStream)); // Open the Stream CHECKHR(hr = m_rFolder.pFolder->OpenStream(ACCESS_WRITE, m_rFolder.faStream, &m_rFolder.pStream)); exit: // Done return hr; } // ------------------------------------------------------------------------------------ // CPop3Task::_CloseFolder // ------------------------------------------------------------------------------------ void CPop3Task::_CloseFolder(void) { // Release the Stream SafeRelease(m_rFolder.pStream); // Release the reference to the stream. If the stream was reused, // it's refCount was incremented down below if (m_rFolder.faStream != 0) { // Must have a folder Assert(m_rFolder.pFolder); // Delete the Stream SideAssert(SUCCEEDED(m_rFolder.pFolder->DeleteStream(m_rFolder.faStream))); // Nill m_rFolder.faStream = 0; } // AddRef SafeRelease(m_rFolder.pFolder); } // -------------------------------------------------------------------------------- // CPop3Task::_HrStartDeleteCycle // -------------------------------------------------------------------------------- HRESULT CPop3Task::_HrStartDeleteCycle(void) { // Locals HRESULT hr=S_OK; ULONG i; LPPOP3ITEM pItem; // Release Folder Objects _ReleaseFolderObjects(); // Check State m_rMetrics.cDelete = 0; m_rMetrics.iCurrent = 0; // Count the number of messages we will have to get a top for for (i=0; idwFlags, POP3ITEM_DOWNLOAD) && !ISFLAGSET(pItem->dwFlags, POP3ITEM_DOWNLOADED)) FLAGCLEAR(pItem->dwFlags, POP3ITEM_DELETEOFFSERVER); // Is it marked for delete ? else if (ISFLAGSET(pItem->dwFlags, POP3ITEM_DELETEOFFSERVER)) m_rMetrics.cDelete++; } // Nothing to delete if (0 == m_rMetrics.cDelete) { // Disconnect m_pTransport->Disconnect(); // Done goto exit; } // Setup Progress m_rMetrics.iCurrent = 0; m_wProgress = 0; m_dwProgressCur = 0; m_dwProgressMax = m_rMetrics.cDelete; m_pUI->SetProgressRange(100); // State m_state = POP3STATE_DELETING; // Do the first one CHECKHR(hr = _HrDeleteNextMessage(0)); exit: // Done return hr; } // ------------------------------------------------------------------------------------ // CPop3Task::_HrDeleteNextMessage // ------------------------------------------------------------------------------------ HRESULT CPop3Task::_HrDeleteNextMessage(DWORD dwPopIdCurrent) { // Locals HRESULT hr=S_OK; CHAR szRes[CCHMAX_RES]; CHAR szMsg[CCHMAX_RES + CCHMAX_RES]; LPPOP3ITEM pItem; // Mark as deleted if (dwPopIdCurrent > 0) { // Get the item pItem = ITEMFROMPOPID(dwPopIdCurrent); // Mark as deleted FLAGSET(pItem->dwFlags, POP3ITEM_DELETED); } // Loop until we find the next message that we are downloading while(1) { // Incremenet dwPopIdCurrent dwPopIdCurrent++; // Last PopId, start the download if (dwPopIdCurrent > m_rTable.cItems) { // Disconnect m_pTransport->Disconnect(); // Done break; } // Readability pItem = ITEMFROMPOPID(dwPopIdCurrent); // Download this message ? if (ISFLAGSET(pItem->dwFlags, POP3ITEM_DELETEOFFSERVER)) { // Increment m_rMetrics.iCurrent m_rMetrics.iCurrent++; // Status //LOADSTRING(IDS_SPS_POP3DELE, szRes); //wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, m_rMetrics.iCurrent, m_rMetrics.cDelete); //m_pUI->SetSpecificProgress(szMsg); // Retrieve this item CHECKHR(hr = m_pTransport->CommandDELE(POP3CMD_GET_POPID, dwPopIdCurrent)); // Count number of items deleted by rule if (ISFLAGSET(pItem->dwFlags, POP3ITEM_DELEBYRULE)) m_rMetrics.cDeleByRule++; // Done break; } } exit: // Done return hr; } // ------------------------------------------------------------------------------------ // CPop3Task::_HrBuildFolderPartialMsgs // ------------------------------------------------------------------------------------ HRESULT CPop3Task::_HrBuildFolderPartialMsgs(IMessageFolder *pFolder, LPPARTIALMSG *ppPartialMsgs, ULONG *pcPartialMsgs, ULONG *pcTotalParts) { // Locals HRESULT hr=S_OK; LPPARTIALMSG pPartialMsgs=NULL; ULONG cPartialMsgs=0, iPartialMsg, iMsgPart, i, cTotalParts=0; ULONG cAlloc=0; MESSAGEINFO MsgInfo={0}; HROWSET hRowset=NULL; BOOL fKnownPartialId; // Check Params Assert(pFolder && ppPartialMsgs && pcPartialMsgs); // Init *ppPartialMsgs = NULL; *pcPartialMsgs = 0; *pcTotalParts = 0; // Create a Rowset CHECKHR(hr = pFolder->CreateRowset(IINDEX_PRIMARY, NOFLAGS, &hRowset)); // Loop while (S_OK == pFolder->QueryRowset(hRowset, 1, (LPVOID *)&MsgInfo, NULL)) { // Is this a partial, i.e. does it have a partial id... if (!FIsEmptyA(MsgInfo.pszPartialId)) { // Assume we don't know th id fKnownPartialId = FALSE; // See if I know this partial id for (iPartialMsg=0; iPartialMsg= cAlloc) { // Realloc the array if (!MemRealloc((LPVOID *)&pPartialMsgs, (cAlloc + 20) * sizeof(PARTIALMSG))) { hr = TrapError(hrMemory); goto exit; } // Zero Init ZeroMemory(pPartialMsgs + cAlloc, 20 * sizeof(PARTIALMSG)); // Realloc cAlloc += 20; } // Set index into partial msgs lsit iPartialMsg = cPartialMsgs; // Set some stuff if (MsgInfo.pszAcctName) StrCpyN(pPartialMsgs[iPartialMsg].szAccount, MsgInfo.pszAcctName, ARRAYSIZE(pPartialMsgs[iPartialMsg].szAccount)); pPartialMsgs[iPartialMsg].pszId = PszDupA(MsgInfo.pszPartialId); pPartialMsgs[iPartialMsg].cTotalParts = LOWORD(MsgInfo.dwPartial); // Increment number of known partial messages cPartialMsgs++; } // Otherwise, we know the partial id already... else { // See if this message details the total number of parts if (pPartialMsgs[iPartialMsg].cTotalParts == 0) pPartialMsgs[iPartialMsg].cTotalParts = LOWORD(MsgInfo.dwPartial); } // Can I add one more msgpart into this list if (pPartialMsgs[iPartialMsg].cMsgParts + 1 >= pPartialMsgs[iPartialMsg].cAlloc) { // Realloc the array if (!MemRealloc((LPVOID *)&pPartialMsgs[iPartialMsg].pMsgParts, (pPartialMsgs[iPartialMsg].cAlloc + 20) * sizeof(MSGPART))) { hr = TrapError(hrMemory); goto exit; } // Zero Init ZeroMemory(pPartialMsgs[iPartialMsg].pMsgParts + pPartialMsgs[iPartialMsg].cAlloc, 20 * sizeof(MSGPART)); // Realloc pPartialMsgs[iPartialMsg].cAlloc += 20; } // Set Message Part iMsgPart = pPartialMsgs[iPartialMsg].cMsgParts; // Set Message Info pPartialMsgs[iPartialMsg].pMsgParts[iMsgPart].iPart = HIWORD(MsgInfo.dwPartial); pPartialMsgs[iPartialMsg].pMsgParts[iMsgPart].msgid = MsgInfo.idMessage; //pPartialMsgs[iPartialMsg].pMsgParts[iMsgPart].phi = phi; //phi = NULL; // Increment the number of parts in the list pPartialMsgs[iPartialMsg].cMsgParts++; } // Free pFolder->FreeRecord(&MsgInfo); } // Lets sort the list by pszId for (i=0; i 0) _QSortMsgParts(pPartialMsgs[i].pMsgParts, 0, pPartialMsgs[i].cMsgParts-1); cTotalParts += pPartialMsgs[i].cMsgParts; } // Success *pcPartialMsgs = cPartialMsgs; *ppPartialMsgs = pPartialMsgs; *pcTotalParts = cTotalParts; exit: // Cleanup if (pFolder) { pFolder->CloseRowset(&hRowset); pFolder->FreeRecord(&MsgInfo); } // If We failed, free stuff if (FAILED(hr)) { _FreePartialMsgs(pPartialMsgs, cPartialMsgs); SafeMemFree(pPartialMsgs); *ppPartialMsgs = NULL; *pcPartialMsgs = 0; *pcTotalParts = 0; } // Done return hr; } // ------------------------------------------------------------------------------------ // CPop3Task::_QSortMsgParts // ------------------------------------------------------------------------------------ void CPop3Task::_QSortMsgParts(LPMSGPART pMsgParts, LONG left, LONG right) { register long i, j; WORD k; MSGPART y; i = left; j = right; k = pMsgParts[(left + right) / 2].iPart; do { while(pMsgParts[i].iPart < k && i < right) i++; while (pMsgParts[j].iPart > k && j > left) j--; if (i <= j) { CopyMemory(&y, &pMsgParts[i], sizeof(MSGPART)); CopyMemory(&pMsgParts[i], &pMsgParts[j], sizeof(MSGPART)); CopyMemory(&pMsgParts[j], &y, sizeof(MSGPART)); i++; j--; } } while (i <= j); if (left < j) _QSortMsgParts(pMsgParts, left, j); if (i < right) _QSortMsgParts(pMsgParts, i, right); } // ------------------------------------------------------------------------------------ // CPop3Task::_FreePartialMsgs // ------------------------------------------------------------------------------------ void CPop3Task::_FreePartialMsgs(LPPARTIALMSG pPartialMsgs, ULONG cPartialMsgs) { // Locals ULONG i, j; // Nothing to free if (pPartialMsgs == NULL) return; // Loop the array for (i=0; iSetSpecificProgress(szRes); m_pUI->SetAnimation(idanDecode, TRUE); m_pUI->SetProgressRange(100); // Get Window if (FAILED(m_pUI->GetWindow(&hwnd))) hwnd = NULL; // open the inbox CHECKHR(hr = m_pSpoolCtx->BindToObject(IID_CLocalStoreInbox, (LPVOID *)&pInbox)); // deleted items folder CHECKHR(hr = m_pSpoolCtx->BindToObject(IID_CLocalStoreDeleted, (LPVOID *)&pDeletedItems)); // Get array of message parts in this folder CHECKHR(hr = _HrBuildFolderPartialMsgs(pInbox, &pPartialMsgs, &cPartialMsgs, &cTotalParts)); // If nothing, were done if (pPartialMsgs == NULL || cPartialMsgs == 0) goto exit; // Setup Progress m_rMetrics.iCurrent = 0; m_wProgress = 0; m_dwProgressCur = 0; m_dwProgressMax = cTotalParts; // Loop through partial messages list for (i=0; i 0) { m_dwProgressCur++; _DoProgress(); } // Open this message if (FAILED(pInbox->OpenMessage(pMsgParts[j].msgid, NOFLAGS, &pMailMsg, NOSTORECALLBACK))) { cErrors++; hr = TrapError(E_FAIL); goto NextPartialMessage; } // Add into pmml pParts->AddPart(pMailMsg); // Release It SafeRelease(pMailMsg); } // Create a new message to combine everyting into Assert(pMailMsgSingle == NULL); // Create a Message hr = pParts->CombineParts(&pMailMsgSingle); if (FAILED(hr)) { cErrors++; TrapError(hr); goto NextPartialMessage; } // Set Account HrSetAccount(pMailMsgSingle, pPartialMsgs[i].szAccount); // Set Combined Flag rUserData.vt = VT_UI4; rUserData.ulVal = MESSAGE_COMBINED; pMailMsgSingle->SetProp(PIDTOSTR(PID_ATT_COMBINED), NOFLAGS, &rUserData); // Save the message hr = pMailMsgSingle->Commit(0); if (FAILED(hr)) { cErrors++; TrapError(hr); goto NextPartialMessage; } // Save It hr = pInbox->SaveMessage(NULL, SAVE_MESSAGE_GENID, ARF_RECEIVED, 0, pMailMsgSingle, NOSTORECALLBACK); if (FAILED(hr)) { cErrors++; TrapError(hr); goto NextPartialMessage; } // Ok, now lets move those original messages to the deleted items folder... for (j=0; jSetSpecificProgress(c_szEmpty); m_pUI->SetProgressRange(100); SafeRelease(pInbox); SafeRelease(pDeletedItems); SafeRelease(pParts); SafeRelease(pMailMsg); SafeRelease(pMailMsgSingle); _FreePartialMsgs(pPartialMsgs, cPartialMsgs); SafeMemFree(pPartialMsgs); // Done return hr; } // ------------------------------------------------------------------------------------ // CPop3Task::_GetMoveFolder // ------------------------------------------------------------------------------------ HRESULT CPop3Task::_GetMoveFolder(LPPOP3ITEM pItem, IMessageFolder ** ppFolder) { HRESULT hr = S_OK; IMessageFolder * pFolder = NULL; ULONG ulIndex = 0; FOLDERID idFolder = FOLDERID_INVALID; FOLDERINFO infoFolder = {0}; SPECIALFOLDER tySpecial = FOLDER_NOTSPECIAL; RULEFOLDERDATA * prfdData = NULL; // Check incoming params if ((NULL == pItem) || (NULL == ppFolder)) { hr = E_INVALIDARG; goto exit; } // Initialize the outgoing param *ppFolder = NULL; // Search for a Move actions for (ulIndex = 0; ulIndex < pItem->cActList; ulIndex++) { switch (pItem->pActList[ulIndex].type) { case ACT_TYPE_MOVE: Assert(VT_BLOB == pItem->pActList[ulIndex].propvar.vt); if ((0 != pItem->pActList[ulIndex].propvar.blob.cbSize) && (NULL != pItem->pActList[ulIndex].propvar.blob.pBlobData)) { // Make life simpler prfdData = (RULEFOLDERDATA *) (pItem->pActList[ulIndex].propvar.blob.pBlobData); // Validate the rule folder data if (S_OK == RuleUtil_HrValidateRuleFolderData(prfdData)) { idFolder = prfdData->idFolder; } } break; case ACT_TYPE_DELETE: case ACT_TYPE_JUNKMAIL: Assert(VT_EMPTY == pItem->pActList[ulIndex].propvar.vt); tySpecial = (ACT_TYPE_JUNKMAIL == pItem->pActList[ulIndex].type) ? FOLDER_JUNK : FOLDER_DELETED; hr = g_pStore->GetSpecialFolderInfo(FOLDERID_LOCAL_STORE, tySpecial, &infoFolder); if (FAILED(hr)) { goto exit;; } idFolder = infoFolder.idFolder; break; } // Are we through? if (idFolder != FOLDERID_INVALID) { break; } } // Did we find anything? if (ulIndex >= pItem->cActList) { hr = S_FALSE; goto exit; } // Get the message folder hr = m_pIExecRules->GetRuleFolder(idFolder, (DWORD_PTR *) (&pFolder)); if (FAILED(hr)) { goto exit; } // Use the new folder *ppFolder = pFolder; pFolder = NULL; // NULL out the actions pItem->pActList[ulIndex].type = ACT_TYPE_NULL; // Set the return value hr = S_OK; exit: SafeRelease(pFolder); g_pStore->FreeRecord(&infoFolder); return hr; } // -------------------------------------------------------------------------------- // CPop3Task::Cancel // -------------------------------------------------------------------------------- STDMETHODIMP CPop3Task::Cancel(void) { // Thread Safety EnterCriticalSection(&m_cs); // Canceled FLAGSET(m_dwState, POP3STATE_CANCELPENDING); // Am I in a state where I can drop the connection??? if (POP3STATE_UIDLSYNC != m_state) { if (POP3STATE_UIDLSYNC != m_state && POP3STATE_DOWNLOADING != m_state && POP3STATE_DELETING != m_state) { // Simply drop the connection //If a dialer UI is not dismissed, before changing the identities or shutting down OE, //the transport object would not have been created. This happens only when the dialer UI is not //modal to the window. Right now IE dialer is modal and MSN dialer is not. //See Bug# 53679 if (m_pTransport) m_pTransport->DropConnection(); } // Otherwise, let the state handle the disconnect else { // Finishing last message... m_pUI->SetSpecificProgress(MAKEINTRESOURCE(idsSpoolerDisconnect)); } } // Thread Safety LeaveCriticalSection(&m_cs); // Done return S_OK; } // -------------------------------------------------------------------------------- // CPop3Task::OnTimeoutResponse // -------------------------------------------------------------------------------- STDMETHODIMP CPop3Task::OnTimeoutResponse(TIMEOUTRESPONSE eResponse) { // Thread Safety EnterCriticalSection(&m_cs); // Should have a handle to the timeout window Assert(m_hwndTimeout); // No timeout window handle m_hwndTimeout = NULL; // Stop ? if (TIMEOUT_RESPONSE_STOP == eResponse) { // Canceled FLAGSET(m_dwState, POP3STATE_CANCELPENDING); // Report error and drop connection _CatchResult(IXP_E_TIMEOUT); } // Thread Safety LeaveCriticalSection(&m_cs); // Done return S_OK; } // -------------------------------------------------------------------------------- // CPop3Task::IsDialogMessage // -------------------------------------------------------------------------------- STDMETHODIMP CPop3Task::IsDialogMessage(LPMSG pMsg) { HRESULT hr=S_FALSE; EnterCriticalSection(&m_cs); if (m_hwndTimeout && IsWindow(m_hwndTimeout)) hr = (TRUE == ::IsDialogMessage(m_hwndTimeout, pMsg)) ? S_OK : S_FALSE; LeaveCriticalSection(&m_cs); return hr; } // -------------------------------------------------------------------------------- // CPop3Task::OnFlagsChanged // -------------------------------------------------------------------------------- STDMETHODIMP CPop3Task::OnFlagsChanged(DWORD dwFlags) { EnterCriticalSection(&m_cs); m_dwFlags = dwFlags; LeaveCriticalSection(&m_cs); return (S_OK); }