|
|
/////////////////////////////////////////////////////////////////////////////
// Copyright (C) 1993-1998 Microsoft Corporation. All Rights Reserved.
//
// MODULE: msgview.cpp
//
// PURPOSE: Implements the Outlook Express view class that handles
// displaying the contents of folders with messages.
//
#include "pch.hxx"
#include "msgview.h"
#include "browser.h"
#include "thormsgs.h"
#include "msglist.h"
#include "msoedisp.h"
#include "statbar.h"
#include "ibodyobj.h"
#include "mehost.h"
#include "util.h"
#include "shlwapip.h"
#include "menuutil.h"
#include "storutil.h"
#include "ruleutil.h"
#include "note.h"
#include "newsutil.h"
#include "menures.h"
#include "ipab.h"
#include "order.h"
#include <inetcfg.h>
#include "instance.h"
/////////////////////////////////////////////////////////////////////////////
// Global Data
//
static const char s_szMessageViewWndClass[] = TEXT("Outlook Express Message View");
extern BOOL g_fBadShutdown;
/////////////////////////////////////////////////////////////////////////////
// Prototypes
//
/////////////////////////////////////////////////////////////////////////////
// Message Macros
//
// void OnPostCreate(HWND hwnd)
#define HANDLE_WM_POSTCREATE(hwnd, wParam, lParam, fn) \
((fn)(hwnd), 0L) #define FORWARD_WM_POSTCREATE(hwnd, fn) \
(void)(fn)((hwnd), WM_POSTCREATE, 0L, 0L)
// LRESULT OnTestGetMsgId(HWND hwnd)
#define HANDLE_WM_TEST_GETMSGID(hwnd, wParam, lParam, fn) \
(LRESULT)((fn)(hwnd)) #define FORWARD_WM_TEST_GETMSGID(hwnd, fn) \
(LRESULT)(fn)((hwnd), WM_TEST_GETMSGID, 0L, 0L)
// LRESULT OnTestSaveMessage(HWND hwnd)
#define HANDLE_WM_TEST_SAVEMSG(hwnd, wParam, lParam, fn) \
(LRESULT)((fn)(hwnd)) #define FORWARD_WM_TEST_SAVEMSG(hwnd, fn) \
(LRESULT)(fn)((hwnd), WM_TEST_SAVEMSG, 0L, 0L)
/////////////////////////////////////////////////////////////////////////////
// Constructors, Destructors, and Initialization
//
CMessageView::CMessageView() { m_cRef = 1;
m_hwnd = NULL; m_hwndParent = NULL;
m_pBrowser = NULL; m_idFolder = FOLDERID_INVALID; m_pDropTarget = NULL;
m_pMsgList = NULL; m_pMsgListCT = NULL; m_pMsgListAO = NULL; m_dwCookie = 0; m_pServer = NULL;
m_pPreview = NULL; m_pPreviewCT = NULL;
m_fSplitHorz = TRUE; SetRect(&m_rcSplit, 0, 0, 0, 0); m_dwSplitVertPct = 50; m_dwSplitHorzPct = 50; m_fDragging = FALSE;
m_uUIState = SVUIA_DEACTIVATE; m_cUnread = 0; m_cItems = 0; m_pGroups = NULL; m_idMessageFocus = MESSAGEID_INVALID; m_pProgress = NULL; m_fNotDownloaded = FALSE; m_cLastChar = GetTickCount();
m_pViewMenu = NULL; }
CMessageView::~CMessageView() { SafeRelease(m_pViewMenu); if (m_pGroups != NULL) { m_pGroups->Close(); m_pGroups->Release(); } SafeRelease(m_pBrowser); SafeRelease(m_pMsgList); SafeRelease(m_pMsgListCT); SafeRelease(m_pMsgListAO); SafeRelease(m_pPreview); SafeRelease(m_pPreviewCT); SafeRelease(m_pProgress); SafeRelease(m_pDropTarget); Assert(NULL == m_pServer); }
//
// FUNCTION: CMessageView::Initialize()
//
// PURPOSE: Get's called to initialize the object and tell it what folder
// it will be looking at.
//
// PARAMETERS:
// [in] pidl
// [in] *pFolder
//
// RETURN VALUE:
// HRESULT
//
HRESULT CMessageView::Initialize(FOLDERID idFolder) { TraceCall("CMessageView::Initialize");
// Copy the pidl, we'll use it later
m_idFolder = idFolder;
return (S_OK); }
/////////////////////////////////////////////////////////////////////////////
// IUnknown
//
HRESULT CMessageView::QueryInterface(REFIID riid, LPVOID *ppvObj) { *ppvObj = NULL;
if (IsEqualIID(riid, IID_IUnknown)) *ppvObj = (LPVOID) (IUnknown *) (IViewWindow *) this; else if (IsEqualIID(riid, IID_IOleWindow)) *ppvObj = (LPVOID) (IViewWindow *) this; else if (IsEqualIID(riid, IID_IViewWindow)) *ppvObj = (LPVOID) (IViewWindow *) this; else if (IsEqualIID(riid, IID_IMessageWindow)) *ppvObj = (LPVOID) (IMessageWindow *) this; else if (IsEqualIID(riid, IID_IOleCommandTarget)) *ppvObj = (LPVOID) (IOleCommandTarget *) this; else if (IsEqualIID(riid, IID_IBodyOptions)) *ppvObj = (LPVOID) (IBodyOptions *) this; else if (IsEqualIID(riid, IID_IDispatch)) *ppvObj = (LPVOID) (IDispatch *) this; else if (IsEqualIID(riid, DIID__MessageListEvents)) *ppvObj = (LPVOID) (IDispatch *) this; else if (IsEqualIID(riid, IID_IServerInfo)) *ppvObj = (LPVOID) (IServerInfo *) this;
if (NULL == *ppvObj) return (E_NOINTERFACE);
AddRef(); return S_OK; }
ULONG CMessageView::AddRef(void) { return InterlockedIncrement((LONG *) &m_cRef); }
ULONG CMessageView::Release(void) { InterlockedDecrement((LONG *) &m_cRef); if (0 == m_cRef) { delete this; return (0); } return (m_cRef); }
/////////////////////////////////////////////////////////////////////////////
// IOleWindow
//
HRESULT CMessageView::GetWindow(HWND *pHwnd) { if (!pHwnd) return (E_INVALIDARG); if (m_hwnd) { *pHwnd = m_hwnd; return (S_OK); }
return (E_FAIL); }
HRESULT CMessageView::ContextSensitiveHelp(BOOL fEnterMode) { return (E_NOTIMPL); }
/////////////////////////////////////////////////////////////////////////////
// IViewWindow
//
//
// FUNCTION: CMessageView::TranslateAccelerator()
//
// PURPOSE: Called by the frame window to give us first crack at messages.
//
// PARAMETERS:
// [in] pMsg - The current message to be processed.
//
// RETURN VALUE:
// S_OK if the message was handled here and should not be processed further.
// S_FALSE if the message should continued to be processed elsewhere.
//
HRESULT CMessageView::TranslateAccelerator(LPMSG pMsg) { DWORD dwState = 0;
// See if the Preview Pane is interested
if (m_pPreview) { if (S_OK == m_pPreview->HrTranslateAccelerator(pMsg)) return (S_OK); if (IsChild(m_hwnd, GetFocus())) { if (pMsg->message == WM_KEYDOWN && pMsg->wParam != VK_SPACE) m_cLastChar = GetTickCount();
if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_SPACE && GetTickCount() - m_cLastChar > 1000) { if (m_fNotDownloaded) { _UpdatePreviewPane(TRUE); } else if (SUCCEEDED(m_pMsgList->GetFocusedItemState(&dwState)) && dwState != 0) { if (m_pPreview->HrScrollPage()!=S_OK) m_pMsgListCT->Exec(NULL, ID_SPACE_ACCEL, 0, NULL, NULL); } else m_pMsgListCT->Exec(NULL, ID_SPACE_ACCEL, 0, NULL, NULL); return S_OK; } } }
// See if the message list is interested
if (m_pMsgListAO) { if (S_OK == m_pMsgListAO->TranslateAccelerator(pMsg)) return (S_OK); }
return (S_FALSE); }
//
// FUNCTION: CMessageView::UIActivate()
//
// PURPOSE: Called to notify the view when different activation and
// deactivation events occur.
//
// PARAMETERS:
// [in] uState - SVUIA_ACTIVATE_FOCUS, SVUIA_ACTIVATE_NOFOCUS, and
// SVUIA_DEACTIVATE.
//
// RETURN VALUE:
// Returns S_OK all the time.
//
HRESULT CMessageView::UIActivate(UINT uState) { if (uState != SVUIA_DEACTIVATE) { // If the focus stays within our frame, bug goes outside our view,
// i.e. the folder list get's focus, then we get an
// SVUIA_ACTIVATE_NOFOCUS. We need to UI Deactivate the preview
// pane when this happens.
if (uState == SVUIA_ACTIVATE_NOFOCUS && m_pPreview) m_pPreview->HrUIActivate(FALSE);
if (m_uUIState != uState) { // Update our internal state
m_uUIState = uState;
// Update the toolbar state
m_pBrowser->UpdateToolbar(); } } else { // Only deactivate if we're not already deactivated
if (m_uUIState != SVUIA_DEACTIVATE) { // Update our internal state
m_uUIState = uState; } } return (S_OK); }
//
// FUNCTION: CMessageView::CreateViewWindow()
//
// PURPOSE: Called when it's time for the view to create it's window.
//
// PARAMETERS:
// [in] pPrevView - Pointer to the previous view if there was one
// [in] pBrowser - Pointer to the browser that hosts this view
// [in] prcView - Initial position and size of the view
// [out] pHwnd - Returns the HWND of the newly created view window
//
// RETURN VALUE:
// S_OK if the view window was created successfully.
// E_FAIL if the window couldn't be created for some reason or another.
//
HRESULT CMessageView::CreateViewWindow(IViewWindow *pPrevView, IAthenaBrowser *pBrowser, RECT *prcView, HWND *pHwnd) { WNDCLASS wc;
// Without a browser pointer nothing will ever work.
if (!pBrowser) return (E_INVALIDARG);
// Hang on to the browser pointer
m_pBrowser = pBrowser; m_pBrowser->AddRef();
// Get the window handle of the browser
m_pBrowser->GetWindow(&m_hwndParent); Assert(IsWindow(m_hwndParent));
// Load our persisted settings. If this fails will just run with defaults.
// _LoadSettings();
// Register our window class if we haven't already
if (!GetClassInfo(g_hInst, s_szMessageViewWndClass, &wc)) { wc.style = 0; wc.lpfnWndProc = CMessageView::ViewWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = g_hInst; wc.hIcon = NULL; wc.hCursor = NULL; wc.hbrBackground = (HBRUSH) (COLOR_3DFACE + 1); wc.lpszMenuName = NULL; wc.lpszClassName = s_szMessageViewWndClass;
if (!RegisterClass(&wc)) return (E_FAIL); }
// Create the view window
m_hwnd = CreateWindowEx(WS_EX_CONTROLPARENT , s_szMessageViewWndClass, NULL, WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, prcView->left, prcView->top, prcView->right - prcView->left, prcView->bottom - prcView->top, m_hwndParent, NULL, g_hInst, (LPVOID) this); if (!m_hwnd) return (E_FAIL);
*pHwnd = m_hwnd;
// Get the message folder object from the previous folder here.
_ReuseMessageFolder(pPrevView);
return (S_OK); }
//
// FUNCTION: CMessageView::DestroyViewWindow()
//
// PURPOSE: Called by the browser to destroy the view window.
//
// RETURN VALUE:
// S_OK is returned always.
//
HRESULT CMessageView::DestroyViewWindow(void) { // This is of course only interesting if we actually _have_ a window to
// destroy.
if (m_hwnd) { // Tell the message list we're done with this folder
if (m_pMsgList) { m_pMsgList->SetFolder(FOLDERID_INVALID, NULL, 0, 0, 0); }
// Unadvise our connection point
if (m_dwCookie) { AtlUnadvise(m_pMsgList, DIID__MessageListEvents, m_dwCookie); m_dwCookie = 0; }
// $REVIEW - PreDestroyViewWindow() used to be called here to tell the subclasses
// of the iminent destruction.
// Set our cached HWND to NULL before destroying prevents us from
// handling notifications after important stuff has been freed.
HWND hwndDest = m_hwnd; m_hwnd = NULL; DestroyWindow(hwndDest); }
return (S_OK); }
//
// FUNCTION: CMessageView::SaveViewState()
//
// PURPOSE: Called by the browser to give the view a chance to save it's
// settings before it is destroyed.
//
// RETURN VALUE:
// E_NOTIMPL
//
HRESULT CMessageView::SaveViewState(void) { FOLDERTYPE ft = GetFolderType(m_idFolder);
// Tell the message list to save it's state
if (m_pMsgList) { m_pMsgList->OnClose();
// We also need to save any settings that might have changed
FOLDER_OPTIONS fo = { 0 };
fo.cbSize = sizeof(FOLDER_OPTIONS); fo.dwMask = FOM_THREAD | FOM_OFFLINEPROMPT | FOM_SHOWDELETED | FOM_SHOWREPLIES;
if (SUCCEEDED(m_pMsgList->GetViewOptions(&fo))) { switch (ft) { case FOLDER_NEWS: SetDwOption(OPT_NEWS_THREAD, fo.fThread, 0, 0); break;
case FOLDER_LOCAL: case FOLDER_HTTPMAIL: SetDwOption(OPT_MAIL_THREAD, fo.fThread, 0, 0); break;
case FOLDER_IMAP: SetDwOption(OPT_MAIL_THREAD, fo.fThread, 0, 0); break; } SetDwOption(OPT_SHOW_DELETED, (DWORD) (fo.fDeleted), 0, 0); SetDwOption(OPT_SHOW_REPLIES, (DWORD) (fo.fReplies), 0, 0); } }
// Reset the contents of the status bar
CStatusBar *pStatusBar; m_pBrowser->GetStatusBar(&pStatusBar); if (pStatusBar) { pStatusBar->SetStatusText(""); pStatusBar->Release(); }
return (S_OK); }
//
// FUNCTION: CMessageView::OnPopupMenu()
//
// PURPOSE: Called whenever the frame receives a WM_INITMENUPOPUP
// notification. The view adds any menu items or sets any
// check marks that are appropriate.
//
// PARAMETERS:
// [in] hMenu - The handle of the root menu bar
// [in] hMenuPopup - The handle of the specific popup menu
// [in] uID - The ID of the popup menu
//
// RETURN VALUE:
// Unused
//
HRESULT CMessageView::OnPopupMenu(HMENU hMenu, HMENU hMenuPopup, UINT uID) { MENUITEMINFO mii; UINT uItem; HCHARSET hCharset;
// Handle our items
switch (uID) { case ID_POPUP_LANGUAGE: { mii.cbSize = sizeof(MENUITEMINFO); mii.fMask = MIIM_SUBMENU; UINT uiCodepage = 0; HMENU hLangMenu = NULL; m_pPreview->HrGetCharset(&hCharset); uiCodepage = CustomGetCPFromCharset(hCharset, TRUE); if(m_pBrowser->GetLanguageMenu(&hLangMenu, uiCodepage) == S_OK) { if(IsMenu(hMenuPopup)) DestroyMenu(hMenuPopup);
hMenuPopup = mii.hSubMenu = hLangMenu; SetMenuItemInfo(hMenu, ID_POPUP_LANGUAGE, FALSE, &mii); } break; }
case ID_POPUP_VIEW: { if (NULL == m_pViewMenu) { // Create the view menu
HrCreateViewMenu(0, &m_pViewMenu); } if (NULL != m_pViewMenu) { mii.cbSize = sizeof(MENUITEMINFO); mii.fMask = MIIM_SUBMENU; if (FALSE == GetMenuItemInfo(hMenuPopup, ID_POPUP_FILTER, FALSE, &mii)) { break; } // Remove the old filter submenu
if(IsMenu(mii.hSubMenu)) DestroyMenu(mii.hSubMenu);
// Replace the view menu
if (FAILED(m_pViewMenu->HrReplaceMenu(0, hMenuPopup))) { break; } } break; } case ID_POPUP_FILTER: { if (NULL != m_pViewMenu) { m_pViewMenu->UpdateViewMenu(0, hMenuPopup, m_pMsgList); } break; } }
// Let the message list update it's menus
if (m_pMsgList) m_pMsgList->OnPopupMenu(hMenuPopup, uID);
// Let the preview pane update it's menus
if (m_pPreview) m_pPreview->HrOnInitMenuPopup(hMenuPopup, uID);
return (S_OK); }
HRESULT CMessageView::OnFrameWindowActivate(BOOL fActivate) { if (m_pPreview) return m_pPreview->HrFrameActivate(fActivate); return (S_OK); }
HRESULT CMessageView::UpdateLayout(BOOL fVisible, BOOL fHeader, BOOL fVert, BOOL fUpdate) { // If we haven't created the preview pane yet, and the call is telling
// us to make it visible, then we need to initialize it first.
if (!m_pPreview && fVisible) { if (!_InitPreviewPane()) return (E_UNEXPECTED); }
// Header on / off
if (m_pPreview) { m_pPreview->HrSetStyle(fHeader ? MESTYLE_PREVIEW : MESTYLE_MINIHEADER); }
// Split direction
if (m_pPreview) { RECT rcClient;
m_fSplitHorz = !fVert; GetClientRect(m_hwnd, &rcClient); OnSize(m_hwnd, SIZE_RESTORED, rcClient.right, rcClient.bottom); }
//
// [PaulHi] 6/11/99 Raid 79491
// Backing out this fix that BrettM made for Raid 63739 because of problems
// with security message warnings.
//
#if 0
if (fVisible) { // if showing update the preview pane
_UpdatePreviewPane(); } else { // if hiding, clear the contents
if (NULL != m_pPreview) m_pPreview->HrUnloadAll(NULL, 0); } #endif
return (S_OK); }
HRESULT CMessageView::GetMessageList(IMessageList ** ppMsgList) { HRESULT hr = S_OK;
// Check incoming params
if (NULL == ppMsgList) { hr = E_INVALIDARG; goto exit; }
// Initialize the outgoing param
*ppMsgList = NULL;
// Get the message list
if (NULL != m_pMsgList) { *ppMsgList = m_pMsgList; (*ppMsgList)->AddRef(); }
// Set the return value
hr = (NULL == *ppMsgList) ? S_FALSE : S_OK; exit: return hr; }
HRESULT CMessageView::GetCurCharSet(UINT *cp) { HCHARSET hCharset;
if(_IsPreview()) { m_pPreview->HrGetCharset(&hCharset); *cp = CustomGetCPFromCharset(hCharset, TRUE); } else *cp = GetACP();
return S_OK; }
//
// FUNCTION: CMessageView::QueryStatus()
//
// PURPOSE: Called by the browser to determine if a list of commands should
// should be enabled or disabled.
//
// PARAMETERS:
// [in] pguidCmdGroup - Group the commands are part of (unused)
// [in] cCmds - Number of commands to be evaluated
// [in] prgCmds - List of commands
// [out] pCmdText - Description text for a command
//
// RETURN VALUE:
// HRESULT
//
HRESULT CMessageView::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText) { DWORD cSel; HRESULT hr; HWND hwndFocus = GetFocus(); BOOL fChildFocus = (hwndFocus != NULL && IsChild(m_hwnd, hwndFocus)); DWORD cFocus; DWORD *rgSelected = 0; FOLDERTYPE ftType;
// Let the sub objects look first
if (m_pMsgListCT) { hr = m_pMsgListCT->QueryStatus(pguidCmdGroup, cCmds, prgCmds, pCmdText); }
if (_IsPreview() && m_pPreviewCT) { hr = m_pPreviewCT->QueryStatus(pguidCmdGroup, cCmds, prgCmds, pCmdText); }
// Up front some work
m_pMsgList->GetSelected(&cFocus, &cSel, &rgSelected);
// Now loop through the commands in the prgCmds array looking for ones the
// sub objects didn't handle.
for (UINT i = 0; i < cCmds; i++) { if (prgCmds[i].cmdf == 0) { // If this command is from the language menu
if (prgCmds[i].cmdID >= ID_LANG_FIRST && prgCmds[i].cmdID <= ID_LANG_LAST) { HCHARSET hCharset;
m_pPreview->HrGetCharset(&hCharset);
// Enable only the supported languages
if (prgCmds[i].cmdID < (UINT) (ID_LANG_FIRST + GetIntlCharsetLanguageCount())) { #if 0
if(SetMimeLanguageCheckMark(CustomGetCPFromCharset(hCharset, TRUE), prgCmds[i].cmdID - ID_LANG_FIRST)) prgCmds[i].cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED | OLECMDF_NINCHED; else prgCmds[i].cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED; #else
prgCmds[i].cmdf = OLECMDF_SUPPORTED | SetMimeLanguageCheckMark(CustomGetCPFromCharset(hCharset, TRUE), prgCmds[i].cmdID - ID_LANG_FIRST); #endif
} else prgCmds[i].cmdf = OLECMDF_SUPPORTED;
continue; }
// if the command id from the View.Current View menu
if ((ID_VIEW_FILTER_FIRST <= prgCmds[i].cmdID) && (ID_VIEW_FILTER_LAST >= prgCmds[i].cmdID)) { if (NULL == m_pViewMenu) { // Create the view menu
HrCreateViewMenu(0, &m_pViewMenu); } if (NULL != m_pViewMenu) { m_pViewMenu->QueryStatus(m_pMsgList, &(prgCmds[i])); }
continue; } // Look to see if it's a command we provide
switch (prgCmds[i].cmdID) { case ID_OPEN: { // Enabled only if the focus is in the ListView and there
// is at least one item selected.
m_pMsgList->GetSelectedCount(&cSel); if (cSel) prgCmds[i].cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED; else prgCmds[i].cmdf = OLECMDF_SUPPORTED; break; }
case ID_REPLY: case ID_REPLY_ALL: { // Enabled only if the focus is in the ListView and there
// is only one item selected
prgCmds[i].cmdf = OLECMDF_SUPPORTED;
if (cSel == 1) { // The message's body must also be downloaded
LPMESSAGEINFO pInfo;
if (SUCCEEDED(m_pMsgList->GetMessageInfo(rgSelected[0], &pInfo))) { if (pInfo->faStream != 0 && (0 == (pInfo->dwFlags & ARF_UNSENT))) prgCmds[i].cmdf |= OLECMDF_ENABLED;
m_pMsgList->FreeMessageInfo(pInfo); } }
break; }
case ID_SAVE_AS: { // Enabled only if the focus is in the ListView and there
// is one item selected
prgCmds[i].cmdf = OLECMDF_SUPPORTED;
if (_IsPreview() && (cSel == 1)) { // The message's body must also be downloaded
LPMESSAGEINFO pInfo;
if (SUCCEEDED(m_pMsgList->GetMessageInfo(rgSelected[0], &pInfo))) { if (pInfo->faStream != 0) prgCmds[i].cmdf |= OLECMDF_ENABLED;
m_pMsgList->FreeMessageInfo(pInfo); } }
break; }
case ID_PRINT: { // Enabled only if the focus is in the ListView and there
// is more than one item selected
prgCmds[i].cmdf = OLECMDF_SUPPORTED;
if (_IsPreview() && cSel > 0) { // The message's body must also be downloaded
LPMESSAGEINFO pInfo;
if (SUCCEEDED(m_pMsgList->GetMessageInfo(rgSelected[0], &pInfo))) { if (pInfo->faStream != 0) prgCmds[i].cmdf |= OLECMDF_ENABLED;
m_pMsgList->FreeMessageInfo(pInfo); } }
break; }
case ID_FORWARD: case ID_FORWARD_AS_ATTACH: { // Enabled only if the focus is in the ListView and there
// is only one item selected
prgCmds[i].cmdf = OLECMDF_SUPPORTED;
if (cSel > 0) { // The message's body must also be downloaded
LPMESSAGEINFO pInfo;
// Default to success
prgCmds[i].cmdf |= OLECMDF_ENABLED; for (DWORD iItem = 0; iItem < cSel && (prgCmds[i].cmdf & OLECMDF_ENABLED); iItem++) { if (SUCCEEDED(m_pMsgList->GetMessageInfo(rgSelected[iItem], &pInfo))) { if (pInfo->faStream == 0 || (0 != (pInfo->dwFlags & ARF_UNSENT))) { prgCmds[i].cmdf &= ~OLECMDF_ENABLED; }
m_pMsgList->FreeMessageInfo(pInfo); } } }
break; }
case ID_REPLY_GROUP: { // Enabled only if there is one news message selected
prgCmds[i].cmdf = OLECMDF_SUPPORTED;
if (cSel == 1) { // The message's body must also be downloaded
LPMESSAGEINFO pInfo;
if (SUCCEEDED(m_pMsgList->GetMessageInfo(rgSelected[0], &pInfo))) { if (pInfo->faStream != 0 && (pInfo->dwFlags & ARF_NEWSMSG) && (0 == (pInfo->dwFlags & ARF_UNSENT))) prgCmds[i].cmdf |= OLECMDF_ENABLED;
m_pMsgList->FreeMessageInfo(pInfo); } } break; }
case ID_CANCEL_MESSAGE: { prgCmds[i].cmdf = OLECMDF_SUPPORTED;
if (DwGetOption(OPT_CANCEL_ALL_NEWS)) prgCmds[i].cmdf |= OLECMDF_ENABLED; else { if (cSel == 1) { LPMESSAGEINFO pInfo;
if (SUCCEEDED(m_pMsgList->GetMessageInfo(rgSelected[0], &pInfo))) { if (NewsUtil_FCanCancel(m_idFolder, pInfo)) { prgCmds[i].cmdf |= OLECMDF_ENABLED; }
m_pMsgList->FreeMessageInfo(pInfo); } } } break; }
case ID_POPUP_FILTER: case ID_PREVIEW_PANE: { prgCmds[i].cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED; break; }
case ID_POPUP_LANGUAGE_DEFERRED: case ID_POPUP_LANGUAGE: case ID_POPUP_LANGUAGE_MORE: case ID_LANGUAGE: { // These are OK if the preview pane is visible and not empty
if (cSel > 0 && _IsPreview()) prgCmds[i].cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED; else prgCmds[i].cmdf = OLECMDF_SUPPORTED;
break; }
case ID_PREVIEW_SHOW: case ID_PREVIEW_BELOW: case ID_PREVIEW_BESIDE: case ID_PREVIEW_HEADER: { FOLDERTYPE ftType; DWORD dwOpt; LAYOUTPOS pos; BOOL fVisible; DWORD dwFlags;
// Default return value
prgCmds[i].cmdf = OLECMDF_SUPPORTED; // Get the folder type
m_pBrowser->GetFolderType(&ftType); if (ftType == FOLDER_NEWS) dwOpt = DISPID_MSGVIEW_PREVIEWPANE_NEWS; else dwOpt = DISPID_MSGVIEW_PREVIEWPANE_MAIL;
// Get the settings from the browser
m_pBrowser->GetViewLayout(dwOpt, &pos, &fVisible, &dwFlags, NULL); switch (prgCmds[i].cmdID) { case ID_PREVIEW_SHOW: { // Always enabled, checked if already visible
if (fVisible) prgCmds[i].cmdf |= (OLECMDF_ENABLED | OLECMDF_LATCHED); else prgCmds[i].cmdf |= OLECMDF_ENABLED; break; }
case ID_PREVIEW_BESIDE: case ID_PREVIEW_BELOW: { // The command is enabled only if the preview pane
// is visible.
if (fVisible) prgCmds[i].cmdf |= OLECMDF_ENABLED;
// If the preview pane is already beside, it should be latched etc.
if ((pos == LAYOUT_POS_LEFT && prgCmds[i].cmdID == ID_PREVIEW_BESIDE) || (pos == LAYOUT_POS_BOTTOM && prgCmds[i].cmdID == ID_PREVIEW_BELOW)) prgCmds[i].cmdf |= OLECMDF_NINCHED;
break; }
case ID_PREVIEW_HEADER: { // Always enabled, checked if already visible
if (dwFlags) prgCmds[i].cmdf |= (OLECMDF_ENABLED | OLECMDF_LATCHED); else prgCmds[i].cmdf |= OLECMDF_ENABLED; break; } }
break; }
case ID_REFRESH: { // Best I can tell, these are always enabled
prgCmds[i].cmdf |= OLECMDF_ENABLED; break; }
case ID_GET_HEADERS: { // Only in news
m_pBrowser->GetFolderType(&ftType); if (ftType != FOLDER_LOCAL) prgCmds[i].cmdf |= OLECMDF_ENABLED; break; }
case ID_ADD_SENDER: case ID_BLOCK_SENDER: { prgCmds[i].cmdf = OLECMDF_SUPPORTED;
// Enabled only if there is only one item selected and
// we have access to the from address
// Not in IMAP or HTTPMAIL
m_pBrowser->GetFolderType(&ftType); if (cSel == 1 && (prgCmds[i].cmdID == ID_ADD_SENDER || (FOLDER_HTTPMAIL != ftType && FOLDER_IMAP != ftType))) { // The message's body must also be downloaded
LPMESSAGEINFO pInfo;
if (SUCCEEDED(m_pMsgList->GetMessageInfo(rgSelected[0], &pInfo))) { if (((NULL != pInfo->pszEmailFrom) && ('\0' != pInfo->pszEmailFrom[0])) || (0 != pInfo->faStream)) prgCmds[i].cmdf |= OLECMDF_ENABLED;
m_pMsgList->FreeMessageInfo(pInfo); } } break; } case ID_CREATE_RULE_FROM_MESSAGE: { prgCmds[i].cmdf = OLECMDF_SUPPORTED;
// Enabled only if there is only one item selected
// Not in IMAP or HTTPMAIL
m_pBrowser->GetFolderType(&ftType); if ((cSel == 1) && (FOLDER_HTTPMAIL != ftType) && (FOLDER_IMAP != ftType)) { LPMESSAGEINFO pInfo; if (SUCCEEDED(m_pMsgList->GetMessageInfo(rgSelected[0], &pInfo))) { prgCmds[i].cmdf |= OLECMDF_ENABLED;
m_pMsgList->FreeMessageInfo(pInfo); } } break; } case ID_COMBINE_AND_DECODE: { // Enabled only if the focus is in the ListView and there
// is at least one item selected.
m_pMsgList->GetSelectedCount(&cSel); if (cSel > 1) prgCmds[i].cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED; else prgCmds[i].cmdf = OLECMDF_SUPPORTED; break; }
} } }
SafeMemFree(rgSelected);
return (S_OK); }
HRESULT CMessageView::_StoreCharsetOntoRows(HCHARSET hCharset) { // Locals
HRESULT hr=S_OK; INETCSETINFO CsetInfo; IMessageTable *pTable=NULL; DWORD *rgRows=NULL; DWORD cRows=0; HCURSOR hCursor=NULL;
// Trace
TraceCall("CMessageView::_StoreCharsetOntoRows");
// Invalid Args
if (NULL == m_pMsgList || NULL == hCharset) return(TraceResult(E_INVALIDARG));
// Wait Cursor
hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
// Get charset info
IF_FAILEXIT(hr = MimeOleGetCharsetInfo(hCharset, &CsetInfo));
// Get selected rows
IF_FAILEXIT(hr = m_pMsgList->GetSelected(NULL, &cRows, &rgRows));
// Get the message table
IF_FAILEXIT(hr = m_pMsgList->GetMessageTable(&pTable));
// Set the Language
SideAssert(SUCCEEDED(pTable->SetLanguage(cRows, rgRows, CsetInfo.cpiInternet)));
exit: // Cleanup
SafeRelease(pTable); SafeMemFree(rgRows);
// Reset Cursor
if (hCursor) SetCursor(hCursor);
// Done
return(hr); }
//
// FUNCTION: CMessageView::Exec()
//
// PURPOSE: Called to execute a verb that this view supports
//
// PARAMETERS:
// [in] pguidCmdGroup - unused
// [in] nCmdID - ID of the command to execute
// [in] nCmdExecOpt - Options that define how the command should execute
// [in] pvaIn - Any arguments for the command
// [out] pvaOut - Any return values for the command
//
// RETURN VALUE:
//
//
HRESULT CMessageView::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdExecOpt, VARIANTARG *pvaIn, VARIANTARG *pvaOut) { // See if our message list wants the command
if (m_pMsgListCT) { if (OLECMDERR_E_NOTSUPPORTED != m_pMsgListCT->Exec(pguidCmdGroup, nCmdID, nCmdExecOpt, pvaIn, pvaOut)) return (S_OK); }
if (m_pPreviewCT) { if (OLECMDERR_E_NOTSUPPORTED != m_pPreviewCT->Exec(&CMDSETID_OutlookExpress, nCmdID, nCmdExecOpt, pvaIn, pvaOut)) return (S_OK); }
// If the sub objects didn't support the command, then we should see if
// it's one of ours
// Language menu first
if (nCmdID >= ID_LANG_FIRST && nCmdID <= ID_LANG_LAST) { HCHARSET hCharset = NULL; HCHARSET hOldCharset = NULL; HRESULT hr = S_OK;
if(!m_pPreview) return S_OK;
m_pPreview->HrGetCharset(&hOldCharset);
hCharset = GetMimeCharsetFromMenuID(nCmdID);
if(!hCharset || (hOldCharset == hCharset)) return(S_OK);
Assert (hCharset);
if(FAILED(hr = m_pPreview->HrSetCharset(hCharset))) { AthMessageBoxW( m_hwnd, MAKEINTRESOURCEW(idsAthena), MAKEINTRESOURCEW((hr == hrIncomplete)?idsViewLangMimeDBBad:idsErrViewLanguage), NULL, MB_OK|MB_ICONEXCLAMATION); return E_FAIL; }
// Set the charset onto the selected rows....
_StoreCharsetOntoRows(hCharset);
// SetDefaultCharset(hCharset);
// SwitchLanguage(nCmdID, TRUE);
return (S_OK); }
// Handle the View.Current View menu
if ((ID_VIEW_FILTER_FIRST <= nCmdID) && (ID_VIEW_FILTER_LAST >= nCmdID)) { if (NULL == m_pViewMenu) { // Create the view menu
HrCreateViewMenu(0, &m_pViewMenu); } if (NULL != m_pViewMenu) { // What we get from the browser is of type VT_I8, but rules only needs filter id which
// is a dword. So changing the type here is safe. Bug# 74275
pvaIn->vt = VT_I4; if (SUCCEEDED(m_pViewMenu->Exec(m_hwnd, nCmdID, m_pMsgList, pvaIn, pvaOut))) { return (S_OK); } } } // Go through the rest of the commands
switch (nCmdID) { case ID_OPEN: return CmdOpen(nCmdID, nCmdExecOpt, pvaIn, pvaOut);
case ID_REPLY: case ID_REPLY_ALL: case ID_FORWARD: case ID_FORWARD_AS_ATTACH: case ID_REPLY_GROUP: return CmdReplyForward(nCmdID, nCmdExecOpt, pvaIn, pvaOut);
case ID_CANCEL_MESSAGE: return CmdCancelMessage(nCmdID, nCmdExecOpt, pvaIn, pvaOut);
case ID_DOWNLOAD_MESSAGE: return CmdFillPreview(nCmdID, nCmdExecOpt, pvaIn, pvaOut);
case ID_PREVIEW_PANE: case ID_PREVIEW_SHOW: case ID_PREVIEW_BELOW: case ID_PREVIEW_BESIDE: case ID_PREVIEW_HEADER: return CmdShowPreview(nCmdID, nCmdExecOpt, pvaIn, pvaOut);
case ID_REFRESH: return CmdRefresh(nCmdID, nCmdExecOpt, pvaIn, pvaOut);
case ID_BLOCK_SENDER: return CmdBlockSender(nCmdID, nCmdExecOpt, pvaIn, pvaOut);
case ID_CREATE_RULE_FROM_MESSAGE: return CmdCreateRule(nCmdID, nCmdExecOpt, pvaIn, pvaOut);
case ID_VIEW_SOURCE: case ID_VIEW_MSG_SOURCE: if (m_pPreview) return m_pPreview->HrViewSource((ID_VIEW_SOURCE==nCmdID)?MECMD_VS_HTML:MECMD_VS_MESSAGE); else break;
case ID_ADD_SENDER: return CmdAddToWab(nCmdID, nCmdExecOpt, pvaIn, pvaOut);
case ID_COMBINE_AND_DECODE: return CmdCombineAndDecode(nCmdID, nCmdExecOpt, pvaIn, pvaOut); }
return (E_FAIL); }
//
// FUNCTION: CMessageView::Invoke()
//
// PURPOSE: This is where we receive notifications from the message list.
//
// PARAMETERS:
// <too many to list>
//
// RETURN VALUE:
// HRESULT
//
HRESULT CMessageView::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, unsigned int* puArgErr) { switch (dispIdMember) {
// Fired whenever the selection in the ListView changes
case DISPID_LISTEVENT_SELECTIONCHANGED: { // Need to load the preview pane with the new selected message
if (_IsPreview()) _UpdatePreviewPane();
// Tell the browser to update it's toolbar
if (m_pBrowser) m_pBrowser->UpdateToolbar(); break; }
// Fired whenever the ListView get's or loses focus.
case DISPID_LISTEVENT_FOCUSCHANGED: { // If the ListView is getting the focus, we need to UI deactivate
// the preview pane.
if (pDispParams->rgvarg[0].lVal) { if (m_pPreview) { m_pPreview->HrUIActivate(FALSE); m_pBrowser->OnViewWindowActive(this); } } break; }
// Fired when the number of messages or unread messages changes
case DISPID_LISTEVENT_COUNTCHANGED: { // If we have a browser, update the status bar
if (m_pBrowser && !m_pProgress) { DWORD cTotal, cUnread, cOnServer;
// Readability forces me to do this
cTotal = pDispParams->rgvarg[0].lVal; cUnread = pDispParams->rgvarg[1].lVal; cOnServer = pDispParams->rgvarg[2].lVal;
// Got to update the status bar if there is one
CStatusBar *pStatusBar = NULL; m_pBrowser->GetStatusBar(&pStatusBar);
if (pStatusBar) { TCHAR szStatus[CCHMAX_STRINGRES + 20]; TCHAR szFmt[CCHMAX_STRINGRES]; DWORD ids;
// If there are still messages on server load a different
// status string.
if (cOnServer) { AthLoadString(idsXMsgsYUnreadZonServ, szFmt, ARRAYSIZE(szFmt)); wnsprintf(szStatus, ARRAYSIZE(szStatus), szFmt, cTotal, cUnread, cOnServer); } else { AthLoadString(idsXMsgsYUnread, szFmt, ARRAYSIZE(szFmt)); wnsprintf(szStatus, ARRAYSIZE(szStatus), szFmt, cTotal, cUnread); }
pStatusBar->SetStatusText(szStatus); pStatusBar->Release(); }
// Also update the toolbar since commands like "Mark as Read" might
// change. However, we only do this if we go between zero and some or
// vice versa.
if ((m_cItems == 0 && cTotal) || (m_cItems != 0 && cTotal == 0) || (m_cUnread == 0 && cUnread) || (m_cUnread != 0 && cUnread == 0)) { m_pBrowser->UpdateToolbar(); }
// Save this for next time.
m_cItems = cTotal; m_cUnread = cUnread; } break; }
// Fired when the message list want's to show status text
case DISPID_LISTEVENT_UPDATESTATUS: { _SetProgressStatusText(pDispParams->rgvarg->bstrVal); break; }
// Fired when progress happens
case DISPID_LISTEVENT_UPDATEPROGRESS: { CBands *pCoolbar = NULL;
// If this is a begin, then we start animating the logo
if (pDispParams->rgvarg[2].lVal == PROGRESS_STATE_BEGIN) { if (SUCCEEDED(m_pBrowser->GetCoolbar(&pCoolbar))) { pCoolbar->Invoke(idDownloadBegin, NULL); pCoolbar->Release(); } }
// If this is a continue, then we might get progress numbers
else if (pDispParams->rgvarg[2].lVal == PROGRESS_STATE_DEFAULT) { if (!m_pProgress) { if (m_pBrowser->GetStatusBar(&m_pProgress)==S_OK) m_pProgress->ShowProgress(pDispParams->rgvarg[1].lVal); }
if (m_pProgress) m_pProgress->SetProgress(pDispParams->rgvarg[0].lVal); }
// Or if this is an end, stop animating and clean up the status bar
else if (pDispParams->rgvarg[2].lVal == PROGRESS_STATE_END) { if (m_pProgress) { m_pProgress->HideProgress(); m_pProgress->Release(); m_pProgress = NULL; }
if (SUCCEEDED(m_pBrowser->GetCoolbar(&pCoolbar))) { pCoolbar->Invoke(idDownloadEnd, NULL); pCoolbar->Release(); }
// Reset the status bar back to it's default state
_SetDefaultStatusText(); }
break; }
// Fired when the user double clicks an item in the ListView
case DISPID_LISTEVENT_ITEMACTIVATE: { CmdOpen(ID_OPEN, OLECMDEXECOPT_DONTPROMPTUSER, NULL, NULL); break; }
// Fired when we need to call update toolbar
case DISPID_LISTEVENT_UPDATECOMMANDSTATE: { PostMessage(m_hwndParent, CM_UPDATETOOLBAR, 0, 0L); break; }
// Fired when a message has been downloaded by the messagelist
case DISPID_LISTEVENT_ONMESSAGEAVAILABLE: { return _OnMessageAvailable((MESSAGEID)((LONG_PTR)pDispParams->rgvarg[0].lVal), (HRESULT)pDispParams->rgvarg[1].scode); }
// Fired when the filter changes
case DISPID_LISTEVENT_FILTERCHANGED: { // If we have a browser, update the status bar
if (m_pBrowser && !m_pProgress) { // Got to update the status bar if there is one
CStatusBar *pStatusBar = NULL; m_pBrowser->GetStatusBar(&pStatusBar);
if (pStatusBar) { pStatusBar->SetFilter((RULEID)((ULONG_PTR)pDispParams->rgvarg[0].ulVal)); pStatusBar->Release(); }
CBands* pBands; if (m_pBrowser->GetCoolbar(&pBands) == S_OK) { pBands->Invoke(idNotifyFilterChange, &pDispParams->rgvarg[0].ulVal); pBands->Release(); } } break; }
case DISPID_LISTEVENT_ADURL_AVAILABLE: { if (m_pBrowser) { m_pBrowser->ShowAdBar(pDispParams->rgvarg[0].bstrVal); } break; }
}
return (S_OK); }
HRESULT CMessageView::GetMarkAsReadTime(LPDWORD pdwSecs) { if (!pdwSecs) { AssertSz(FALSE, "Null Pointer"); return (E_INVALIDARG); }
*pdwSecs = DwGetOption(OPT_MARKASREAD); return (S_OK); }
HRESULT CMessageView::GetAccount(IImnAccount **ppAcct) { FOLDERINFO FolderInfo; HRESULT hr = E_FAIL; CHAR szAccountId[CCHMAX_ACCOUNT_NAME]; if (g_pStore && SUCCEEDED(g_pStore->GetFolderInfo(m_idFolder, &FolderInfo))) { if (SUCCEEDED(GetFolderAccountId(&FolderInfo, szAccountId, ARRAYSIZE(szAccountId)) && *szAccountId)) { hr = g_pAcctMan->FindAccount(AP_ACCOUNT_ID, szAccountId, ppAcct); // If local store then we can fail
if(FAILED(hr)) { DWORD dwRow = 0; DWORD cSel = 0; if (SUCCEEDED(m_pMsgList->GetSelected(&dwRow, &cSel, NULL))) { LPMESSAGEINFO pMsgInfo; if (SUCCEEDED(m_pMsgList->GetMessageInfo(dwRow, &pMsgInfo))) { hr = g_pAcctMan->FindAccount(AP_ACCOUNT_ID, pMsgInfo->pszAcctId, ppAcct); m_pMsgList->FreeMessageInfo(pMsgInfo); } } } } g_pStore->FreeRecord(&FolderInfo); } return(hr); }
HRESULT CMessageView::GetFlags(LPDWORD pdwFlags) { FOLDERTYPE ftType;
if (!pdwFlags) { AssertSz(FALSE, "Null Pointer"); return (E_INVALIDARG); }
*pdwFlags = BOPT_AUTOINLINE | BOPT_HTML | BOPT_INCLUDEMSG | BOPT_FROMSTORE;
if (m_pMsgList) { DWORD dwRow = 0; DWORD cSel = 0; if (SUCCEEDED(m_pMsgList->GetSelected(&dwRow, &cSel, NULL))) { LPMESSAGEINFO pMsgInfo;
if (cSel > 1) *pdwFlags |= BOPT_MULTI_MSGS_SELECTED;
if (SUCCEEDED(m_pMsgList->GetMessageInfo(dwRow, &pMsgInfo))) { if (0 == (pMsgInfo->dwFlags & ARF_READ)) *pdwFlags |= BOPT_UNREAD; if (0 == (pMsgInfo->dwFlags & ARF_NOSECUI)) *pdwFlags |= BOPT_SECURITYUIENABLED; m_pMsgList->FreeMessageInfo(pMsgInfo); } } }
m_pBrowser->GetFolderType(&ftType); if (FOLDER_NEWS != ftType) *pdwFlags |= BOPT_MAIL;
return (S_OK); }
//
// FUNCTION: CMessageView::EventOccurred()
//
// PURPOSE: Get's hit whenever an interesting event happens in the preview
// pane.
//
// PARAMETERS:
// DWORD nCmdID
//
// RETURN VALUE:
// HRESULT
//
HRESULT CMessageView::EventOccurred(DWORD nCmdID, IMimeMessage *pMessage) { TraceCall("CMessageView::EventOccurred");
switch (nCmdID) { case MEHC_CMD_DOWNLOAD: Assert(m_fNotDownloaded); // If we're offline, we can make the reasonable assumption that
// the user wants to be online since they said they wanted to
// download this message.
if (g_pConMan && g_pConMan->IsGlobalOffline()) g_pConMan->SetGlobalOffline(FALSE);
_UpdatePreviewPane(TRUE); break;
case MEHC_CMD_MARK_AS_READ: if (m_pMsgList) m_pMsgList->MarkRead(TRUE, 0); break;
case MEHC_CMD_CONNECT: if (g_pConMan) g_pConMan->SetGlobalOffline(FALSE); _UpdatePreviewPane(); break;
case MEHC_BTN_OPEN: case MEHC_BTN_CONTINUE: // Update the toolbar state
m_pBrowser->UpdateToolbar(); break;
case MEHC_UIACTIVATE: m_pBrowser->OnViewWindowActive(this); break;
case MEHC_CMD_PROCESS_RECEIPT: if (m_pMsgList) m_pMsgList->ProcessReceipt(pMessage); break;
default: /* AssertSz(FALSE, "CMessageView::EventOccured() - Unhandled Event."); */ // Valid situation - Warning message for S/MIME
break; }
return (S_FALSE); }
HRESULT CMessageView::GetFolderId(FOLDERID *pID) { if (pID) { *pID = m_idFolder; return (S_OK); }
return (E_INVALIDARG); }
HRESULT CMessageView::GetMessageFolder(IMessageServer **ppServer) { if (m_pMsgList) return (m_pMsgList->GetMessageServer(ppServer));
return (E_NOTIMPL); }
/////////////////////////////////////////////////////////////////////////////
//
// Window Message Handling
//
//
// FUNCTION: CMessageView::ViewWndProc()
//
// PURPOSE: Callback handler for the view window. This function grabs the
// correct this pointer for the window and uses that to dispatch
// the message to the private message handler.
//
LRESULT CALLBACK CMessageView::ViewWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { LRESULT lResult; CMessageView *pThis;
// WM_NCCREATE is the first message our window will receive. The lParam
// will have the pointer to the object that created this instance of the
// window.
if (uMsg == WM_NCCREATE) { // Save the object pointer in the window's extra bytes.
pThis = (CMessageView *) ((LPCREATESTRUCT) lParam)->lpCreateParams; SetWindowLongPtr(hwnd, GWLP_USERDATA, (LPARAM) pThis); } else { // If this is any other message, we need to get the object pointer
// from the window before dispatching the message.
pThis = (CMessageView *) GetWindowLongPtr(hwnd, GWLP_USERDATA); }
// If this ain't true, we're in trouble.
if (pThis) { return (pThis->_WndProc(hwnd, uMsg, wParam, lParam)); } else { Assert(pThis); return DefWindowProc(hwnd, uMsg, wParam, lParam); } }
//
// FUNCTION: CMessageView::_WndProc()
//
// PURPOSE: This private message handler dispatches messages to the
// appropriate handler.
//
LRESULT CALLBACK CMessageView::_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { HANDLE_MSG(hwnd, WM_CREATE, OnCreate); HANDLE_MSG(hwnd, WM_POSTCREATE, OnPostCreate); HANDLE_MSG(hwnd, WM_SIZE, OnSize); HANDLE_MSG(hwnd, WM_LBUTTONDOWN, OnLButtonDown); HANDLE_MSG(hwnd, WM_MOUSEMOVE, OnMouseMove); HANDLE_MSG(hwnd, WM_LBUTTONUP, OnLButtonUp); HANDLE_MSG(hwnd, WM_NOTIFY, OnNotify); HANDLE_MSG(hwnd, WM_DESTROY, OnDestroy); HANDLE_MSG(hwnd, WM_SETFOCUS, OnSetFocus); HANDLE_MSG(hwnd, WM_TEST_GETMSGID, OnTestGetMsgId); HANDLE_MSG(hwnd, WM_TEST_SAVEMSG, OnTestSaveMessage);
case WM_FOLDER_LOADED: OnFolderLoaded(hwnd, wParam, lParam); break;
case WM_NEW_MAIL: // Propagate up to browser
PostMessage(m_hwndParent, WM_NEW_MAIL, 0, 0); break;
case NVM_GETNEWGROUPS: if (m_pGroups != NULL) { m_pGroups->HandleGetNewGroups(); m_pGroups->Release(); m_pGroups = NULL; } return(0);
case WM_UPDATE_PREVIEW: if (m_idMessageFocus == (MESSAGEID)wParam) { _UpdatePreviewPane(); } break;
case CM_OPTIONADVISE: _OptionUpdate((DWORD) wParam); break;
case WM_MENUSELECT: // HANDLE_WM_MENUSELECT() has a bug that prevents popups from displaying correctly.
OnMenuSelect(hwnd, wParam, lParam); return (0);
case WM_SYSCOLORCHANGE: case WM_WININICHANGE: case WM_FONTCHANGE: if (m_pMsgList) { IOleWindow *pWindow; if (SUCCEEDED(m_pMsgList->QueryInterface(IID_IOleWindow, (LPVOID *) &pWindow))) { HWND hwndList; pWindow->GetWindow(&hwndList); SendMessage(hwndList, uMsg, wParam, lParam); pWindow->Release(); } } return (0); }
return (DefWindowProc(hwnd, uMsg, wParam, lParam)); } // PURPOSE: WM_FOLDER_LOADED message is sent when messagelist is done loading the cached headers/messages etc
void CMessageView::OnFolderLoaded(HWND hwnd, WPARAM wParam, LPARAM lParam) { FOLDERINFO FolderInfo; if (g_pStore && SUCCEEDED(g_pStore->GetFolderInfo(m_idFolder, &FolderInfo))) { CHAR szAccountId[CCHMAX_ACCOUNT_NAME];
if (SUCCEEDED(GetFolderAccountId(&FolderInfo, szAccountId, ARRAYSIZE(szAccountId)))) { HRESULT hr;
if (g_pConMan) { hr = g_pConMan->CanConnect(szAccountId); if ((hr != S_OK) && (hr != HR_E_DIALING_INPROGRESS) && (hr != HR_E_OFFLINE)) g_pConMan->Connect(szAccountId, hwnd, TRUE); } } g_pStore->FreeRecord(&FolderInfo); } }
//
// FUNCTION: CMessageView::OnCreate()
//
// PURPOSE: Handler for the WM_CREATE message. In return we create our
// dependant objects and initialize them.
//
// PARAMETERS:
// [in] hwnd - Handle of the window being created
// [in] lpCreateStruct - Pointer to a structure with information about the
// creation.
//
// RETURN VALUE:
// Returns FALSE if something fails and the window should not be created,
// and returns TRUE if everything works fine.
//
BOOL CMessageView::OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct) { HRESULT hr; HWND hwndList;
TraceCall("CMessageView::OnCreate");
// Save the window handle
m_hwnd = hwnd;
// Create the message list object
if (!_InitMessageList()) return (FALSE);
// Create the preview pane. If it fails that's OK, we'll just
// run without it.
_InitPreviewPane();
// Get updates when options change
OptionAdvise(m_hwnd);
// For later
PostMessage(m_hwnd, WM_POSTCREATE, 0, 0);
return (TRUE); }
//
// FUNCTION: CMessageView::OnPostCreate()
//
// PURPOSE: Notifies when the view has finished being created. Any
// initialization that takes time can happen here, like loading
// the message table etc.
//
// PARAMETERS:
// [in] hwnd - Handle of the window
//
void CMessageView::OnPostCreate(HWND hwnd) { HRESULT hr; FOLDERTYPE FolderType; FOLDERINFO fiServerNode = {0}; HRESULT hrTemp;
TraceCall("CMessageView::OnPostCreate");
if (!g_pStore) return;
FolderType = GetFolderType(m_idFolder); ProcessICW(hwnd, FolderType);
// BETA-2: If this is IMAP folder, check if IMAP folderlist is dirty.
// If so, prompt user to refresh folderlist
hrTemp = GetFolderServer(m_idFolder, &fiServerNode); TraceError(hrTemp); if (SUCCEEDED(hrTemp)) { if (FOLDER_IMAP == FolderType) CheckIMAPDirty(fiServerNode.pszAccountId, hwnd, fiServerNode.idFolder, NOFLAGS); }
// Tell the Message List control to load itself
if (m_pMsgList) { // Tell the message list to change folders
hr = m_pMsgList->SetFolder(m_idFolder, m_pServer, FALSE, NULL, NOSTORECALLBACK); if (FAILED(hr) && hr != E_PENDING && m_pPreview) { m_pPreview->LoadHtmlErrorPage(c_szErrPage_FldrFail); } }
if (m_pServer) { m_pServer->ConnectionRelease(); m_pServer->Close(MSGSVRF_HANDS_OFF_SERVER); m_pServer->Release(); m_pServer = NULL; }
// Create a drop target
m_pDropTarget = new CDropTarget(); if (m_pDropTarget) { if (SUCCEEDED(m_pDropTarget->Initialize(m_hwnd, m_idFolder))) { RegisterDragDrop(m_hwnd, m_pDropTarget); } }
if (FolderType == FOLDER_NEWS) NewsUtil_CheckForNewGroups(hwnd, m_idFolder, &m_pGroups);
// If its HTTP folder (Should have been hotmail folder), and if we are connected we ask for the ad url.
if ((FolderType == FOLDER_HTTPMAIL) && (g_pConMan && (S_OK == g_pConMan->CanConnect(fiServerNode.pszAccountId)))) { m_pMsgList->GetAdBarUrl(); }
g_pStore->FreeRecord(&fiServerNode); }
#define SPLIT_SIZE 3
void CMessageView::OnSize(HWND hwnd, UINT state, int cxClient, int cyClient) { RECT rc = {0, 0, cxClient, cyClient}; int split;
// If we are displaying the preview pane, we need to split the client area
// based on the position of the split bar.
if (_IsPreview()) { // Line the windows up based on the split direction
if (m_fSplitHorz) { // Determine the split height
split = (cyClient * m_dwSplitHorzPct) / 100;
// Save the rect that the split bar occupies
SetRect(&m_rcSplit, 0, split, cxClient, split + SPLIT_SIZE);
// Set the position of the preview pane
rc.top = m_rcSplit.bottom; rc.bottom = cyClient; if (m_pPreview) m_pPreview->HrSetSize(&rc);
// Set the position of the message list
SetRect(&rc, -1, 0, cxClient + 2, split); m_pMsgList->SetRect(rc); } else { // Determine the split width
split = (cxClient * m_dwSplitVertPct) / 100;
// Save the rect that the split bar occupies
SetRect(&m_rcSplit, split, 0, split + SPLIT_SIZE, cyClient);
// Set the position of the message list
rc.right = split; m_pMsgList->SetRect(rc);
// Set the position of the preview pane
rc.left = m_rcSplit.right; rc.right = cxClient; if (m_pPreview) m_pPreview->HrSetSize(&rc); } } else { SetRect(&rc, -1, 0, cxClient + 2, cyClient); m_pMsgList->SetRect(rc); }
return; }
//
// FUNCTION: CMessageView::OnLButtonDown
//
// PURPOSE: We check to see if we're over the splitter bar and if so start
// a drag operation.
//
// PARAMETERS:
// hwnd - Handle to the view window.
// fDoubleClick - TRUE if this is a double click.
// x, y - Position of the mouse in client coordinates.
// keyFlags - State of the keyboard.
//
void CMessageView::OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags) { POINT pt = {x, y};
// Check to see if the mouse is over the split bar
if (_IsPreview() && PtInRect(&m_rcSplit, pt)) { // Capture the mouse
SetCapture(m_hwnd);
// Start dragging
m_fDragging = TRUE; } }
//
// FUNCTION: CMessageView::OnMouseMove
//
// PURPOSE: We update any drag and drop information in response to mouse
// moves if a drag and drop is in progress.
//
// PARAMETERS:
// hwnd - Handle to the view window.
// x, y - Position of the mouse in client coordinates.
// keyFlags - State of the keyboard.
//
void CMessageView::OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags) { HCURSOR hcur; POINT pt = {x, y}; RECT rcClient;
// If we're dragging the split bar, update the window sizes
if (m_fDragging) { // Get the size of the window
GetClientRect(m_hwnd, &rcClient);
// Calculate the new split percentage
if (m_fSplitHorz) { // Make sure the user hasn't gone off the deep end
if (y > 32 && y < (rcClient.bottom - 32)) m_dwSplitHorzPct = (y * 100) / rcClient.bottom; } else { // Make sure the user hasn't gone off the deep end
if (x > 32 && x < (rcClient.right - 32)) m_dwSplitVertPct = (x * 100) / rcClient.right; }
// Update the window sizes
OnSize(m_hwnd, SIZE_RESTORED, rcClient.right, rcClient.bottom); } else { // Just update the cursor
if (PtInRect(&m_rcSplit, pt)) { if (m_fSplitHorz) hcur = LoadCursor(NULL, MAKEINTRESOURCE(IDC_SIZENS)); else hcur = LoadCursor(NULL, MAKEINTRESOURCE(IDC_SIZEWE)); } else hcur = LoadCursor(NULL, IDC_ARROW);
SetCursor(hcur); } }
//
// FUNCTION: CMessageView::OnLButtonUp
//
// PURPOSE: If a drag opteration is currently in progress (as determined
// by the g_fDragging variable) then this function handles
// ending the drag and updating the split position.
//
// PARAMETERS:
// hwnd - handle of the window receiving the message
// x - horizontal mouse position in client coordinates
// y - vertical mouse position in client coordinates
// keyFlags - Indicates whether various virtual keys are down
//
void CMessageView::OnLButtonUp(HWND hwnd, int x, int y, UINT keyFlags) { DWORD dwHeader; DWORD dwSize; BOOL fVisible; DWORD dwOpt; FOLDERTYPE ftType;
if (m_fDragging) { ReleaseCapture(); m_fDragging = FALSE;
// Get the old settings
m_pBrowser->GetFolderType(&ftType); if (ftType == FOLDER_NEWS) dwOpt = DISPID_MSGVIEW_PREVIEWPANE_NEWS; else dwOpt = DISPID_MSGVIEW_PREVIEWPANE_MAIL;
m_pBrowser->GetViewLayout(dwOpt, 0, &fVisible, &dwHeader, &dwSize);
// Update the new splits
if (m_fSplitHorz) dwSize = MAKELONG(m_dwSplitHorzPct, 0); else dwSize = MAKELONG(0, m_dwSplitVertPct);
// Set the settings back to the browser
m_pBrowser->SetViewLayout(dwOpt, LAYOUT_POS_NA, fVisible, dwHeader, dwSize); } }
//
// FUNCTION: CMessageView::OnMenuSelect()
//
// PURPOSE: Put's helpful text on the status bar describing the selected
// menu item.
//
void CMessageView::OnMenuSelect(HWND hwnd, WPARAM wParam, LPARAM lParam) { // Let the preview pane have it first
if (m_pPreview) { if (S_OK == m_pPreview->HrWMMenuSelect(hwnd, wParam, lParam)) return; }
// Handle it ourselves
CStatusBar *pStatusBar = NULL; m_pBrowser->GetStatusBar(&pStatusBar); HandleMenuSelect(pStatusBar, wParam, lParam); pStatusBar->Release(); }
//
// FUNCTION: CMessageView::OnNotify
//
// PURPOSE: Processes the various notifications we receive from our child
// controls.
//
// PARAMETERS:
// hwnd - Handle of the view window.
// idCtl - identifies the control sending the notification
// pnmh - points to a NMHDR struct with more information regarding the
// notification
//
// RETURN VALUE:
// Dependant on the specific notification.
//
LRESULT CMessageView::OnNotify(HWND hwnd, int idFrom, LPNMHDR pnmhdr) { switch (pnmhdr->code) { case BDN_HEADERDBLCLK: { if (m_pPreview) { DWORD dw = 0; BOOL f = 0; FOLDERTYPE ftType; DWORD dwOpt;
m_pBrowser->GetFolderType(&ftType); if (ftType == FOLDER_NEWS) dwOpt = DISPID_MSGVIEW_PREVIEWPANE_NEWS; else dwOpt = DISPID_MSGVIEW_PREVIEWPANE_MAIL;
m_pBrowser->GetViewLayout(dwOpt, 0, &f, &dw, 0); m_pPreview->HrSetStyle(!dw ? MESTYLE_PREVIEW : MESTYLE_MINIHEADER); m_pBrowser->SetViewLayout(dwOpt, LAYOUT_POS_NA, f, !dw, 0); } break; } case BDN_MARKASSECURE: { if (m_pMsgList) { DWORD dwRow = 0; if (SUCCEEDED(m_pMsgList->GetSelected(&dwRow, NULL, NULL))) m_pMsgList->MarkMessage(dwRow, MARK_MESSAGE_NOSECUI); } break; } }
return (0); }
void CMessageView::OnDestroy(HWND hwnd) { if (m_pDropTarget) { RevokeDragDrop(hwnd); m_pDropTarget->Release(); m_pDropTarget = 0; }
// Stop advising for option changes
OptionUnadvise(m_hwnd);
// Release the preview pane
if (m_pPreview) { m_pPreview->HrUnloadAll(NULL, 0); m_pPreview->HrClose(); } }
void CMessageView::OnSetFocus(HWND hwnd, HWND hwndOldFocus) { IOleWindow *pWindow = 0; HWND hwndList = 0;
if (m_pMsgList) { if (SUCCEEDED(m_pMsgList->QueryInterface(IID_IOleWindow, (LPVOID *) &pWindow))) { if (SUCCEEDED(pWindow->GetWindow(&hwndList))) { SetFocus(hwndList); } pWindow->Release(); } } }
//
// FUNCTION: CMessageView::OnTestGetMsgId()
//
// PURPOSE: This function is for the testing team. Please consult Racheli
// before modifying it in any way.
//
LRESULT CMessageView::OnTestGetMsgId(HWND hwnd) { DWORD cSel; DWORD *rgSelected = NULL; LRESULT lResult = -1; LPMESSAGEINFO pInfo;
TraceCall("CMessageView::OnTestGetMsgId");
// Only handle this if we're in test mode
if (!DwGetOption(OPT_TEST_MODE)) return (-1);
// Get the range of selected messages
if (SUCCEEDED(m_pMsgList && m_pMsgList->GetSelected(NULL, &cSel, &rgSelected))) { // Get the message info for the selected row
if (cSel && SUCCEEDED(m_pMsgList->GetMessageInfo(*rgSelected, &pInfo))) { lResult = (LRESULT) pInfo->idMessage; m_pMsgList->FreeMessageInfo(pInfo); }
MemFree(&rgSelected); }
return (lResult); }
//
// FUNCTION: CMessageView::OnTestSaveMessage()
//
// PURPOSE: This method is for the testing team. Please consult Racheli
// before making any changes.
//
LRESULT CMessageView::OnTestSaveMessage(HWND hwnd) { DWORD cSel; DWORD *rgSelected = NULL; TCHAR szFile[MAX_PATH]; IUnknown *pUnkMessage; IMimeMessage *pMessage = NULL; LRESULT lResult = -1;
TraceCall("CMessageView::OnTestSaveMessage");
// Make sure we only do this in test mode
if (!DwGetOption(OPT_TEST_MODE)) return (-1);
// Get the dump file name
if (!GetOption(OPT_DUMP_FILE, szFile, ARRAYSIZE(szFile))) return (-1);
// Get the selected range
if (SUCCEEDED(m_pMsgList->GetSelected(NULL, &cSel, &rgSelected))) { // Load the first selected message from the store
if (cSel && SUCCEEDED(m_pMsgList->GetMessage(*rgSelected, FALSE, FALSE, &pUnkMessage))) { // Get the IMimeMessage interface from the message
if (pUnkMessage && SUCCEEDED(pUnkMessage->QueryInterface(IID_IMimeMessage, (LPVOID *) &pMessage))) { // Save the message
HrSaveMsgToFile(pMessage, (LPTSTR) szFile); pMessage->Release(); lResult = 0; }
pUnkMessage->Release(); }
MemFree(rgSelected); }
return (lResult); }
//
// FUNCTION: CMessageView::CmdOpen()
//
// PURPOSE: Opens the selected messages.
//
// RETURN VALUE:
// HRESULT
//
HRESULT CMessageView::CmdOpen(DWORD nCmdID, DWORD nCmdExecOpt, VARIANTARG *pvaIn, VARIANTARG *pvaOut) { HRESULT hr;
TraceCall("CMessageView::CmdOpen");
// If more than 10 messages are selected, warn the user with a "Don't show
// me again" dialog that this could be bad.
DWORD dwSel = 0; m_pMsgList->GetSelectedCount(&dwSel); if (dwSel > 10) { TCHAR szBuffer[CCHMAX_STRINGRES]; LRESULT lResult;
AthLoadString(idsErrOpenManyMessages, szBuffer, ARRAYSIZE(szBuffer)); lResult = DoDontShowMeAgainDlg(m_hwnd, c_szRegManyMsgWarning, MAKEINTRESOURCE(idsAthena), szBuffer, MB_OKCANCEL); if (IDCANCEL == lResult) return (S_OK); }
// Get the array of selected rows from the message list
DWORD *rgRows = NULL; DWORD cRows = 0;
if (FAILED(hr = m_pMsgList->GetSelected(NULL, &cRows, &rgRows))) return (hr);
// It's possible for the message list to go away while we're doing this.
// To keep us from crashing, make sure you verify it still exists during
// the loop.
LPMESSAGEINFO pInfo; IMessageTable *pTable = NULL;
hr = m_pMsgList->GetMessageTable(&pTable); if (SUCCEEDED(hr)) { for (DWORD i = 0; (i < cRows && m_pMsgList != NULL); i++) { if (SUCCEEDED(hr = m_pMsgList->GetMessageInfo(rgRows[i], &pInfo))) { INIT_MSGSITE_STRUCT initStruct; DWORD dwCreateFlags; initStruct.initTable.pListSelect = NULL; m_pMsgList->GetListSelector(&initStruct.initTable.pListSelect); // Initialize note struct
initStruct.dwInitType = OEMSIT_MSG_TABLE; initStruct.initTable.pMsgTable = pTable; initStruct.folderID = m_idFolder; initStruct.initTable.rowIndex = rgRows[i];
// Decide whether it is news or mail
if (pInfo->dwFlags & ARF_NEWSMSG) dwCreateFlags = OENCF_NEWSFIRST; else dwCreateFlags = 0;
m_pMsgList->FreeMessageInfo(pInfo);
// Create and Open Note
hr = CreateAndShowNote(OENA_READ, dwCreateFlags, &initStruct, m_hwnd); ReleaseObj(initStruct.initTable.pListSelect);
if (FAILED(hr)) break; } } pTable->Release(); }
if (SUCCEEDED(hr) && g_pInstance) { FOLDERTYPE ft = GetFolderType(m_idFolder); if (ft == FOLDER_IMAP || ft == FOLDER_LOCAL || ft == FOLDER_HTTPMAIL) g_pInstance->UpdateTrayIcon(TRAYICONACTION_REMOVE); }
SafeMemFree(rgRows); return (S_OK); }
//
// FUNCTION: CMessageView::CmdReply()
//
// PURPOSE: Replies or Reply-All's to the selected message.
//
// RETURN VALUE:
// HRESULT
//
HRESULT CMessageView::CmdReplyForward(DWORD nCmdID, DWORD nCmdExecOpt, VARIANTARG *pvaIn, VARIANTARG *pvaOut) { HRESULT hr; DWORD dwFocused; DWORD *rgRows = NULL; DWORD cRows = 0; OLECMD cmd; IMessageTable *pTable = NULL; PROPVARIANT var;
// We can hit this via accelerators. Since accelerators don't go through
// QueryStatus(), we need to make sure this should really be enabled.
cmd.cmdID = nCmdID; cmd.cmdf = 0; if (FAILED(QueryStatus(NULL, 1, &cmd, NULL)) || (0 == (cmd.cmdf & OLECMDF_ENABLED))) return (S_OK);
if (m_pMsgList) { // Figure out which message is focused
if (SUCCEEDED(m_pMsgList->GetSelected(&dwFocused, &cRows, &rgRows))) { INIT_MSGSITE_STRUCT rInitSite; DWORD dwCreateFlags; DWORD dwAction = 0;
// Get the message table from the message list. The note will need
// this to deal with next / prev commands
hr = m_pMsgList->GetMessageTable(&pTable); if (FAILED(hr)) goto exit;
if ((1 < cRows) && ((ID_FORWARD == nCmdID) || (ID_FORWARD_AS_ATTACH == nCmdID))) { IMimeMessage *pMsgFwd = NULL; BOOL fErrorsOccured = FALSE, fCreateNote = TRUE;
hr = HrCreateMessage(&pMsgFwd); if (FAILED(hr)) goto exit;
// Raid 80277; Set default charset
if (NULL == g_hDefaultCharsetForMail) ReadSendMailDefaultCharset();
pMsgFwd->SetCharset(g_hDefaultCharsetForMail, CSET_APPLY_ALL); rInitSite.dwInitType = OEMSIT_MSG; rInitSite.pMsg = pMsgFwd; rInitSite.folderID = m_idFolder;
dwCreateFlags = 0; dwAction = OENA_COMPOSE;
for (DWORD i = 0; i < cRows; i++) { DWORD iRow = rgRows[i]; IMimeMessage *pMsg = NULL;
// Since this command is
hr = pTable->OpenMessage(iRow, OPEN_MESSAGE_SECURE, &pMsg, NOSTORECALLBACK); if (SUCCEEDED(hr)) { // If this is the first message, get the account ID from it
if (i == 0) { var.vt = VT_LPSTR; if (SUCCEEDED(pMsg->GetProp(PIDTOSTR(PID_ATT_ACCOUNTID), NOFLAGS, &var))) { pMsgFwd->SetProp(PIDTOSTR(PID_ATT_ACCOUNTID), NOFLAGS, &var); } }
if (FAILED(pMsgFwd->AttachObject(IID_IMimeMessage, (LPVOID)pMsg, NULL))) fErrorsOccured = TRUE; pMsg->Release(); } else fErrorsOccured = TRUE; }
if (fErrorsOccured) { if(AthMessageBoxW(m_hwnd, MAKEINTRESOURCEW(idsAthenaMail), MAKEINTRESOURCEW(idsErrorAttachingMsgsToNote), NULL, MB_OKCANCEL) == IDCANCEL) fCreateNote = FALSE; }
if (fCreateNote) hr = CreateAndShowNote(dwAction, dwCreateFlags, &rInitSite, m_hwnd); pMsgFwd->Release(); } else { LPMESSAGEINFO pInfo;
// Get some information about the message
if (SUCCEEDED(hr = m_pMsgList->GetMessageInfo(dwFocused, &pInfo))) { // Determine if this is a news or mail message.
if (pInfo->dwFlags & ARF_NEWSMSG) dwCreateFlags = OENCF_NEWSFIRST; else dwCreateFlags = 0;
// Reply or forward
if (nCmdID == ID_FORWARD) dwAction = OENA_FORWARD; else if (nCmdID == ID_FORWARD_AS_ATTACH) dwAction = OENA_FORWARDBYATTACH; else if (nCmdID == ID_REPLY) dwAction = OENA_REPLYTOAUTHOR; else if (nCmdID == ID_REPLY_ALL) dwAction = OENA_REPLYALL; else if (nCmdID == ID_REPLY_GROUP) dwAction = OENA_REPLYTONEWSGROUP; else AssertSz(FALSE, "Didn't ask for a valid action");
// Fill out the initialization information
rInitSite.dwInitType = OEMSIT_MSG_TABLE; rInitSite.initTable.pMsgTable = pTable; rInitSite.initTable.pListSelect = NULL; rInitSite.folderID = m_idFolder; rInitSite.initTable.rowIndex = dwFocused;
m_pMsgList->FreeMessageInfo(pInfo);
// Create the note object
hr = CreateAndShowNote(dwAction, dwCreateFlags, &rInitSite, m_hwnd); } } } }
exit: ReleaseObj(pTable); SafeMemFree(rgRows); return (S_OK); }
HRESULT CMessageView::CmdCancelMessage(DWORD nCmdID, DWORD nCmdExecOpt, VARIANTARG *pvaIn, VARIANTARG *pvaOut) { HRESULT hr; DWORD dwFocused; DWORD *rgRows = NULL; DWORD cRows = 0;
if (m_pMsgList) { // Figure out which message is focused
if (SUCCEEDED(m_pMsgList->GetSelected(&dwFocused, &cRows, &rgRows))) { IMessageTable *pTable = NULL; LPMESSAGEINFO pInfo; // Get the message table from the message list. The note will need
// this to deal with next / prev commands
hr = m_pMsgList->GetMessageTable(&pTable); if (FAILED(hr)) goto exit;
// Get some information about the message
if (SUCCEEDED(hr = m_pMsgList->GetMessageInfo(dwFocused, &pInfo))) { hr = NewsUtil_HrCancelPost(m_hwnd, m_idFolder, pInfo);
m_pMsgList->FreeMessageInfo(pInfo); } pTable->Release(); } }
exit: SafeMemFree(rgRows); return (S_OK); }
//
// FUNCTION: CMessageView::CmdFillPreview()
//
// PURPOSE: Fills the preview pane with the selected & focused message.
//
// RETURN VALUE:
// HRESULT
//
HRESULT CMessageView::CmdFillPreview(DWORD nCmdID, DWORD nCmdExecOpt, VARIANTARG *pvaIn, VARIANTARG *pvaOut) { AssertSz(FALSE, "NYI"); return (E_NOTIMPL); }
//
// FUNCTION: CMessageView::CmdShowPreview()
//
// PURPOSE: Handles updating the settings dealing with the preview pane.
//
// RETURN VALUE:
// HRESULT
//
HRESULT CMessageView::CmdShowPreview(DWORD nCmdID, DWORD nCmdExecOpt, VARIANTARG *pvaIn, VARIANTARG *pvaOut) { FOLDERTYPE ftType; DWORD dwOpt; LAYOUTPOS pos; BOOL fVisible; DWORD dwFlags;
// Get the folder type
m_pBrowser->GetFolderType(&ftType); if (ftType == FOLDER_NEWS) dwOpt = DISPID_MSGVIEW_PREVIEWPANE_NEWS; else dwOpt = DISPID_MSGVIEW_PREVIEWPANE_MAIL;
// Get the current settings from the browser
m_pBrowser->GetViewLayout(dwOpt, NULL, &fVisible, &dwFlags, NULL);
// Update the settings just based on the command
switch (nCmdID) { case ID_PREVIEW_PANE: case ID_PREVIEW_SHOW: { // Set the complement of the visible bit
m_pBrowser->SetViewLayout(dwOpt, LAYOUT_POS_NA, !fVisible, dwFlags, NULL); if (!fVisible) { // if showing update the preview pane
_UpdatePreviewPane(); } else { // if hiding, clear the contents
m_pPreview->HrUnloadAll(NULL, 0); }
break; }
case ID_PREVIEW_BELOW: { // Update the position
m_pBrowser->SetViewLayout(dwOpt, LAYOUT_POS_BOTTOM, fVisible, dwFlags, NULL); break; }
case ID_PREVIEW_BESIDE: { // Update the position
m_pBrowser->SetViewLayout(dwOpt, LAYOUT_POS_LEFT, fVisible, dwFlags, NULL); break; }
case ID_PREVIEW_HEADER: { // Toggle the header flags
m_pBrowser->SetViewLayout(dwOpt, LAYOUT_POS_NA, fVisible, !dwFlags, NULL); break; }
default: Assert(FALSE); }
return (S_OK); }
//
// FUNCTION: CMessageView::CmdRefresh()
//
// PURPOSE: Refreshes the contents of the message list.
//
// RETURN VALUE:
// HRESULT
//
HRESULT CMessageView::CmdRefresh(DWORD nCmdID, DWORD nCmdExecOpt, VARIANTARG* pvaIn, VARIANTARG *pvaOut) { HRESULT hr = E_FAIL; FOLDERINFO FolderInfo;
TraceCall("CMessageView::CmdRefresh");
// Call into the message list now and let it refresh
if (m_pMsgListCT) hr = m_pMsgListCT->Exec(NULL, ID_REFRESH_INNER, nCmdExecOpt, pvaIn, pvaOut);
// If we succeeded in refreshing the message list, also try to reload the
// preview pane.
_UpdatePreviewPane();
// If this is a local folder and this isn't newsonly mode, in the past we
// do a Send & Recieve.
if (FOLDER_LOCAL == GetFolderType(m_idFolder) && 0 == (g_dwAthenaMode & MODE_NEWSONLY)) PostMessage(m_hwndParent, WM_COMMAND, ID_SEND_RECEIVE, 0);
return (hr); }
//
// FUNCTION: CMessageView::CmdBlockSender()
//
// PURPOSE: Add the sender of the selected messages to the block senders list
//
// RETURN VALUE:
// HRESULT
//
HRESULT CMessageView::CmdBlockSender(DWORD nCmdID, DWORD nCmdExecOpt, VARIANTARG *pvaIn, VARIANTARG *pvaOut) { HRESULT hr = S_OK; DWORD * rgRows = NULL; DWORD cRows = 0; LPMESSAGEINFO pInfo = NULL; IUnknown * pUnkMessage = NULL; IMimeMessage * pMessage = 0; LPSTR pszEmailFrom = NULL; ADDRESSPROPS rSender = {0}; CHAR szRes[CCHMAX_STRINGRES]; LPSTR pszResult = NULL; IOERule * pIRule = NULL; BOOL fMsgInfoFreed = FALSE;
TraceCall("CMessageView::CmdBlockSender");
hr = m_pMsgList->GetSelected(NULL, &cRows, &rgRows); if (FAILED(hr)) { goto exit; }
// It's possible for the message list to go away while we're doing this.
// To keep us from crashing, make sure you verify it still exists during
// the loop.
hr = m_pMsgList->GetMessageInfo(rgRows[0], &pInfo); if (FAILED(hr)) { goto exit; }
// Do we already have the address?
if ((NULL != pInfo->pszEmailFrom) && ('\0' != pInfo->pszEmailFrom[0])) { pszEmailFrom = PszDupA(pInfo->pszEmailFrom); if (NULL == pszEmailFrom) { hr = E_OUTOFMEMORY; goto exit; }
} else { // Load that message from the store
hr = m_pMsgList->GetMessage(rgRows[0], FALSE, FALSE, &pUnkMessage); if (FAILED(hr)) { goto exit; } if (NULL == pUnkMessage) { hr = E_FAIL; goto exit; } // Get the IMimeMessage interface from the message
hr = pUnkMessage->QueryInterface(IID_IMimeMessage, (LPVOID *) &pMessage); if (FAILED(hr)) { goto exit; }
rSender.dwProps = IAP_EMAIL; hr = pMessage->GetSender(&rSender); if (FAILED(hr)) { goto exit; } Assert(rSender.pszEmail && ISFLAGSET(rSender.dwProps, IAP_EMAIL)); if ((NULL == rSender.pszEmail) || ('\0' == rSender.pszEmail[0])) { hr = E_FAIL; goto exit; }
pszEmailFrom = PszDupA(rSender.pszEmail); if (NULL == pszEmailFrom) { hr = E_OUTOFMEMORY; goto exit; }
// We don't need the message anymore
g_pMoleAlloc->FreeAddressProps(&rSender); ZeroMemory(&rSender, sizeof(rSender)); SafeRelease(pMessage); }
// Free up the info
m_pMsgList->FreeMessageInfo(pInfo); fMsgInfoFreed = TRUE;
// Bring up the rule editor for this message
hr = RuleUtil_HrAddBlockSender((0 != (pInfo->dwFlags & ARF_NEWSMSG)) ? RULE_TYPE_NEWS : RULE_TYPE_MAIL, pszEmailFrom); if (FAILED(hr)) { goto exit; } // Load the template string
AthLoadString(idsSenderAddedPrompt, szRes, sizeof(szRes));
// Allocate the space to hold the final string
DWORD cchSize = (lstrlen(szRes) + lstrlen(pszEmailFrom) + 1); hr = HrAlloc((VOID **) &pszResult, sizeof(*pszResult) * cchSize); if (FAILED(hr)) { goto exit; }
// Build up the warning string
wnsprintf(pszResult, cchSize, szRes, pszEmailFrom);
// Show the success dialog
if (IDYES == AthMessageBox(m_hwnd, MAKEINTRESOURCE(idsAthena), pszResult, NULL, MB_YESNO | MB_ICONINFORMATION)) { // Create a block sender rule
hr = HrBlockSendersFromFolder(m_hwnd, 0, m_idFolder, &pszEmailFrom, 1); if (FAILED(hr)) { goto exit; } }
hr = S_OK;
exit: SafeRelease(pIRule); SafeMemFree(pszResult); g_pMoleAlloc->FreeAddressProps(&rSender); SafeRelease(pMessage); SafeRelease(pUnkMessage); SafeMemFree(pszEmailFrom); if (FALSE == fMsgInfoFreed) { m_pMsgList->FreeMessageInfo(pInfo); } SafeMemFree(rgRows); if (FAILED(hr)) { AthMessageBoxW(m_hwnd, MAKEINTRESOURCEW(idsAthena), MAKEINTRESOURCEW(idsSenderError), NULL, MB_OK | MB_ICONERROR); } return (hr); }
//
// FUNCTION: CMessageView::CmdCreateRule()
//
// PURPOSE: Add the sender of the selected messages to the block senders list
//
// RETURN VALUE:
// HRESULT
//
HRESULT CMessageView::CmdCreateRule(DWORD nCmdID, DWORD nCmdExecOpt, VARIANTARG *pvaIn, VARIANTARG *pvaOut) { HRESULT hr; DWORD * rgRows = NULL; DWORD cRows = 0; LPMESSAGEINFO pInfo = NULL; IUnknown * pUnkMessage = NULL; IMimeMessage * pMessage = 0;
TraceCall("CMessageView::CmdCreateRule");
// Get the array of selected rows from the message list
if (FAILED(hr = m_pMsgList->GetSelected(NULL, &cRows, &rgRows))) return (hr);
// It's possible for the message list to go away while we're doing this.
// To keep us from crashing, make sure you verify it still exists during
// the loop.
if (SUCCEEDED(hr = m_pMsgList->GetMessageInfo(rgRows[0], &pInfo))) { // Load that message from the store
if (S_OK == m_pMsgList->GetMessage(rgRows[0], FALSE, FALSE, &pUnkMessage)) { // Get the IMimeMessage interface from the message
if (NULL != pUnkMessage) { pUnkMessage->QueryInterface(IID_IMimeMessage, (LPVOID *) &pMessage); } } // Bring up the rule editor for this message
hr = HrCreateRuleFromMessage(m_hwnd, (0 != (pInfo->dwFlags & ARF_NEWSMSG)) ? CRFMF_NEWS : CRFMF_MAIL, pInfo, pMessage); }
SafeRelease(pMessage); SafeRelease(pUnkMessage); m_pMsgList->FreeMessageInfo(pInfo); SafeMemFree(rgRows); return (S_OK); }
//
// FUNCTION: CMessageView::CmdAddToWab()
//
// PURPOSE: Add the sender of the selected messages to the WAB
//
// RETURN VALUE:
// HRESULT
//
HRESULT CMessageView::CmdAddToWab(DWORD nCmdID, DWORD nCmdExecOpt, VARIANTARG *pvaIn, VARIANTARG *pvaOut) { HRESULT hr = S_OK; DWORD *rgRows = NULL; DWORD cRows = 0; LPMESSAGEINFO pInfo; LPWAB pWAB = 0;
TraceCall("CMessageView::CmdAddToWab");
// Get the array of selected rows from the message list
if (FAILED(hr = m_pMsgList->GetSelected(NULL, &cRows, &rgRows))) return (hr);
// Get the header info for the message
if (SUCCEEDED(hr = m_pMsgList->GetMessageInfo(rgRows[0], &pInfo))) { // Get a WAB object
if (SUCCEEDED(hr = HrCreateWabObject(&pWAB))) { // Add the sender to the WAB
if (FAILED(hr = pWAB->HrAddNewEntryA(pInfo->pszDisplayFrom, pInfo->pszEmailFrom))) { if (hr == MAPI_E_COLLISION) AthMessageBoxW(m_hwnd, MAKEINTRESOURCEW(idsAthena), MAKEINTRESOURCEW(idsErrAddrDupe), 0, MB_OK | MB_ICONSTOP); else AthMessageBoxW(m_hwnd, MAKEINTRESOURCEW(idsAthena), MAKEINTRESOURCEW(idsErrAddToWabSender), 0, MB_OK | MB_ICONSTOP); }
pWAB->Release(); } m_pMsgList->FreeMessageInfo(pInfo); }
SafeMemFree(rgRows); return (S_OK); }
//
// FUNCTION: CMessageView::CmdCombineAndDecode()
//
// PURPOSE: Combines the selected messages into a single message.
//
// RETURN VALUE:
// HRESULT
//
HRESULT CMessageView::CmdCombineAndDecode(DWORD nCmdID, DWORD nCmdExecOpt, VARIANTARG *pvaIn, VARIANTARG *pvaOut) { DWORD *rgRows = NULL; DWORD cRows = 0; CCombineAndDecode *pDecode = NULL; HRESULT hr;
// Create the decoder object
pDecode = new CCombineAndDecode(); if (!pDecode) return (S_OK);
// Get the array of selected rows from the message list
if (FAILED(hr = m_pMsgList->GetSelected(NULL, &cRows, &rgRows))) return (hr);
// Get a pointer to the message table
IMessageTable *pTable = NULL; if (SUCCEEDED(m_pMsgList->GetMessageTable(&pTable))) { // Initialize the decoder
pDecode->Start(m_hwnd, pTable, rgRows, cRows, m_idFolder); }
SafeMemFree(rgRows); pDecode->Release(); pTable->Release();
return (S_OK); }
//
// FUNCTION: CMessageView::_SetListOptions()
//
// PURPOSE: Maps the folder that we're about to view to the correct column
// set and various options.
//
// RETURN VALUE:
// Returns S_OK if the column set was identified and set correctly. Returns
// a standard error HRESULT otherwise.
//
HRESULT CMessageView::_SetListOptions(void) { HRESULT hr; BOOL fSelectFirst = FALSE; FOLDERTYPE ft = GetFolderType(m_idFolder);
// Make sure this badboy exists
if (!m_pMsgList) return (E_UNEXPECTED);
FOLDER_OPTIONS fo = {0}; fo.cbSize = sizeof(FOLDER_OPTIONS); fo.dwMask = FOM_EXPANDTHREADS | FOM_SELECTFIRSTUNREAD | FOM_THREAD | FOM_MESSAGELISTTIPS | FOM_POLLTIME | FOM_COLORWATCHED | FOM_GETXHEADERS | FOM_SHOWDELETED | FOM_SHOWREPLIES; fo.fExpandThreads = DwGetOption(OPT_AUTOEXPAND); fo.fMessageListTips = DwGetOption(OPT_MESSAGE_LIST_TIPS); fo.dwPollTime = DwGetOption(OPT_POLLFORMSGS); fo.clrWatched = DwGetOption(OPT_WATCHED_COLOR); fo.dwGetXHeaders = DwGetOption(OPT_DOWNLOADCHUNKS); fo.fDeleted = DwGetOption(OPT_SHOW_DELETED); fo.fReplies = DwGetOption(OPT_SHOW_REPLIES);
switch (ft) { case FOLDER_NEWS: fo.fThread = DwGetOption(OPT_NEWS_THREAD); fo.fSelectFirstUnread = TRUE; break;
case FOLDER_LOCAL: case FOLDER_HTTPMAIL: fo.fThread = DwGetOption(OPT_MAIL_THREAD); fo.fSelectFirstUnread = FALSE; break;
case FOLDER_IMAP: fo.fThread = DwGetOption(OPT_MAIL_THREAD); fo.fSelectFirstUnread = FALSE; break; }
hr = m_pMsgList->SetViewOptions(&fo); return (hr); }
BOOL CMessageView::_IsPreview(void) { FOLDERTYPE ftType; DWORD dwOpt;
// Get the folder type
m_pBrowser->GetFolderType(&ftType); if (ftType == FOLDER_NEWS) dwOpt = DISPID_MSGVIEW_PREVIEWPANE_NEWS; else dwOpt = DISPID_MSGVIEW_PREVIEWPANE_MAIL;
// Ask the browser if it should be on or off
BOOL f = FALSE; if (m_pBrowser) m_pBrowser->GetViewLayout(dwOpt, 0, &f, 0, 0);
return f; }
BOOL CMessageView::_InitMessageList(void) { HWND hwndList;
// Create the message list object
if (FAILED(CreateMessageList(NULL, &m_pMsgList))) return (FALSE);
// Initialize the message list
m_pMsgList->CreateList(m_hwnd, (IViewWindow *) this, &hwndList);
// Get the command target interface for the list
m_pMsgList->QueryInterface(IID_IOleCommandTarget, (LPVOID *) &m_pMsgListCT); m_pMsgList->QueryInterface(IID_IOleInPlaceActiveObject, (LPVOID *) &m_pMsgListAO);
// Request Notifications
AtlAdvise(m_pMsgList, (IUnknown *)(IViewWindow *) this, DIID__MessageListEvents, &m_dwCookie);
// Set the column set for the message list
_SetListOptions();
return (TRUE); }
//
// FUNCTION: CMessageView::_InitPreviewPane()
//
// PURPOSE: Creates the Preview Pane object and initializes it.
//
// RETURN VALUE:
// TRUE if the object was created and initialized, FALSE otherwise.
//
BOOL CMessageView::_InitPreviewPane(void) { CMimeEditDocHost *pDocHost = NULL; CStatusBar *pStatusBar = NULL; DWORD dwHeader; LAYOUTPOS pos; BOOL fVisible; DWORD dwOpt; HRESULT hr; FOLDERTYPE ftType; DWORD dwSize;
TraceCall("CMessageView::_InitPreviewPane");
// We only create the preview pane if it's supposed to be visible.
m_pBrowser->GetFolderType(&ftType); if (ftType == FOLDER_NEWS) dwOpt = DISPID_MSGVIEW_PREVIEWPANE_NEWS; else dwOpt = DISPID_MSGVIEW_PREVIEWPANE_MAIL;
// Get the settings from the browser
m_pBrowser->GetViewLayout(dwOpt, &pos, &fVisible, &dwHeader, &dwSize);
// Stash this info
m_dwSplitHorzPct = LOWORD(dwSize); m_dwSplitVertPct = HIWORD(dwSize);
if (fVisible) { // Create the dochost
pDocHost = new CMimeEditDocHost(MEBF_OUTERCLIENTEDGE); if (!pDocHost) goto error; // We want to get the IBodyObj2 interface from it.
pDocHost->QueryInterface(IID_IBodyObj2, (LPVOID *) &m_pPreview); if (!m_pPreview) goto error; pDocHost->Release();
// Also get the IOleCommandTarget interface from it. If it fails, that's OK.
m_pPreview->QueryInterface(IID_IOleCommandTarget, (LPVOID *) &m_pPreviewCT);
if (m_pBrowser->GetStatusBar(&pStatusBar)==S_OK) { m_pPreview->HrSetStatusBar(pStatusBar); pStatusBar->Release(); }
// Create the preview window
if (FAILED(m_pPreview->HrInit(m_hwnd, IBOF_DISPLAYTO|IBOF_TABLINKS, (IBodyOptions *) this))) goto error;
hr = m_pPreview->HrShow(fVisible); if (FAILED(hr)) goto error;
m_pPreview->HrSetText(MAKEINTRESOURCE(idsHTMLEmptyPreviewSel)); UpdateLayout(fVisible, dwHeader, pos == LAYOUT_POS_LEFT, FALSE);
// Give the preview pane our event sink interface
m_pPreview->SetEventSink((IMimeEditEventSink *) this); return (TRUE); }
error: SafeRelease(pDocHost); SafeRelease(m_pPreview);
return (FALSE); }
void CMessageView::_UpdatePreviewPane(BOOL fForceDownload) { DWORD dwFocused; DWORD cSelected; DWORD *rgSelected = 0; IUnknown *pUnkMessage = 0; HRESULT hr;
if (m_pMsgList && m_pPreview) { m_idMessageFocus = MESSAGEID_INVALID; m_fNotDownloaded = FALSE;
// Figure out which message is focused
if (SUCCEEDED(m_pMsgList->GetSelected(&dwFocused, &cSelected, &rgSelected))) { // If there is a focused item
if (-1 == dwFocused || 0 == cSelected) { m_pPreview->HrUnloadAll(idsHTMLEmptyPreviewSel, 0); } else { // Load that message from the store
hr = m_pMsgList->GetMessage(dwFocused, fForceDownload || DwGetOption(OPT_AUTOFILLPREVIEW), TRUE, &pUnkMessage); switch (hr) { case MIME_E_SECURITY_CANTDECRYPT: m_pPreview->LoadHtmlErrorPage(c_szErrPage_SMimeEncrypt); break;
#ifdef SMIME_V3
case MIME_E_SECURITY_LABELACCESSDENIED: case MIME_E_SECURITY_LABELACCESSCANCELLED: case MIME_E_SECURITY_LABELCORRUPT: m_pPreview->LoadHtmlErrorPage(c_szErrPage_SMimeLabel); break; #endif // SMIME_V3
case STORE_E_EXPIRED: m_pPreview->LoadHtmlErrorPage(c_szErrPage_Expired); break; case STORE_E_NOBODY: AssertSz(DwGetOption(OPT_AUTOFILLPREVIEW)==FALSE, "AutoPreview is on, download should have been started!"); if (g_pConMan->IsGlobalOffline()) m_pPreview->LoadHtmlErrorPage(c_szErrPage_Offline); else m_pPreview->LoadHtmlErrorPage(c_szErrPage_NotDownloaded); m_fNotDownloaded = TRUE; break; case DB_E_DISKFULL: m_pPreview->LoadHtmlErrorPage(c_szErrPage_DiskFull); break;
case DB_S_NOTFOUND: { FOLDERINFO FolderInfo;
//I don't think we need this coz its being handled in callbackcanconnect
//If the message is not found in the store, we ask it to download.
if (g_pStore && SUCCEEDED(g_pStore->GetFolderInfo(m_idFolder, &FolderInfo))) { if(g_pConMan && !(g_pConMan->IsGlobalOffline())) { CHAR szAccountId[CCHMAX_ACCOUNT_NAME];
if (SUCCEEDED(GetFolderAccountId(&FolderInfo, szAccountId, ARRAYSIZE(szAccountId)))) { if (g_pConMan->Connect(szAccountId, m_hwnd, TRUE)== S_OK) hr = m_pMsgList->GetMessage(dwFocused, TRUE, TRUE, &pUnkMessage); } } g_pStore->FreeRecord(&FolderInfo); } break; }
case STORE_S_ALREADYPENDING: case E_PENDING: { // if the message is being downloaded, let's store the message-id and wait for an update
LPMESSAGEINFO pInfo;
// clear the contents waiting for the new message to download
m_pPreview->HrUnloadAll(NULL, 0);
if (SUCCEEDED(m_pMsgList->GetMessageInfo(dwFocused, &pInfo))) { m_idMessageFocus = pInfo->idMessage; m_pMsgList->FreeMessageInfo(pInfo); } break; }
case E_NOT_ONLINE: { m_pPreview->LoadHtmlErrorPage(c_szErrPage_Offline); break; }
case S_OK: { // Get the IMimeMessage interface from the message
IMimeMessage *pMessage = 0;
if (pUnkMessage && SUCCEEDED(pUnkMessage->QueryInterface(IID_IMimeMessage, (LPVOID *) &pMessage))) { // bobn, brianv says we have to remove this...
/*if (g_dwBrowserFlags == 1)
{ LPSTR lpsz = NULL; if (SUCCEEDED(MimeOleGetBodyPropA(pMessage, HBODY_ROOT, PIDTOSTR(PID_HDR_SUBJECT), NOFLAGS, &lpsz))) { if (0 == strcmp(lpsz, "Credits")) g_dwBrowserFlags |= 2; else g_dwBrowserFlags = 0;
SafeMimeOleFree(lpsz); } }*/
if (_DoEmailBombCheck(pMessage)==S_OK) { // Get the load interface from the preview pane object
IPersistMime *pPersistMime = 0;
if (SUCCEEDED(m_pPreview->QueryInterface(IID_IPersistMime, (LPVOID *) &pPersistMime))) { DWORD dwHeader; LAYOUTPOS pos; BOOL fVisible; DWORD dwOpt; DWORD dwSize; FOLDERTYPE ftType;
CStatusBar *pStatusBar = NULL;
// remember focus
BOOL fFocused = ((m_pPreview->HrHasFocus() == S_OK) ? TRUE : FALSE);
m_pBrowser->GetFolderType(&ftType); if (ftType == FOLDER_NEWS) dwOpt = DISPID_MSGVIEW_PREVIEWPANE_NEWS; else dwOpt = DISPID_MSGVIEW_PREVIEWPANE_MAIL;
// Get the settings from the browser
m_pBrowser->GetViewLayout(dwOpt, &pos, &fVisible, &dwHeader, &dwSize); m_pPreview->HrResetDocument(); m_pPreview->HrSetStyle(dwHeader ? MESTYLE_PREVIEW : MESTYLE_MINIHEADER); // Give the preview pane our event sink interface
m_pPreview->SetEventSink((IMimeEditEventSink *) this); pPersistMime->Load(pMessage); pPersistMime->Release();
// restore status bar
if (m_pBrowser->GetStatusBar(&pStatusBar)==S_OK) { m_pPreview->HrSetStatusBar(pStatusBar); pStatusBar->Release(); }
// return focus
if(fFocused) m_pPreview->HrSetUIActivate(); } } pMessage->Release(); } pUnkMessage->Release(); break; } default: m_pPreview->LoadHtmlErrorPage(c_szErrPage_GenFailure); break; } }
if (rgSelected) MemFree(rgSelected); } } }
//
// FUNCTION: CMessageView::_SetProgressStatusText()
//
// PURPOSE: Takes the provided BSTR, converts it to ANSI, and smacks it
// on the status bar.
//
// PARAMETERS:
// [in] bstr - henious BSTR to put on the status bar.
//
void CMessageView::_SetProgressStatusText(BSTR bstr) { LPTSTR psz = NULL; CStatusBar *pStatusBar = NULL; m_pBrowser->GetStatusBar(&pStatusBar);
if (pStatusBar) { pStatusBar->SetStatusText((LPTSTR) bstr); /*
CComBSTR cString(bstr);
// Allocate a string large enough
if (MemAlloc((LPVOID *) &psz, 2 * cString.Length())) { WideCharToMultiByte(CP_ACP, 0, cString, -1, psz, 2 * cString.Length(), NULL, NULL); pStatusBar->SetStatusText((LPTSTR) psz); MemFree(psz); } */ pStatusBar->Release(); } }
//
// FUNCTION: CMessageView::_OnMessageAvailable()
//
// PURPOSE: Fired by the listview when a message has completed downloading
// if the message is the currently selected message in the preview
// then we update it. If it is not, we ignore the notification.
// We check for downloading errors and display and appropriate message
//
// PARAMETERS:
// [in] idMessage - message id of the message that was downloaded
// [in] hrCompletion - hresult indicating possible error failure
//
HRESULT CMessageView::_OnMessageAvailable(MESSAGEID idMessage, HRESULT hrCompletion) { if (m_idMessageFocus != idMessage) return S_FALSE;
switch (hrCompletion) { // if we get a STORE_E_EXPIRED, then reload the preview pane to show error
case S_OK: case STORE_E_EXPIRED: // we post a message to ourselves to update the preview pane. We do this because
// any refcounts on the IStream into the store at this point have it locked for write
// if we post, then the stack is unwound after the notifications are fired and we're in a
// good state.
PostMessage(m_hwnd, WM_UPDATE_PREVIEW, (WPARAM)idMessage, 0); break;
case S_FALSE: case STORE_E_OPERATION_CANCELED: case hrUserCancel: case IXP_E_USER_CANCEL: // S_FALSE means the operation was canceled
if (m_idMessageFocus != MESSAGEID_INVALID) m_pPreview->LoadHtmlErrorPage(c_szErrPage_DownloadCanceled); break;
case STG_E_MEDIUMFULL: m_pPreview->LoadHtmlErrorPage(c_szErrPage_DiskFull); break;
case HR_E_USER_CANCEL_CONNECT: case HR_E_OFFLINE: m_pPreview->LoadHtmlErrorPage(c_szErrPage_Offline); break;
case MIME_E_SECURITY_CANTDECRYPT: m_pPreview->LoadHtmlErrorPage(c_szErrPage_SMimeEncrypt); break;
#ifdef SMIME_V3
case MIME_E_SECURITY_LABELACCESSDENIED: case MIME_E_SECURITY_LABELACCESSCANCELLED: case MIME_E_SECURITY_LABELCORRUPT: m_pPreview->LoadHtmlErrorPage(c_szErrPage_SMimeLabel); break; #endif // SMIME_V3
default: m_pPreview->LoadHtmlErrorPage(c_szErrPage_GenFailure); break; } return S_OK; }
//
// FUNCTION: CMessageView::_DoEmailBombCheck
//
// PURPOSE: Validates to ensure that the last time we closed OE we shutdown
// correctly. If we did not shutdown correctly, we look at the msgid stamp
// that we stored in the registry for the last selected preview message
// if it was the message we are about to preview, we do not show the
// message, to prevent jscript attacks etc.
//
// PARAMETERS:
// none
//
HRESULT CMessageView::_DoEmailBombCheck(LPMIMEMESSAGE pMsg) { FILETIME ft; PROPVARIANT va; DWORD dwType, cb;
va.vt = VT_FILETIME; if (pMsg && pMsg->GetProp(PIDTOSTR(STR_HDR_DATE), 0, &va)==S_OK) { if (g_fBadShutdown) { g_fBadShutdown=FALSE; cb = sizeof(FILETIME); if (AthUserGetValue(NULL, c_szLastMsg, &dwType, (LPBYTE)&ft, &cb)==S_OK && (ft.dwLowDateTime == va.filetime.dwLowDateTime && ft.dwHighDateTime == va.filetime.dwHighDateTime)) { // possible the same dude
m_pPreview->LoadHtmlErrorPage(c_szErrPage_MailBomb); return S_FALSE; } } AthUserSetValue(NULL, c_szLastMsg, REG_BINARY, (LPBYTE)&va.filetime, sizeof(FILETIME)); } return S_OK; }
void CMessageView::_OptionUpdate(DWORD dwUpdate) { if (m_pMsgList && (dwUpdate == OPT_AUTOEXPAND || dwUpdate == OPT_MESSAGE_LIST_TIPS || dwUpdate == OPT_POLLFORMSGS || dwUpdate == OPT_WATCHED_COLOR || dwUpdate == OPT_DOWNLOADCHUNKS)) { FOLDER_OPTIONS fo = {0}; fo.cbSize = sizeof(FOLDER_OPTIONS); fo.dwMask = FOM_EXPANDTHREADS | FOM_MESSAGELISTTIPS | FOM_POLLTIME | FOM_COLORWATCHED | FOM_GETXHEADERS; fo.fExpandThreads = DwGetOption(OPT_AUTOEXPAND); fo.fMessageListTips = DwGetOption(OPT_MESSAGE_LIST_TIPS); fo.dwPollTime = DwGetOption(OPT_POLLFORMSGS); fo.clrWatched = DwGetOption(OPT_WATCHED_COLOR); fo.dwGetXHeaders = DwGetOption(OPT_DOWNLOADCHUNKS);
m_pMsgList->SetViewOptions(&fo); } }
void CMessageView::_SetDefaultStatusText(void) { DWORD cTotal; DWORD cUnread; DWORD cOnServer; CStatusBar *pStatusBar = NULL; TCHAR szStatus[CCHMAX_STRINGRES + 20]; TCHAR szFmt[CCHMAX_STRINGRES]; DWORD ids;
// If we don't have a browser pointer, we can't get the status bar
if (!m_pBrowser || !m_pMsgList) return;
// Get the status bar if there is one.
m_pBrowser->GetStatusBar(&pStatusBar); if (pStatusBar) { // Get the counts from the table
if (SUCCEEDED(m_pMsgList->GetMessageCounts(&cTotal, &cUnread, &cOnServer))) { // If there are still messages on server load a different
// status string.
if (cOnServer) { AthLoadString(idsXMsgsYUnreadZonServ, szFmt, ARRAYSIZE(szFmt)); wnsprintf(szStatus, ARRAYSIZE(szStatus), szFmt, cTotal, cUnread, cOnServer); } else { AthLoadString(idsXMsgsYUnread, szFmt, ARRAYSIZE(szFmt)); wnsprintf(szStatus, ARRAYSIZE(szStatus), szFmt, cTotal, cUnread); } pStatusBar->SetStatusText(szStatus);
// Also update the toolbar since commands like "Mark as Read" might
// change. However, we only do this if we go between zero and some or
// vice versa.
if ((m_cItems == 0 && cTotal) || (m_cItems != 0 && cTotal == 0) || (m_cUnread == 0 && cUnread) || (m_cUnread != 0 && cUnread == 0)) { m_pBrowser->UpdateToolbar(); }
// Save this for next time.
m_cItems = cTotal; m_cUnread = cUnread; }
pStatusBar->Release(); } }
BOOL CMessageView::_ReuseMessageFolder(IViewWindow *pPrevView) { IServerInfo *pInfo = NULL; FOLDERID idPrev = FOLDERID_INVALID; FOLDERID idServerPrev = FOLDERID_INVALID; FOLDERID idServerCur = FOLDERID_INVALID; BOOL fReturn = FALSE;
if (pPrevView && SUCCEEDED(pPrevView->QueryInterface(IID_IServerInfo, (LPVOID *) &pInfo))) { if (SUCCEEDED(pInfo->GetFolderId(&idPrev))) { if (SUCCEEDED(GetFolderServerId(idPrev, &idServerPrev))) { if (SUCCEEDED(GetFolderServerId(m_idFolder, &idServerCur))) { if (idServerPrev == idServerCur) { if (S_OK == pInfo->GetMessageFolder(&m_pServer)) { m_pServer->ConnectionAddRef(); fReturn = TRUE; } } } } }
pInfo->Release(); }
return (fReturn); }
|