5113 lines
154 KiB
C++
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;
|
|
} |