2020-09-30 16:53:55 +02:00

5113 lines
154 KiB
C++

#include "pch.hxx"
#include "note.h"
#include "header.h"
#include "envcid.h"
#include "envguid.h"
#include "bodyutil.h"
#include "sigs.h"
#include "mehost.h"
#include "conman.h"
#include "menuutil.h"
#include "url.h"
#include "fonts.h"
#include "multlang.h"
#include "statnery.h"
#include "spell.h"
#include "oleutil.h"
#include "htmlhelp.h"
#include "shared.h"
#include "acctutil.h"
#include "menures.h"
#include "instance.h"
#include "inetcfg.h"
#include "ipab.h"
#include "msgprop.h"
#include "finder.h"
#include "tbbands.h"
#include "demand.h"
#include "multiusr.h"
#include <ruleutil.h>
#include "instance.h"
#include "mapiutil.h"
#include "regutil.h"
#include "storecb.h"
#include "receipts.h"
#include "mirror.h"
#include "secutil.h"
#include "seclabel.h"
#include "shlwapip.h"
#include "mshtmcid.h"
#define cxRect(rc) (rc.right - rc.left)
#define cyRect(rc) (rc.bottom - rc.top)
#define cyMinEdit 30
enum {
MORFS_UNKNOWN = 0,
MORFS_CLEARING,
MORFS_SETTING,
};
// Static Variables
static const TCHAR c_szEditWebPage[] = "EditWebPages";
static DWORD g_dwTlsActiveNote = 0xffffffff;
static HIMAGELIST g_himlToolbar = 0;
static RECT g_rcLastResize = {50,30,450,450}; // default size
static HACCEL g_hAccelRead = 0,
g_hAccelSend = 0;
//Static Functions
void SetTlsGlobalActiveNote(CNote* pNote)
{
SideAssert(0 != TlsSetValue(g_dwTlsActiveNote, pNote));
}
CNote* GetTlsGlobalActiveNote(void)
{
return (CNote*)TlsGetValue(g_dwTlsActiveNote);
}
void InitTlsActiveNote()
{
// Allocate a global TLS active note index
g_dwTlsActiveNote = TlsAlloc();
Assert(g_dwTlsActiveNote != 0xffffffff);
SideAssert(0 != TlsSetValue(g_dwTlsActiveNote, NULL));
}
void DeInitTlsActiveNote()
{
// Free the tls index
TlsFree(g_dwTlsActiveNote);
g_dwTlsActiveNote = 0xffffffff;
}
// *************************
HRESULT CreateOENote(IUnknown *pUnkOuter, IUnknown **ppUnknown)
{
TraceCall("CreateOENote");
Assert(ppUnknown);
*ppUnknown = NULL;
// Create me
CNote *pNew = new CNote();
if (NULL == pNew)
return TraceResult(E_OUTOFMEMORY);
// Cast to unknown
*ppUnknown = SAFECAST(pNew, IOENote *);
// Done
return S_OK;
}
// *************************
BOOL Note_Init(BOOL fInit)
{
static BOOL fInited=FALSE;
WNDCLASSW wc;
DOUTL(4, "Note_Init: %d", (int)fInit);
if(fInit)
{
if(fInited)
{
DOUTL(4, "Note_Init: already inited");
return TRUE;
}
wc.style = CS_BYTEALIGNWINDOW;
wc.lpfnWndProc = CNote::ExtNoteWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = g_hInst;
wc.hIcon = LoadIcon(g_hLocRes, MAKEINTRESOURCE(idiMessageAtt));
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = c_wszNoteWndClass;
if(!RegisterClassWrapW(&wc))
return FALSE;
if(!FHeader_Init(TRUE))
return FALSE;
fInited=TRUE;
DOUTL(4, "Note_Init: success");
return TRUE;
}
else
{
// save back to registry
UnregisterClassWrapW(c_wszNoteWndClass, g_hInst);
if(g_himlToolbar)
{
ImageList_Destroy(g_himlToolbar);
g_himlToolbar=0;
}
FHeader_Init(FALSE);
fInited=FALSE;
DOUTL(4, "Note_Init: deinit OK");
return TRUE;
}
}
HRESULT _HrBlockSender(RULE_TYPE typeRule, IMimeMessage * pMsg, HWND hwnd)
{
HRESULT hr = S_OK;
ADDRESSPROPS rSender = {0};
CHAR szRes[CCHMAX_STRINGRES];
LPSTR pszResult = NULL;
// Check incoming params
if ((NULL == pMsg) || (NULL == hwnd))
{
hr = E_INVALIDARG;
goto exit;
}
// Get the address to add
rSender.dwProps = IAP_EMAIL;
hr = pMsg->GetSender(&rSender);
if (FAILED(hr))
{
goto exit;
}
Assert(ISFLAGSET(rSender.dwProps, IAP_EMAIL));
if ((NULL == rSender.pszEmail) || ('\0' == rSender.pszEmail[0]))
{
goto exit;
}
// Add the sender to the list
hr = RuleUtil_HrAddBlockSender(typeRule, rSender.pszEmail);
if (FAILED(hr))
{
goto exit;
}
// Load the template string
AthLoadString(idsSenderAdded, szRes, sizeof(szRes));
// Allocate the space to hold the final string
DWORD cchSize = (lstrlen(szRes) + lstrlen(rSender.pszEmail) + 1);
hr = HrAlloc((VOID **) &pszResult, sizeof(*pszResult) * cchSize);
if (FAILED(hr))
{
goto exit;
}
// Build up the warning string
wnsprintf(pszResult, cchSize, szRes, rSender.pszEmail);
// Show the success dialog
AthMessageBox(hwnd, MAKEINTRESOURCE(idsAthena), pszResult, NULL, MB_OK | MB_ICONINFORMATION);
// Set the return value
hr = S_OK;
exit:
SafeMemFree(pszResult);
g_pMoleAlloc->FreeAddressProps(&rSender);
if (FAILED(hr))
{
AthMessageBoxW(hwnd, MAKEINTRESOURCEW(idsAthena),
MAKEINTRESOURCEW(idsSenderError), NULL, MB_OK | MB_ICONERROR);
}
return hr;
}
// *************************
LRESULT CALLBACK CNote::ExtNoteWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
CNote *pNote=0;
if(msg==WM_CREATE)
{
pNote=(CNote*)((LPCREATESTRUCT)lParam)->lpCreateParams;
if(pNote && pNote->WMCreate(hwnd))
return 0;
else
return -1;
}
pNote = (CNote*)GetWndThisPtr(hwnd);
if(pNote)
{
return pNote->WndProc(hwnd, msg, wParam, lParam);
}
else
return DefWindowProcWrapW(hwnd, msg, wParam, lParam);
}
// *************************
CNote::CNote()
{
// Initialized in Init:
// m_rHtmlOpt
// m_rPlainOpt
// Set before used:
// m_pTabStopArray
CoIncrementInit("CNote", MSOEAPI_START_SHOWERRORS, NULL, NULL);
m_punkPump = NULL;
m_pHdr = NULL;
m_pMsg = NULL;
m_pCancel = NULL;
m_pstatus = NULL;
m_pMsgSite = NULL;
m_pPrstMime = NULL;
m_pBodyObj2 = NULL;
m_pCmdTargetHdr = NULL;
m_pCmdTargetBody = NULL;
m_pDropTargetHdr = NULL;
m_pTridentDropTarget = NULL;
m_pToolbarObj = NULL;
m_hwnd = 0;
m_hMenu = 0;
m_hIcon = 0;
m_hbmBack = 0;
m_hCursor = 0;
m_hCharset = 0;
m_hTimeout = 0;
m_hwndRebar = 0;
m_hwndFocus = 0;
m_hwndOwner = 0;
m_hmenuLater = 0;
m_hwndToolbar = 0;
m_hmenuAccounts = 0;
m_hmenuLanguage = 0;
m_dwNoteAction = 0;
m_dwIdentCookie = 0;
m_dwNoteCreateFlags = 0;
m_dwMarkOnReplyForwardState = MORFS_UNKNOWN;
m_dwCBMarkType = MARK_MAX;
m_OrigOperationType = SOT_INVALID;
m_fHtml = TRUE;
m_fMail = TRUE;
m_fCBCopy = FALSE;
m_fReadNote = FALSE;
m_fProgress = FALSE;
m_fCommitSave = TRUE;
m_fTabStopsSet = FALSE;
m_fCompleteMsg = FALSE;
m_fHasBeenSaved = FALSE;
m_fPackageImages = TRUE;
m_fWindowDisabled = FALSE;
m_fHeaderUIActive = FALSE;
m_fOrgCmdWasDelete = FALSE;
m_fUseReplyHeaders = FALSE;
m_fCBDestroyWindow = FALSE;
m_fBypassDropTests = FALSE;
m_fOnDocReadyHandled = FALSE;
m_fOriginallyWasRead = FALSE;
m_fUseStationeryFonts = FALSE;
m_fBodyContainsFrames = FALSE;
m_fPreventConflictDlg = FALSE;
m_fInternal = FALSE;
m_fForceClose = FALSE;
m_pLabel = NULL;
if(FPresentPolicyRegInfo() && IsSMIME3Supported())
{
m_fSecurityLabel = !!DwGetOption(OPT_USE_LABELS);
HrGetOELabel(&m_pLabel);
}
else
m_fSecurityLabel = FALSE;
if(IsSMIME3Supported())
{
m_fSecReceiptRequest = !!DwGetOption(OPT_SECREC_USE);
}
else
m_fSecReceiptRequest = FALSE;
m_ulPct = 0;
m_iIndexOfBody = -1;
m_cRef = 1;
m_cAcctMenu = 0;
m_cAcctLater = 0;
m_cTabStopCount = 0;
m_fStatusbarVisible = !!DwGetOption(OPT_SHOW_NOTE_STATUSBAR);
m_fFormatbarVisible = !!DwGetOption(OPT_SHOW_NOTE_FMTBAR);
InitializeCriticalSection(&m_csNoteState);
m_nisNoteState = NIS_INIT;
if (!g_hAccelRead)
g_hAccelRead = LoadAccelerators(g_hLocRes, MAKEINTRESOURCE(IDA_READ_NOTE_ACCEL));
if (!g_hAccelSend)
g_hAccelSend = LoadAccelerators(g_hLocRes, MAKEINTRESOURCE(IDA_SEND_NOTE_ACCEL));
ZeroMemory(&m_hlDisabled, sizeof(HWNDLIST));
m_dwRequestMDNLocked = GetLockKeyValue(c_szRequestMDNLocked);
}
// *************************
CNote::~CNote()
{
if (0 != m_hmenuLanguage)
{
// unload global MIME language codepage data
DeinitMultiLanguage();
DestroyMenu(m_hmenuLanguage);
}
if (m_hMenu != NULL)
DestroyMenu(m_hMenu);
if (m_hIcon)
DestroyIcon(m_hIcon);
if (m_hbmBack)
DeleteObject(m_hbmBack);
// sometimes we get a setfocus in our processing of DestroyWindow
// this causes a WM_ACTIVATE to the note without a corresponding
// WM_DEACTIVATE. if at the time the note dies, the global note ptr
// has our this ptr in it, null it out to be safe.
if (this == GetTlsGlobalActiveNote())
{
Assert(!(m_dwNoteCreateFlags & OENCF_MODAL));
SetTlsGlobalActiveNote(NULL);
}
SafeMemFree(m_pLabel);
ReleaseObj(m_pMsg);
ReleaseObj(m_pHdr);
ReleaseObj(m_pstatus);
ReleaseObj(m_pCancel);
ReleaseObj(m_pMsgSite);
ReleaseObj(m_punkPump);
ReleaseObj(m_pPrstMime);
ReleaseObj(m_pBodyObj2);
ReleaseObj(m_pCmdTargetHdr);
ReleaseObj(m_pCmdTargetBody);
ReleaseObj(m_pDropTargetHdr);
ReleaseObj(m_pTridentDropTarget);
SafeRelease(m_pToolbarObj);
CallbackCloseTimeout(&m_hTimeout);
DeleteCriticalSection(&m_csNoteState);
CoDecrementInit("CNote", NULL);
}
// *************************
ULONG CNote::AddRef()
{
return ++m_cRef;
}
// *************************
ULONG CNote::Release()
{
if (--m_cRef == 0)
{
delete this;
return 0;
}
return m_cRef;
}
// *************************
HRESULT CNote::QueryInterface(REFIID riid, LPVOID FAR *ppvObj)
{
HRESULT hr;
if(!ppvObj)
return E_INVALIDARG;
if (IsEqualIID(riid, IID_IUnknown))
*ppvObj = ((IUnknown *)(IOENote *)this);
else if(IsEqualIID(riid, IID_IOENote))
*ppvObj = (IOENote *)this;
else if (IsEqualIID(riid, IID_IBodyOptions))
*ppvObj = (IBodyOptions *)this;
else if(IsEqualIID(riid, IID_IDropTarget))
*ppvObj = (IDropTarget *)this;
else if (IsEqualIID(riid, IID_IHeaderSite))
*ppvObj = (IHeaderSite *)this;
else if(IsEqualIID(riid, IID_IPersistMime))
*ppvObj = (IPersistMime *)this;
else if(IsEqualIID(riid, IID_IServiceProvider))
*ppvObj = (IServiceProvider *)this;
else if (IsEqualIID(riid, IID_IDockingWindowSite))
*ppvObj = (IDockingWindowSite*)this;
else if (IsEqualIID(riid, IID_IIdentityChangeNotify))
*ppvObj = (IIdentityChangeNotify*)this;
else if (IsEqualIID(riid, IID_IOleCommandTarget))
*ppvObj = (IOleCommandTarget*)this;
else if (IsEqualIID(riid, IID_IStoreCallback))
*ppvObj = (IStoreCallback *) this;
else if (IsEqualIID(riid, IID_ITimeoutCallback))
*ppvObj = (ITimeoutCallback *) this;
else
{
*ppvObj = NULL;
hr = E_NOINTERFACE;
goto exit;
}
((IUnknown *)*ppvObj)->AddRef();
hr = NOERROR;
exit:
return hr;
}
// *************************
HRESULT CNote::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pCmdText)
{
HRESULT hr = OLECMDERR_E_UNKNOWNGROUP;
if (!rgCmds)
return E_INVALIDARG;
if (!pguidCmdGroup)
return hr;
// We are closing down
if (!m_pMsgSite)
return E_UNEXPECTED;
if (m_pCmdTargetHdr)
m_pCmdTargetHdr->QueryStatus(pguidCmdGroup, cCmds, rgCmds, pCmdText);
if (m_pCmdTargetBody)
m_pCmdTargetBody->QueryStatus(pguidCmdGroup, cCmds, rgCmds, pCmdText);
MenuUtil_NewMessageIDsQueryStatus(pguidCmdGroup, cCmds, rgCmds, pCmdText, m_fMail);
if (IsEqualGUID(CMDSETID_OutlookExpress, *pguidCmdGroup))
{
DWORD dwStatusFlags = 0;
BOOL fCompleteMsg = !!m_fCompleteMsg;
BOOL fHtmlSettingsOK = m_fHtml && !m_fBodyContainsFrames;
m_pMsgSite->GetStatusFlags(&dwStatusFlags);
for (ULONG ul = 0; ul < cCmds; ul++)
{
ULONG cmdID = rgCmds[ul].cmdID;
// There are certain cases that need to be overridden even if the earlier
// components enabled or disabled them. They are in this switch statement.
switch (cmdID)
{
// Until trident allows printing in edit mode, don't allow this. RAID 35635
case ID_PRINT:
case ID_PRINT_NOW:
rgCmds[ul].cmdf = QS_ENABLED(fCompleteMsg && m_fReadNote);
continue;
}
if (0 != rgCmds[ul].cmdf)
continue;
switch (cmdID)
{
case ID_POPUP_LANGUAGE:
rgCmds[ul].cmdf = QS_ENABLED(fCompleteMsg);
break;
case ID_NOTE_SAVE_AS:
rgCmds[ul].cmdf = QS_ENABLED(fCompleteMsg || !m_fReadNote);
break;
case ID_WORK_OFFLINE:
rgCmds[ul].cmdf = QS_CHECKED(g_pConMan->IsGlobalOffline());
break;
case ID_CREATE_RULE_FROM_MESSAGE:
case ID_BLOCK_SENDER:
rgCmds[ul].cmdf = QS_ENABLED(m_fReadNote && !m_fBodyContainsFrames && (0 == (OEMSF_RULESNOTENABLED & dwStatusFlags)));
break;
case ID_REPLY:
case ID_REPLY_ALL:
rgCmds[ul].cmdf = QS_ENABLED(m_fReadNote && !m_fBodyContainsFrames && fCompleteMsg);
break;
case ID_REPLY_GROUP:
rgCmds[ul].cmdf = QS_ENABLED(m_fReadNote && !m_fBodyContainsFrames && !m_fMail && fCompleteMsg);
break;
case ID_FORWARD:
case ID_FORWARD_AS_ATTACH:
rgCmds[ul].cmdf = QS_ENABLED(m_fReadNote && fCompleteMsg);
break;
case ID_UNSCRAMBLE:
rgCmds[ul].cmdf = QS_ENABLED(!m_fMail && m_fReadNote);
break;
case ID_POPUP_FORMAT:
case ID_INSERT_SIGNATURE:
rgCmds[ul].cmdf = QS_ENABLED(!m_fBodyContainsFrames);
break;
case ID_NOTE_COPY_TO_FOLDER:
rgCmds[ul].cmdf = QS_ENABLED(fCompleteMsg && (OEMSF_CAN_COPY & dwStatusFlags));
break;
// Can move message if is readnote, or compose note where the message was store based.
case ID_NOTE_MOVE_TO_FOLDER:
rgCmds[ul].cmdf = QS_ENABLED(fCompleteMsg && (OEMSF_CAN_MOVE & dwStatusFlags) && (m_fReadNote || (OENA_COMPOSE == m_dwNoteAction)));
break;
case ID_NOTE_DELETE:
// We should be able to delete anything that msgsite says we can delete
// so long as we are a read note, or we are a drafts message.
rgCmds[ul].cmdf = QS_ENABLED((OEMSF_CAN_DELETE & dwStatusFlags) && (m_fReadNote || (OENA_COMPOSE == m_dwNoteAction)));
break;
case ID_REDO:
rgCmds[ul].cmdf = QS_ENABLED(m_fHeaderUIActive);
break;
case ID_SAVE:
rgCmds[ul].cmdf = QS_ENABLED(fCompleteMsg && (OEMSF_CAN_SAVE & dwStatusFlags) && (m_fOnDocReadyHandled || !m_fReadNote));
break;
case ID_NEXT_UNREAD_MESSAGE:
case ID_NEXT_MESSAGE:
rgCmds[ul].cmdf = QS_ENABLED(OEMSF_CAN_NEXT & dwStatusFlags);
break;
case ID_POPUP_NEXT:
rgCmds[ul].cmdf = QS_ENABLED((OEMSF_CAN_PREV & dwStatusFlags) || (OEMSF_CAN_NEXT & dwStatusFlags));
break;
case ID_MARK_THREAD_READ:
rgCmds[ul].cmdf = QS_ENABLED(OEMSF_THREADING_ENABLED & dwStatusFlags);
break;
case ID_NEXT_UNREAD_THREAD:
rgCmds[ul].cmdf = QS_ENABLED((OEMSF_THREADING_ENABLED & dwStatusFlags) && (OEMSF_CAN_NEXT & dwStatusFlags));
break;
case ID_PREVIOUS:
rgCmds[ul].cmdf = QS_ENABLED(OEMSF_CAN_PREV & dwStatusFlags);
break;
case ID_FORMAT_COLOR:
case ID_FORMAT_COLOR1:
case ID_FORMAT_COLOR2:
case ID_FORMAT_COLOR3:
case ID_FORMAT_COLOR4:
case ID_FORMAT_COLOR5:
case ID_FORMAT_COLOR6:
case ID_FORMAT_COLOR7:
case ID_FORMAT_COLOR8:
case ID_FORMAT_COLOR9:
case ID_FORMAT_COLOR10:
case ID_FORMAT_COLOR11:
case ID_FORMAT_COLOR12:
case ID_FORMAT_COLOR13:
case ID_FORMAT_COLOR14:
case ID_FORMAT_COLOR15:
case ID_FORMAT_COLOR16:
case ID_BACK_COLOR_AUTO:
case ID_FORMAT_COLORAUTO:
case ID_POPUP_BACKGROUND:
rgCmds[ul].cmdf = QS_ENABLED(fHtmlSettingsOK);
break;
case ID_FORMATTING_TOOLBAR:
rgCmds[ul].cmdf = QS_ENABLECHECK((m_fHtml && !m_fBodyContainsFrames), m_fFormatbarVisible);
break;
case ID_SHOW_TOOLBAR:
rgCmds[ul].cmdf = QS_CHECKED(m_fToolbarVisible);
break;
case ID_STATUS_BAR:
rgCmds[ul].cmdf = QS_CHECKED(m_fStatusbarVisible);
break;
case ID_SEND_OBJECTS:
rgCmds[ul].cmdf = QS_ENABLECHECK(fHtmlSettingsOK, m_fPackageImages);
break;
case ID_RICH_TEXT:
rgCmds[ul].cmdf = QS_RADIOED(m_fHtml);
break;
case ID_PLAIN_TEXT:
rgCmds[ul].cmdf = QS_RADIOED(!m_fHtml);
break;
case ID_FLAG_MESSAGE:
rgCmds[ul].cmdf = QS_ENABLECHECK(OEMSF_CAN_MARK & dwStatusFlags, IsFlagged());
break;
case ID_WATCH_THREAD:
rgCmds[ul].cmdf = QS_CHECKED(IsFlagged(ARF_WATCH));
break;
case ID_IGNORE_THREAD:
rgCmds[ul].cmdf = QS_CHECKED(IsFlagged(ARF_IGNORE));
break;
case ID_POPUP_NEW:
case ID_NOTE_PROPERTIES:
case ID_CLOSE:
case ID_POPUP_FIND:
case ID_POPUP_LANGUAGE_DEFERRED:
case ID_POPUP_FONTS:
case ID_ADDRESS_BOOK:
case ID_POPUP_ADDRESS_BOOK:
case ID_ADD_SENDER:
case ID_ADD_ALL_TO:
case ID_POPUP_TOOLBAR:
case ID_CUSTOMIZE:
// Help Menus
case ID_HELP_CONTENTS:
case ID_README:
case ID_POPUP_MSWEB:
case ID_MSWEB_FREE_STUFF:
case ID_MSWEB_PRODUCT_NEWS:
case ID_MSWEB_FAQ:
case ID_MSWEB_SUPPORT:
case ID_MSWEB_FEEDBACK:
case ID_MSWEB_BEST:
case ID_MSWEB_SEARCH:
case ID_MSWEB_HOME:
case ID_MSWEB_HOTMAIL:
case ID_ABOUT:
case ID_FIND_MESSAGE:
case ID_FIND_PEOPLE:
case ID_FIND_TEXT:
case ID_SELECT_ALL:
case ID_POPUP_LANGUAGE_MORE:
case ID_SEND_NOW:
case ID_SEND_LATER:
case ID_SEND_MESSAGE:
case ID_SEND_DEFAULT:
rgCmds[ul].cmdf = QS_ENABLED(TRUE);
break;
case ID_REQUEST_READRCPT:
if (m_fMail)
{
rgCmds[ul].cmdf = QS_CHECKFORLATCH(!m_dwRequestMDNLocked,
!!(dwStatusFlags & OEMSF_MDN_REQUEST));
}
else
{
rgCmds[ul].cmdf = QS_ENABLED(FALSE);
}
break;
case ID_INCLUDE_LABEL:
if(m_pHdr->IsHeadSigned() == S_OK)
rgCmds[ul].cmdf = QS_CHECKED(m_fSecurityLabel);
else
rgCmds[ul].cmdf = QS_ENABLED(FALSE);
break;
case ID_LABEL_SETTINGS:
if(m_pHdr->IsHeadSigned() == S_OK)
rgCmds[ul].cmdf = QS_ENABLED(m_fSecurityLabel);
else
rgCmds[ul].cmdf = QS_ENABLED(FALSE);
break;
case ID_SEC_RECEIPT_REQUEST:
if(m_pHdr->IsHeadSigned() == S_OK)
rgCmds[ul].cmdf = QS_CHECKED(m_fSecReceiptRequest);
else
rgCmds[ul].cmdf = QS_ENABLED(FALSE);
default:
if ((ID_LANG_FIRST <= cmdID) && (ID_LANG_LAST >= cmdID))
{
rgCmds[ul].cmdf = OLECMDF_SUPPORTED | SetMimeLanguageCheckMark(CustomGetCPFromCharset(m_hCharset, m_fReadNote), cmdID - ID_LANG_FIRST);
}
if (((ID_ADD_RECIPIENT_FIRST <= cmdID) && (ID_ADD_RECIPIENT_LAST >= cmdID)) ||
((ID_APPLY_STATIONERY_0 <= cmdID) && (ID_APPLY_STATIONERY_NONE >= cmdID)))
rgCmds[ul].cmdf = QS_ENABLED(TRUE);
else if ((ID_SIGNATURE_FIRST <= cmdID) && (ID_SIGNATURE_LAST >= cmdID))
rgCmds[ul].cmdf = QS_ENABLED(!m_fBodyContainsFrames);
break;
}
}
hr = S_OK;
}
return hr;
}
// *************************
HRESULT CNote::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdExecOpt, VARIANTARG *pvaIn, VARIANTARG *pvaOut)
{
return E_NOTIMPL;
}
// *************************
HRESULT CNote::ClearDirtyFlag()
{
m_pBodyObj2->HrSetDirtyFlag(FALSE);
HeaderExecCommand(MSOEENVCMDID_DIRTY, MSOCMDEXECOPT_DODEFAULT, NULL);
return S_OK;
}
// *************************
HRESULT CNote::IsDirty(void)
{
OLECMD rgCmd[] = {{MSOEENVCMDID_DIRTY, 0}};
BOOL fBodyDirty = FALSE;
m_pBodyObj2->HrIsDirty(&fBodyDirty);
if (fBodyDirty)
return S_OK;
if (m_pCmdTargetHdr)
m_pCmdTargetHdr->QueryStatus(&CGID_Envelope, 1, rgCmd, NULL);
return (0 != (rgCmd[0].cmdf&OLECMDF_ENABLED)) ? S_OK : S_FALSE;
}
// *************************
HRESULT CNote::Load(LPMIMEMESSAGE pMsg)
{
HRESULT hr;
VARIANTARG var;
IPersistMime *pPMHdr=0;
BOOL fWarnUser = (OENA_WEBPAGE == m_dwNoteAction ) ||
(OENA_COMPOSE == m_dwNoteAction ) ||
(OENA_STATIONERY == m_dwNoteAction ) ||
(OENA_FORWARD == m_dwNoteAction);
if (!m_pHdr)
return E_FAIL;
// OnDocumentReady will get call on the CheckForFramesets function.
// Don't want that document ready to matter. Set this flag to true so
// the doc ready doesn't do anything. Once the check is done, we will
// set this flag to false again.
m_fOnDocReadyHandled = TRUE;
// If not a read note and contains frames, need to see what user wants to do
if (!m_fReadNote)
{
hr = HrCheckForFramesets(pMsg, fWarnUser);
if (FAILED(hr))
goto Exit;
if (hr == S_READONLY)
m_fBodyContainsFrames = TRUE;
}
ReplaceInterface(m_pMsg, pMsg);
// The next OnDocumentReady should be run.
m_fOnDocReadyHandled = FALSE;
hr = m_pHdr->QueryInterface(IID_IPersistMime, (LPVOID*)&pPMHdr);
if (FAILED(hr))
return hr;
hr = pPMHdr->Load(pMsg);
if (FAILED(hr))
goto Exit;
m_pHdr->SetFlagState(IsFlagged(ARF_FLAGGED) ? MARK_MESSAGE_FLAGGED : MARK_MESSAGE_UNFLAGGED);
if (IsFlagged(ARF_WATCH))
m_pHdr->SetFlagState(MARK_MESSAGE_WATCH);
else if (IsFlagged(ARF_IGNORE))
m_pHdr->SetFlagState(MARK_MESSAGE_IGNORE);
else
m_pHdr->SetFlagState(MARK_MESSAGE_NORMALTHREAD);
if (m_fCompleteMsg)
hr = m_pPrstMime->Load(pMsg);
CheckAndForceEncryption();
Exit:
if (FAILED(hr))
// ~~~ This should eventually be an html error message
m_pBodyObj2->HrUnloadAll(idsErrHtmlBodyFailedToLoad, NULL);
ReleaseObj(pPMHdr);
return hr;
}
// *************************
void CNote::CheckAndForceEncryption()
{
BOOL fCheck = FALSE;
if(m_fSecurityLabel && m_pLabel)
{
DWORD dwFlags;
if (SUCCEEDED(HrGetPolicyFlags(m_pLabel->pszObjIdSecurityPolicy, &dwFlags)))
{
if(dwFlags & SMIME_POLICY_MODULE_FORCE_ENCRYPTION)
fCheck = TRUE;
}
}
m_pHdr->ForceEncryption(&fCheck, TRUE);
}
// *************************
HRESULT CNote::SetCharsetUnicodeIfNeeded(IMimeMessage *pMsg)
{
HRESULT hr = S_OK;
VARIANTARG va;
PROPVARIANT Variant;
int ret;
HCHARSET hCharSet;
UINT cpID = 0;
// Call dialog only if sending a mime message
// See raid 8436 or 79339 in the IE/OE 5 database. We can't send
// unicode encoding unless we are a mime message.
if (m_fHtml || m_rPlainOpt.fMime)
{
m_fPreventConflictDlg = FALSE;
if (SUCCEEDED(GetCharset(&hCharSet)))
{
cpID = CustomGetCPFromCharset(hCharSet, FALSE);
}
else
{
pMsg->GetCharset(&hCharSet);
cpID = CustomGetCPFromCharset(hCharSet, FALSE);
}
// Check to see if have chars that don't work in encoding
va.vt = VT_UI4;
va.ulVal = cpID;
IF_FAILEXIT(hr = m_pCmdTargetBody->Exec(&CMDSETID_MimeEdit, MECMDID_CANENCODETEXT, 0, &va, NULL));
if (MIME_S_CHARSET_CONFLICT == hr)
{
// Don't let header call conflict dialog again
m_fPreventConflictDlg = TRUE;
ret = IntlCharsetConflictDialogBox();
if (idcSendAsUnicode == ret)
{
// User choose to send as Unicode (UTF8). set new charset and resnd
hCharSet = GetMimeCharsetFromCodePage(CP_UTF8);
ChangeCharset(hCharSet);
}
else if (IDOK != ret)
{
// return to edit mode and bail out
hr = MAPI_E_USER_CANCEL;
goto exit;
}
}
}
else
// Since we are not mime, don't show dialog ever.
m_fPreventConflictDlg = TRUE;
exit:
return hr;
}
// *************************
HRESULT CNote::Save(LPMIMEMESSAGE pMsg, DWORD dwFlags)
{
HRESULT hr;
IPersistMime* pPersistMimeHdr=0;
DWORD dwHtmlFlags = PMS_TEXT;
if(!m_pHdr)
IF_FAILEXIT(hr = E_FAIL);
IF_FAILEXIT(hr = SetCharsetUnicodeIfNeeded(pMsg));
IF_FAILEXIT(hr = m_pHdr->QueryInterface(IID_IPersistMime, (LPVOID*)&pPersistMimeHdr));
IF_FAILEXIT(hr = pPersistMimeHdr->Save(pMsg, TRUE));
if (m_fHtml)
dwHtmlFlags |= PMS_HTML;
IF_FAILEXIT(hr = m_pPrstMime->Save(pMsg, dwHtmlFlags));
UpdateMsgOptions(pMsg);
// During a send, don't want to commit at this time. m_fCommitSave
// is set to false during a send.
if (m_fCommitSave)
{
hr = pMsg->Commit(0);
// temporary hack for #27823
if((hr == MIME_E_SECURITY_NOSIGNINGCERT) ||
(hr == MIME_E_SECURITY_ENCRYPTNOSENDERCERT) ||
(hr == MIME_E_SECURITY_CERTERROR) ||
(hr == MIME_E_SECURITY_NOCERT) ) // too early for this error
hr = S_OK;
}
exit:
ReleaseObj(pPersistMimeHdr);
return hr;
}
// *************************
HRESULT CNote::InitNew(void)
{
return E_NOTIMPL;
}
// *************************
HRESULT CNote::GetClassID(CLSID *pClsID)
{
return NOERROR;
}
// *************************
HRESULT CNote::SignatureEnabled(BOOL fAuto)
{
int cSig;
HRESULT hr;
DWORD dwSigFlag;
if (m_fBodyContainsFrames || m_fReadNote || (OENA_WEBPAGE == m_dwNoteAction))
return S_FALSE;
if (FAILED(g_pSigMgr->GetSignatureCount(&cSig)) || (0 == cSig))
return S_FALSE;
if (!fAuto) // for non-auto scenario's it's cool to insert a sig, as there is one.
return S_OK;
// From this point down, we are only talking about insertion upon creation
if (OENCF_NOSIGNATURE & m_dwNoteCreateFlags)
return S_FALSE;
dwSigFlag = DwGetOption(OPT_SIGNATURE_FLAGS);
// if its a sendnote: check autonew. for automatically appending the signature. We only append on a virgin sendnote or a stationery sendnote.
// as if it's been saved to the store, the signature is already there.
// if in a reply or forward, then check for auto-reply.
switch (m_dwNoteAction)
{
// If it is a compose note, make sure it wasn't from the store or file system, that it doesn't have any
// body parts, and that the sig flag is set
case OENA_COMPOSE:
{
Assert(m_pMsgSite);
if (m_pMsgSite)
hr = (!m_fOriginallyWasRead && (S_FALSE == HrHasBodyParts(m_pMsg)) && (dwSigFlag & SIGFLAG_AUTONEW)) ? S_OK : S_FALSE;
else
hr = S_FALSE;
break;
}
// For stationery, check sig flag
case OENA_STATIONERY:
{
hr = (dwSigFlag & SIGFLAG_AUTONEW) ? S_OK : S_FALSE;
break;
}
// Check sig flag
case OENA_REPLYTOAUTHOR:
case OENA_REPLYTONEWSGROUP:
case OENA_REPLYALL:
case OENA_FORWARD:
case OENA_FORWARDBYATTACH:
{
hr = (dwSigFlag & SIGFLAG_AUTOREPLY) ? S_OK : S_FALSE;
break;
}
default:
AssertSz(FALSE, "Bad note action type for signature");
hr = S_FALSE;
}
return hr;
}
// *************************
HRESULT CNote::GetSignature(LPCSTR szSigID, LPDWORD pdwSigOptions, BSTR *pbstr)
{
HRESULT hr;
IImnAccount *pAcct = NULL;
GETSIGINFO si;
if (m_fBodyContainsFrames)
return E_NOTIMPL;
hr = m_pHdr->HrGetAccountInHeader(&pAcct);
if (FAILED(hr))
return hr;
si.szSigID = szSigID;
si.pAcct = pAcct;
si.hwnd = m_hwnd;
si.fHtmlOk = m_fHtml;
si.fMail = m_fMail;
si.uCodePage = GetACP();
hr = HrGetMailNewsSignature(&si, pdwSigOptions, pbstr);
ReleaseObj(pAcct);
return hr;
}
// *************************
HRESULT CNote::GetMarkAsReadTime(LPDWORD pdwSecs)
{
// Notes don't care about mark as read timers, only Views
return E_NOTIMPL;
}
// *************************
HRESULT CNote::GetFlags(LPDWORD pdwFlags)
{
DWORD dwMsgSiteFlags = 0;
if (!pdwFlags)
return E_INVALIDARG;
*pdwFlags= BOPT_FROM_NOTE;
Assert(m_pMsgSite);
if (m_pMsgSite)
m_pMsgSite->GetStatusFlags(&dwMsgSiteFlags);
// if a readnote, we can auto-inline attachments
if (m_fReadNote)
*pdwFlags |= BOPT_AUTOINLINE;
// set HTML flag
if (m_fHtml)
*pdwFlags |= BOPT_HTML;
else
*pdwFlags |= BOPT_NOFONTTAG;
if (IsReplyNote())
{
// If block quote option is ON, and is HTML messages
if (m_fHtml && DwGetOption(m_fMail?OPT_MAIL_MSG_HTML_INDENT_REPLY:OPT_NEWS_MSG_HTML_INDENT_REPLY))
*pdwFlags |= BOPT_BLOCKQUOTE;
// Set this in all cases except where we are a reply note and the INCLUDEMSG is not set
if (DwGetOption(OPT_INCLUDEMSG))
*pdwFlags |= BOPT_INCLUDEMSG;
}
else
*pdwFlags |= BOPT_INCLUDEMSG;
// If is reply or forward...
if (IsReplyNote() || (OENA_FORWARD == m_dwNoteAction) || (OENA_FORWARDBYATTACH == m_dwNoteAction) )
{
*pdwFlags |= BOPT_REPLYORFORWARD;
// ... and spell ignore is set
if(DwGetOption(OPT_SPELLIGNOREPROTECT))
*pdwFlags |= BOPT_SPELLINGOREORIGINAL;
}
// If not a read note, or a compose note that started as a compose note (ie one that was previously saved)
if (!m_fReadNote && !m_fOriginallyWasRead)
*pdwFlags |= BOPT_AUTOTEXT;
if (!m_fReadNote && m_fPackageImages)
*pdwFlags |= BOPT_SENDIMAGES;
// ugh. OK, this is big-time sleazy. We found a security hole in SP1. To
// plug this we need to at reply and forward time
// mark incoming images etc as NOSEND=1 links. We do this for all messages
// EXCEPT stationery or webpages
if ((OENA_STATIONERY == m_dwNoteAction) || (OENA_WEBPAGE == m_dwNoteAction))
*pdwFlags |= BOPT_SENDEXTERNALS;
if (m_fUseStationeryFonts)
*pdwFlags |= BOPT_NOFONTTAG;
if (m_fReadNote && (dwMsgSiteFlags & OEMSF_SEC_UI_ENABLED))
*pdwFlags |= BOPT_SECURITYUIENABLED;
if (dwMsgSiteFlags & OEMSF_FROM_STORE)
*pdwFlags |= BOPT_FROMSTORE;
if (dwMsgSiteFlags & OEMSF_UNREAD)
*pdwFlags |= BOPT_UNREAD;
if (!m_fBodyContainsFrames && m_fUseReplyHeaders)
*pdwFlags |= BOPT_USEREPLYHEADER;
if (m_fMail)
*pdwFlags |= BOPT_MAIL;
return S_OK;
}
// *************************
HRESULT CNote::GetInfo(BODYOPTINFO *pBOI)
{
HRESULT hr = S_OK;
if (m_fBodyContainsFrames)
return E_NOTIMPL;
if (pBOI->dwMask & BOPTF_QUOTECHAR)
{
pBOI->chQuote = NULL;
// we allow quote char in plain-text mode only
if (!m_fHtml && (IsReplyNote() || (OENA_FORWARD == m_dwNoteAction)))
pBOI->chQuote =(CHAR)DwGetOption(m_fMail?OPT_MAILINDENT:OPT_NEWSINDENT);
}
if (pBOI->dwMask & BOPTF_REPLYTICKCOLOR)
pBOI->dwReplyTickColor = DwGetOption(m_fMail?OPT_MAIL_FONTCOLOR:OPT_NEWS_FONTCOLOR);
if (pBOI->dwMask & BOPTF_COMPOSEFONT)
hr = HrGetComposeFontString(pBOI->rgchComposeFont, ARRAYSIZE(pBOI->rgchComposeFont), m_fMail);
return hr;
}
HRESULT CNote::GetAccount(IImnAccount **ppAcct)
{
HRESULT hr = S_OK;
#ifdef YST
FOLDERINFO fi;
FOLDERID FolderID;
hr = m_pMsgSite->GetFolderID(&FolderID);
if (FOLDERID_INVALID != FolderID)
{
hr = g_pStore->GetFolderInfo(FolderID, &fi);
if (SUCCEEDED(hr))
{
// Set account based upon the folder ID passed down
if (FOLDER_LOCAL != fi.tyFolder)
{
char szAcctId[CCHMAX_ACCOUNT_NAME];
hr = GetFolderAccountId(&fi, szAcctId, ARRAYSIZE(szAcctId));
if (SUCCEEDED(hr))
hr = g_pAcctMan->FindAccount(AP_ACCOUNT_ID, szAcctId, ppAcct);
}
else
hr = m_pMsgSite->GetCurrentAccount(ppAcct);
g_pStore->FreeRecord(&fi);
}
}
else
hr = E_FAIL;
#endif // 0
hr = m_pHdr->HrGetAccountInHeader(ppAcct);
return(hr);
}
// *************************
void CNote::WMSize(int cxNote, int cyNote, BOOL fInternal)
{
RECT rc;
int cy = 0;
// assume the header autosizes itself..., unless an internal size requires we recalc...
if(fInternal)
{
// if the size is coming from the header... figure out the current size
// of the note... as cxNote and cyNote are bogus at this point...
GetClientRect(m_hwnd, &rc);
cxNote = cxRect(rc);
cyNote = cyRect(rc);
}
if (m_pToolbarObj)
{
//Ideally we should be calling ResizeBorderDW. But
HWND rebarHwnd = m_hwndRebar;
m_pToolbarObj->ResizeBorderDW(&rc, (IUnknown*)(IDockingWindowSite*)this, 0);
GetWindowRect(GetParent(rebarHwnd), &rc);
cy += cyRect(rc);
}
ResizeChildren(cxNote, cyNote, cy, fInternal);
}
void CNote::ResizeChildren(int cxNote, int cyNote, int cy, BOOL fInternal)
{
int cyBottom;
RECT rc;
int cyStatus = 0;
static int cxBorder = 0,
cyBorder = 0;
if(!cxBorder || !cyBorder)
{
cyBorder = GetSystemMetrics(SM_CYBORDER);
cxBorder = GetSystemMetrics(SM_CXBORDER);
}
// size the header
GetClientRect(m_hwnd, &rc);
// remember the actual bottom
cyBottom = rc.bottom;
cy += 4;
InflateRect(&rc, -1, -1);
rc.bottom = GetRequiredHdrHeight();
rc.top = cy;
rc.bottom += rc.top;
if(!fInternal && m_pHdr)
m_pHdr->SetRect(&rc);
// WARNING: the header may resize itself during a size, due to an edit
// growing
cy += GetRequiredHdrHeight()+2;
cy += cyBorder;
if (m_pstatus)
{
m_pstatus->OnSize(cxNote, cyNote);
m_pstatus->GetHeight(&cyStatus);
}
rc.top = cy;
rc.bottom = cyBottom-cyBorder; // edit has a minimum size, clip if if gets too tight...
rc.bottom -= cyStatus;
if (m_pBodyObj2)
m_pBodyObj2->HrSetSize(&rc);
}
// *************************
BOOL CNote::IsReplyNote()
{
return ((OENA_REPLYTOAUTHOR == m_dwNoteAction) || (OENA_REPLYTONEWSGROUP == m_dwNoteAction) || (OENA_REPLYALL == m_dwNoteAction));
}
// *************************
HRESULT CNote::Resize(void)
{
WMSize(0, 0, TRUE);
return S_OK;
}
// *************************
HRESULT CNote::UpdateTitle()
{
HRESULT hr;
WCHAR wszTitle[cchHeaderMax+1];
Assert(m_pHdr);
*wszTitle = 0x0000;
hr = m_pHdr->GetTitle(wszTitle, ARRAYSIZE(wszTitle));
if(SUCCEEDED(hr))
SetWindowTextWrapW(m_hwnd, wszTitle);
return hr;
}
// *************************
HRESULT CNote::Update(void)
{
m_pToolbarObj->Update();
UpdateTitle();
return S_OK;
}
// *************************
HRESULT CNote::OnSetFocus(HWND hwndFrom)
{
HWND hwndBody;
// setfocus from a kid and not a body. make sure we
// UIDeactivate the docobj
SideAssert(m_pBodyObj2->HrGetWindow(&hwndBody)==NOERROR);
if(hwndFrom != hwndBody)
m_pBodyObj2->HrUIActivate(FALSE);
// if focus goes to a kid, update the toolbar
m_pToolbarObj->Update();
// focus is going to a kid. Enable/Disable the formatbar
m_pBodyObj2->HrUpdateFormatBar();
return S_OK;
}
// *************************
HRESULT CNote::OnUIActivate()
{
m_fHeaderUIActive = TRUE;
return OnSetFocus(0);
}
// *************************
HRESULT CNote::OnKillFocus()
{
m_pToolbarObj->Update();
return S_OK;
}
// *************************
HRESULT CNote::OnUIDeactivate(BOOL)
{
m_fHeaderUIActive = FALSE;
return OnKillFocus();
}
// *************************
HRESULT CNote::IsHTML(void)
{
return m_fHtml ? S_OK : S_FALSE;
}
HRESULT CNote::IsModal()
{
return (m_dwNoteCreateFlags & OENCF_MODAL) ? S_OK : S_FALSE;
}
// *************************
HRESULT CNote::SetHTML(BOOL fHTML)
{
m_fHtml = !!fHTML;
return NOERROR;
}
#ifdef SMIME_V3
// return selected label in note
// S_OK user select label
// S_FALSE user uncheck using security labels
HRESULT CNote::GetLabelFromNote(PSMIME_SECURITY_LABEL *pplabel)
{
if(m_fSecurityLabel && m_fMail)
{
*pplabel = m_pLabel;
return S_OK;
}
else
{
*pplabel = NULL;
return S_FALSE;
}
}
HRESULT CNote::IsSecReceiptRequest(void)
{
if(m_fSecReceiptRequest)
return(S_OK);
else
return(S_FALSE);
}
HRESULT CNote::IsForceEncryption(void)
{
return(m_pHdr->ForceEncryption(NULL, FALSE));
}
#endif // SMIME_V3
// *************************
HRESULT CNote::SaveAttachment(void)
{
return m_pBodyObj2 ? m_pBodyObj2->HrSaveAttachment() : E_FAIL;
}
// *************************
HRESULT CNote::DragEnter(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
{
DWORD dwEffectSave = *pdwEffect;;
m_fBypassDropTests = FALSE;
Assert(m_pDropTargetHdr && m_pTridentDropTarget);
if (m_pHdr->HrIsDragSource() == S_OK)
{
m_fBypassDropTests = TRUE; // treated as drop to itself.
*pdwEffect = DROPEFFECT_NONE;
return S_OK;
}
m_pDropTargetHdr->DragEnter(pDataObj, grfKeyState, pt, pdwEffect);
if (*pdwEffect == DROPEFFECT_NONE)
{
if (!m_fHtml) // plain text mode. If there is no text, we should not take it.
{
IEnumFORMATETC* pEnum = NULL;
FORMATETC fetc = {0};
ULONG celtFetched = 0;
BOOL fCFTEXTFound = FALSE;
// see if there is CF_TEXT format
if (SUCCEEDED(pDataObj->EnumFormatEtc(DATADIR_GET, &pEnum)))
{
pEnum->Reset();
while (S_OK == pEnum->Next(1, &fetc, &celtFetched))
{
Assert(celtFetched == 1);
if (fetc.cfFormat == CF_TEXT)
{
fCFTEXTFound = TRUE;
break;
}
}
pEnum->Release();
}
if (!fCFTEXTFound) // no CF_TEXT, cannot drop in plain text mode.
{
*pdwEffect = DROPEFFECT_NONE;
m_fBypassDropTests = TRUE; // treated as drop to itself.
return S_OK;
}
}
*pdwEffect = dwEffectSave;
m_pTridentDropTarget->DragEnter(pDataObj, grfKeyState, pt, pdwEffect);
}
return S_OK;
}
// *************************
HRESULT CNote::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
{
DWORD dwEffectSave = *pdwEffect;
if (m_fBypassDropTests)
{
*pdwEffect = DROPEFFECT_NONE;
return S_OK;
}
m_pDropTargetHdr->DragOver(grfKeyState, pt, pdwEffect);
if (*pdwEffect == DROPEFFECT_NONE)
{
*pdwEffect = dwEffectSave;
m_pTridentDropTarget->DragOver(grfKeyState, pt, pdwEffect);
}
return S_OK;
}
// *************************
HRESULT CNote::DragLeave(void)
{
if (m_fBypassDropTests)
return S_OK;
m_pDropTargetHdr->DragLeave();
m_pTridentDropTarget->DragLeave();
return NOERROR;
}
// *************************
HRESULT CNote::Drop(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
{
IDataObject *pDataObjNew = NULL;
HRESULT hr = S_OK;
STGMEDIUM stgmed;
DWORD dwEffectSave = *pdwEffect;
ZeroMemory(&stgmed, sizeof(stgmed));
if (m_fBypassDropTests)
{
*pdwEffect = DROPEFFECT_NONE;
return NOERROR;
}
m_pDropTargetHdr->Drop(pDataObj, grfKeyState, pt, pdwEffect);
if (*pdwEffect == DROPEFFECT_NONE) // it is Trident's drag&drop
{
if(!m_fHtml)
{
hr = m_pBodyObj2->PublicFilterDataObject(pDataObj, &pDataObjNew);
if(FAILED(hr))
return E_UNEXPECTED;
}
else
{
pDataObjNew = pDataObj;
pDataObj->AddRef();
}
*pdwEffect = dwEffectSave;
m_pTridentDropTarget->Drop(pDataObjNew, grfKeyState, pt, pdwEffect);
}
ReleaseObj(pDataObjNew);
return hr;
}
// *************************
HRESULT CNote::InitWindows(RECT *prc, HWND hwndOwner)
{
HWND hwnd;
HMENU hMenu;
RECT rcCreate,
rc;
HCURSOR hcur;
HWND hwndCapture;
DWORD dwStyle = WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN;
HRESULT hr = S_OK;
DWORD dwExStyle = WS_EX_WINDOWEDGE | WS_EX_CONTROLPARENT | (IS_BIDI_LOCALIZED_SYSTEM() ? RTL_MIRRORED_WINDOW : 0L);
WINDOWPLACEMENT wp = {0};
Assert(hwndOwner == NULL || IsWindow(hwndOwner));
m_hwndOwner = hwndOwner;
hcur=SetCursor(LoadCursor(NULL, IDC_WAIT));
if(!Note_Init(TRUE))
IF_FAILEXIT(hr = E_FAIL);
if(prc)
CopyRect(&rcCreate, prc);
else
CopyRect(&rcCreate, &g_rcLastResize);
m_hMenu = LoadMenu(g_hLocRes, MAKEINTRESOURCE(m_fReadNote?IDR_READ_NOTE_MENU:IDR_SEND_NOTE_MENU));
MenuUtil_ReplaceHelpMenu(m_hMenu);
MenuUtil_ReplaceNewMsgMenus(m_hMenu);
if (m_dwNoteCreateFlags & OENCF_MODAL)
{
// Check to make sure nobody has captured the mouse from us
hwndCapture = GetCapture();
if (hwndCapture)
SendMessage(hwndCapture, WM_CANCELMODE, 0, 0);
// Let's make sure we have a real topmost owner
if (m_hwndOwner)
{
HWND hwndParent = GetParent(m_hwndOwner);
// IsChild checks the WM_CHILD bit in the window. This will only be
// set with controls or subs of a window. So, a dialog's parent might be
// a note, but that dialog will not be a child of the parent.
// RAID 37188
while(IsChild(hwndParent, m_hwndOwner))
{
m_hwndOwner = hwndParent;
hwndParent = GetParent(m_hwndOwner);
}
// Lose the minimize box for modal notes if there is a parent
dwStyle &= ~WS_MINIMIZEBOX;
}
}
hwnd = CreateWindowExWrapW( dwExStyle,
c_wszNoteWndClass,
NULL, //caption set by en_change of subject
dwStyle,
prc?rcCreate.left:CW_USEDEFAULT, // use windows default for x and y.
prc?rcCreate.top:CW_USEDEFAULT,
cxRect(rcCreate), cyRect(rcCreate), m_hwndOwner, NULL, g_hInst, (LPVOID)this);
IF_NULLEXIT(hwnd);
if ((m_dwNoteCreateFlags & OENCF_MODAL) && (NULL != m_hwndOwner))
EnableWindow(m_hwndOwner, FALSE);
if ( GetOption(OPT_MAILNOTEPOSEX, (LPVOID)&wp, sizeof(wp)) )
{
wp.length = sizeof(wp);
wp.showCmd = SW_HIDE;
SetWindowPlacement(hwnd, &wp);
}
else
{
CenterDialog(hwnd);
}
exit:
SetCursor(hcur);
return hr;
}
// *************************
HRESULT CNote::Init(DWORD dwAction, DWORD dwCreateFlags, RECT *prc, HWND hwnd, INIT_MSGSITE_STRUCT *pInitStruct, IOEMsgSite *pMsgSite, IUnknown *punkPump)
{
HRESULT hr,
tempHr = S_OK;
IMimeMessage *pMsg = NULL;
DWORD dwFormatFlags,
dwStatusFlags = 0,
dwMsgFlags = (OENA_FORWARDBYATTACH == dwAction) ? (OEGM_ORIGINAL|OEGM_AS_ATTACH) : NOFLAGS;
LPSTR pszUnsent = NULL;
BOOL fBool = FALSE,
fOffline=FALSE;
Assert((pInitStruct && !pMsgSite)|| (!pInitStruct && pMsgSite));
ReplaceInterface(m_punkPump, punkPump);
// If passed in an INIT_MSGSITE_STRUCT, must convert it to a pMsgSite
if (pInitStruct)
{
m_pMsgSite = new COEMsgSite();
if (!m_pMsgSite)
{
hr = E_OUTOFMEMORY;
goto exit;
}
Assert(pInitStruct);
hr = m_pMsgSite->Init(pInitStruct);
if (FAILED(hr))
goto exit;
}
else
ReplaceInterface(m_pMsgSite, pMsgSite);
if(m_pMsgSite)
m_pMsgSite->GetStatusFlags(&dwStatusFlags);
AssertSz(m_pMsgSite, "Why don't we have a msgSite???");
m_dwNoteAction = dwAction;
m_fReadNote = !!(OENA_READ == m_dwNoteAction);
m_fOriginallyWasRead = m_fReadNote;
m_dwNoteCreateFlags = dwCreateFlags;
// The storeCallback needs to be set. m_hwnd will be reset once we have a valid handle
m_hwnd = hwnd;
m_pMsgSite->SetStoreCallback(this);
hr = m_pMsgSite->GetMessage(&pMsg, &fBool, dwMsgFlags, &tempHr);
if (FAILED(hr))
goto exit;
// Raid 80277; Set default charset
if(OENA_FORWARDBYATTACH == dwAction)
{
if (NULL == g_hDefaultCharsetForMail)
ReadSendMailDefaultCharset();
pMsg->SetCharset(g_hDefaultCharsetForMail, CSET_APPLY_ALL);
}
m_fCompleteMsg = !!fBool; // m_f* is a bitfield
fOffline = (hr == HR_S_OFFLINE);
switch (m_dwNoteAction)
{
case OENA_REPLYTOAUTHOR:
case OENA_FORWARDBYATTACH:
case OENA_FORWARD:
m_fMail = TRUE;
break;
case OENA_REPLYTONEWSGROUP:
m_fMail = FALSE;
case OENA_STATIONERY:
case OENA_WEBPAGE:
case OENA_COMPOSE:
m_fMail = (0 == (m_dwNoteCreateFlags & OENCF_NEWSFIRST));
break;
case OENA_REPLYALL:
case OENA_READ:
{
DWORD dwStatusFlags = 0;
hr = m_pMsgSite->GetStatusFlags(&dwStatusFlags);
if (FAILED(hr))
goto exit;
m_fMail = (0 == (OEMSF_BASEISNEWS & dwStatusFlags));
break;
}
}
ProcessIncompleteAccts(hwnd);
hr = ProcessICW(hwnd, m_fMail ? FOLDER_LOCAL : FOLDER_NEWS);
if (FAILED(hr))
goto exit;
// If this is an unsent message and is a read note, then change the type to compose. This needs
// to happen after setting the m_fMail flag since we mangle the noteAction.
ChangeReadToComposeIfUnsent(pMsg);
if (m_fMail)
{
m_fPackageImages = !!DwGetOption(OPT_MAIL_SENDINLINEIMAGES);
dwFormatFlags = FMT_MAIL;
}
else
{
PROPVARIANT var;
IImnAccount *pAcct = NULL;
TCHAR szAcctID[CCHMAX_ACCOUNT_NAME];
DWORD dw;
m_fPackageImages = !!DwGetOption(OPT_NEWS_SENDINLINEIMAGES);
*szAcctID = 0;
dwFormatFlags = FMT_NEWS;
// Bug #24267 - Check the message object for a server name before defaulting
// to the default server.
var.vt = VT_LPSTR;
if (SUCCEEDED(pMsg->GetProp(PIDTOSTR(PID_ATT_ACCOUNTID), NOFLAGS, &var)))
{
StrCpyN(szAcctID, var.pszVal, ARRAYSIZE(szAcctID));
SafeMemFree(var.pszVal);
}
if (*szAcctID)
hr = g_pAcctMan->FindAccount(AP_ACCOUNT_ID, szAcctID, &pAcct);
// No account present, or the listed one no longer exists try to get the default
if (!*szAcctID || (*szAcctID && FAILED(hr)))
hr = m_pMsgSite->GetDefaultAccount(ACCT_NEWS, &pAcct);
if ((OENA_WEBPAGE == dwAction) || (OENA_STATIONERY == dwAction))
dwFormatFlags |= FMT_FORCE_HTML;
else if (SUCCEEDED(hr) && pAcct && SUCCEEDED(pAcct->GetPropDw(AP_NNTP_POST_FORMAT, &dw)))
{
if (dw == POST_USE_HTML)
dwFormatFlags |= FMT_FORCE_HTML;
else if (dw == POST_USE_PLAIN_TEXT)
dwFormatFlags |= FMT_FORCE_PLAIN;
else
Assert(dw == POST_USE_DEFAULT);
}
ReleaseObj(pAcct);
}
GetDefaultOptInfo(&m_rHtmlOpt, &m_rPlainOpt, &fBool, dwFormatFlags);
switch (m_dwNoteAction)
{
case OENA_FORWARDBYATTACH:
m_fHtml = !!fBool;
break;
case OENA_COMPOSE:
if (m_fOriginallyWasRead)
{
DWORD dwFlags = 0;
pMsg->GetFlags(&dwFlags);
m_fHtml = !!(dwFlags & IMF_HTML);
}
else
m_fHtml = !!fBool;
break;
case OENA_STATIONERY:
case OENA_WEBPAGE:
case OENA_READ:
m_fHtml = TRUE; // HTML is always cool in a readnote
break;
case OENA_REPLYTOAUTHOR:
case OENA_REPLYTONEWSGROUP:
case OENA_REPLYALL:
case OENA_FORWARD:
// when replying, if option to repect sender format is on, do so
if (DwGetOption(OPT_REPLYINORIGFMT))
{
DWORD dwFlags = 0;
pMsg->GetFlags(&dwFlags);
m_fHtml = !!(dwFlags & IMF_HTML);
}
else
m_fHtml = !!fBool;
// Bug 76570, 76575
// Set security label
if(pMsg)
{
SECSTATE SecState;
HrGetSecurityState(pMsg, &SecState, NULL);
// only in case of signing message check label
if(IsSigned(SecState.type))
{
PCRYPT_ATTRIBUTE pattrLabel;
LPBYTE pbLabel = NULL;
DWORD cbLabel;
PSMIME_SECURITY_LABEL plabel = NULL;
IMimeSecurity2 * pSMIME3 = NULL;
IMimeBody *pBody = NULL;
if(pMsg->BindToObject(HBODY_ROOT, IID_IMimeBody, (void **)&pBody) == S_OK)
{
if(pBody->QueryInterface(IID_IMimeSecurity2, (LPVOID *) &pSMIME3) == S_OK)
{
// Get label attribute
if(pSMIME3->GetAttribute(0, 0, SMIME_ATTRIBUTE_SET_SIGNED,
0, szOID_SMIME_Security_Label,
&pattrLabel) == S_OK)
{
// decode label
if(CryptDecodeObjectEx(X509_ASN_ENCODING,
szOID_SMIME_Security_Label,
pattrLabel->rgValue[0].pbData,
pattrLabel->rgValue[0].cbData,
CRYPT_DECODE_ALLOC_FLAG,
&CryptDecodeAlloc, &plabel, &cbLabel))
{
if(plabel)
{
m_fSecurityLabel = TRUE;
SafeMemFree(m_pLabel);
m_pLabel = plabel;
}
}
}
else
{ // Secure receipt is binary message and pMsg->GetFlags always will retutn non-HTML, but we
// forward (or Replay) with our HTML screen and need to set this to HTML.
if(CheckSecReceipt(pMsg) == S_OK)
m_fHtml = TRUE;
}
SafeRelease(pSMIME3);
}
ReleaseObj(pBody);
}
}
CleanupSECSTATE(&SecState);
}
break;
}
hr = InitWindows(prc, (dwCreateFlags & OENCF_MODAL) ? hwnd : 0);
if (FAILED(hr))
goto exit;
hr = Load(pMsg);
if (FAILED(hr))
goto exit;
if (FAILED(tempHr))
ShowErrorScreen(tempHr);
m_fFullHeaders = (S_OK == m_pHdr->FullHeadersShowing());
if (fOffline)
ShowErrorScreen(HR_E_OFFLINE);
hr = InitMenusAndToolbars();
// Register with identity manager
SideAssert(SUCCEEDED(hr = MU_RegisterIdentityNotifier((IUnknown *)(IOENote *)this, &m_dwIdentCookie)));
exit:
ReleaseObj(pMsg);
if (FAILED(hr) && m_pMsgSite && !pMsgSite)
m_pMsgSite->Close();
return hr;
}
// Will return after close if is modal, otherwise returns immediately
HRESULT CNote::Show(void)
{
ShowWindow(m_hwnd, SW_SHOW);
SetForegroundWindow(m_hwnd);
if (m_dwNoteCreateFlags & OENCF_MODAL)
{
MSG msg;
HWNDLIST hwndList;
EnableThreadWindows(&hwndList, FALSE, 0, m_hwnd);
while (GetMessageWrapW(&msg, NULL, 0, 0))
{
// This is a member function, so don't need to wrap
if (TranslateAccelerator(&msg) == S_OK)
continue;
::TranslateMessage(&msg);
::DispatchMessageWrapW(&msg);
}
EnableThreadWindows(&hwndList, TRUE, 0, m_hwnd);
}
return S_OK;
}
// *************************
BOOL CNote::WMCreate(HWND hwnd)
{
LPTBBUTTON lpButtons;
ULONG cBtns;
HWND hwndRebar;
CMimeEditDocHost *pNoteBody;
DWORD dwStyle;
RECT rc;
VARIANTARG var;
IUnknown *pUnk = NULL;
REBARBANDINFO rbbi;
m_hwnd = hwnd;
SetWndThisPtr(hwnd, this);
AddRef();
Assert(IsWindow(m_hwnd));
SetProp(hwnd, c_szOETopLevel, (HANDLE)TRUE);
//Create a new bandsclass and intialize it
m_pToolbarObj = new CBands();
if (!m_pToolbarObj)
return FALSE;
m_pToolbarObj->HrInit(0, m_hMenu, PARENT_TYPE_NOTE);
m_pToolbarObj->SetSite((IOENote*)this);
m_pToolbarObj->ShowDW(TRUE);
m_pToolbarObj->SetFolderType(GetNoteType());
m_fToolbarVisible = m_pToolbarObj->IsToolbarVisible();
m_hwndToolbar = m_pToolbarObj->GetToolbarWnd();
m_hwndRebar = m_pToolbarObj->GetRebarWnd();
pNoteBody = new CMimeEditDocHost(MEBF_INNERCLIENTEDGE);
if (!pNoteBody)
return FALSE;
pNoteBody->QueryInterface(IID_IBodyObj2, (LPVOID *)&m_pBodyObj2);
pNoteBody->Release();
if (!m_pBodyObj2)
return FALSE;
m_pBodyObj2->QueryInterface(IID_IPersistMime, (LPVOID*)&m_pPrstMime);
if (!m_pPrstMime)
return FALSE;
m_pstatus = new CStatusBar();
if (NULL == m_pstatus)
return FALSE;
m_pstatus->Initialize(m_hwnd, SBI_HIDE_SPOOLER | SBI_HIDE_CONNECTED | SBI_HIDE_FILTERED);
m_pstatus->ShowStatus(m_fStatusbarVisible);
m_pBodyObj2->HrSetStatusBar(m_pstatus);
CreateInstance_Envelope(NULL, (IUnknown**)&pUnk);
if (!pUnk)
return FALSE;
pUnk->QueryInterface(IID_IHeader, (LPVOID*)&m_pHdr);
pUnk->Release();
if (!m_pHdr)
return FALSE;
m_pHdr->QueryInterface(IID_IDropTarget, (LPVOID*)&m_pDropTargetHdr);
if (!m_pDropTargetHdr)
return FALSE;
m_pHdr->QueryInterface(IID_IOleCommandTarget, (LPVOID*)&m_pCmdTargetHdr);
if (!m_pCmdTargetHdr)
return FALSE;
if (!m_fMail)
HeaderExecCommand(MSOEENVCMDID_NEWS, MSOCMDEXECOPT_DODEFAULT, NULL);
var.vt = VT_I4;
var.lVal = m_dwNoteAction;
HeaderExecCommand(MSOEENVCMDID_SETACTION, MSOCMDEXECOPT_DODEFAULT, &var);
if (FAILED(m_pHdr->Init((IHeaderSite*)this, hwnd)))
return FALSE;
if (FAILED(InitBodyObj()))
return FALSE;
// Set focus in the To: line
switch (m_dwNoteAction)
{
case OENA_COMPOSE:
case OENA_FORWARD:
case OENA_FORWARDBYATTACH:
case OENA_WEBPAGE:
case OENA_STATIONERY:
m_pHdr->SetInitFocus(FALSE);
break;
}
m_pBodyObj2->SetEventSink((IMimeEditEventSink *) this);
SetForegroundWindow(m_hwnd);
return TRUE;
}
// *************************
void CNote::InitSendAndBccBtns()
{
DWORD idiIcon;
HICON hIconTemp = 0;
Assert(m_hwnd);
if (m_fMail)
idiIcon = m_fReadNote?idiMsgPropSent:idiMsgPropUnSent;
else
idiIcon = m_fReadNote?idiArtPropPost:idiArtPropUnpost;
// don't have to free HICON loaded from LoadIcon
SendMessage(m_hwnd, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon(g_hLocRes, MAKEINTRESOURCE(idiIcon)));
if (m_fMail)
idiIcon = m_fReadNote?idiSmallMsgPropSent:idiSmallMsgPropUnSent;
else
idiIcon = m_fReadNote?idiSmallArtPropPost:idiSmallArtPropUnpost;
if(m_hIcon)
{
hIconTemp = m_hIcon;
}
m_hIcon = (HICON)LoadImage(g_hLocRes, MAKEINTRESOURCE(idiIcon), IMAGE_ICON,
GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0);
// don't have to free HICON loaded from LoadIcon
SendMessage(m_hwnd, WM_SETICON, ICON_SMALL, (LPARAM)m_hIcon);
if(hIconTemp)
{
//Bug #101345 - (erici) ICON leaked when 'Previous' or 'Next' button clicked
DestroyIcon(hIconTemp);
}
// If this is a news send note, then we spruce up the send button on the toolbar
if ((FALSE == m_fReadNote) && (FALSE == m_fMail))
{
TBBUTTONINFO tbi;
ZeroMemory(&tbi, sizeof(TBBUTTONINFO));
tbi.cbSize = sizeof(TBBUTTONINFO);
tbi.dwMask = TBIF_IMAGE;
tbi.iImage = TBIMAGE_SEND_NEWS;
SendMessage(m_hwndToolbar, TB_SETBUTTONINFO, ID_SEND_DEFAULT, (LPARAM) &tbi);
}
}
// *************************
HRESULT CNote::HeaderExecCommand(UINT uCmdID, DWORD nCmdExecOpt, VARIANTARG *pvaIn)
{
HRESULT hr = S_FALSE;
if (uCmdID && m_pCmdTargetHdr)
hr = m_pCmdTargetHdr->Exec(&CGID_Envelope, uCmdID, nCmdExecOpt, pvaIn, NULL);
return hr;
}
// *************************
HRESULT CNote::InitBodyObj()
{
DWORD dwBodyStyle = MESTYLE_NOHEADER;
HRESULT hr;
int idsErr=0;
hr = m_pBodyObj2->HrInit(m_hwnd, IBOF_TABLINKS, (IBodyOptions *)this);
if (FAILED(hr))
goto fail;
hr = m_pBodyObj2->QueryInterface(IID_IOleCommandTarget, (LPVOID*)&m_pCmdTargetBody);
if (FAILED(hr))
goto fail;
hr = m_pBodyObj2->HrShow(TRUE);
if (FAILED(hr))
goto fail;
// if not in html mode, don't show format bar...
// we do this test here, as HrLoad could determine that a previously saved message
// is indeed in html, which overrides the default setting
if(!m_fHtml)
m_fFormatbarVisible = FALSE;
if (!m_fReadNote && !m_fBodyContainsFrames && m_fFormatbarVisible)
dwBodyStyle = MESTYLE_FORMATBAR;
m_pBodyObj2->HrEnableHTMLMode(m_fHtml);
m_pBodyObj2->HrSetStyle(dwBodyStyle);
// all is groovey
return hr;
fail:
switch (hr)
{
case INET_E_UNKNOWN_PROTOCOL:
idsErr = idsErrLoadProtocolBad;
break;
default:
idsErr = idsErrNoteDeferedInit;
break;
}
AthMessageBoxW(g_hwndInit, MAKEINTRESOURCEW(idsAthena), MAKEINTRESOURCEW(idsErr), NULL, MB_OK);
return hr;
}
// *************************
HRESULT CNote::InitMenusAndToolbars()
{
DWORD dwStatusFlags;
HRESULT hr;
BOOL fComposeNote,
fCompleteMsg = !!m_fCompleteMsg, // m_fCompleteMsg is a bit field.
fNextPrevious;
HMENU hMenu = m_hMenu;
m_fUseReplyHeaders = FALSE;
Assert(m_pMsgSite);
if (m_pMsgSite)
m_pMsgSite->GetStatusFlags(&dwStatusFlags);
switch (m_dwNoteAction)
{
case OENA_FORWARDBYATTACH:
case OENA_COMPOSE:
// if it's a virgin compose-note, we check the regsettings to see if they want to compose
// from a stationery file. If so, we set the html stream to that file.
if (m_fHtml && !(m_dwNoteCreateFlags & OENCF_NOSTATIONERY) && (OEMSF_VIRGIN & dwStatusFlags))
SetComposeStationery();
break;
case OENA_STATIONERY:
if (m_dwNoteCreateFlags & OENCF_USESTATIONERYFONT)
m_fUseStationeryFonts = TRUE;
break;
case OENA_REPLYTOAUTHOR:
case OENA_REPLYTONEWSGROUP:
case OENA_REPLYALL:
case OENA_FORWARD:
m_fUseReplyHeaders = TRUE;
break;
}
InitSendAndBccBtns();
if (m_fMail)
{
if (m_fReadNote || IsReplyNote())
m_pBodyObj2->HrUIActivate(TRUE);
}
else
{
if ((OENA_COMPOSE == m_dwNoteAction) && (OEMSF_VIRGIN & dwStatusFlags))
// for a sendnote in news, put focus in the subject as the to: line is filled in. bug #24720
m_pHdr->SetInitFocus(TRUE);
else
// else , always put focus in the BODY
m_pBodyObj2->HrUIActivate(TRUE);
}
RECT rc;
GetClientRect(m_hwnd, &rc);
SendMessage(m_hwnd, WM_SIZE, SIZE_RESTORED, MAKELPARAM(rc.right, rc.bottom));
// put us into edit mode if not a readnote...
hr=m_pBodyObj2->HrSetEditMode(!m_fReadNote && !m_fBodyContainsFrames);
if (FAILED(hr))
goto error;
if (m_fBodyContainsFrames)
DisableSendNoteOnlyMenus();
// get the character set of the message being loaded
if (m_pMsg)
m_pMsg->GetCharset(&m_hCharset);
error:
return hr;
}
// *************************
void CNote::DisableSendNoteOnlyMenus()
{
}
// *************************
HACCEL CNote::GetAcceleratorTable()
{
return (m_fReadNote ? g_hAccelRead : g_hAccelSend);
}
// *************************
HRESULT CNote::TranslateAccelerator(LPMSG lpmsg)
{
HWND hwndT,
hwndFocus;
if (IsMenuMessage(lpmsg) == S_OK)
return S_OK;
// handle the mousewheel messages for this note
if ((g_msgMSWheel && (lpmsg->message == g_msgMSWheel)) || (lpmsg->message == WM_MOUSEWHEEL))
{
POINT pt;
HWND hwndT;
pt.x = GET_X_LPARAM(lpmsg->lParam);
pt.y = GET_Y_LPARAM(lpmsg->lParam);
hwndT = WindowFromPoint(pt);
hwndFocus = GetFocus();
if (hwndT != m_hwnd && IsChild(m_hwnd, hwndT))
SendMessage(hwndT, lpmsg->message, lpmsg->wParam, lpmsg->lParam);
else if (hwndFocus != m_hwnd && IsChild(m_hwnd, hwndFocus))
SendMessage(hwndFocus, lpmsg->message, lpmsg->wParam, lpmsg->wParam);
else
return S_FALSE;
return S_OK;
}
// our accelerators have higher priority.
if(::TranslateAcceleratorWrapW(m_hwnd, GetAcceleratorTable(), lpmsg))
return S_OK;
// see if the body want it for the docobject...
if(m_pBodyObj2 &&
m_pBodyObj2->HrTranslateAccelerator(lpmsg)==S_OK)
return S_OK;
if (lpmsg->message == WM_KEYDOWN &&
lpmsg->wParam == VK_TAB &&
!(GetKeyState(VK_CONTROL) & 0x8000 ))
{
BOOL fGoForward = ( GetKeyState( VK_SHIFT ) & 0x8000 ) == 0;
CycleThroughControls(fGoForward);
return S_OK;
}
return S_FALSE;
}
// *************************
LRESULT CNote::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
LRESULT lResult;
LRESULT lres;
MSG Menumsg;
HWND hwndActive;
WINDOWPLACEMENT wp;
Menumsg.hwnd = hwnd;
Menumsg.message = msg;
Menumsg.wParam = wParam;
Menumsg.lParam = lParam;
if (m_pToolbarObj && (m_pToolbarObj->TranslateMenuMessage(&Menumsg, &lres) == S_OK))
return lres;
wParam = Menumsg.wParam;
lParam = Menumsg.lParam;
switch(msg)
{
case WM_ENABLE:
if (!m_fInternal)
{
Assert (wParam || (m_hlDisabled.cHwnd == NULL && m_hlDisabled.rgHwnd == NULL));
EnableThreadWindows(&m_hlDisabled, !!wParam, ETW_OE_WINDOWS_ONLY, hwnd);
g_hwndActiveModal = wParam ? NULL : hwnd;
}
break;
case WM_OE_DESTROYNOTE:
m_fForceClose = 1;
SendMessage(hwnd, WM_CLOSE, 0, 0);
break;
case WM_OENOTE_ON_COMPLETE:
_OnComplete((STOREOPERATIONTYPE)lParam, (HRESULT) wParam);
break;
case WM_OE_ENABLETHREADWINDOW:
m_fInternal = 1;
EnableWindow(hwnd, (BOOL)wParam);
m_fInternal = 0;
break;
case WM_OE_ACTIVATETHREADWINDOW:
hwndActive = GetLastActivePopup(hwnd);
if (hwndActive && IsWindowEnabled(hwndActive) && IsWindowVisible(hwndActive))
ActivatePopupWindow(hwndActive);
break;
case NWM_GETDROPTARGET:
SafeRelease(m_pTridentDropTarget);
m_pTridentDropTarget = (IDropTarget*) wParam;
if (m_pTridentDropTarget)
m_pTridentDropTarget->AddRef();
AddRef();
return (LRESULT)(IDropTarget *) this;
case WM_DESTROY:
// Unregister with Identity manager
if (m_dwIdentCookie != 0)
{
MU_UnregisterIdentityNotifier(m_dwIdentCookie);
m_dwIdentCookie = 0;
}
wp.length = sizeof(wp);
GetWindowPlacement(hwnd, &wp);
SetOption(OPT_MAILNOTEPOSEX, (LPVOID)&wp, sizeof(wp), NULL, 0);
RemoveProp(hwnd, c_szOETopLevel);
DeinitSigPopupMenu(hwnd);
if(m_pBodyObj2)
{
m_pBodyObj2->HrSetStatusBar(NULL);
m_pBodyObj2->HrClose();
}
SafeRelease(m_pTridentDropTarget);
if (m_pToolbarObj)
{
DWORD dwReserved = 0;
m_pToolbarObj->SetSite(NULL);
m_pToolbarObj->CloseDW(dwReserved);
}
if (m_pCancel)
m_pCancel->Cancel(CT_ABORT);
if (m_pMsgSite)
m_pMsgSite->Close();
break;
case WM_NCDESTROY:
DOUTL(8, "CNote::WMNCDESTROY");
WMNCDestroy();
return 0;
case WM_ACTIVATEAPP:
if (wParam && g_hwndActiveModal && g_hwndActiveModal != hwnd &&
!IsWindowEnabled(hwnd))
{
// $MODAL
// if we are getting activated, and are disabled then
// bring our 'active' window to the top
Assert (IsWindow(g_hwndActiveModal));
PostMessage(g_hwndActiveModal, WM_OE_ACTIVATETHREADWINDOW, 0, 0);
}
break;
case WM_SYSCOMMAND:
// if we're minimizing, get the control with focus, as when we get the
// next WM_ACTIVATE we will already be minimized
if (wParam == SC_MINIMIZE)
m_hwndFocus = GetFocus();
break;
case WM_ACTIVATE:
if (m_pBodyObj2)
m_pBodyObj2->HrFrameActivate(LOWORD(wParam) != WA_INACTIVE);
break;
case WM_ENDSESSION:
DOUTL(2, "CNote::WM_ENDSESSION");
if (wParam)
DestroyWindow(hwnd);
return 0;
case WM_QUERYENDSESSION:
DOUTL(2, "CNote::WM_QUERYENDSESSION");
// fall thro'
case WM_CLOSE:
if (!m_fForceClose && !FCanClose())
return 0;
// listen-up:
// we have to do this EnableWindowof the modal owner in the WM_CLOSE
// handler, as WM_DESTROY is too late - USER may have SetFocus to the next
// active toplevel z-order window (as the note has been hidden by then) - if the
// window is in another process SetFocus back to the owner will be ignored.
// Also, in the places we call DestroyWindow we need to make sure we go thro' this
// WM_CLOSE handler. So all calls to DestroyWindow instead call WM_OE_DESTROYNOTE
// which sets an internal flag to force down the note (so we don't prompt if dirty)
// and then calls WM_CLOSE, which falls thro' to DefWndProc and results in a DestroyWindow
// got it?
if (m_dwNoteCreateFlags & OENCF_MODAL)
{
// Need to enable the owner window
if (NULL != m_hwndOwner)
{
EnableWindow(m_hwndOwner, TRUE);
}
}
break;
case WM_MEASUREITEM:
if(m_pBodyObj2 &&
m_pBodyObj2->HrWMMeasureMenuItem(hwnd, (LPMEASUREITEMSTRUCT)lParam)==S_OK)
return 0;
break;
case WM_DRAWITEM:
if(m_pBodyObj2 &&
m_pBodyObj2->HrWMDrawMenuItem(hwnd, (LPDRAWITEMSTRUCT)lParam)==S_OK)
return 0;
break;
case WM_DROPFILES:
if (m_pHdr)
m_pHdr->DropFiles((HDROP)wParam, FALSE);
return 0;
case WM_COMMAND:
WMCommand( GET_WM_COMMAND_HWND(wParam, lParam),
GET_WM_COMMAND_ID(wParam, lParam),
GET_WM_COMMAND_CMD(wParam, lParam));
return 0;
case WM_INITMENUPOPUP:
return WMInitMenuPopup(hwnd, (HMENU)wParam, (UINT)LOWORD(lParam));
case WM_GETMINMAXINFO:
WMGetMinMaxInfo((LPMINMAXINFO)lParam);
break;
case WM_MENUSELECT:
if (LOWORD(wParam)>=ID_STATIONERY_RECENT_0 && LOWORD(wParam)<=ID_STATIONERY_RECENT_9)
{
m_pstatus->ShowSimpleText(MAKEINTRESOURCE(idsRSListGeneralHelp));
return 0;
}
if (LOWORD(wParam)>=ID_APPLY_STATIONERY_0 && LOWORD(wParam)<=ID_APPLY_STATIONERY_9)
{
m_pstatus->ShowSimpleText(MAKEINTRESOURCE(idsApplyStationeryGeneralHelp));
return 0;
}
if (LOWORD(wParam)>=ID_SIGNATURE_FIRST && LOWORD(wParam)<=ID_SIGNATURE_LAST)
{
m_pstatus->ShowSimpleText(MAKEINTRESOURCE(idsInsertSigGeneralHelp));
return 0;
}
if (LOWORD(wParam)>=ID_FORMAT_FIRST && LOWORD(wParam)<=ID_FORMAT_LAST)
{
m_pstatus->ShowSimpleText(MAKEINTRESOURCE(idsApplyFormatGeneralHelp));
return 0;
}
HandleMenuSelect(m_pstatus, wParam, lParam);
return 0;
case NWM_TESTGETDISP:
case NWM_TESTGETADDR:
return lTestHook(msg, wParam, lParam);
case NWM_UPDATETOOLBAR:
m_pToolbarObj->Update();
return 0;
case NWM_PASTETOATTACHMENT:
if (m_pHdr)
m_pHdr->DropFiles((HDROP)wParam, (BOOL)lParam);
return 0;
case WM_CONTEXTMENU:
break;
case WM_SIZE:
if(wParam==SIZE_RESTORED) // update global last-size
GetWindowRect(hwnd, &g_rcLastResize);
WMSize(LOWORD(lParam), HIWORD(lParam), FALSE);
break;
case WM_NOTIFY:
WMNotify((int) wParam, (NMHDR *)lParam);
break;
case WM_SETCURSOR:
if (!!m_fWindowDisabled)
{
HourGlass();
return TRUE;
}
break;
case WM_DISPLAYCHANGE:
{
WINDOWPLACEMENT wp;
wp.length = sizeof(wp);
GetWindowPlacement(hwnd, &wp);
SetWindowPlacement(hwnd, &wp);
}
// Drop through
case WM_WININICHANGE:
case WM_SYSCOLORCHANGE:
case WM_QUERYNEWPALETTE:
case WM_PALETTECHANGED:
{
HWND hwndT;
// pass down to trident
if (m_pBodyObj2 &&
m_pBodyObj2->HrGetWindow(&hwndT)==S_OK)
SendMessage(hwndT, msg, wParam, lParam);
if (m_pToolbarObj &&
m_pToolbarObj->GetWindow(&hwndT)==S_OK)
SendMessage(hwndT, msg, wParam, lParam);
}
break;
default:
if (g_msgMSWheel && (msg == g_msgMSWheel))
{
HWND hwndFocus = GetFocus();
if (hwndFocus != hwnd)
return SendMessage(hwndFocus, msg, wParam, lParam);
}
break;
}
lResult=DefWindowProcWrapW(hwnd, msg, wParam, lParam);
if (msg==WM_ACTIVATE)
{
// need to post-process this
// save the control with the focus don't do this is we're
// minimized, otherwise GetFocus()==m_hwnd
if (!HIWORD(wParam))
{
// if not minimized, save/restore child focus
if ((LOWORD(wParam) == WA_INACTIVE))
{
// if deactivating then save the focus
m_hwndFocus = GetFocus();
DOUTL(4, "Focus was on 0x%x", m_hwndFocus);
}
else
{
// if activating, and not minimized then restore focus
if (IsWindow(m_hwndFocus) &&
IsChild(hwnd, m_hwndFocus))
{
DOUTL(4, "Restoring Focus to: 0x%x", m_hwndFocus);
SetFocus(m_hwndFocus);
}
}
}
if (!(m_dwNoteCreateFlags & OENCF_MODAL))
SetTlsGlobalActiveNote((LOWORD(wParam)==WA_INACTIVE)?NULL:this);
DOUTL(8, "CNote::WMActivate:: %x", GetTlsGlobalActiveNote());
}
return lResult;
}
// *************************
BOOL CNote::FCanClose()
{
int id;
HRESULT hr = S_OK;
if(IsDirty()==S_FALSE)
return TRUE;
// TODO: set the title properly
id = AthMessageBoxW(m_hwnd, MAKEINTRESOURCEW(idsAthena), MAKEINTRESOURCEW(idsSaveChangesMsg), NULL, MB_YESNOCANCEL|MB_ICONWARNING);
if(id==IDCANCEL)
return FALSE;
// Note - It's the job of the subclass to display any UI that might
// describe why saving failed.
if (id == IDYES)
hr = SaveMessage(NOFLAGS);
if (FAILED(hr))
{
if (E_PENDING == hr)
m_fCBDestroyWindow = TRUE;
return FALSE;
}
return TRUE;
}
// *************************
HRESULT CNote::SaveMessage(DWORD dwSaveFlags)
{
HRESULT hr;
IMimeMessage *pMsg = NULL;
IImnAccount *pAcct = NULL;
hr = HrCreateMessage(&pMsg);
if (FAILED(hr))
goto exit;
hr = Save(pMsg, 0);
if (SUCCEEDED(hr))
{
hr = m_pHdr->HrGetAccountInHeader(&pAcct);
if (FAILED(hr))
goto exit;
dwSaveFlags |= OESF_UNSENT;
if (m_fOriginallyWasRead && (OENA_COMPOSE == m_dwNoteAction))
dwSaveFlags |= OESF_SAVE_IN_ORIG_FOLDER;
if(IsSecure(pMsg))
{
if(AthMessageBoxW(m_hwnd, MAKEINTRESOURCEW(idsAthenaMail),
MAKEINTRESOURCEW(idsSaveSecMsgToDraft), NULL, MB_OKCANCEL) == IDCANCEL)
{
hr = MAPI_E_USER_CANCEL;
goto exit;
}
else
{
PROPVARIANT rVariant;
IMimeBody *pBody = NULL;
rVariant.vt = VT_BOOL;
rVariant.boolVal = TRUE;
hr = pMsg->BindToObject(HBODY_ROOT, IID_IMimeBody, (void **)&pBody);
if(SUCCEEDED(hr))
{
pBody->SetOption(OID_NOSECURITY_ONSAVE, &rVariant);
ReleaseObj(pBody);
}
}
}
m_fHasBeenSaved = TRUE;
_SetPendingOp(SOT_PUT_MESSAGE);
hr = m_pMsgSite->Save(pMsg, dwSaveFlags, pAcct);
if (SUCCEEDED(hr))
_OnComplete(SOT_PUT_MESSAGE, S_OK);
else
if (hr == E_PENDING)
EnableNote(FALSE);
}
exit:
ReleaseObj(pAcct);
ReleaseObj(pMsg);
return hr;
}
// *************************
void CNote::WMNCDestroy()
{
if (m_dwNoteCreateFlags & OENCF_MODAL)
PostQuitMessage(0);
SetWndThisPtr(m_hwnd, NULL);
m_hwnd=NULL;
Release();
}
// *************************
void CNote::ChangeReadToComposeIfUnsent(IMimeMessage *pMsg)
{
DWORD dwStatusFlags = 0;
if (m_fReadNote && SUCCEEDED(m_pMsgSite->GetStatusFlags(&dwStatusFlags)) &&
(OEMSF_UNSENT & dwStatusFlags))
{
m_dwNoteAction = OENA_COMPOSE;
m_fReadNote = FALSE;
}
}
// *************************
void CNote::ReloadMessageFromSite(BOOL fOriginal)
{
IMimeMessage *pMsg = NULL;
BOOL fBool = FALSE,
fTempHtml;
DWORD dwBodyStyle = MESTYLE_NOHEADER,
dwMsgFlags;
HRESULT hr = S_OK,
tempHr;
if (OENA_FORWARDBYATTACH == m_dwNoteAction)
dwMsgFlags = (OEGM_ORIGINAL|OEGM_AS_ATTACH);
else
dwMsgFlags = (fOriginal ? OEGM_ORIGINAL : NOFLAGS);
hr = m_pMsgSite->GetMessage(&pMsg, &fBool, dwMsgFlags, &tempHr);
if (SUCCEEDED(hr))
{
// ~~~ Check what happens here if message is not downloaded and hit forward as attach
DWORD dwFlags = 0;
m_fCompleteMsg = !!fBool;
// All notes will be read note unless unsent
m_dwNoteAction = OENA_READ;
m_fOriginallyWasRead = TRUE;
m_fReadNote = TRUE;
// Is this an unsent message and is a read note? Then should be a compose.
ChangeReadToComposeIfUnsent(pMsg);
// This needs to be called for the case where we load an IMAP message. In this
// case we don't know if it is html or not. We won't know until after it is
// downloaded. That is what is happening at this point. Before we do our
// load, let's make sure that we have set m_fHtml properly. RAID 46327
if(CheckSecReceipt(pMsg) == S_OK)
fTempHtml = TRUE;
else
{
pMsg->GetFlags(&dwFlags);
fTempHtml = !!(dwFlags & IMF_HTML);
}
// If m_fHtml was already set correctly, then don't do it again.
if (fTempHtml != m_fHtml)
{
m_fFormatbarVisible = m_fHtml = fTempHtml;
if (!m_fReadNote && !m_fBodyContainsFrames && m_fFormatbarVisible)
dwBodyStyle = MESTYLE_FORMATBAR;
m_pBodyObj2->HrSetStyle(dwBodyStyle);
m_pBodyObj2->HrEnableHTMLMode(m_fHtml);
}
Load(pMsg);
InitMenusAndToolbars();
pMsg->Release();
if (FAILED(tempHr))
ShowErrorScreen(tempHr);
}
else
{
if (E_FAIL == hr)
m_fCBDestroyWindow = TRUE;
}
}
// *************************
HRESULT CNote::WMCommand(HWND hwndCmd, int id, WORD wCmd)
{
int iRet = 0;
DWORD dwFlags = 0;
FOLDERID folderID = FOLDERID_INVALID;
DOUTL(4, "CNote::WMCommand");
OLECMD cmd;
// 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 = id;
cmd.cmdf = 0;
if (FAILED(QueryStatus(&CMDSETID_OutlookExpress, 1, &cmd, NULL)) || (0 == (cmd.cmdf & OLECMDF_ENABLED)))
return (S_OK);
// see if any of these are for the body control, if so we're done...
if(m_pBodyObj2 && SUCCEEDED(m_pBodyObj2->HrWMCommand(hwndCmd, id, wCmd)))
return S_OK;
// give the header a shot after the note is done
if (m_pHdr &&
m_pHdr->WMCommand(hwndCmd, id, wCmd)==S_OK)
return S_OK;
// Don't handle anything that isn't a menu item or accelerator
if (wCmd <= 1)
{
if ((id == ID_SEND_NOW) || (id >= ID_SEND_NOW_ACCOUNT_FIRST && id <= ID_SEND_NOW_ACCOUNT_LAST) ||
(id == ID_SEND_LATER) || (id >= ID_SEND_LATER_ACCOUNT_FIRST && id <= ID_SEND_LATER_ACCOUNT_LAST))
{
HrSendMail(id);
return S_OK;
}
if (id >= ID_LANG_FIRST && id <= ID_LANG_LAST)
{
SwitchLanguage(id);
return S_OK;
}
if (id>=ID_ADD_RECIPIENT_FIRST && id<=ID_ADD_RECIPIENT_LAST)
{
if (m_pHdr)
m_pHdr->AddRecipient(id - ID_ADD_RECIPIENT_FIRST);
return S_OK;
}
if (id > ID_MSWEB_BASE && id < ID_MSWEB_LAST)
{
OnHelpGoto(m_hwnd, id);
return S_OK;
}
// Handle all "create new note" IDs
Assert(m_pMsgSite);
if (m_pMsgSite)
{
m_pMsgSite->GetFolderID(&folderID);
if (MenuUtil_HandleNewMessageIDs(id, m_hwnd, folderID, m_fMail, (m_dwNoteCreateFlags & OENCF_MODAL)?TRUE:FALSE, m_punkPump))
return S_OK;
}
// ONLY processing menu accelerators
switch(id)
{
case ID_SEND_DEFAULT:
HrSendMail(DwGetOption(OPT_SENDIMMEDIATE) && !g_pConMan->IsGlobalOffline() ? ID_SEND_NOW : ID_SEND_LATER);
return S_OK;
case ID_ABOUT:
DoAboutAthena(m_hwnd, idiMail);
return S_OK;
case ID_SAVE:
SaveMessage(NOFLAGS);
return S_OK;
case ID_NOTE_DELETE:
{
HRESULT hr;
m_fOrgCmdWasDelete = TRUE;
_SetPendingOp(SOT_DELETING_MESSAGES);
hr = m_pMsgSite->Delete(NOFLAGS);
if (SUCCEEDED(hr))
_OnComplete(SOT_DELETING_MESSAGES, S_OK);
else
{
if (hr == E_PENDING)
EnableNote(FALSE);
else
AthMessageBoxW(m_hwnd, MAKEINTRESOURCEW(idsAthenaMail), MAKEINTRESOURCEW(idsErrDeleteMsg), NULL, MB_OK);
}
return S_OK;
}
case ID_NOTE_COPY_TO_FOLDER:
case ID_NOTE_MOVE_TO_FOLDER:
{
HRESULT hr;
IMimeMessage *pMsg = NULL;
DWORD dwStatusFlags = 0;
m_fCBCopy = (ID_NOTE_COPY_TO_FOLDER == id);
m_pMsgSite->GetStatusFlags(&dwStatusFlags);
if (S_OK == IsDirty() || ((OEMSF_FROM_MSG | OEMSF_VIRGIN) & dwStatusFlags))
{
CommitChangesInNote();
pMsg = m_pMsg;
}
if(IsSecure(m_pMsg) && !m_fReadNote)
{
if(AthMessageBoxW(m_hwnd, MAKEINTRESOURCEW(idsAthenaMail),
MAKEINTRESOURCEW(idsSaveSecMsgToFolder), NULL, MB_OKCANCEL) == IDCANCEL)
return S_OK;
else
{
PROPVARIANT rVariant;
IMimeBody *pBody = NULL;
rVariant.vt = VT_BOOL;
rVariant.boolVal = TRUE;
hr = m_pMsg->BindToObject(HBODY_ROOT, IID_IMimeBody, (void **)&pBody);
if(SUCCEEDED(hr))
{
pBody->SetOption(OID_NOSECURITY_ONSAVE, &rVariant);
ReleaseObj(pBody);
}
}
}
_SetPendingOp(SOT_COPYMOVE_MESSAGE);
hr = m_pMsgSite->DoCopyMoveToFolder(m_fCBCopy, pMsg, !m_fReadNote);
if (SUCCEEDED(hr))
_OnComplete(SOT_COPYMOVE_MESSAGE, S_OK);
else if (E_PENDING == hr)
EnableNote(FALSE);
return S_OK;
}
case ID_NEXT_UNREAD_MESSAGE:
case ID_NEXT_UNREAD_THREAD:
case ID_NEXT_UNREAD_ARTICLE:
dwFlags = OENF_UNREAD;
if (ID_NEXT_UNREAD_THREAD == id)
dwFlags |= OENF_THREAD;
// Fall through
case ID_PREVIOUS:
case ID_NEXT_MESSAGE:
{
HRESULT hr;
dwFlags |= (m_fMail ? OENF_SKIPMAIL : OENF_SKIPNEWS);
hr = m_pMsgSite->DoNextPrev((ID_PREVIOUS != id), dwFlags);
if (SUCCEEDED(hr))
{
ReloadMessageFromSite();
AssertSz(!m_fCBDestroyWindow, "Shouldn't need to destroy the window...");
}
#ifdef DEBUG
// All DoNextPrev does is set the new message ID. Should never need to go
// E_PENDING to get that information
else if (E_PENDING == hr)
AssertSz(FALSE, "Didn't expect to get an E_PENDING with NextPrev.");
#endif
else
MessageBeep(MB_OK);
return S_OK;
}
case ID_MARK_THREAD_READ:
MarkMessage(MARK_MESSAGE_READ, APPLY_CHILDREN);
return S_OK;
case ID_NOTE_PROPERTIES:
DoProperties();
return S_OK;
case ID_REPLY:
case ID_REPLY_GROUP:
case ID_REPLY_ALL:
case ID_FORWARD:
case ID_FORWARD_AS_ATTACH:
{
DWORD dwAction = 0;
RECT rc;
HRESULT hr = S_OK;
GetWindowRect(m_hwnd, &rc);
switch (id)
{
case ID_REPLY: dwAction = OENA_REPLYTOAUTHOR; break;
case ID_REPLY_GROUP: dwAction = OENA_REPLYTONEWSGROUP; break;
case ID_REPLY_ALL: dwAction = OENA_REPLYALL; break;
case ID_FORWARD: dwAction = OENA_FORWARD; break;
case ID_FORWARD_AS_ATTACH: dwAction = OENA_FORWARDBYATTACH; break;
default: AssertSz(dwAction, "We are about to create a note with no action."); break;
};
AssertSz(m_pMsgSite, "We are about to create a note with a null m_pMsgSite.");
hr = CreateAndShowNote(dwAction, m_dwNoteCreateFlags, NULL, m_hwnd, m_punkPump, &rc, m_pMsgSite);
if (SUCCEEDED(hr))
{
// Since the new note has this site now, I don't need to keep track of it.
// More importantly, if I do, I break the new note since I will try to
// close the msgsite on my destroy notification. If I haven't released it,
// I would then null out items in
SafeRelease(m_pMsgSite);
PostMessage(m_hwnd, WM_OE_DESTROYNOTE, 0, 0);
}
else if (m_fReadNote && (MAPI_E_USER_CANCEL != hr))
AthMessageBoxW(m_hwnd, MAKEINTRESOURCEW(idsAthenaMail), MAKEINTRESOURCEW(idsErrReplyForward), NULL, MB_OK);
return S_OK;
}
case ID_HELP_CONTENTS:
OEHtmlHelp(GetParent(m_hwnd), c_szMailHelpFileHTML, HH_DISPLAY_TOPIC, (DWORD_PTR) (LPCSTR) c_szCtxHelpDefault);
return S_OK;
case ID_README:
DoReadme(m_hwnd);
break;
case ID_SEND_OBJECTS:
m_fPackageImages = !m_fPackageImages;
return S_OK;
case ID_NEW_CONTACT:
#if 0
Assert(g_pABInit);
if (g_pABInit)
g_pABInit->NewContact( m_hwnd );
#endif
nyi("New contact");
return S_OK;
case ID_NOTE_SAVE_AS:
SaveMessageAs();
return S_OK;
case ID_CHECK_NAMES:
HeaderExecCommand(MSOEENVCMDID_CHECKNAMES, MSOCMDEXECOPT_PROMPTUSER, NULL);
return S_OK;
case ID_SELECT_RECIPIENTS:
HeaderExecCommand(MSOEENVCMDID_SELECTRECIPIENTS, MSOCMDEXECOPT_DODEFAULT, NULL);
return S_OK;
case ID_SELECT_NEWSGROUPS:
HeaderExecCommand(MSOEENVCMDID_PICKNEWSGROUPS, MSOCMDEXECOPT_DODEFAULT, NULL);
return S_OK;
case ID_NEWSGROUPS:
HeaderExecCommand(MSOEENVCMDID_PICKNEWSGROUPS, MSOCMDEXECOPT_DODEFAULT, NULL);
return S_OK;
case ID_ADDRESS_BOOK:
HeaderExecCommand(MSOEENVCMDID_VIEWCONTACTS, MSOCMDEXECOPT_DODEFAULT, NULL);
return S_OK;
case ID_CREATE_RULE_FROM_MESSAGE:
{
MESSAGEINFO msginfo = {0};
return HrCreateRuleFromMessage(m_hwnd, (FALSE == m_fMail) ? CRFMF_NEWS : CRFMF_MAIL, &msginfo, m_pMsg);
}
break;
case ID_BLOCK_SENDER:
{
return _HrBlockSender((FALSE == m_fMail) ? RULE_TYPE_NEWS : RULE_TYPE_MAIL, m_pMsg, m_hwnd);
}
break;
case ID_FIND_MESSAGE:
DoFindMsg(FOLDERID_ROOT, FOLDER_ROOTNODE);
break;
case ID_FIND_PEOPLE:
{
TCHAR szWABExePath[MAX_PATH];
if(S_OK == HrLoadPathWABEXE(szWABExePath, sizeof(szWABExePath)))
ShellExecute(NULL, "open", szWABExePath, "/find", "", SW_SHOWNORMAL);
break;
}
case ID_OPTIONS:
ShowOptions(m_hwnd, ATHENA_OPTIONS, 0, NULL);
break;
case ID_ACCOUNTS:
{
DoAccountListDialog(m_hwnd, m_fMail?ACCT_MAIL:ACCT_NEWS);
break;
}
case ID_ADD_ALL_TO:
HeaderExecCommand(MSOEENVCMDID_ADDALLONTO, MSOCMDEXECOPT_DODEFAULT, NULL);
break;
case ID_ADD_SENDER:
if(m_fMail)
{
if (m_pHdr)
m_pHdr->AddRecipient(-1);
}
else
HeaderExecCommand(MSOEENVCMDID_ADDSENDER, MSOCMDEXECOPT_DODEFAULT, NULL);
return S_OK;
case ID_INSERT_CONTACT_INFO:
HeaderExecCommand(MSOEENVCMDID_VCARD, MSOCMDEXECOPT_DODEFAULT, NULL);
return S_OK;
case ID_FULL_HEADERS:
m_fFullHeaders = !m_fFullHeaders;
if(m_pHdr)
m_pHdr->ShowAdvancedHeaders(m_fFullHeaders);
if (m_fMail)
SetDwOption((m_fReadNote ? OPT_MAILNOTEADVREAD : OPT_MAILNOTEADVSEND), m_fFullHeaders, NULL, 0);
else
SetDwOption((m_fReadNote ? OPT_NEWSNOTEADVREAD : OPT_NEWSNOTEADVSEND), m_fFullHeaders, NULL, 0);
return S_OK;
case ID_CUT:
SendMessage(GetFocus(), WM_CUT, 0, 0);
return S_OK;
case ID_NOTE_COPY:
case ID_COPY:
SendMessage(GetFocus(), WM_COPY, 0, 0);
return S_OK;
case ID_PASTE:
SendMessage(GetFocus(), WM_PASTE, 0, 0);
return S_OK;
case ID_SHOW_TOOLBAR:
ToggleToolbar();
return S_OK;
case ID_CUSTOMIZE:
SendMessage(m_hwndToolbar, TB_CUSTOMIZE, 0, 0);
break;
case ID_FORMATTING_TOOLBAR:
ToggleFormatbar();
return S_OK;
case ID_STATUS_BAR:
ToggleStatusbar();
return S_OK;
case ID_UNDO:
Edit_Undo(GetFocus());
return S_OK;
case ID_SELECT_ALL:
Edit_SetSel(GetFocus(), 0, -1);
return S_OK;
case ID_CLOSE:
SendMessage(m_hwnd, WM_CLOSE, 0, 0);
return S_OK;
case ID_SPELLING:
if (FCheckSpellAvail() && (!m_fReadNote))
{
HWND hwndFocus = GetFocus();
HRESULT hr;
hr = m_pBodyObj2->HrSpellCheck(FALSE);
if(FAILED(hr))
AthMessageBoxW(m_hwnd, MAKEINTRESOURCEW(idsAthenaMail), MAKEINTRESOURCEW(idsErrSpellGenericSpell), NULL, MB_OK | MB_ICONSTOP);
SetFocus(hwndFocus);
}
return S_OK;
case ID_FORMAT_SETTINGS:
FormatSettings();
return S_OK;
case ID_WORK_OFFLINE:
if (g_pConMan)
g_pConMan->SetGlobalOffline(!g_pConMan->IsGlobalOffline(), hwndCmd);
if (m_pToolbarObj)
m_pToolbarObj->Update();
break;
case ID_RICH_TEXT:
case ID_PLAIN_TEXT:
// noops
if(id==ID_RICH_TEXT && m_fHtml)
return S_OK;
if(id==ID_PLAIN_TEXT && !m_fHtml)
return S_OK;
// if going to plain, warn the user he'll loose formatting...
if((ID_PLAIN_TEXT == id) &&
(IDCANCEL == DoDontShowMeAgainDlg(m_hwnd, c_szDSHtmlToPlain, MAKEINTRESOURCE(idsAthena),
MAKEINTRESOURCE(idsWarnHTMLToPlain), MB_OKCANCEL)))
return S_OK;
m_fHtml=!!(id==ID_RICH_TEXT);
m_fFormatbarVisible=!!m_fHtml;
m_pBodyObj2->HrSetStyle(m_fHtml ? MESTYLE_FORMATBAR : MESTYLE_NOHEADER);
m_pBodyObj2->HrEnableHTMLMode(m_fHtml);
// if going into plain-mode blow away formatting
if (!m_fHtml)
m_pBodyObj2->HrDowngradeToPlainText();
return S_OK;
case ID_DIGITALLY_SIGN:
HeaderExecCommand(MSOEENVCMDID_DIGSIGN, MSOCMDEXECOPT_DODEFAULT, NULL);
return S_OK;
case ID_ENCRYPT:
if(m_pHdr->ForceEncryption(NULL, FALSE) == S_FALSE)
HeaderExecCommand(MSOEENVCMDID_ENCRYPT, MSOCMDEXECOPT_DODEFAULT, NULL);
return S_OK;
case ID_INCLUDE_LABEL:
m_fSecurityLabel = !m_fSecurityLabel;
CheckAndForceEncryption();
return S_OK;
case ID_LABEL_SETTINGS:
if(m_pLabel)
{
if(DialogBoxParamWrapW(g_hLocRes, MAKEINTRESOURCEW(iddSelectLabel),
m_hwnd, SecurityLabelsDlgProc, (LPARAM) &m_pLabel) != IDOK)
return (S_FALSE);
CheckAndForceEncryption();
}
return S_OK;
case ID_SEC_RECEIPT_REQUEST:
m_fSecReceiptRequest = !m_fSecReceiptRequest;
break;
case ID_FLAG_MESSAGE:
m_dwCBMarkType = (!IsFlagged(ARF_FLAGGED)) ? MARK_MESSAGE_FLAGGED : MARK_MESSAGE_UNFLAGGED;
MarkMessage(m_dwCBMarkType, APPLY_SPECIFIED);
return S_OK;
case ID_WATCH_THREAD:
m_dwCBMarkType = (!IsFlagged(ARF_WATCH)) ? MARK_MESSAGE_WATCH : MARK_MESSAGE_NORMALTHREAD;
MarkMessage(m_dwCBMarkType, APPLY_SPECIFIED);
return S_OK;
case ID_IGNORE_THREAD:
m_dwCBMarkType = (!IsFlagged(ARF_IGNORE)) ? MARK_MESSAGE_IGNORE : MARK_MESSAGE_NORMALTHREAD;
MarkMessage(m_dwCBMarkType, APPLY_SPECIFIED);
return S_OK;
case ID_APPLY_STATIONERY_0:
case ID_APPLY_STATIONERY_1:
case ID_APPLY_STATIONERY_2:
case ID_APPLY_STATIONERY_3:
case ID_APPLY_STATIONERY_4:
case ID_APPLY_STATIONERY_5:
case ID_APPLY_STATIONERY_6:
case ID_APPLY_STATIONERY_7:
case ID_APPLY_STATIONERY_8:
case ID_APPLY_STATIONERY_9:
case ID_APPLY_STATIONERY_MORE:
case ID_APPLY_STATIONERY_NONE:
{
AssertSz(m_fHtml, "QueryStatus should have caught this and not let this function run.");
HRESULT hr;
WCHAR wszBuf[INTERNET_MAX_URL_LENGTH+1];
*wszBuf = 0;
switch (id)
{
case ID_APPLY_STATIONERY_MORE:
hr = HrGetMoreStationeryFileName(m_hwnd, wszBuf);
break;
case ID_APPLY_STATIONERY_NONE:
*wszBuf=0;
hr = NOERROR;
break;
default:
hr = HrGetStationeryFileName(id - ID_APPLY_STATIONERY_0, wszBuf);
if (FAILED(hr))
{
AthMessageBoxW(m_hwnd, MAKEINTRESOURCEW(idsAthena),
MAKEINTRESOURCEW(idsErrStationeryNotFound), NULL, MB_OK | MB_ICONERROR);
HrRemoveFromStationeryMRU(wszBuf);
}
break;
}
if(m_pBodyObj2 && SUCCEEDED(hr))
{
hr = m_pBodyObj2->HrApplyStationery(wszBuf);
if(SUCCEEDED(hr))
HrAddToStationeryMRU(wszBuf);
}
return S_OK;
case IDOK:
case IDCANCEL:
// ignore these
return S_OK;
case ID_REQUEST_READRCPT:
m_pMsgSite->Notify(OEMSN_TOGGLE_READRCPT_REQ);
return S_OK;
default:
if(id>=ID_ADDROBJ_OLE_FIRST && id <=ID_ADDROBJ_OLE_LAST)
{
DoNoteOleVerb(id-ID_ADDROBJ_OLE_FIRST);
return S_OK;
}
}
}
}
if(wCmd==NHD_SIZECHANGE &&
id==idcNoteHdr)
{
DOUTL(8, "CNote::NHD_SIZECHANGE - doing note WMSize");
//header control is requesting a resize
WMSize(NULL, NULL, TRUE);
return S_OK;
}
return S_FALSE;
}
// *************************
BOOL CNote::IsFlagged(DWORD dwFlag)
{
BOOL fFlagged = FALSE;
MESSAGEFLAGS dwCurrFlags = 0;
Assert(m_pMsgSite);
if (m_pMsgSite)
{
// Readnote and compose note are the only ones that can be flagged. The others might
// be flagged in the store, but since we are replying or forwarding, etc, they can't
// be flagged. RAID 37729
if ((m_fReadNote || (OENA_COMPOSE == m_dwNoteAction)) && SUCCEEDED(m_pMsgSite->GetMessageFlags(&dwCurrFlags)))
fFlagged = (0 != (dwFlag & dwCurrFlags));
}
return fFlagged;
}
// *************************
void CNote::DeferedLanguageMenu()
{
HMENU hMenu = m_hMenu;
Assert (hMenu);
if (!m_hmenuLanguage)
{ // load global MIME language codepage data
InitMultiLanguage();
}
else
{
// Charset chaching mechanism requires us to reconstruct
// language menu every time
DestroyMenu(m_hmenuLanguage);
}
m_hmenuLanguage = CreateMimeLanguageMenu(m_fMail, m_fReadNote, CustomGetCPFromCharset(m_hCharset, m_fReadNote));
}
// *************************
LRESULT CNote::WMInitMenuPopup(HWND hwnd, HMENU hmenuPopup, UINT uPos)
{
MENUITEMINFO mii;
HMENU hmenuMain;
HWND hwndFocus=GetFocus();
DWORD dwFlags=0;
BOOL fEnableStyleMenu = FALSE;
hmenuMain = m_hMenu;
mii.cbSize = sizeof(MENUITEMINFO);
mii.fMask = MIIM_ID | MIIM_SUBMENU;
if (hmenuMain == NULL ||!GetMenuItemInfo(hmenuMain, uPos, TRUE, &mii) || mii.hSubMenu != hmenuPopup)
{
if (GetMenuItemInfo(hmenuMain, ID_POPUP_LANGUAGE_DEFERRED, FALSE, &mii) && mii.hSubMenu == hmenuPopup)
{
mii.wID=ID_POPUP_LANGUAGE;
mii.fMask = MIIM_ID;
SetMenuItemInfo(hmenuMain, ID_POPUP_LANGUAGE_DEFERRED, FALSE, &mii);
}
mii.fMask = MIIM_ID | MIIM_SUBMENU;
if (GetMenuItemInfo(hmenuMain, ID_POPUP_LANGUAGE, FALSE, &mii) && mii.hSubMenu == hmenuPopup)
{
DeferedLanguageMenu();
mii.fMask = MIIM_SUBMENU;
mii.wID=ID_POPUP_LANGUAGE;
hmenuPopup = mii.hSubMenu = m_hmenuLanguage;
SetMenuItemInfo(hmenuMain, ID_POPUP_LANGUAGE, FALSE, &mii);
}
else return 1;
}
switch (mii.wID)
{
case ID_POPUP_FILE:
case ID_POPUP_EDIT:
case ID_POPUP_VIEW:
break;
case ID_POPUP_INSERT:
InitSigPopupMenu(hmenuPopup, NULL);
break;
case ID_POPUP_FORMAT:
{
AddStationeryMenu(hmenuPopup, ID_POPUP_STATIONERY, ID_APPLY_STATIONERY_0, ID_APPLY_STATIONERY_MORE);
fEnableStyleMenu = TRUE;
break;
}
case ID_POPUP_TOOLS:
if (m_fMail)
{
DeleteMenu(hmenuPopup, ID_SELECT_NEWSGROUPS, MF_BYCOMMAND);
#ifdef SMIME_V3
if (!FPresentPolicyRegInfo())
{
DeleteMenu(hmenuPopup, ID_INCLUDE_LABEL, MF_BYCOMMAND);
DeleteMenu(hmenuPopup, ID_LABEL_SETTINGS, MF_BYCOMMAND);
m_fSecurityLabel = FALSE;
}
if(!IsSMIME3Supported())
{
DeleteMenu(hmenuPopup, ID_SEC_RECEIPT_REQUEST, MF_BYCOMMAND);
m_fSecReceiptRequest = FALSE;
}
#endif
}
else
{
DeleteMenu(hmenuPopup, ID_REQUEST_READRCPT, MF_BYCOMMAND);
#ifdef SMIME_V3
DeleteMenu(hmenuPopup, ID_INCLUDE_LABEL, MF_BYCOMMAND);
DeleteMenu(hmenuPopup, ID_LABEL_SETTINGS, MF_BYCOMMAND);
DeleteMenu(hmenuPopup, ID_SEC_RECEIPT_REQUEST, MF_BYCOMMAND);
m_fSecurityLabel = FALSE;
m_fSecReceiptRequest = FALSE;
#endif
}
if (GetMenuItemInfo(hmenuPopup, ID_POPUP_ADDRESS_BOOK, FALSE, &mii))
m_pHdr->UpdateRecipientMenu(mii.hSubMenu);
break;
case ID_POPUP_MESSAGE:
{
AddStationeryMenu(hmenuPopup, ID_POPUP_NEW_MSG, ID_STATIONERY_RECENT_0, ID_STATIONERY_MORE);
break;
}
case ID_POPUP_LANGUAGE:
{
if (m_pBodyObj2)
m_pBodyObj2->HrOnInitMenuPopup(hmenuPopup, ID_POPUP_LANGUAGE);
break;
}
}
MenuUtil_EnablePopupMenu(hmenuPopup, this);
if (fEnableStyleMenu)
{
if (m_pBodyObj2)
m_pBodyObj2->UpdateBackAndStyleMenus(hmenuPopup);
}
return S_OK;
}
// *************************
void CNote::RemoveNewMailIcon(void)
{
HRESULT hr;
FOLDERINFO fiFolderInfo;
FOLDERID idFolder;
// If a message is marked (read or deleted) and it's from the Inbox,
// remove the new mail notification icon from the tray
if (NULL == g_pInstance || NULL == m_pMsgSite || NULL == g_pStore)
return;
hr = m_pMsgSite->GetFolderID(&idFolder);
if (FAILED(hr))
return;
hr = g_pStore->GetFolderInfo(idFolder, &fiFolderInfo);
if (SUCCEEDED(hr))
{
if (FOLDER_INBOX == fiFolderInfo.tySpecial)
g_pInstance->UpdateTrayIcon(TRAYICONACTION_REMOVE);
g_pStore->FreeRecord(&fiFolderInfo);
}
}
// *************************
LRESULT CNote::OnInitMenuPopup(HWND hwnd, HMENU hmenuPopup, UINT uPos, UINT wID)
{
return 0;
}
// *************************
void CNote::WMGetMinMaxInfo(LPMINMAXINFO pmmi)
{
MINMAXINFO mmi={0};
RECT rc;
int cy;
ULONG cyAttMan=0;
HWND hwnd;
cy=GetRequiredHdrHeight();
Assert(IsWindow(m_hwndToolbar));
if(IsWindowVisible(m_hwndToolbar))
{
GetWindowRect(m_hwndToolbar, &rc);
cy += cyRect(rc);
}
cy += GetSystemMetrics(SM_CYCAPTION);
cy += GetSystemMetrics(SM_CYMENU);
cy += 2*cyMinEdit;
pmmi->ptMinTrackSize.x=200; //hack
pmmi->ptMinTrackSize.y=cy;
}
// *************************
INT CNote::GetRequiredHdrHeight()
{
RECT rc={0};
if(m_pHdr)
m_pHdr->GetRect(&rc);
return cyRect(rc);
}
// *************************
LONG CNote::lTestHook(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return 0;
}
// *************************
void CNote::WMNotify(int idFrom, NMHDR *pnmh)
{
switch(pnmh->code)
{
case NM_SETFOCUS:
if (pnmh)
OnSetFocus(pnmh->hwndFrom);
break;
case NM_KILLFOCUS:
OnKillFocus();
break;
case BDN_DOWNLOADCOMPLETE:
OnDocumentReady();
break;
case BDN_MARKASSECURE:
MarkMessage(MARK_MESSAGE_NOSECUI, APPLY_SPECIFIED);
break;
case TBN_DROPDOWN:
OnDropDown(m_hwnd, pnmh);
break;
}
}
// *************************
void CNote::OnDocumentReady()
{
if (!m_fOnDocReadyHandled && m_fCompleteMsg)
{
HRESULT hr;
DWORD dwStatusFlags;
m_fOnDocReadyHandled = TRUE;
m_pMsgSite->GetStatusFlags(&dwStatusFlags);
// once, we've got a successfull download, we can init the attachment manager.
// we can't do this before, as we have to wait until Trident has requested MHTML parts so we
// can mark them as inlined. If we're in a reply or reply all then we have to remove the unused
// attachments at this time
if (IsReplyNote())
HrRemoveAttachments(m_pMsg, FALSE);
// #62618: hack. if forwarding a multi/altern in (force) plain-text mode then the html part
// shows up as an attachment
// we call GetTextBody here on the html body if we're a plaintext node in forward so that
// PID_ATT_RENDERED is set before we load teh attachment well
if (m_dwNoteAction == OENA_FORWARD && m_fHtml == FALSE)
{
HBODY hBody;
IStream *pstm;
if (m_pMsg &&
!FAILED(m_pMsg->GetTextBody(TXT_HTML, IET_DECODED, &pstm, NULL)))
pstm->Release();
}
if (m_pHdr)
{
if (FAILED(m_pHdr->OnDocumentReady(m_pMsg)))
AthMessageBoxW(m_hwnd, MAKEINTRESOURCEW(idsAthena), MAKEINTRESOURCEW(idsErrAttmanLoadFail), NULL, MB_OK|MB_ICONEXCLAMATION);
m_pHdr->SetVCard((OEMSF_FROM_MSG|OEMSF_VIRGIN) & dwStatusFlags);
}
ClearDirtyFlag();
// RAID-25300 - FE-J:Athena: Newsgroup article and mail sent with charset=_autodetect
// Internet Encoded and Windows Encoding are CPI_AUTODETECT
{
INETCSETINFO CsetInfo ;
HCHARSET hCharset = NULL ;
int nIdm = 0 ;
// if it is a new message, check if charset equals to default charset
if ((OENA_COMPOSE == m_dwNoteAction) && (OEMSF_VIRGIN & dwStatusFlags))
{
// defer default charset reading until now ..
if (g_hDefaultCharsetForMail==NULL)
ReadSendMailDefaultCharset();
if (m_hCharset != g_hDefaultCharsetForMail )
hCharset = g_hDefaultCharsetForMail ;
// get CharsetInfo from HCHARSET
if ( hCharset)
MimeOleGetCharsetInfo(hCharset,&CsetInfo);
else
MimeOleGetCharsetInfo(m_hCharset,&CsetInfo);
}
else
// get CharsetInfo from HCHARSET
MimeOleGetCharsetInfo(m_hCharset,&CsetInfo);
// re-map CP_JAUTODETECT and CP_KAUTODETECT if necessary
// re-map iso-2022-jp to default charset if they are in the same category
if (!m_fReadNote)
{
hCharset = GetMimeCharsetFromCodePage(GetMapCP(CsetInfo.cpiInternet, FALSE));
}
else
{
VARIANTARG va;
va.vt = VT_BOOL;
va.boolVal = VARIANT_TRUE;
m_pCmdTargetBody->Exec(&CMDSETID_MimeEdit, MECMDID_TABLINKS, 0, &va, NULL);
}
// has a new charset defined, change it
ChangeCharset(hCharset);
// if user want's auto complete, enable it once we're fully loaded
if (DwGetOption(OPT_USEAUTOCOMPLETE))
HeaderExecCommand(MSOEENVCMDID_AUTOCOMPLETE, MSOCMDEXECOPT_DODEFAULT, NULL);
if (m_fReadNote && m_fMail && m_pMsgSite)
{
if(m_pMsgSite->Notify(OEMSN_PROCESS_READRCPT_REQ) != S_OK)
return;
}
}
if(DwGetOption(OPT_RTL_MSG_DIR) && ((m_dwNoteAction == OENA_FORWARDBYATTACH) || (OEMSF_VIRGIN & dwStatusFlags)))
{
if(FAILED(m_pCmdTargetBody->Exec(&CMDSETID_Forms3, IDM_DIRRTL, OLECMDEXECOPT_DODEFAULT, NULL, NULL)))
AthMessageBoxW(g_hwndInit, MAKEINTRESOURCEW(idsAthena), MAKEINTRESOURCEW(idsErrRTLDirFailed), NULL, MB_OK);
}
EnterCriticalSection(&m_csNoteState);
if(m_nisNoteState == NIS_INIT)
m_nisNoteState = NIS_NORMAL;
LeaveCriticalSection(&m_csNoteState);
}
}
HRESULT CNote::ChangeCharset(HCHARSET hCharset)
{
HRESULT hr = S_OK;
if (hCharset && (hCharset != m_hCharset))
{
Assert(m_pBodyObj2);
IF_FAILEXIT(hr = m_pBodyObj2->HrSetCharset(hCharset));
// set the new charset into the message and call HrLanguageChange to update the headers
m_hCharset = hCharset;
if (m_pMsg)
m_pMsg->SetCharset(hCharset, CSET_APPLY_ALL);
if (m_pHdr)
m_pHdr->ChangeLanguage(m_pMsg);
UpdateTitle();
}
exit:
return hr;
}
HRESULT CNote::GetCharset(HCHARSET *phCharset)
{
Assert(phCharset);
*phCharset = m_hCharset;
return S_OK;
}
// *************************
LRESULT CNote::OnDropDown(HWND hwnd, LPNMHDR lpnmh)
{
UINT i;
HMENU hMenuPopup;
RECT rc;
DWORD dwCmd;
TBNOTIFY *ptbn = (TBNOTIFY *)lpnmh;
if (ptbn->iItem == ID_SET_PRIORITY)
{
hMenuPopup = LoadPopupMenu(IDR_PRIORITY_POPUP);
if (hMenuPopup != NULL)
{
for (i = 0; i < 3; i++)
CheckMenuItem(hMenuPopup, i, MF_UNCHECKED | MF_BYPOSITION);
m_pHdr->GetPriority(&i);
Assert(i != priNone);
CheckMenuItem(hMenuPopup, 2 - i, MF_CHECKED | MF_BYPOSITION);
DoToolbarDropdown(hwnd, lpnmh, hMenuPopup);
DestroyMenu(hMenuPopup);
}
}
else if (ptbn->iItem == ID_INSERT_SIGNATURE)
{
hMenuPopup = CreatePopupMenu();
if (hMenuPopup != NULL)
{
FillSignatureMenu(hMenuPopup, NULL);
DoToolbarDropdown(hwnd, lpnmh, hMenuPopup);
DestroyMenu(hMenuPopup);
}
}
else if(ptbn->iItem == ID_POPUP_LANGUAGE)
{
DeferedLanguageMenu();
hMenuPopup = m_hmenuLanguage;
if(hMenuPopup)
{
MenuUtil_EnablePopupMenu(hMenuPopup, this);
DoToolbarDropdown(hwnd, lpnmh, hMenuPopup);
}
}
return(TBDDRET_DEFAULT);
}
// *************************
void CNote::UpdateMsgOptions(LPMIMEMESSAGE pMsg)
{
// Store the options onto the message object
SideAssert(SUCCEEDED(HrSetMailOptionsOnMessage(pMsg, &m_rHtmlOpt, &m_rPlainOpt, m_hCharset, m_fHtml)));
}
// *************************
HRESULT CNote::SetComposeStationery()
{
LPSTREAM pstm;
WCHAR wszFile[MAX_PATH];
HRESULT hr=E_FAIL;
HCHARSET hCharset;
ENCODINGTYPE ietEncoding = IET_DECODED;
BOOL fLittleEndian;
AssertSz(m_fHtml, "Are you sure you want to set stationery in plain-text mode??");
if (!(m_dwNoteCreateFlags & OENCF_NOSTATIONERY) && m_pMsg &&
DwGetOption(m_fMail?OPT_MAIL_USESTATIONERY:OPT_NEWS_USESTATIONERY) &&
SUCCEEDED(GetDefaultStationeryName(m_fMail, wszFile)))
{
if (SUCCEEDED(hr = HrCreateBasedWebPage(wszFile, &pstm)))
{
if (S_OK == HrIsStreamUnicode(pstm, &fLittleEndian))
{
if (SUCCEEDED(MimeOleFindCharset("utf-8", &hCharset)))
{
m_pMsg->SetCharset(hCharset, CSET_APPLY_ALL);
}
ietEncoding = IET_UNICODE;
}
hr = m_pMsg->SetTextBody(TXT_HTML, ietEncoding, NULL, pstm, NULL);
pstm->Release();
m_fUseStationeryFonts = TRUE;
}
}
return hr;
}
// *************************
HRESULT CNote::CycleThroughControls(BOOL fForward)
{
HRESULT hr = CheckTabStopArrays();
if (SUCCEEDED(hr))
{
int index, newIndex;
BOOL fFound = FALSE;
HWND hCurr = GetFocus();
for (index = 0; index < m_cTabStopCount; index++)
if (hCurr == m_pTabStopArray[index])
{
fFound = TRUE;
break;
}
newIndex = fFound ? GetNextIndex(index, fForward) : m_iIndexOfBody;
if (newIndex == m_iIndexOfBody)
m_pBodyObj2->HrUIActivate(TRUE);
else
SetFocus(m_pTabStopArray[newIndex]);
}
return hr;
}
// *************************
HRESULT CNote::CheckTabStopArrays()
{
HRESULT hr = S_OK;
if (m_fTabStopsSet)
return S_OK;
m_fTabStopsSet = TRUE;
HWND *pArray = m_pTabStopArray;
int cCount = MAX_HEADER_COMP;
hr = m_pHdr->GetTabStopArray(pArray, &cCount);
if (FAILED(hr))
goto error;
pArray += cCount;
m_cTabStopCount = cCount;
cCount = MAX_BODY_COMP;
hr = m_pBodyObj2->GetTabStopArray(pArray, &cCount);
if (FAILED(hr))
goto error;
// This assumes that the first in the list returned from m_pBodyObj2-GetTabStopArray
// is the Trident window handle. If that changes where it returns more than one
// handle, or something else, this simple index scheme won't work
m_iIndexOfBody = m_cTabStopCount;
pArray += cCount;
m_cTabStopCount += cCount;
cCount = MAX_ATTMAN_COMP;
m_cTabStopCount += cCount;
return S_OK;
error:
m_cTabStopCount = 0;
m_fTabStopsSet = FALSE;
return hr;
}
// *************************
int CNote::GetNextIndex(int index, BOOL fForward)
{
LONG style;
int cTotalTested = 0;
BOOL fGoodHandleFound;
do
{
if (fForward)
{
index++;
if (index >= m_cTabStopCount)
index = 0;
}
else
{
// If this is true, other asserts should have fired before now.
Assert(m_cTabStopCount > 0);
index--;
if (index < 0)
index = m_cTabStopCount - 1;
}
style = GetWindowLong(m_pTabStopArray[index], GWL_STYLE);
cTotalTested++;
fGoodHandleFound = ((0 == (style & WS_DISABLED)) &&
(style & WS_VISIBLE) &&
((style & WS_TABSTOP) || (index == m_iIndexOfBody))); // Trident doesn't mark itself as a tabstop
} while (!fGoodHandleFound && (cTotalTested < m_cTabStopCount));
if (cTotalTested >= m_cTabStopCount)
index = m_iIndexOfBody;
return index;
}
// *************************
HRESULT CreateAndShowNote(DWORD dwAction, DWORD dwCreateFlags, INIT_MSGSITE_STRUCT *pInitStruct,
HWND hwnd, IUnknown *punk, RECT *prc, IOEMsgSite *pMsgSite)
{
HRESULT hr = S_OK;
CNote *pNote = NULL;
AssertSz((pMsgSite || pInitStruct), "Should have either a pInitStruct or a pMsgSite...");
// If we are coming from news, we might need to pass off this call to the smapi
// client. If we reply or forward a message that was news, pass it off to smapi
if ((OENCF_NEWSFIRST & dwCreateFlags) && ((OENA_REPLYTOAUTHOR == dwAction) || (OENA_FORWARD == dwAction) || (OENA_FORWARDBYATTACH == dwAction)))
{
// fIsDefaultMailConfiged hits the reg, only check for last result
if (!FIsDefaultMailConfiged())
{
IOEMsgSite *pSite = NULL;
CStoreCB *pCB = NULL;
//send using smapi
if (pInitStruct)
{
pCB = new CStoreCB;
if (!pCB)
hr = E_OUTOFMEMORY;
if (SUCCEEDED(hr))
hr = pCB->Initialize(hwnd, MAKEINTRESOURCE(idsSendingToOutbox), TRUE);
if (SUCCEEDED(hr))
pSite = new COEMsgSite();
if (!pSite)
hr = E_OUTOFMEMORY;
if (SUCCEEDED(hr))
hr = pSite->Init(pInitStruct);
if (SUCCEEDED(hr))
pSite->SetStoreCallback(pCB);
}
else
ReplaceInterface(pSite, pMsgSite);
if (pSite)
{
if (SUCCEEDED(hr))
{
IMimeMessage *pMsg = NULL;
BOOL fCompleteMsg;
HRESULT hres = E_FAIL;
DWORD dwMsgFlags = (OENA_FORWARDBYATTACH == dwAction) ? (OEGM_ORIGINAL|OEGM_AS_ATTACH) : NOFLAGS;
hr = pSite->GetMessage(&pMsg, &fCompleteMsg, dwMsgFlags, &hres);
if (E_PENDING == hr)
{
AssertSz((pCB && pMsgSite), "Should never get E_PENDING with pMsgSite being NULL");
pCB->Block();
pCB->Close();
hr = pSite->GetMessage(&pMsg, &fCompleteMsg, dwMsgFlags, &hres);
}
if (pCB)
pCB->Close();
if (SUCCEEDED(hr))
{
if (SUCCEEDED(hres))
hr = NewsUtil_ReFwdByMapi(hwnd, pMsg, dwAction);
pMsg->Release();
}
}
// Don't want to close the site if it came from another note...
if (!pMsgSite)
pSite->Close();
pSite->Release();
}
ReleaseObj(pCB);
// if we succeeded, then we need to tell the creator that we
// cancelled the creation through OE and went with the smapi client
return (FAILED(hr) ? hr : MAPI_E_USER_CANCEL);
}
}
//We are the default smapi client
pNote = new CNote;
if (pNote)
hr = pNote->Init(dwAction, dwCreateFlags, prc, hwnd, pInitStruct, pMsgSite, punk);
else
hr = E_OUTOFMEMORY;
if (SUCCEEDED(hr))
hr = pNote->Show();
ReleaseObj(pNote);
if (FAILED(hr))
AthErrorMessageW(hwnd, MAKEINTRESOURCEW(idsAthena), MAKEINTRESOURCEW(idsErrNewsCantOpen), hr);
return hr;
}
// *************************
HRESULT CNote::SaveMessageAs()
{
HRESULT hr=S_OK;
IMimeMessage *pSecMsg=NULL;
BOOL fCanbeDurt = !m_fReadNote;
PROPVARIANT rVariant;
IMimeBody *pBody = NULL;
// Raid #25822: we can't just get the message source if it
// is a secure message
if (m_fReadNote/* && IsSecure(m_pMsg)*/)
{
// Won't care about these since the user already loaded the message
BOOL fCompleteMsg = FALSE;
HRESULT tempHr = S_OK;
m_pMsgSite->GetMessage(&pSecMsg, &fCompleteMsg, OEGM_ORIGINAL, &tempHr);
AssertSz(fCompleteMsg && SUCCEEDED(tempHr), "Shouldn't have reached this point if the load failed now.");
}
else
{
hr = CommitChangesInNote();
if (FAILED(hr))
goto error;
// if a compose note, set the X-Unsent header if saving to .eml files, and save the props.
MimeOleSetBodyPropA(m_pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_XUNSENT), NOFLAGS, "1");
if(IsSecure(m_pMsg))
{
if(AthMessageBoxW(m_hwnd, MAKEINTRESOURCEW(idsAthenaMail),
MAKEINTRESOURCEW(idsSaveSecMsgToFolder), NULL, MB_OKCANCEL) == IDCANCEL)
goto error;
else
{
rVariant.vt = VT_BOOL;
rVariant.boolVal = TRUE;
hr = m_pMsg->BindToObject(HBODY_ROOT, IID_IMimeBody, (void **)&pBody);
if(SUCCEEDED(hr))
{
pBody->SetOption(OID_NOSECURITY_ONSAVE, &rVariant);
ReleaseObj(pBody);
}
fCanbeDurt = FALSE;
}
}
}
// SaveMessageToFile displays a failure error.
_SetPendingOp(SOT_PUT_MESSAGE);
hr = HrSaveMessageToFile(m_hwnd, (pSecMsg ? pSecMsg : m_pMsg), m_pMsg, !m_fMail, fCanbeDurt);
if (SUCCEEDED(hr))
_OnComplete(SOT_PUT_MESSAGE, S_OK);
else if (E_PENDING == hr)
{
EnableNote(FALSE);
hr = S_OK;
}
error:
ReleaseObj(pSecMsg);
return hr;
}
// *************************
HRESULT CNote::CommitChangesInNote()
{
LPMIMEMESSAGE pMsg=0;
HRESULT hr=S_OK;
Assert(m_pMsg);
if (!m_fReadNote && !m_fBodyContainsFrames)
{
if (FAILED(HrCreateMessage(&pMsg)))
return E_FAIL;
hr = Save(pMsg, 0);
if (SUCCEEDED(hr))
ReplaceInterface(m_pMsg, pMsg)
pMsg->Release();
}
return hr;
}
// *************************
void CNote::ToggleFormatbar()
{
m_fFormatbarVisible = !m_fFormatbarVisible;
SetDwOption(OPT_SHOW_NOTE_FMTBAR, m_fFormatbarVisible, NULL, 0);
m_pBodyObj2->HrSetStyle(m_fFormatbarVisible ? MESTYLE_FORMATBAR : MESTYLE_NOHEADER);
}
// *************************
void CNote::ToggleStatusbar()
{
RECT rc;
m_fStatusbarVisible = !m_fStatusbarVisible;
SetDwOption(OPT_SHOW_NOTE_STATUSBAR, m_fStatusbarVisible, NULL, 0);
m_pstatus->ShowStatus(m_fStatusbarVisible);
// cause a size
GetWindowRect(m_hwnd, &rc);
WMSize(rc.right-rc.left, rc.bottom-rc.top, FALSE);
}
// *************************
HRESULT CNote::ToggleToolbar()
{
RECT rc;
m_fToolbarVisible = !m_fToolbarVisible;
if (m_pToolbarObj)
m_pToolbarObj->HideToolbar(!m_fToolbarVisible);
GetWindowRect(m_hwnd, &rc);
// cause a size
WMSize(rc.right-rc.left, rc.bottom-rc.top, FALSE);
return S_OK;
}
// *************************
void CNote::FormatSettings()
{
AssertSz(m_fReadNote, "this is broken for readnote!!!");
if (m_fHtml)
FGetHTMLOptions(m_hwnd, &m_rHtmlOpt);
else
FGetPlainOptions(m_hwnd, &m_rPlainOpt);
}
// *************************
void CNote::SwitchLanguage(int idm)
{
HCHARSET hCharset, hOldCharset;
HRESULT hr;
hCharset = GetMimeCharsetFromMenuID(idm);
if (!hCharset || (hCharset == m_hCharset))
return;
hOldCharset = m_hCharset;
// View|Language in a view does not affect the listview as in v1. It only affect the preview.
// the user can change his default charset to get changes in the listview
// setcharset on the body object will cause it to refresh with new fonts etc.
hr = ChangeCharset(hCharset);
if (FAILED(hr))
{
AthMessageBoxW( m_hwnd, MAKEINTRESOURCEW(idsAthena),
MAKEINTRESOURCEW((hr == hrIncomplete)?idsViewLangMimeDBBad:idsErrViewLanguage),
NULL, MB_OK|MB_ICONEXCLAMATION);
goto Exit;
}
// here after we ask user if he wants to add this change to charset remapping list
m_pMsgSite->SwitchLanguage(hOldCharset, hCharset);
Exit:
return;
}
// *************************
BOOL CNote::DoProperties()
{
NOMSGDATA noMsgData;
MSGPROP msgProp;
UINT pri;
TCHAR szSubj[256];
TCHAR szLocation[1024];
LPSTR pszLocation = NULL;
WCHAR wszLocation[1024];
BOOL fSucceeded;
msgProp.pNoMsgData = &noMsgData;
msgProp.hwndParent = m_hwnd;
msgProp.type = (m_fMail ? MSGPROPTYPE_MAIL : MSGPROPTYPE_NEWS);
msgProp.mpStartPage = MP_GENERAL;
msgProp.szFolderName = 0; // This one needs to have special handling
msgProp.pSecureMsg = NULL;
msgProp.lpWabal = NULL;
msgProp.szFolderName = szLocation;
*szLocation = 0;
m_pMsgSite->GetLocation(wszLocation, ARRAYSIZE(wszLocation));
pszLocation = PszToANSI(CP_ACP, wszLocation);
StrCpyN(szLocation, pszLocation, ARRAYSIZE(szLocation));
MemFree(pszLocation);
if (m_fReadNote)
{
msgProp.dwFlags = ARF_RECEIVED;
msgProp.pMsg = m_pMsg;
msgProp.fSecure = IsSecure(msgProp.pMsg);
if (msgProp.fSecure)
{
BOOL fCompleteMsg = FALSE;
HRESULT tempHr = S_OK;
m_pMsgSite->GetMessage(&msgProp.pSecureMsg, &fCompleteMsg, OEGM_ORIGINAL, &tempHr);
AssertSz(fCompleteMsg && SUCCEEDED(tempHr), "Shouldn't have reached this point if the load failed now.");
HrGetWabalFromMsg(msgProp.pMsg, &msgProp.lpWabal);
}
}
else
{
msgProp.dwFlags = ARF_UNSENT;
msgProp.pMsg = NULL;
}
m_pHdr->GetPriority(&pri);
if (pri==priLow)
noMsgData.Pri=IMSG_PRI_LOW;
else if (pri==priHigh)
noMsgData.Pri=IMSG_PRI_HIGH;
else
noMsgData.Pri=IMSG_PRI_NORMAL;
noMsgData.pszFrom = NULL;
noMsgData.pszSent = NULL;
noMsgData.ulSize = 0;
noMsgData.cAttachments = 0;
m_pHdr->HrGetAttachCount(&noMsgData.cAttachments);
GetWindowText(m_hwnd, szSubj, sizeof(szSubj)/sizeof(TCHAR));
noMsgData.pszSubject = szSubj;
msgProp.fFromListView = FALSE;
fSucceeded = (S_OK == HrMsgProperties(&msgProp));
ReleaseObj(msgProp.lpWabal);
ReleaseObj(msgProp.pSecureMsg);
return fSucceeded;
}
// *************************
HRESULT CNote::HrSendMail(int id)
{
IImnAccount *pAccount=NULL;
ULONG i;
BOOL fFound=FALSE;
HRESULT hr;
BOOL fSendLater = (id == ID_SEND_LATER);
VARIANTARG varIn;
DWORD dwMsgSiteFlags=0;
// Do spell check if needed
if (FCheckSpellAvail() && FCheckOnSend())
{
HWND hwndFocus=GetFocus();
hr=m_pBodyObj2->HrSpellCheck(TRUE);
if (FAILED(hr) || hr==HR_S_SPELLCANCEL)
{
if (AthMessageBoxW(m_hwnd, MAKEINTRESOURCEW(idsAthenaMail), MAKEINTRESOURCEW(idsSpellMsgSendOK), NULL, MB_YESNO | MB_ICONEXCLAMATION ) != IDYES)
{
SetFocus(hwndFocus);
return E_FAIL;
}
}
}
if (!m_fMail && m_pBodyObj2)
{
BOOL fEmpty = FALSE;
if (SUCCEEDED(m_pBodyObj2->HrIsEmpty(&fEmpty)) && fEmpty)
{
if (AthMessageBoxW(m_hwnd, MAKEINTRESOURCEW(idsAthenaMail), MAKEINTRESOURCEW(idsNoTextInNewsPost), NULL, MB_YESNO | MB_ICONEXCLAMATION ) != IDYES)
return MAPI_E_USER_CANCEL;
}
}
// During the send, a call to the note save gets made. During
// that call, IMimeMessage::Commit gets called. That is a big perf hit.
// It turns out that commit will get called a second time anyway. So
// set a flag to tell the save not to commit.
m_fCommitSave = FALSE;
hr = HeaderExecCommand(MSOEENVCMDID_SEND, fSendLater?MSOCMDEXECOPT_DODEFAULT:MSOCMDEXECOPT_DONTPROMPTUSER, NULL);
m_fCommitSave = TRUE;
// REVIEW: dhaws: I don't think this happens anymore. I think the send call no longer returns the conflict
//RAID 8780: This message MIME_S_CHARSET_CONFLICT will get propagated to here. Now change it to an E_FAIL;
if (MIME_S_CHARSET_CONFLICT == hr)
hr = E_FAIL;
if (FAILED(hr))
goto error;
if (m_pMsgSite)
m_pMsgSite->GetStatusFlags(&dwMsgSiteFlags);
// If has been saved, then this note is store based in drafts and
// need to delete the draft.
if (((OENA_COMPOSE == m_dwNoteAction) || m_fHasBeenSaved) && !(dwMsgSiteFlags & OEMSF_FROM_FAT))
{
HRESULT hr;
_SetPendingOp(SOT_DELETING_MESSAGES);
hr = m_pMsgSite->Delete(DELETE_MESSAGE_NOTRASHCAN | DELETE_MESSAGE_NOPROMPT);
if (SUCCEEDED(hr))
{
m_fCBDestroyWindow = TRUE;
_OnComplete(SOT_DELETING_MESSAGES, S_OK);
}
else if (E_PENDING == hr)
{
EnableNote(FALSE);
m_fCBDestroyWindow = TRUE;
}
else
{
// ~~~ Can we handle this a bit better???
AthMessageBoxW(m_hwnd, MAKEINTRESOURCEW(idsAthenaMail), MAKEINTRESOURCEW(idsErrDeleteMsg), NULL, MB_OK);
}
}
// If note is reply or forward, then mark the message as appropriate
else if (IsReplyNote() || (OENA_FORWARD == m_dwNoteAction) || (OENA_FORWARDBYATTACH == m_dwNoteAction))
{
HRESULT hr;
BOOL fForwarded = (OENA_FORWARD == m_dwNoteAction) || (OENA_FORWARDBYATTACH == m_dwNoteAction);
// Clear any previous flags so we don't show both, only the most recent
m_dwMarkOnReplyForwardState = MORFS_CLEARING;
hr = MarkMessage(fForwarded ? MARK_MESSAGE_UNREPLIED : MARK_MESSAGE_UNFORWARDED, APPLY_SPECIFIED);
if (FAILED(hr) && (E_PENDING != hr))
{
// Even though we have an error, we can still close the note because the send did work.
PostMessage(m_hwnd, WM_OE_DESTROYNOTE, 0, 0);
m_dwMarkOnReplyForwardState = MORFS_UNKNOWN;
}
}
// Web Page and stationery
else
PostMessage(m_hwnd, WM_OE_DESTROYNOTE, 0, 0);
error:
ReleaseObj(pAccount);
return hr;
}
// *************************
HRESULT CNote::QueryService(REFGUID guidService, REFIID riid, LPVOID *ppvObject)
{
if (IsEqualGUID(guidService, IID_IOEMsgSite) &&
IsEqualGUID(riid, IID_IOEMsgSite))
{
if (!m_pMsgSite)
return E_FAIL;
*ppvObject = (LPVOID)m_pMsgSite;
m_pMsgSite->AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
// *************************
HRESULT CNote::MarkMessage(MARK_TYPE dwFlags, APPLYCHILDRENTYPE dwApplyType)
{
HRESULT hr;
// [PaulHi] 6/8/99 We need to restore the pending operation
// if the MarkMessage() call fails.
STOREOPERATIONTYPE tyPrevOperation = m_OrigOperationType;
_SetPendingOp(SOT_SET_MESSAGEFLAGS);
hr = m_pMsgSite->MarkMessage(dwFlags, dwApplyType);
if (SUCCEEDED(hr))
_OnComplete(SOT_SET_MESSAGEFLAGS, S_OK);
else if (E_PENDING == hr)
{
EnableNote(FALSE);
EnterCriticalSection(&m_csNoteState);
if(m_nisNoteState == NIS_INIT)
m_nisNoteState = NIS_FIXFOCUS;
LeaveCriticalSection(&m_csNoteState);
hr = S_OK;
}
else
{
// Restore previous operation to ensure the note window will be
// re-enabled.
_SetPendingOp(tyPrevOperation);
}
return hr;
}
HRESULT CNote::_SetPendingOp(STOREOPERATIONTYPE tyOperation)
{
m_OrigOperationType = tyOperation;
return S_OK;
}
void CNote::EnableNote(BOOL fEnable)
{
Assert (IsWindow(m_hwnd));
m_fInternal = 1;
if (fEnable)
{
if (m_fWindowDisabled)
{
EnableWindow(m_hwnd, TRUE);
if (m_hCursor)
{
SetCursor(m_hCursor);
m_hCursor = 0;
}
m_fWindowDisabled = FALSE;
}
}
else
{
if (!m_fWindowDisabled)
{
m_fWindowDisabled = TRUE;
EnableWindow(m_hwnd, FALSE);
m_hCursor = HourGlass();
}
}
m_fInternal = 0;
}
// *************************
void CNote::SetStatusText(LPSTR szBuf)
{
if(m_pstatus)
m_pstatus->SetStatusText(szBuf);
}
// *************************
void CNote::SetProgressPct(INT iPct)
{
// if (m_pstatus)
// m_pstatus->SetProgressBarPos(1, iPct, FALSE);
}
// *************************
HRESULT CNote::GetBorderDW(IUnknown* punkSrc, LPRECT lprectBorder)
{
GetClientRect(m_hwnd, lprectBorder);
DOUTL(4, "CNote::GetBorderDW called returning=%x,%x,%x,%x",
lprectBorder->left, lprectBorder->top, lprectBorder->right, lprectBorder->bottom);
return S_OK;
}
// *************************
HRESULT CNote::RequestBorderSpaceDW(IUnknown* punkSrc, LPCBORDERWIDTHS pborderwidths)
{
DOUTL(4, "CNote::ReqestBorderSpaceST pborderwidths=%x,%x,%x,%x",
pborderwidths->left, pborderwidths->top, pborderwidths->right, pborderwidths->bottom);
return S_OK;
}
// *************************
HRESULT CNote::SetBorderSpaceDW(IUnknown* punkSrc, LPCBORDERWIDTHS pborderwidths)
{
DOUTL(4, "CNote::SetBorderSpaceDW pborderwidths=%x,%x,%x,%x",
pborderwidths->left, pborderwidths->top, pborderwidths->right, pborderwidths->bottom);
RECT rcNote = {0};
GetClientRect(m_hwnd, &rcNote);
//WMSize(cxRect(rcNote), cyRect(rcNote), FALSE);
ResizeChildren(cxRect(rcNote), cyRect(rcNote), pborderwidths->top, FALSE);
return S_OK;
}
// *************************
HRESULT CNote::GetWindow(HWND * lphwnd)
{
*lphwnd = m_hwnd;
return (m_hwnd ? S_OK : E_FAIL);
}
// *************************
BYTE CNote::GetNoteType()
{
BYTE retval;
if (m_fReadNote)
retval = m_fMail ? MailReadNoteType : NewsReadNoteType;
else
retval = m_fMail ? MailSendNoteType : NewsSendNoteType;
return retval;
}
// *************************
HRESULT CNote::IsMenuMessage(MSG *lpmsg)
{
Assert(m_pToolbarObj);
if (m_pToolbarObj)
return m_pToolbarObj->IsMenuMessage(lpmsg);
else
return S_FALSE;
}
// *************************
HRESULT CNote::EventOccurred(DWORD nCmdID, IMimeMessage *)
{
switch (nCmdID)
{
case MEHC_CMD_MARK_AS_READ:
RemoveNewMailIcon();
MarkMessage(MARK_MESSAGE_READ, APPLY_SPECIFIED);
break;
case MEHC_CMD_CONNECT:
if (g_pConMan)
g_pConMan->SetGlobalOffline(FALSE);
ReloadMessageFromSite(TRUE);
AssertSz(!m_fCBDestroyWindow, "Shouldn't need to destroy the window...");
break;
default:
return S_FALSE;
}
return S_OK;
}
// *************************
HRESULT CNote::QuerySwitchIdentities()
{
IImnAccount *pAcct = NULL;
DWORD dwServType;
HRESULT hr;
if (!IsWindowEnabled(m_hwnd))
{
Assert(IsWindowVisible(m_hwnd));
return E_PROCESS_CANCELLED_SWITCH;
}
if (IsDirty() != S_FALSE)
{
if (FAILED(hr = m_pHdr->HrGetAccountInHeader(&pAcct)))
goto fail;
if (FAILED(hr = pAcct->GetServerTypes(&dwServType)))
goto fail;
ReleaseObj(pAcct);
pAcct = NULL;
SetForegroundWindow(m_hwnd);
if (!!(dwServType & SRV_POP3) || !!(dwServType & SRV_NNTP))
{
if (!FCanClose())
return E_USER_CANCELLED;
}
else
{
// IMAP and HTTPMail would have to remote the note, which they
// can't do at this point, so fail the switch until the window is closed.
AthMessageBoxW(m_hwnd, MAKEINTRESOURCEW(idsCantSaveMsg),
MAKEINTRESOURCEW(idsNoteCantSwitchIdentity),
NULL, MB_OK | MB_ICONEXCLAMATION);
return E_USER_CANCELLED;
}
}
return S_OK;
fail:
ReleaseObj(pAcct);
return E_PROCESS_CANCELLED_SWITCH;
}
// *************************
HRESULT CNote::SwitchIdentities()
{
HRESULT hr;
if (IsDirty() != S_FALSE)
hr = SaveMessage(OESF_FORCE_LOCAL_DRAFT);
SendMessage(m_hwnd, WM_CLOSE, 0, 0);
return S_OK;
}
// *************************
HRESULT CNote::IdentityInformationChanged(DWORD dwType)
{
return S_OK;
}
// *************************
HRESULT CNote::OnBegin(STOREOPERATIONTYPE tyOperation, STOREOPERATIONINFO *pOpInfo,
IOperationCancel *pCancel)
{
Assert(m_pCancel == NULL);
if (NULL != pCancel)
{
m_pCancel = pCancel;
m_pCancel->AddRef();
}
return(S_OK);
}
// *************************
void CNote::ShowErrorScreen(HRESULT hr)
{
switch (hr)
{
case IXP_E_NNTP_ARTICLE_FAILED:
case STORE_E_EXPIRED:
if (m_pBodyObj2)
m_pBodyObj2->LoadHtmlErrorPage(c_szErrPage_Expired);
break;
case HR_E_USER_CANCEL_CONNECT:
case HR_E_OFFLINE:
if (m_pBodyObj2)
m_pBodyObj2->LoadHtmlErrorPage(c_szErrPage_Offline);
SetFocus(m_hwnd);
break;
case STG_E_MEDIUMFULL:
if (m_pBodyObj2)
m_pBodyObj2->LoadHtmlErrorPage(c_szErrPage_DiskFull);
break;
case MIME_E_SECURITY_CANTDECRYPT:
if (m_pBodyObj2)
m_pBodyObj2->LoadHtmlErrorPage(c_szErrPage_SMimeEncrypt);
break;
#ifdef SMIME_V3
case MIME_E_SECURITY_LABELACCESSDENIED:
case MIME_E_SECURITY_LABELACCESSCANCELLED:
case MIME_E_SECURITY_LABELCORRUPT:
if (m_pBodyObj2)
m_pBodyObj2->LoadHtmlErrorPage(c_szErrPage_SMimeLabel);
break;
#endif // SMIME_V3
case MAPI_E_USER_CANCEL:
if (m_pBodyObj2)
m_pBodyObj2->LoadHtmlErrorPage(c_szErrPage_DownloadCanceled);
break;
default:
if (m_pBodyObj2)
m_pBodyObj2->LoadHtmlErrorPage(c_szErrPage_GenFailure);
break;
}
m_fCompleteMsg = FALSE;
}
// *************************
HRESULT CNote::OnProgress(STOREOPERATIONTYPE tyOperation, DWORD dwCurrent,
DWORD dwMax, LPCSTR pszStatus)
{
TCHAR szRes[CCHMAX_STRINGRES],
szRes2[CCHMAX_STRINGRES],
szRes3[CCHMAX_STRINGRES];
MSG msg;
if (m_pstatus && pszStatus)
m_pstatus->SetStatusText(const_cast<LPSTR>(pszStatus));
CallbackCloseTimeout(&m_hTimeout);
switch (tyOperation)
{
case SOT_GET_MESSAGE:
if (m_pstatus)
{
if (0 != dwMax)
{
if (!m_fProgress)
{
m_fProgress = TRUE;
m_pstatus->ShowProgress(dwMax);
}
if (m_pstatus)
m_pstatus->SetProgress(dwCurrent);
if (!pszStatus)
{
AthLoadString(idsDownloadingArticle, szRes, ARRAYSIZE(szRes));
wnsprintf(szRes2, ARRAYSIZE(szRes2), szRes, (100 * dwCurrent ) / dwMax );
m_pstatus->SetStatusText(szRes2);
}
}
else if (0 != dwCurrent)
{
// dwCurrent is non-zero, but no max has been specified.
// This implies that dwCurrent is a byte count.
AthLoadString(idsDownloadArtBytes, szRes, ARRAYSIZE(szRes));
AthFormatSizeK(dwCurrent, szRes2, ARRAYSIZE(szRes2));
wnsprintf(szRes3, ARRAYSIZE(szRes3), szRes, szRes2);
m_pstatus->SetStatusText(szRes3);
}
}
break;
}
return S_OK;
}
// *************************
HRESULT CNote::OnComplete(STOREOPERATIONTYPE tyOperation, HRESULT hrComplete, LPSTOREOPERATIONINFO pOpInfo, LPSTOREERROR pErrorInfo)
{
if ((SOT_PUT_MESSAGE == tyOperation) && SUCCEEDED(hrComplete) && pOpInfo && m_pMsgSite)
m_pMsgSite->UpdateCallbackInfo(pOpInfo);
// Close any timeout dialog, if present
CallbackCloseTimeout(&m_hTimeout);
if (m_pstatus)
{
if (m_fProgress)
{
m_pstatus->HideProgress();
m_fProgress = FALSE;
}
m_pstatus->SetStatusText(const_cast<LPSTR>(c_szEmpty));
}
if (m_pCancel != NULL)
{
m_pCancel->Release();
m_pCancel = NULL;
}
PostMessage(m_hwnd, WM_OENOTE_ON_COMPLETE, hrComplete, (DWORD)tyOperation);
// This is not a very neat fix. But, at this time it is a safe fix.
// Here is the reason why we can't do it any other place.
// _OnComplete posts a destroy message to the note window depending on the operation.
// To avoid this object from being destroyed before this function returns, the above
// message is posted. Since there is no way to pass in the error info through PostMessage,
// we will handle this error here. I am not handling other operation types because some
// of them do get handled in _OnComplete
if (tyOperation == SOT_DELETING_MESSAGES)
{
// Display an Error on Failures
if (FAILED(hrComplete) && hrComplete != HR_E_OFFLINE)
{
// Call into my swanky utility
CallbackDisplayError(m_hwnd, hrComplete, pErrorInfo);
}
}
return S_OK;
}
// *************************
void CNote::_OnComplete(STOREOPERATIONTYPE tyOperation, HRESULT hrComplete)
{
BOOL fExpectedComplete = TRUE;
STOREOPERATIONTYPE tyNewOp = SOT_INVALID;
m_pMsgSite->OnComplete(tyOperation, hrComplete, &tyNewOp);
if ((SOT_INVALID != tyNewOp) && (SOT_INVALID != m_OrigOperationType))
m_OrigOperationType = tyNewOp;
if (SUCCEEDED(hrComplete))
{
switch (tyOperation)
{
case SOT_GET_MESSAGE:
switch (hrComplete)
{
case S_OK:
ReloadMessageFromSite();
AssertSz(!m_fCBDestroyWindow, "Shouldn't need to destroy the window...");
break;
case S_FALSE:
// S_FALSE means the operation was canceled
ShowErrorScreen(MAPI_E_USER_CANCEL);
break;
}
break;
case SOT_PUT_MESSAGE:
ClearDirtyFlag();
break;
case SOT_DELETING_MESSAGES:
if (!m_fCBDestroyWindow && m_fOrgCmdWasDelete)
ReloadMessageFromSite(TRUE);
m_fOrgCmdWasDelete = FALSE;
break;
case SOT_COPYMOVE_MESSAGE:
if (!m_fCBCopy)
ReloadMessageFromSite();
break;
case SOT_SET_MESSAGEFLAGS:
if ((MARK_MAX != m_dwCBMarkType) && m_pHdr)
{
m_pHdr->SetFlagState(m_dwCBMarkType);
m_dwCBMarkType = MARK_MAX;
}
if (MORFS_UNKNOWN != m_dwMarkOnReplyForwardState)
{
if (MORFS_CLEARING == m_dwMarkOnReplyForwardState)
{
HRESULT hr;
BOOL fForwarded = (OENA_FORWARD == m_dwNoteAction) || (OENA_FORWARDBYATTACH == m_dwNoteAction);
MARK_TYPE dwMarkType = (fForwarded ? MARK_MESSAGE_FORWARDED : MARK_MESSAGE_REPLIED);
m_dwMarkOnReplyForwardState = MORFS_SETTING;
hr = MarkMessage(dwMarkType, APPLY_SPECIFIED);
if (FAILED(hr) && (E_PENDING != hr))
m_dwMarkOnReplyForwardState = MORFS_UNKNOWN;
}
else
{
PostMessage(m_hwnd, WM_OE_DESTROYNOTE, 0, 0);
m_dwMarkOnReplyForwardState = MORFS_UNKNOWN;
}
}
// Remove new mail notification icon
RemoveNewMailIcon();
break;
default:
fExpectedComplete = FALSE;
break;
}
}
else
{
switch (tyOperation)
{
case SOT_GET_MESSAGE:
ShowErrorScreen(hrComplete);
break;
case SOT_PUT_MESSAGE:
if (FAILED(hrComplete))
{
HRESULT hrTemp;
// Can't save to remote server for whatever reason. Save to local Drafts instead
// First, inform user of the situation, if special folders SHOULD have worked
if (STORE_E_NOREMOTESPECIALFLDR != hrComplete)
{
AthMessageBoxW(m_hwnd, MAKEINTRESOURCEW(idsAthena),
MAKEINTRESOURCEW(idsForceSaveToLocalDrafts),
NULL, MB_OK | MB_ICONEXCLAMATION);
}
hrTemp = SaveMessage(OESF_FORCE_LOCAL_DRAFT);
TraceError(hrTemp);
}
break;
case SOT_SET_MESSAGEFLAGS:
if (MORFS_UNKNOWN != m_dwMarkOnReplyForwardState)
m_dwMarkOnReplyForwardState = MORFS_UNKNOWN;
break;
case SOT_DELETING_MESSAGES:
m_fOrgCmdWasDelete = FALSE;
break;
default:
fExpectedComplete = FALSE;
break;
}
}
// If the original operation was originated from the note, then
// we will need to re-enable the note as well as check to see
// if we need to close the window.
if (tyOperation == m_OrigOperationType)
{
_SetPendingOp(SOT_INVALID);
EnableNote(TRUE);
EnterCriticalSection(&m_csNoteState);
if ((tyOperation == SOT_SET_MESSAGEFLAGS) && (m_nisNoteState == NIS_FIXFOCUS))
{
if(GetForegroundWindow() == m_hwnd)
m_pBodyObj2->HrFrameActivate(TRUE);
else
m_pBodyObj2->HrGetWindow(&m_hwndFocus);
m_nisNoteState = NIS_NORMAL;
}
LeaveCriticalSection(&m_csNoteState);
if (!!m_fCBDestroyWindow)
{
m_fCBDestroyWindow = FALSE;
PostMessage(m_hwnd, WM_OE_DESTROYNOTE, 0, 0);
}
}
}
// *************************
HRESULT CNote::OnTimeout(LPINETSERVER pServer, LPDWORD pdwTimeout, IXPTYPE ixpServerType)
{
// Display a timeout dialog
return CallbackOnTimeout(pServer, ixpServerType, *pdwTimeout, (ITimeoutCallback *)this, &m_hTimeout);
}
// *************************
HRESULT CNote::CanConnect(LPCSTR pszAccountId, DWORD dwFlags)
{
// Call into general CanConnect Utility
//return CallbackCanConnect(pszAccountId, m_hwnd, FALSE);
//Always TRUE will prompt to go online if we are offline, which is what we want to do.
return CallbackCanConnect(pszAccountId, m_hwnd, TRUE);
}
// *************************
HRESULT CNote::OnLogonPrompt(LPINETSERVER pServer, IXPTYPE ixpServerType)
{
// Close any timeout dialog, if present
CallbackCloseTimeout(&m_hTimeout);
// Call into general OnLogonPrompt Utility
return CallbackOnLogonPrompt(m_hwnd, pServer, ixpServerType);
}
// *************************
HRESULT CNote::OnPrompt(HRESULT hrError, LPCTSTR pszText, LPCTSTR pszCaption, UINT uType, INT *piUserResponse)
{
// Close any timeout dialog, if present
CallbackCloseTimeout(&m_hTimeout);
// Call into my swanky utility
return CallbackOnPrompt(m_hwnd, hrError, pszText, pszCaption, uType, piUserResponse);
}
// *************************
HRESULT CNote::GetParentWindow(DWORD dwReserved, HWND *phwndParent)
{
*phwndParent = m_hwnd;
return(S_OK);
}
// *************************
HRESULT CNote::OnTimeoutResponse(TIMEOUTRESPONSE eResponse)
{
HRESULT hr = S_OK;
// Call into general timeout response utility
if (NULL != m_pCancel)
hr = CallbackOnTimeoutResponse(eResponse, m_pCancel, &m_hTimeout);
return hr;
}
// *************************
HRESULT CNote::CheckCharsetConflict()
{
return m_fPreventConflictDlg ? S_FALSE : S_OK;
}