//************************************************* // h e a d e r . c p p // // Purpose: // implements Header UI for Read|SendNote // // Owner: // brettm. // // History: // July '95: Created // // Copyright (C) Microsoft Corp. 1993, 1994. //************************************************* #include #include #include #include #include "oleutil.h" #include "fonts.h" #include "error.h" #include "header.h" #include "options.h" #include "note.h" #include "ipab.h" #include "addrobj.h" #include "hotlinks.h" #include #include #include #include "menuutil.h" #include "shlwapi.h" #include "envcid.h" #include "ourguid.h" #include "mimeutil.h" #include "strconst.h" #include "mailutil.h" #include "regutil.h" #include "spoolapi.h" #include "init.h" #include "instance.h" #include "attman.h" #include "envguid.h" #include //ICW #include #include "menures.h" #include "storecb.h" #include "mimeolep.h" #include "multlang.h" #include "mirror.h" #include "seclabel.h" #include "shlwapip.h" #include "reutil.h" #include #include "msgprop.h" #include "demand.h" ASSERTDATA extern UINT GetCurColorRes(void); class CFieldSizeMgr : public CPrivateUnknown, public IFontCacheNotify, public IConnectionPoint { public: // IUnknown virtual STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj) { return CPrivateUnknown::QueryInterface(riid, ppvObj); }; virtual STDMETHODIMP_(ULONG) AddRef(void) { return CPrivateUnknown::AddRef();}; virtual STDMETHODIMP_(ULONG) Release(void) { return CPrivateUnknown::Release(); }; // IFontCacheNotify HRESULT STDMETHODCALLTYPE OnPreFontChange(void); HRESULT STDMETHODCALLTYPE OnPostFontChange(void); // IConnectionPoint HRESULT STDMETHODCALLTYPE GetConnectionInterface(IID *pIID); HRESULT STDMETHODCALLTYPE GetConnectionPointContainer(IConnectionPointContainer **ppCPC); HRESULT STDMETHODCALLTYPE Advise(IUnknown *pUnkSink, DWORD *pdwCookie); HRESULT STDMETHODCALLTYPE Unadvise(DWORD dwCookie); HRESULT STDMETHODCALLTYPE EnumConnections(IEnumConnections **ppEnum); // CPrivateUnknown HRESULT PrivateQueryInterface(REFIID riid, LPVOID * ppvObj); int GetScalingFactor(void); void ResetGlobalSizes(void); HRESULT Init(void); // This one should only be called from headers' OnPostFontChange calls BOOL FontsChanged(void) {return m_fFontsChanged;} CFieldSizeMgr(IUnknown *pUnkOuter=NULL); ~CFieldSizeMgr(); private: IUnknownList *m_pAdviseRegistry; CRITICAL_SECTION m_rAdviseCritSect; BOOL m_fFontsChanged; DWORD m_dwFontNotify; }; // ********************************************************** // ***** Debug stuff for handling painting and resizing ***** // ********************************************************** const int PAINTING_DEBUG_LEVEL = 4; const int RESIZING_DEBUG_LEVEL = 8; const int GEN_HEADER_DEBUG_LEVEL = 16; #ifdef DEBUG class StackRegistry { public: StackRegistry(LPSTR pszTitle, INT_PTR p1 = 0, INT_PTR p2 = 0, INT_PTR p3 = 0, INT_PTR p4 = 0, INT_PTR p5 = 0); ~StackRegistry(); private: int m_StackLevel; CHAR m_szTitle[256+1]; static int gm_cStackLevel; static int gm_strLen; static LPSTR gm_Indent; }; int StackRegistry::gm_cStackLevel = 0; LPSTR StackRegistry::gm_Indent = "------------------------------"; int StackRegistry::gm_strLen = lstrlen(gm_Indent); StackRegistry::StackRegistry(LPSTR pszTitle, INT_PTR p1, INT_PTR p2, INT_PTR p3, INT_PTR p4, INT_PTR p5) { gm_cStackLevel++; m_StackLevel = (gm_cStackLevel > gm_strLen) ? gm_strLen : gm_cStackLevel; StrCpyN(m_szTitle, pszTitle, ARRAYSIZE(m_szTitle)); m_szTitle[256] = 0; if (1 == gm_cStackLevel) DOUTL(RESIZING_DEBUG_LEVEL, "\n*********** BEGIN TRACE ***********"); DOUTL(RESIZING_DEBUG_LEVEL, "IN*** %s%s - %x, %x, %x, %x, %x", gm_Indent+gm_strLen-m_StackLevel, m_szTitle, p1, p2, p3, p4, p5); } StackRegistry::~StackRegistry() { DOUTL(RESIZING_DEBUG_LEVEL, "OUT** %s%s", gm_Indent+gm_strLen-m_StackLevel, m_szTitle); if (1 == gm_cStackLevel) DOUTL(RESIZING_DEBUG_LEVEL, "************ END TRACE ************\n"); gm_cStackLevel--; Assert(gm_cStackLevel >= 0); } #define STACK StackRegistry stack #else // BUGBUG (neilbren) WIN64 // Figure out when __noop was introduced (MSC_VER ?) so we don't have to key off of WIN64 #define STACK __noop #endif // ****************************** // ***** End of debug stuff ***** // ****************************** // c o n s t a n t s const DWORD SETWINPOS_DEF_FLAGS = SWP_NOZORDER|SWP_NOACTIVATE; #define GET_WM_COMMAND_ID(wp, lp) LOWORD(wp) #define GET_WM_COMMAND_HWND(wp, lp) (HWND)(lp) #define GET_WM_COMMAND_CMD(wp, lp) HIWORD(wp) #define WC_ATHHEADER wszHeaderWndClass #define RGB_TRANSPARENT RGB(255,0,255) #define HDM_TESTQUERYPRI (WM_USER + 1) #define cxBorder (GetSystemMetrics(SM_CXBORDER)) #define cyBorder (GetSystemMetrics(SM_CYBORDER)) // HDRCB_VCARD must remain -1 and all others must be negative enum { HDRCB_VCARD = -1, HDRCB_SIGNED = -2, HDRCB_ENCRYPT = -3, HDRCB_NO_BUTTON = -4 }; // WARNING:: This next macro is only to be used with g_rgBtnInd inside the CNoteHdr class. // Make sure that they match the entries in g_rgBtnInd #define BUTTON_STATES m_fDigSigned, m_fEncrypted, m_fVCard #define BUTTON_USE_IN_COMPOSE FALSE, FALSE, TRUE static const DWORD g_rgBtnInd[] = {HDRCB_SIGNED, HDRCB_ENCRYPT, HDRCB_VCARD}; static const int cchMaxWab = 512; static const int cxTBButton = 16; static const int BUTTON_BUFFER = 2; static const int cxBtn = 16; static const int cyBtn = cxBtn; static const int cxFlags = 12; static const int cyFlags = cxFlags; static const int cxFlagsDelta = cxFlags + 4; static const int MAX_ATTACH_PIXEL_HEIGHT = 50; static const int ACCT_ENTRY_SIZE = CCHMAX_ACCOUNT_NAME + CCHMAX_EMAIL_ADDRESS + 10; static const int INVALID_PHCI_Y = -1; static const int cMaxRecipMenu = (ID_ADD_RECIPIENT_LAST-ID_ADD_RECIPIENT_FIRST); static const int NUM_COMBO_LINES = 9; static const int MAX_RICHEDIT_LINES = 4; static const int DEFER_WINDOW_SIZE = MAX_HEADER_COMP + 1 + 1 + 1 + 5; // +1=header window, +1=field resize, +1 toolbar static const LPTSTR GRP_DELIMITERS = " ,\t;\n\r"; #define c_wszEmpty L"" #define c_aszEmpty "" // t y p e d e f s typedef struct TIPLOOKUP_tag { int idm; int ids; } TIPLOOKUP; typedef struct CMDMAPING_tag { DWORD cmdIdOffice, cmdIdOE; } CMDMAPING; typedef struct PERSISTHEADER_tag { DWORD cbSize; // size so we can version the stuct DWORD dwRes1, // padding just in case... dwRes2; } PERSISTHEADER; #define cchMaxSubject 256 typedef struct WELLINIT_tag { INT idField; ULONG uMAPI; } WELLINIT, *PWELLINIT; // s t a t i c d a t a static HIMAGELIST g_himlStatus = 0, g_himlBtns = 0, g_himlSecurity = 0; static TCHAR g_szStatFlagged[cchHeaderMax+1] = c_aszEmpty, g_szStatLowPri[cchHeaderMax+1] = c_aszEmpty, g_szStatHighPri[cchHeaderMax+1] = c_aszEmpty, g_szStatWatched[cchHeaderMax+1] = c_aszEmpty, g_szStatIgnored[cchHeaderMax+1] = c_aszEmpty, g_szStatFormat1[cchHeaderMax+1] = c_aszEmpty, g_szStatFormat2[cchHeaderMax+1] = c_aszEmpty, g_szStatFormat3[cchHeaderMax+1] = c_aszEmpty, g_szStatUnsafeAtt[cchHeaderMax+1] = c_aszEmpty; static CFieldSizeMgr *g_pFieldSizeMgr = NULL; static WNDPROC g_lpfnREWndProc = NULL; static CHARFORMAT g_cfHeader = {0}; static int g_cyFont = 0, g_cyLabelHeight = 0; static char const szButton[]="BUTTON"; static WCHAR const wszHeaderWndClass[]=L"OE_Envelope"; // KEEP in ssync with c_rgTipLookup const TBBUTTON c_btnsOfficeEnvelope[]= { {TBIMAGE_SEND_MAIL, ID_SEND_NOW, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0, -1}, __TOOLBAR_SEP__, { TBIMAGE_CHECK_NAMES, ID_CHECK_NAMES, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0, 0}, 0, -1}, { TBIMAGE_ADDRESS_BOOK, ID_ADDRESS_BOOK, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0, 0}, 0, -1}, __TOOLBAR_SEP__, {TBIMAGE_SET_PRIORITY, ID_SET_PRIORITY, TBSTATE_ENABLED, TBSTYLE_DROPDOWN, {0,0}, 0, -1}, {TBIMAGE_INSERT_ATTACHMENT, ID_INSERT_ATTACHMENT, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0, -1}, __TOOLBAR_SEP__, { TBIMAGE_ENVELOPE_BCC, ID_ENV_BCC, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0, -1} }; // KEEP in ssync with c_btnsOfficeEnvelope const TIPLOOKUP c_rgTipLookup[] = { {ID_SEND_NOW, idsSendMsgTT}, {ID_CHECK_NAMES, idsCheckNamesTT}, {ID_ADDRESS_BOOK, idsAddressBookTT}, {ID_SET_PRIORITY, idsSetPriorityTT}, {ID_INSERT_ATTACHMENT, idsInsertFileTT}, {ID_ENV_BCC, idsEnvBccTT} }; // Prototypes HRESULT ParseFollowup(LPMIMEMESSAGE pMsg, LPTSTR* ppszGroups, BOOL* pfPoster); DWORD HdrGetRichEditText(HWND hwnd, LPWSTR pwchBuff, DWORD dwNumChars, BOOL fSelection); void HdrSetRichEditText(HWND hwnd, LPWSTR pwchBuff, BOOL fReplace); // i n l i n e s void HdrSetRichEditText(HWND hwnd, LPWSTR pwchBuff, BOOL fReplace) { if (!hwnd) return; PHCI phci = (HCI*)GetWindowLongPtr(hwnd, GWLP_USERDATA); AssertSz(phci, "We are calling HdrSetRichEditText on a non-richedit control"); SetRichEditText(hwnd, pwchBuff, fReplace, phci->pDoc, (phci->dwFlags & HCF_READONLY)); } DWORD HdrGetRichEditText(HWND hwnd, LPWSTR pwchBuff, DWORD dwNumChars, BOOL fSelection) { if (!hwnd) return 0; PHCI phci = (HCI*)GetWindowLongPtr(hwnd, GWLP_USERDATA); AssertSz(phci, "We are calling HdrSetRichEditText on a non-richedit control"); return GetRichEditText(hwnd, pwchBuff, dwNumChars, fSelection, phci->pDoc); } inline void GetRealClientRect(HWND hwnd, RECT *prc) { GetClientRect(hwnd, prc); AdjustWindowRectEx(prc, GetWindowLong(hwnd, GWL_STYLE), FALSE, GetWindowLong(hwnd, GWL_EXSTYLE)); } inline int GetCtrlWidth(HWND hwnd) { RECT rc; GetWindowRect(hwnd, &rc); return rc.right - rc.left; } inline int GetControlSize(BOOL fIncludeBorder, int cLines) { int size = cLines * g_cyFont; // If borders, include the metrics if (fIncludeBorder) size += 7; return size; } inline int GetCtrlHeight(HWND hwnd) { DWORD id = GetWindowLong(hwnd, GWL_ID); if (idFromCombo == id) { return GetControlSize(TRUE, 1); } else { RECT rc; GetWindowRect(hwnd, &rc); return rc.bottom - rc.top; } } inline int GetStatusHeight(int cLines) {return ((cyBtn HDRCB_VCARD); } inline HFONT GetFont(BOOL fBold) { return HGetSystemFont(fBold?FNT_SYS_ICON_BOLD:FNT_SYS_ICON); } static IMSGPRIORITY priLookup[3]= { IMSG_PRI_LOW, IMSG_PRI_NORMAL, IMSG_PRI_HIGH }; #define HCI_ENTRY(flg,opt,ide,idb,idsl,idse,idst) \ { \ flg, opt, \ ide, idb, \ idsl, idse, idst, \ NOFLAGS, TRUE, \ NULL, NULL, \ 0, 0, 0, 0, \ c_wszEmpty, c_wszEmpty \ } static int rgIDTabOrderMailSend[] = { idFromCombo, idADTo, idADCc, idADBCc, idTXTSubject, idwAttachWell }; static HCI rgMailHeaderSend[]= { HCI_ENTRY(HCF_COMBO|HCF_ADVANCED|HCF_BORDER, 0, idFromCombo, 0, idsFromField, NULL, NULL), HCI_ENTRY(HCF_MULTILINE|HCF_HASBUTTON|HCF_ADDRBOOK|HCF_ADDRWELL|HCF_BORDER, 0, idADTo, idbtnTo, idsToField, idsEmptyTo, idsTTRecipients), HCI_ENTRY(HCF_MULTILINE|HCF_HASBUTTON|HCF_ADDRBOOK|HCF_ADDRWELL|HCF_BORDER, 0, idADCc, idbtnCc, idsCcField, idsEmptyCc, idsTTRecipients), HCI_ENTRY(HCF_MULTILINE|HCF_HASBUTTON|HCF_ADDRBOOK|HCF_ADDRWELL|HCF_ADVANCED|HCF_BORDER, 0, idADBCc, idbtnBCc, idsBCcField, idsEmptyBCc, idsTTRecipients), HCI_ENTRY(HCF_USECHARSET|HCF_BORDER, 0, idTXTSubject, 0, idsSubjectField, idsEmptySubject, idsTTSubject), HCI_ENTRY(HCF_BORDER|HCF_ATTACH, 0, idwAttachWell, 0, idsAttachment, 0, idsTTAttachment), }; static int rgIDTabOrderMailRead[] = { idADFrom, idTXTDate, idADTo, idADCc, idTXTSubject, idwAttachWell, idSecurity }; static HCI rgMailHeaderRead[]= { HCI_ENTRY(HCF_MULTILINE|HCF_READONLY|HCF_ADDRWELL, 0, idADFrom, 0, idsFromField, idsNoFromField, NULL), HCI_ENTRY(HCF_READONLY, 0, idTXTDate, 0, idsDateField, NULL, NULL), HCI_ENTRY(HCF_MULTILINE|HCF_READONLY|HCF_ADDRWELL, 0, idADTo, 0, idsToField, idsNoCcOrTo, NULL), HCI_ENTRY(HCF_MULTILINE|HCF_READONLY|HCF_ADVANCED|HCF_ADDRWELL, 0, idADCc, 0, idsCcField, idsNoCcOrTo, NULL), HCI_ENTRY(HCF_READONLY|HCF_USECHARSET, 0, idTXTSubject, 0, idsSubjectField, idsEmptySubjectRO, NULL), HCI_ENTRY(HCF_READONLY|HCF_BORDER|HCF_ATTACH, 0, idwAttachWell, 0, idsAttachment, 0, NULL), HCI_ENTRY(HCF_READONLY|HCF_ADVANCED, // HCF_ADVANCED will hide it when empty 0, idSecurity, 0, idsSecurityField, NULL, NULL), }; static int rgIDTabOrderNewsSend[] = { idFromCombo, idADNewsgroups, idTXTFollowupTo, idADCc, idADReplyTo, idTXTDistribution, idTXTKeywords, idTXTSubject, idwAttachWell, idADApproved, idTxtControl }; static HCI rgNewsHeaderSend[]= { HCI_ENTRY(HCF_COMBO|HCF_ADVANCED|HCF_BORDER, 0, idFromCombo, 0, idsNewsServer, NULL, NULL), HCI_ENTRY(HCF_MULTILINE|HCF_HASBUTTON|HCF_NEWSPICK|HCF_BORDER, 0, idADNewsgroups, idbtnTo, idsNewsgroupsField, idsEmptyNewsgroups, idsTTNewsgroups), HCI_ENTRY(HCF_ADVANCED|HCF_HASBUTTON|HCF_NEWSPICK|HCF_MULTILINE|HCF_USECHARSET|HCF_BORDER, 0, idTXTFollowupTo, idbtnFollowup, idsFollowupToField, idsEmptyFollowupTo, idsTTFollowup), HCI_ENTRY(HCF_MULTILINE|HCF_ADDRWELL|HCF_HASBUTTON|HCF_ADDRBOOK|HCF_BORDER, 0, idADCc, idbtnCc, idsCcField, idsEmptyCc, idsTTRecipients), HCI_ENTRY(HCF_ADVANCED|HCF_ADDRWELL|HCF_HASBUTTON|HCF_ADDRBOOK|HCF_BORDER, 0, idADReplyTo, idbtnReplyTo, idsReplyToField, idsEmptyReplyTo, idsTTReplyTo), HCI_ENTRY(HCF_MULTILINE|HCF_ADVANCED|HCF_BORDER, 0, idTXTDistribution, 0, idsDistributionField, idsEmptyDistribution, idsTTDistribution), HCI_ENTRY(HCF_MULTILINE|HCF_ADVANCED|HCF_USECHARSET|HCF_BORDER, 0, idTXTKeywords, 0, idsKeywordsField, idsEmptyKeywords, idsTTKeywords), HCI_ENTRY(HCF_USECHARSET|HCF_BORDER, 0, idTXTSubject, 0, idsSubjectField, idsEmptySubject, idsTTSubject), HCI_ENTRY(HCF_BORDER|HCF_ATTACH, 0, idwAttachWell, 0, idsAttachment, 0, idsTTAttachment), HCI_ENTRY(HCF_ADVANCED|HCF_OPTIONAL, OPT_NEWSMODERATOR, idADApproved, 0, idsApprovedField, idsEmptyApproved, idsTTApproved), HCI_ENTRY(HCF_ADVANCED|HCF_OPTIONAL, OPT_NEWSCONTROLHEADER, idTxtControl, 0, idsControlField, idsEmptyControl, idsTTControl), }; static int rgIDTabOrderNewsRead[] = { idADFrom, idADReplyTo, idTXTOrg, idTXTDate, idADNewsgroups, idTXTFollowupTo, idTXTDistribution, idTXTKeywords, idTXTSubject, idwAttachWell, idSecurity }; static HCI rgNewsHeaderRead[]= { HCI_ENTRY(HCF_MULTILINE|HCF_READONLY|HCF_ADDRWELL, 0, idADFrom, 0, idsFromField, idsNoFromField, NULL), HCI_ENTRY(HCF_READONLY|HCF_ADVANCED|HCF_ADDRWELL, 0, idADReplyTo, 0, idsReplyToField, idsNotSpecified, NULL), HCI_ENTRY(HCF_READONLY|HCF_ADVANCED|HCF_USECHARSET, 0, idTXTOrg, 0, idsOrgField, idsNotSpecified, NULL), HCI_ENTRY(HCF_READONLY, 0, idTXTDate, 0, idsDateField, idsNotSpecified, NULL), HCI_ENTRY(HCF_MULTILINE|HCF_READONLY, 0, idADNewsgroups, 0, idsNewsgroupsField, idsNotSpecified, NULL), HCI_ENTRY(HCF_READONLY|HCF_ADVANCED, 0, idTXTFollowupTo, 0, idsFollowupToField, idsNotSpecified, NULL), HCI_ENTRY(HCF_MULTILINE|HCF_READONLY|HCF_ADVANCED, 0, idTXTDistribution, 0, idsDistributionField, idsNotSpecified, NULL), HCI_ENTRY(HCF_MULTILINE|HCF_READONLY|HCF_ADVANCED|HCF_USECHARSET, 0, idTXTKeywords, 0, idsKeywordsField, idsNotSpecified, NULL), HCI_ENTRY(HCF_READONLY|HCF_USECHARSET, 0, idTXTSubject, 0, idsSubjectField, idsEmptySubjectRO, NULL), HCI_ENTRY(HCF_READONLY|HCF_BORDER|HCF_ATTACH, 0, idwAttachWell, 0, idsAttachment, 0, NULL), HCI_ENTRY(HCF_READONLY|HCF_ADVANCED, 0, idSecurity, 0, idsSecurityField, NULL, NULL), }; // p r o t o t y p e s void _ValidateNewsgroups(LPWSTR pszGroups); INT_PTR CALLBACK _PlainWarnDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); #ifdef DEBUG void DEBUGHdrName(HWND hwnd); void DEBUGDumpHdr(HWND hwnd, int cHdr, PHCI rgHCI) { PHCI phci; char sz[cchHeaderMax+1]; RECT rc; HWND hwndEdit; #ifndef DEBUG_SIZINGCODE return; #endif DOUTL(GEN_HEADER_DEBUG_LEVEL, "-----"); for (int i=0; i<(int)cHdr; i++) { phci=&rgHCI[i]; hwndEdit=GetDlgItem(hwnd, phci->idEdit); GetChildRect(hwnd, hwndEdit, &rc); DEBUGHdrName(hwndEdit); wnsprintf(sz, ARRAYSIZE(sz), "\tat:(%d,%d) \tsize:(%d,%d)\r\n", rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top); OutputDebugString(sz); } GetWindowRect(hwnd, &rc); DOUTL(GEN_HEADER_DEBUG_LEVEL, "HeaderSize: (%d,%d)\r\n-----", rc.right-rc.left, rc.bottom-rc.top); } void DEBUGHdrName(HWND hwnd) { char sz[cchHeaderMax+1]; char *psz=0; switch (GetDlgCtrlID(hwnd)) { case idTXTSubject: psz="Subject"; break; case idTXTOrg: psz="Org"; break; case idADTo: psz="To"; break; case idADCc: psz="Cc"; break; case idADFrom: psz="From"; break; case idTXTDate: psz="Date"; break; case idTXTDistribution: psz="Distribution"; break; case idADApproved: psz="Approved"; break; case idADReplyTo: psz="ReplyTo"; break; case idTXTKeywords: psz="Keywords"; break; case idADNewsgroups: psz="NewsGroup"; break; case idTXTFollowupTo: psz="FollowUp"; break; default: psz=""; break; } wnsprintf(sz, ARRAYSIZE(sz), "%s: ", psz); OutputDebugString(sz); } #endif // FHeader_Init // // Purpose: called to init and de-init global header stuff, eg. // wndclasses, static data etc. // // Comments: // TODO: defer this initialisation // BOOL FHeader_Init(BOOL fInit) { WNDCLASSW wc={0}; static BOOL s_fInited=FALSE; BOOL fSucceeded = TRUE; if (fInit) { if (s_fInited) goto exit; Assert(!g_pFieldSizeMgr); g_pFieldSizeMgr = new CFieldSizeMgr; if (!g_pFieldSizeMgr || FAILED(g_pFieldSizeMgr->Init())) { fSucceeded = FALSE; goto exit; } wc.style = 0; wc.lpfnWndProc = CNoteHdr::ExtCNoteHdrWndProc; wc.hInstance = g_hInst; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1); wc.lpszClassName = WC_ATHHEADER; if (!RegisterClassWrapW(&wc)) { fSucceeded = FALSE; goto exit; } g_himlStatus=ImageList_LoadBitmap(g_hLocRes, MAKEINTRESOURCE(idbHeaderStatus), cxFlags, 0, RGB_TRANSPARENT); if (!g_himlStatus) { fSucceeded = FALSE; goto exit; } g_himlBtns=ImageList_LoadBitmap(g_hLocRes, MAKEINTRESOURCE(idbBtns), cxBtn, 0, RGB_TRANSPARENT); if (!g_himlBtns) { fSucceeded = FALSE; goto exit; } g_himlSecurity=ImageList_LoadBitmap(g_hLocRes, MAKEINTRESOURCE(idbSecurity), cxBtn, 0, RGB_TRANSPARENT); if (!g_himlSecurity) { fSucceeded = FALSE; goto exit; } ImageList_SetBkColor(g_himlStatus, CLR_NONE); ImageList_SetBkColor(g_himlBtns, CLR_NONE); ImageList_SetBkColor(g_himlSecurity, CLR_NONE); AthLoadString(idsStatusFlagged, g_szStatFlagged, cchHeaderMax); AthLoadString(idsStatusLowPri, g_szStatLowPri, cchHeaderMax); AthLoadString(idsStatusHighPri, g_szStatHighPri, cchHeaderMax); AthLoadString(idsStatusWatched, g_szStatWatched, cchHeaderMax); AthLoadString(idsStatusIgnored, g_szStatIgnored, cchHeaderMax); AthLoadString(idsStatusFormat1, g_szStatFormat1, cchHeaderMax); AthLoadString(idsStatusFormat2, g_szStatFormat2, cchHeaderMax); AthLoadString(idsStatusFormat3, g_szStatFormat3, cchHeaderMax); AthLoadString(idsStatusUnsafeAttach, g_szStatUnsafeAtt, cchHeaderMax); s_fInited=TRUE; } // De-Init ****** else { UnregisterClassWrapW(WC_ATHHEADER, g_hInst); if (g_himlStatus) { ImageList_Destroy(g_himlStatus); g_himlStatus = 0; } if (g_himlBtns) { ImageList_Destroy(g_himlBtns); g_himlBtns = 0; } if (g_himlSecurity) { ImageList_Destroy(g_himlSecurity); g_himlSecurity = 0; } s_fInited=FALSE; SafeRelease(g_pFieldSizeMgr); } exit: if (!fSucceeded) SafeRelease(g_pFieldSizeMgr); return fSucceeded; } HRESULT CreateInstance_Envelope(IUnknown *pUnkOuter, IUnknown **ppUnknown) { // Locals HRESULT hr=S_OK; CNoteHdr *pNew=NULL; // Trace TraceCall("CreateInstance_Envelope"); if (NULL != pUnkOuter) return CLASS_E_NOAGGREGATION; // Invalid Arg Assert(NULL != ppUnknown && NULL == pUnkOuter); // Create IF_NULLEXIT(pNew = new CNoteHdr); // Return the Innter *ppUnknown = (IMsoEnvelope*) pNew; exit: // Done return hr; } CNoteHdr::CNoteHdr() { // Not initialised // Member: Initialised In: // --------------------+--------------------------- // m_wNoteType Finit m_cRef = 1; m_cHCI = 0; m_cAccountIDs = 0; m_iCurrComboIndex = 0; m_hwnd = 0; m_hwndLastFocus = 0; m_hwndRebar = 0; m_pri = priNorm; // default to Normal Pri m_cfAccept = CF_NULL; m_ntNote = OENA_COMPOSE; m_fMail = TRUE; m_fVCard = FALSE; m_fDirty = FALSE; m_fInSize = FALSE; m_fFlagged = FALSE; m_fAdvanced = FALSE; m_fResizing = FALSE; m_fUIActive = FALSE; m_fDigSigned = FALSE; m_fEncrypted = FALSE; m_fSkipLayout = TRUE; // Skip layout until after load m_fSignTrusted = TRUE; m_fOfficeInit = FALSE; m_fStillLoading = TRUE; m_fEncryptionOK = TRUE; m_fHandleChange = TRUE; m_fAutoComplete = FALSE; m_fSendImmediate = FALSE; m_fVCardSave = !m_fVCard; m_fSecurityInited = FALSE; m_fAddressesChanged = FALSE; m_fForceEncryption = FALSE; m_fThisHeadDigSigned = FALSE; m_fThisHeadEncrypted = FALSE; m_fDropTargetRegister = FALSE; m_pMsg = NULL; m_lpWab = NULL; m_rgHCI = NULL; m_hwndTT = NULL; m_pTable = NULL; m_lpWabal = NULL; m_pszRefs = NULL; m_pMsgSend = NULL; m_hCharset = NULL; m_pAccount = NULL; m_hInitRef = NULL; m_lpAttMan = NULL; m_hwndParent = NULL; m_pAddrWells = NULL; m_hwndToolbar = NULL; m_pHeaderSite = NULL; m_pEnvelopeSite = NULL; m_pMsoComponentMgr = NULL; m_lpszSecurityField = NULL; m_ppAccountIDs = NULL; *m_szLastLang = 0; m_MarkType = MARK_MESSAGE_NORMALTHREAD; m_hwndOldCapture = NULL; m_dwCurrentBtn = HDRCB_NO_BUTTON; m_dwClickedBtn = HDRCB_NO_BUTTON; m_dwEffect = 0; m_cCapture = 0; m_dwDragType = 0; m_dwComponentMgrID = 0; m_dwIMEStartCount = 0; m_dwFontNotify = 0; m_dxTBOffset = 0; m_grfKeyState = 0; m_cxLeftMargin = 0; m_himl = NULL; m_fPoster = FALSE; ZeroMemory(&m_SecState, sizeof(m_SecState)); } CNoteHdr::~CNoteHdr() { Assert (m_pMsgSend==NULL); if (m_hwnd) DestroyWindow(m_hwnd); ReleaseObj(m_pTable); ReleaseObj(m_lpWabal); ReleaseObj(m_lpWab); SafeMemFree(m_pszRefs); ReleaseObj(m_pAccount); CleanupSECSTATE(&m_SecState); ReleaseObj(m_lpAttMan); ReleaseObj(m_pMsg); SafeMemFree(m_lpszSecurityField); if (m_pAddrWells) delete m_pAddrWells; if (m_himl) ImageList_Destroy(m_himl); if (m_fOfficeInit) HrOfficeInitialize(FALSE); if (m_cAccountIDs) { while (m_cAccountIDs--) SafeMemFree(m_ppAccountIDs[m_cAccountIDs]); } SafeMemFree(m_ppAccountIDs); } ULONG CNoteHdr::AddRef() { return ++m_cRef; } ULONG CNoteHdr::Release() { if (--m_cRef==0) { delete this; return 0; } return m_cRef; } HRESULT CNoteHdr::QueryInterface(REFIID riid, LPVOID *lplpObj) { if (!lplpObj) return E_INVALIDARG; *lplpObj = NULL; if (IsEqualIID(riid, IID_IUnknown)) *lplpObj = (LPVOID)this; else if (IsEqualIID(riid, IID_IHeader)) *lplpObj = (LPVOID)(LPHEADER)this; else if (IsEqualIID(riid, IID_IMsoEnvelope)) *lplpObj = (LPVOID)(IMsoEnvelope*)this; else if (IsEqualIID(riid, IID_IMsoComponent)) *lplpObj = (LPVOID)(IMsoComponent*)this; else if (IsEqualIID(riid, IID_IPersistMime)) *lplpObj = (LPVOID)(LPPERSISTMIME)this; else if (IsEqualIID(riid, IID_IOleCommandTarget)) *lplpObj = (LPVOID)(LPOLECOMMANDTARGET)this; else if (IsEqualIID(riid, IID_IDropTarget)) *lplpObj = (LPVOID)(IDropTarget*)this; else if (IsEqualIID(riid, IID_IFontCacheNotify)) *lplpObj = (LPVOID)(IFontCacheNotify*)this; else return E_NOINTERFACE; AddRef(); return NOERROR; } // IOleCommandTarget HRESULT CNoteHdr::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pCmdText) { ULONG ul; HWND hwndFocus = GetFocus(); DWORD dwFlags = 0; BOOL fFound = FALSE; if (!rgCmds) return E_INVALIDARG; for (int i=0; i<(int)m_cHCI; i++) { // if it's in our control-list and not a combobox if (hwndFocus == GetDlgItem(m_hwnd, m_rgHCI[i].idEdit) && !(m_rgHCI[i].dwFlags & HCF_COMBO)) { GetEditDisableFlags(hwndFocus, &dwFlags); fFound = TRUE; break; } } if (pguidCmdGroup == NULL) { for (ul=0;ulHrIsDirty()==S_OK); if (fDirty) rgCmds[ul].cmdf = MSOCMDF_ENABLED; else rgCmds[ul].cmdf = 0; } break; case MSOEENVCMDID_SEND: case MSOEENVCMDID_CHECKNAMES: case MSOEENVCMDID_AUTOCOMPLETE: case MSOEENVCMDID_SETACTION: case MSOEENVCMDID_PRIORITY: rgCmds[ul].cmdf = MSOCMDF_ENABLED; break; default: rgCmds[ul].cmdf = 0; break; } } return NOERROR; } return OLECMDERR_E_UNKNOWNGROUP; } // IOleCommandTarget HRESULT CNoteHdr::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdExecOpt, VARIANTARG *pvaIn, VARIANTARG *pvaOut) { HRESULT hr = NOERROR; HWND hwndFocus; UINT msg = 0; WPARAM wParam = 0; LPARAM lParam = 0; BOOL fOfficeCmd=FALSE; if (pguidCmdGroup == NULL) { switch (nCmdID) { case OLECMDID_CUT: msg = WM_CUT; break; case OLECMDID_PASTE: msg = WM_PASTE; break; case OLECMDID_COPY: msg = WM_COPY; break; case OLECMDID_UNDO: msg = WM_UNDO; break; case OLECMDID_SELECTALL: msg = EM_SETSEL; lParam = (LPARAM)(INT)-1; break; case OLECMDID_CLEARSELECTION: msg = WM_CLEAR; break; default: hr = _ConvertOfficeCmdIDToOE(&nCmdID); if (hr==S_OK) { //if sucess, nCmdId now points to an OE command fOfficeCmd = TRUE; goto oe_cmd; } else hr = OLECMDERR_E_NOTSUPPORTED; } if (0 != msg) { hwndFocus = GetFocus(); if (IsChild(m_hwnd, hwndFocus)) SendMessage(hwndFocus, msg, wParam, lParam); } return hr; } else if (IsEqualGUID(*pguidCmdGroup, CGID_Envelope)) { oe_cmd: switch (nCmdID) { case MSOEENVCMDID_ATTACHFILE: if (m_lpAttMan) m_lpAttMan->WMCommand(0, ID_INSERT_ATTACHMENT, NULL); break; case MSOEENVCMDID_FOCUSTO: ::SetFocus(GetDlgItem(m_hwnd, idADTo)); break; case MSOEENVCMDID_FOCUSCC: ::SetFocus(GetDlgItem(m_hwnd, idADCc)); break; case MSOEENVCMDID_FOCUSSUBJ: ::SetFocus(GetDlgItem(m_hwnd, idTXTSubject)); break; case MSOEENVCMDID_SEND: if (MSOCMDEXECOPT_DONTPROMPTUSER == nCmdExecOpt) m_fSendImmediate = TRUE; else m_fSendImmediate = FALSE; hr = HrSend(); break; case MSOEENVCMDID_NEWS: m_fMail = FALSE; break; case MSOEENVCMDID_CHECKNAMES: hr = HrCheckNames((MSOCMDEXECOPT_PROMPTUSER == nCmdExecOpt)? FALSE: TRUE, TRUE); if (!m_fMail) { hr = HrCheckGroups(FALSE); if (hrNoRecipients == hr) hr = S_OK; } break; case MSOEENVCMDID_AUTOCOMPLETE: m_fAutoComplete = TRUE; break; case MSOEENVCMDID_VIEWCONTACTS: hr = HrViewContacts(); break; case MSOEENVCMDID_DIGSIGN: hr = HrHandleSecurityIDMs(TRUE); break; case MSOEENVCMDID_ENCRYPT: hr = HrHandleSecurityIDMs(FALSE); break; case MSOEENVCMDID_SETACTION: if (pvaIn->vt == VT_I4) m_ntNote = pvaIn->lVal; break; case MSOEENVCMDID_SELECTRECIPIENTS: hr = HrPickNames(0); break; case MSOEENVCMDID_ADDSENDER: hr = HrAddSender(); break; case MSOEENVCMDID_ADDALLONTO: hr = HrAddAllOnToList(); break; case MSOEENVCMDID_PICKNEWSGROUPS: if (!m_fMail) { if (idTXTFollowupTo == GetWindowLong(GetFocus(), GWL_ID)) OnButtonClick(idbtnFollowup); else OnButtonClick(idbtnTo); } break; case MSOEENVCMDID_VCARD: m_fVCard = !m_fVCard; hr = HrOnOffVCard(); break; case MSOEENVCMDID_DIRTY: _ClearDirtyFlag(); break; default: hr = OLECMDERR_E_NOTSUPPORTED; } // suppress OE errors when running under office-envelope if (fOfficeCmd && hr != OLECMDERR_E_NOTSUPPORTED) hr = S_OK; return hr; } return OLECMDERR_E_UNKNOWNGROUP; } BOOL CNoteHdr::IsReplyNote() { return (m_ntNote==OENA_REPLYTOAUTHOR || m_ntNote==OENA_REPLYTONEWSGROUP || m_ntNote==OENA_REPLYALL); } ////////////////////////////////////////////////////////////////////////////// // IPersistMime::Load // before calling this function, need to set m_ntNote by MSOEENVCMDID_SETACTION. HRESULT CNoteHdr::Load(LPMIMEMESSAGE pMsg) { HRESULT hr=S_OK; HCHARSET hCharset = NULL; PROPVARIANT var; Assert(pMsg); if (!pMsg) return E_INVALIDARG; m_fStillLoading = TRUE; m_fSkipLayout = TRUE; m_fHandleChange = TRUE; ReplaceInterface(m_pMsg, pMsg); pMsg->GetCharset(&hCharset); // bug #43295 // If we are in same codepages, we can pass FALSE to UpdateCharSetFont(). // But if we are in the differnet codepages, we need to update font to // display the header (decoded) in the correct codepage. // UpdateCharSetFonts(hCharset, FALSE); if (hCharset) HrUpdateCharSetFonts(hCharset, hCharset != m_hCharset); // If there is an account set in the message, make sure that we use it. var.vt = VT_LPSTR; if (SUCCEEDED(pMsg->GetProp(PIDTOSTR(PID_ATT_ACCOUNTID), NOFLAGS, &var))) { IImnAccount *pAcct = NULL; if (SUCCEEDED(g_pAcctMan->FindAccount(AP_ACCOUNT_ID, var.pszVal, &pAcct))) { HWND hwndCombo = GetDlgItem(m_hwnd, idFromCombo); if (hwndCombo) { int cEntries = ComboBox_GetCount(hwndCombo); for (int i = 0; i < cEntries; i++) { LPSTR idStr = (LPSTR)ComboBox_GetItemData(hwndCombo, i); if (0 == lstrcmp(idStr, var.pszVal)) { ComboBox_SetCurSel(hwndCombo, i); m_iCurrComboIndex = i; ReplaceInterface(m_pAccount, pAcct); break; } } } else ReplaceInterface(m_pAccount, pAcct); pAcct->Release(); } SafeMemFree(var.pszVal); } HrInitSecurity(); HrUpdateSecurity(pMsg); // Modify subject if need to add a Fw: or a Re: if (m_ntNote==OENA_FORWARD || IsReplyNote()) HrSetReplySubject(pMsg, OENA_FORWARD != m_ntNote); else HrSetupNote(pMsg); SetReferences(pMsg); if (m_fMail) hr = HrSetMailRecipients(pMsg); else hr = HrSetNewsRecipients(pMsg); if (OENA_READ == m_ntNote) _SetEmptyFieldStrings(); // Update fiels, which depends from language _UpdateTextFields(FALSE); // setup priority, default to normal if a reply if (!IsReplyNote()) HrSetPri(pMsg); // on reply's auto add to the wab else HrAutoAddToWAB(); HrClearUndoStack(); m_fSkipLayout = FALSE; ReLayout(); m_fDirty=FALSE; if (m_pHeaderSite) m_pHeaderSite->Update(); return hr; } void CNoteHdr::_SetEmptyFieldStrings(void) { PHCI phci = m_rgHCI; AssertSz((OENA_READ == m_ntNote), "Should only get here in a read note."); // No longer want EN_CHANGE messages to be handled in the richedits. At this // point we will be setting text in the edits but don't want the phci->fEmpty // to be set. That message causes the phci->fEmpty to be set. m_fHandleChange = FALSE; for (int i = 0; (ULONG)i < m_cHCI; i++, phci++) if (phci->fEmpty) { if (0 == (phci->dwFlags & (HCF_COMBO|HCF_ATTACH))) HdrSetRichEditText(GetDlgItem(m_hwnd, phci->idEdit), phci->szEmpty, FALSE); else SetWindowTextWrapW(GetDlgItem(m_hwnd, phci->idEdit), phci->szEmpty); } } HRESULT CNoteHdr::_AttachVCard(IMimeMessage *pMsg) { HRESULT hr = 0; LPWAB lpWab = 0; TCHAR szVCardName[MAX_PATH], szTempDir[MAX_PATH], szVCardTempFile[MAX_PATH], szVCFName[MAX_PATH]; UINT uFile=0; INT iLen=0; LPTSTR lptstr = NULL; LPSTREAM pstmFile=NULL, pstmCopy=NULL; *szVCardName = 0; *szTempDir = 0; *szVCardTempFile = 0; *szVCFName = 0; if (m_lpAttMan && (S_OK == m_lpAttMan->HrCheckVCardExists(m_fMail))) goto error; hr = HrCreateWabObject(&lpWab); if(FAILED(hr)) goto error; GetOption(m_fMail?OPT_MAIL_VCARDNAME:OPT_NEWS_VCARDNAME, szVCardName, MAX_PATH); if(*szVCardName == '\0') { hr = E_FAIL; goto error; } GetTempPath(sizeof(szTempDir), szTempDir); uFile = GetTempFileName(szTempDir, "VCF", 0, szVCardTempFile); if (uFile == 0) { hr = E_FAIL; goto error; } hr = lpWab->HrCreateVCardFile(szVCardName, szVCardTempFile); if(FAILED(hr)) goto error; hr = OpenFileStream((LPSTR)szVCardTempFile, OPEN_EXISTING, GENERIC_READ, &pstmFile); if(FAILED(hr)) goto error; hr = MimeOleCreateVirtualStream(&pstmCopy); if(FAILED(hr)) goto error; hr = HrCopyStream(pstmFile, pstmCopy, NULL); if(FAILED(hr)) goto error; wnsprintf(szVCFName, ARRAYSIZE(szVCFName), "%s%s", szVCardName, ".vcf"); hr = pMsg->AttachFile(szVCFName, pstmCopy, FALSE); if(FAILED(hr)) goto error; error: ReleaseObj(pstmFile); ReleaseObj(pstmCopy); ReleaseObj(lpWab); DeleteFile(szVCardTempFile); return hr; } // IPersistMime::Save HRESULT CNoteHdr::Save(LPMIMEMESSAGE pMsg, DWORD dwFlags) { HRESULT hr = NOERROR; BOOL fSkipCheck = FALSE; Assert(m_lpWabal); // If sending, then previously did a CheckNames passing FALSE. If get here, // then either all the names are resolved, or we are not sending so don't care // what error codes are returned. HrCheckNames(TRUE, FALSE); // RAID 41350. If the save fails after leaving the header, the header // recipients might be in a bad state. Make sure that they are resolved again // after the save. m_fAddressesChanged = TRUE; // Is the security inited??? if(dwFlags != 0) m_fSecurityInited = FALSE; // This call will check if the dialog has been shown or if we are not mime and // therefore should not show the dialog either. if (m_pHeaderSite) fSkipCheck = (S_OK != m_pHeaderSite->CheckCharsetConflict()); if (fSkipCheck) { IF_FAILEXIT(hr = _UnicodeSafeSave(pMsg, FALSE)); // Ignore any charset conflict errors. hr = S_OK; } else { IF_FAILEXIT(hr = _UnicodeSafeSave(pMsg, TRUE)); if (MIME_S_CHARSET_CONFLICT == hr) { int ret; PROPVARIANT Variant; HCHARSET hCharset; // Setup the Variant Variant.vt = VT_UI4; if (m_pEnvelopeSite && m_fShowedUnicodeDialog) ret = m_iUnicodeDialogResult; else { ret = IntlCharsetConflictDialogBox(); if (m_pEnvelopeSite) { m_fShowedUnicodeDialog = TRUE; m_iUnicodeDialogResult = ret; } } // Save As Is... if (ret == IDOK) { IF_FAILEXIT(hr = _UnicodeSafeSave(pMsg, FALSE)); // User choose to send as is. Bail out and pretend no charset conflict hr = S_OK; } // Save as Unicode else if (ret == idcSendAsUnicode) { // User choose to send as Unicode (UTF8). set new charset and resnd hCharset = GetMimeCharsetFromCodePage(CP_UTF8); if (m_pHeaderSite) m_pHeaderSite->ChangeCharset(hCharset); else { pMsg->SetCharset(hCharset, CSET_APPLY_ALL); ChangeLanguage(m_pMsg); // bobn [6/23/99] Raid 77019 // If we switch to unicode and we're a word note, we // need to remember that we're unicode so that we // will not have the body encoding out of sync with // the header encoding if (m_pEnvelopeSite) m_hCharset = hCharset; } IF_FAILEXIT(hr = _UnicodeSafeSave(pMsg, FALSE)); Assert(MIME_S_CHARSET_CONFLICT != hr); } else { // return to edit mode and bail out hr = MAPI_E_USER_CANCEL; goto exit; } } else { IF_FAILEXIT(hr = _UnicodeSafeSave(pMsg, FALSE)); Assert(MIME_S_CHARSET_CONFLICT != hr); } } exit: return hr; } HRESULT CNoteHdr::_UnicodeSafeSave(IMimeMessage *pMsg, BOOL fCheckConflictOnly) { HRESULT hr = S_OK; UINT cpID = 0; WCHAR wsz[cchMaxSubject+1]; PROPVARIANT rVariant; SYSTEMTIME st; HdrGetRichEditText(GetDlgItem(m_hwnd, idTXTSubject), wsz, ARRAYSIZE(wsz), FALSE); // All checks in here had better exit if get a MIME_S_CHARSET_CONFLICT if (fCheckConflictOnly) { HCHARSET hCharSet; BOOL fGetDefault = TRUE; // Get charset for header if (m_pHeaderSite) { if (SUCCEEDED(m_pHeaderSite->GetCharset(&hCharSet))) { cpID = CustomGetCPFromCharset(hCharSet, FALSE); fGetDefault = FALSE; } } // Get default charset if didn't get one from header if (fGetDefault) { pMsg->GetCharset(&hCharSet); cpID = CustomGetCPFromCharset(hCharSet, FALSE); } // If we are unicode, then there is no need to check because // we will always work, so exit. if (CP_UTF7 == cpID || CP_UTF8 == cpID || CP_UNICODE == cpID) goto exit; IF_FAILEXIT(hr = HrSetSenderInfoUtil(pMsg, m_pAccount, m_lpWabal, m_fMail, cpID, TRUE)); if (MIME_S_CHARSET_CONFLICT == hr) goto exit; IF_FAILEXIT(hr = HrSafeToEncodeToCP(wsz, cpID)); if (MIME_S_CHARSET_CONFLICT == hr) goto exit; if (m_pszRefs) { IF_FAILEXIT(hr = HrSafeToEncodeToCP(m_pszRefs, cpID)); if (MIME_S_CHARSET_CONFLICT == hr) goto exit; } IF_FAILEXIT(hr = HrCheckDisplayNames(m_lpWabal, cpID)); if (MIME_S_CHARSET_CONFLICT == hr) goto exit; if (m_lpAttMan) { IF_FAILEXIT(hr = m_lpAttMan->CheckAttachNameSafeWithCP(cpID)); if (MIME_S_CHARSET_CONFLICT == hr) goto exit; } if (!m_fMail) { IF_FAILEXIT(hr = HrNewsSave(pMsg, cpID, TRUE)); if (MIME_S_CHARSET_CONFLICT == hr) goto exit; } // this checking produced a 4 bugs in OE 5.01 and 5.5 and I disaable it (YST) #ifdef YST if (m_pEnvelopeSite) { IF_FAILEXIT(hr = _CheckMsoBodyCharsetConflict(cpID)); if (MIME_S_CHARSET_CONFLICT == hr) goto exit; } #endif } else { // ************************ // This portion only happens on save, so don't try to do for fCheckConflictOnly // Anything not in this section had better be mirrored in the fCheckConflictOnly block above IF_FAILEXIT(hr = HrSetAccountByAccount(pMsg, m_pAccount)); if (m_fVCard) { HWND hwndFocus=GetFocus(); hr = _AttachVCard(pMsg); if (FAILED(hr)) { if (AthMessageBoxW(m_hwnd, MAKEINTRESOURCEW(m_fMail?idsAthenaMail:idsAthenaNews), MAKEINTRESOURCEW(idsErrAttachVCard), NULL, MB_YESNO | MB_ICONEXCLAMATION ) != IDYES) { ::SetFocus(hwndFocus); IF_FAILEXIT(hr); } } } // set the time rVariant.vt = VT_FILETIME; GetSystemTime(&st); SystemTimeToFileTime(&st, &rVariant.filetime); pMsg->SetProp(PIDTOSTR(PID_ATT_SENTTIME), 0, &rVariant); // Priority if (m_pri!=priNone) { rVariant.vt = VT_UI4; rVariant.ulVal = priLookup[m_pri]; pMsg->SetProp(PIDTOSTR(PID_ATT_PRIORITY), 0, &rVariant); } IF_FAILEXIT(hr = HrSaveSecurity(pMsg)); // end of save only portion. // ************************* m_lpWabal->DeleteRecipType(MAPI_ORIG); IF_FAILEXIT(hr = HrSetSenderInfoUtil(pMsg, m_pAccount, m_lpWabal, m_fMail, 0, FALSE)); IF_FAILEXIT(hr = MimeOleSetBodyPropW(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_SUBJECT), NOFLAGS, wsz)); if (m_pszRefs) IF_FAILEXIT(hr = MimeOleSetBodyPropW(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_REFS), NOFLAGS, m_pszRefs)); // This must be called after HrSaveSecurity IF_FAILEXIT(hr = HrSetWabalOnMsg(pMsg, m_lpWabal)); if (m_lpAttMan) IF_FAILEXIT(hr = m_lpAttMan->Save(pMsg, 0)); if (!m_fMail) IF_FAILEXIT(hr = HrNewsSave(pMsg, cpID, FALSE)); } exit: return hr; } // IPersist::GetClassID HRESULT CNoteHdr::GetClassID(CLSID *pClsID) { //TODO: *pClsID = CLSID_OEEnvelope; return NOERROR; } ////////////////////////////////////////////////////////////////////////////// // IHeader::SetRect HRESULT CNoteHdr::SetRect(LPRECT prc) { MoveWindow(m_hwnd, prc->left, prc->top, prc->right-prc->left, prc->bottom - prc->top, TRUE); return NOERROR; } // IHeader::GetRect HRESULT CNoteHdr::GetRect(LPRECT prcView) { GetRealClientRect(m_hwnd, prcView); return NOERROR; } // IHeader::Init HRESULT CNoteHdr::Init(IHeaderSite* pHeaderSite, HWND hwndParent) { if (pHeaderSite==NULL || hwndParent==NULL) return E_INVALIDARG; m_pHeaderSite = pHeaderSite; m_pHeaderSite->AddRef(); m_hwndParent = hwndParent; return HrInit(NULL); } // IHeader::SetPriority HRESULT CNoteHdr::SetPriority(UINT pri) { RECT rc; if ((UINT)m_pri != pri) { m_pri = pri; InvalidateStatus(); ReLayout(); SetDirtyFlag(); } return NOERROR; } // IHeader::GetPriority HRESULT CNoteHdr::GetPriority(UINT* ppri) { *ppri = m_pri; return NOERROR; } // Update fiels, which depends from language void CNoteHdr::_UpdateTextFields(BOOL fSetWabal) { LPWSTR lpszOrg = NULL, lpszSubj = NULL, lpszKeywords = NULL; if (IsReadOnly()) { // if it's a readnote, reload the header that depend on a charset MimeOleGetBodyPropW(m_pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_SUBJECT), NOFLAGS, &lpszSubj); MimeOleGetBodyPropW(m_pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_KEYWORDS), NOFLAGS, &lpszKeywords); MimeOleGetBodyPropW(m_pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_ORG), NOFLAGS, &lpszOrg); if(lpszOrg) { HdrSetRichEditText(GetDlgItem(m_hwnd, idTXTOrg), lpszOrg, FALSE); MemFree(lpszOrg); } if(lpszKeywords) { HdrSetRichEditText(GetDlgItem(m_hwnd, idTXTKeywords), lpszKeywords, FALSE); MemFree(lpszKeywords); } if(lpszSubj) { HdrSetRichEditText(GetDlgItem(m_hwnd, idTXTSubject), lpszSubj, FALSE); MemFree(lpszSubj); } if (fSetWabal) { LPWABAL lpWabal = NULL; Assert(m_hwnd); Assert(m_pMsg); Assert(m_lpWabal); if (SUCCEEDED(HrGetWabalFromMsg(m_pMsg, &lpWabal))) { ReplaceInterface(m_lpWabal, lpWabal); if (SUCCEEDED(m_pAddrWells->HrSetWabal(m_lpWabal))) { m_lpWabal->HrResolveNames(NULL, FALSE); m_pAddrWells->HrDisplayWells(m_hwnd); } } ReleaseObj(lpWabal); } m_fDirty = FALSE; // don't make dirty if a readnote } } // IHeader::ChangeLanguage HRESULT CNoteHdr::ChangeLanguage(LPMIMEMESSAGE pMsg) { HCHARSET hCharset=NULL; if (!pMsg) return E_INVALIDARG; pMsg->GetCharset(&hCharset); // Update fields, which depends from language _UpdateTextFields(TRUE); // update the fonts scripts etc HrUpdateCharSetFonts(hCharset, TRUE); // notify the addr wells that the font need to change m_pAddrWells->OnFontChange(); return S_OK; } HRESULT CNoteHdr::OnPreFontChange() { HWND hwndFrom=GetDlgItem(m_hwnd, idFromCombo); if (hwndFrom) SendMessage(hwndFrom, WM_SETFONT, 0, 0); return S_OK; } HRESULT CNoteHdr::OnPostFontChange() { ULONG cxNewLeftMargin = _GetLeftMargin(); HWND hwndFrom=GetDlgItem(m_hwnd, idFromCombo); HFONT hFont; HWND hwndBlock = HwndStartBlockingPaints(m_hwnd); BOOL fLayout=FALSE; if (g_pFieldSizeMgr->FontsChanged() || (m_cxLeftMargin != cxNewLeftMargin)) { m_cxLeftMargin = cxNewLeftMargin; fLayout=TRUE; } // update the fonts ChangeLanguage(m_pMsg); // update the account combo if (hwndFrom && g_lpIFontCache && g_lpIFontCache->GetFont(FNT_SYS_ICON, NULL, &hFont)==S_OK) SendMessage(hwndFrom, WM_SETFONT, (WPARAM)hFont, 0); if (fLayout) ReLayout(); if (hwndBlock) StopBlockingPaints(hwndBlock); return S_OK; } // IHeader::GetTitle HRESULT CNoteHdr::GetTitle(LPWSTR pwszTitle, ULONG cch) { // Locals static WCHAR s_wszNoteTitle[cchHeaderMax+1] = L""; static DWORD s_cLenTitle = 0; INETCSETINFO CsetInfo; UINT uiCodePage = 0; HRESULT hr = S_OK; LPWSTR pwszLang = NULL; BOOL fWinNT = g_OSInfo.dwPlatformId == VER_PLATFORM_WIN32_NT; if (pwszTitle==NULL || cch==0) return E_INVALIDARG; if (*s_wszNoteTitle == L'\0') { if (fWinNT) { AthLoadStringW(idsNoteLangTitle, s_wszNoteTitle, ARRAYSIZE(s_wszNoteTitle)); // -4 for the %1 and %2 that will be replaced s_cLenTitle = lstrlenW(s_wszNoteTitle) - 4; } else { AthLoadStringW(idsNoteLangTitle9x, s_wszNoteTitle, ARRAYSIZE(s_wszNoteTitle)); // -2 for the %s that will be replaced s_cLenTitle = lstrlenW(s_wszNoteTitle) - 2; } } if (m_hCharset) { MimeOleGetCharsetInfo(m_hCharset,&CsetInfo); uiCodePage = CsetInfo.cpiWindows; } if (uiCodePage == 0 || uiCodePage == GetACP()) { HdrGetRichEditText(GetDlgItem(m_hwnd, idTXTSubject), pwszTitle, cch-1, FALSE); if (0 == *pwszTitle) AthLoadStringW((OENA_READ == m_ntNote) ? idsNoSubject : idsNewNote, pwszTitle, cch-1); ConvertTabsToSpacesW(pwszTitle); } else { AssertSz(cch > (ARRAYSIZE(CsetInfo.szName) + s_cLenTitle), "Won't fit language. Get bigger cch!!!"); // if no lang pack then s_szLastLang is empty and we need to try to restore message header IF_NULLEXIT(pwszLang = PszToUnicode(CP_ACP, *m_szLastLang ? m_szLastLang : CsetInfo.szName)); if (fWinNT) { WCHAR wszSubj[cchHeaderMax+1]; DWORD cchLang, cchTotal, cchSubj; LPSTR pArgs[2]; *wszSubj = 0; HdrGetRichEditText(GetDlgItem(m_hwnd, idTXTSubject), wszSubj, ARRAYSIZE(wszSubj), FALSE); if (0 == *wszSubj) AthLoadStringW((OENA_READ == m_ntNote) ? idsNoSubject : idsNewNote, wszSubj, ARRAYSIZE(wszSubj)); ConvertTabsToSpacesW(wszSubj); cchSubj = lstrlenW(wszSubj); cchLang = lstrlenW(pwszLang); cchTotal = s_cLenTitle + cchLang + cchSubj + 1; // If too big, truncate the subject, not language since // asserting that we have enough for language. if (cchTotal > cch) { cchSubj -= (cchTotal - cch); wszSubj[cchSubj] = L'\0'; } pArgs[0] = (LPSTR)wszSubj; pArgs[1] = (LPSTR)pwszLang; *pwszTitle = L'\0'; FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY, s_wszNoteTitle, 0, 0, pwszTitle, cch, (va_list*)pArgs); } else { wnsprintfW(pwszTitle, cch, s_wszNoteTitle, pwszLang); } } exit: MemFree(pwszLang); return hr; } void CNoteHdr::_AddRecipTypeToMenu(HMENU hmenu) { ADRINFO adrInfo; WCHAR wszDisp[256]; ULONG uPos=0; BOOL fFound = m_lpWabal->FGetFirst(&adrInfo); while (fFound && (uPos < cMaxRecipMenu)) { if (adrInfo.lRecipType==MAPI_TO || adrInfo.lRecipType==MAPI_CC) { if(lstrlenW(adrInfo.lpwszDisplay) > 255) { StrCpyNW(wszDisp, adrInfo.lpwszDisplay, 255); wszDisp[255] = '\0'; } else { StrCpyNW(wszDisp, adrInfo.lpwszDisplay, ARRAYSIZE(wszDisp)); } AppendMenuWrapW(hmenu, MF_STRING , ID_ADD_RECIPIENT_FIRST+uPos, wszDisp); uPos++; } fFound = m_lpWabal->FGetNext(&adrInfo); } } // IHeader::UpdateRecipientMenu HRESULT CNoteHdr::UpdateRecipientMenu(HMENU hmenu) { HRESULT hr = E_FAIL; BOOL fSucceeded = TRUE; // destory current recipients while (fSucceeded) fSucceeded = DeleteMenu(hmenu, 2, MF_BYPOSITION); if (!m_lpWabal) return E_FAIL; // Add To: and Cc: people _AddRecipTypeToMenu(hmenu); return NOERROR; } // IHeader::SetInitFocus HRESULT CNoteHdr::SetInitFocus(BOOL fSubject) { if (m_rgHCI) { if (fSubject) ::SetFocus(GetDlgItem(m_hwnd, idTXTSubject)); else { if (0 == (m_rgHCI[0].dwFlags & HCF_COMBO)) ::SetFocus(GetDlgItem(m_hwnd, m_rgHCI[0].idEdit)); else ::SetFocus(GetDlgItem(m_hwnd, m_rgHCI[1].idEdit)); } } return NOERROR; } // IHeader::SetVCard HRESULT CNoteHdr::SetVCard(BOOL fFresh) { HRESULT hr = NOERROR; TCHAR szBuf[MAX_PATH]; LPWAB lpWab = NULL; ULONG cbEID=0; LPENTRYID lpEID = NULL; WORD wVCard; if (m_ntNote == OENA_READ) wVCard = (m_lpAttMan->HrFVCard() == S_OK) ? VCardTRUE : VCardFALSE; else if (!fFresh) //not a fresh note. wVCard = VCardFALSE; else if (m_ntNote == OENA_FORWARD) wVCard = (m_lpAttMan->HrCheckVCardExists(m_fMail) == S_OK) ? VCardFALSE : VCardDONTKNOW; else wVCard = VCardDONTKNOW; if (wVCard != VCardDONTKNOW) m_fVCard = wVCard; else { hr = HrGetVCardName(szBuf, sizeof(szBuf)); if (FAILED(hr)) // no vcard name selected { if (m_fMail) SetDwOption(OPT_MAIL_ATTACHVCARD, FALSE, NULL, 0); else SetDwOption(OPT_NEWS_ATTACHVCARD, FALSE, NULL, 0); } if (m_fMail) m_fVCard = (BOOL)DwGetOption(OPT_MAIL_ATTACHVCARD); else m_fVCard = (BOOL)DwGetOption(OPT_NEWS_ATTACHVCARD); } hr = HrOnOffVCard(); if (FAILED(hr)) goto error; error: ReleaseObj(lpWab); return hr; } // IHeader::IsSecured HRESULT CNoteHdr::IsSecured() { if (m_fDigSigned || m_fEncrypted) return S_OK; else return S_FALSE; } HRESULT CNoteHdr::IsHeadSigned() { if (m_fDigSigned) return S_OK; else return S_FALSE; } // set ForvrEncryption form policy module if fSet is TRUE // if fSet is not set then returns S_FALSE if ForceEncryption was not set HRESULT CNoteHdr::ForceEncryption(BOOL *fEncrypt, BOOL fSet) { HRESULT hr = S_FALSE; if(fSet) { Assert(fEncrypt); if(m_fDigSigned) { if(*fEncrypt) m_fEncrypted = TRUE; } m_fForceEncryption = *fEncrypt; if(m_ntNote != OENA_READ) HrUpdateSecurity(); hr = S_OK; } else if(m_fForceEncryption && m_fDigSigned) { m_fEncrypted = TRUE; hr = S_OK; } return(hr); } // IHeader::AddRecipient HRESULT CNoteHdr::AddRecipient(int idOffset) { BOOL fFound; ULONG uPos=0; ADRINFO adrInfo; LPADRINFO lpAdrInfo=0; LPWAB lpWab; HRESULT hr=E_FAIL; Assert(m_lpWabal); fFound = m_lpWabal->FGetFirst(&adrInfo); while (fFound && (uPos < cMaxRecipMenu)) { if (idOffset==-1 && adrInfo.lRecipType==MAPI_ORIG) { lpAdrInfo=&adrInfo; break; } if (adrInfo.lRecipType==MAPI_TO || adrInfo.lRecipType==MAPI_CC) { if (idOffset==(int)uPos) { lpAdrInfo=&adrInfo; break; } uPos++; } fFound=m_lpWabal->FGetNext(&adrInfo); } if (lpAdrInfo && !FAILED (HrCreateWabObject (&lpWab))) { hr=lpWab->HrAddToWAB(m_hwnd, lpAdrInfo); lpWab->Release (); } if (FAILED(hr) && hr!=MAPI_E_USER_CANCEL) { if (hr==MAPI_E_COLLISION) AthMessageBoxW(m_hwnd, MAKEINTRESOURCEW(idsAthenaMail), MAKEINTRESOURCEW(idsErrAddrDupe), NULL, MB_OK); else AthMessageBoxW(m_hwnd, MAKEINTRESOURCEW(idsAthenaMail), MAKEINTRESOURCEW(idsErrAddToWAB), NULL, MB_OK); } return NOERROR; } // IHeader::OnDocumentReady HRESULT CNoteHdr::OnDocumentReady(LPMIMEMESSAGE pMsg) { HRESULT hr = S_OK; m_fStillLoading = FALSE; if (m_lpAttMan) hr = m_lpAttMan->Load(pMsg); return hr; } // IHeader::DropFiles HRESULT CNoteHdr::DropFiles(HDROP hDrop, BOOL fMakeLinks) { HRESULT hr = S_OK; if (m_lpAttMan) hr = m_lpAttMan->HrDropFiles(hDrop, fMakeLinks); return hr; } ////////////////////////////////////////////////////////////////////////////// // IMsoEnvelope:Init HRESULT CNoteHdr::Init(IUnknown* punk, IMsoEnvelopeSite* pesit, DWORD grfInit) { HRESULT hr = S_OK; if (punk == NULL && pesit == NULL && grfInit == 0) { SafeRelease(m_pEnvelopeSite); hr = E_FAIL; goto Exit; } if (pesit==NULL) { hr = E_INVALIDARG; goto Exit; } ReplaceInterface(m_pEnvelopeSite, pesit); hr = HrInit(NULL); if (FAILED(hr)) goto Exit; if (grfInit & ENV_INIT_FROMSTREAM) { IStream *pstm = NULL; // no IStream to work with? if (!punk) return E_INVALIDARG; hr = punk->QueryInterface(IID_IStream, (LPVOID*)&pstm); if (!FAILED(hr)) { hr = _LoadFromStream(pstm); pstm->Release(); } } _SetButtonText(ID_SEND_NOW, MAKEINTRESOURCE((grfInit & ENV_INIT_DOCBEHAVIOR)?idsEnvSendCopy:idsEnvSend)); Exit: return hr; } // IMsoEnvelope::SetParent // we create the envelope window here HRESULT CNoteHdr::SetParent(HWND hwndParent) { Assert (IsWindow(m_hwnd)); ShowWindow(m_hwnd, hwndParent ? SW_SHOW : SW_HIDE); if (hwndParent) { _RegisterWithComponentMgr(TRUE); _RegisterAsDropTarget(TRUE); _RegisterWithFontCache(TRUE); } else { _RegisterWithComponentMgr(FALSE); _RegisterAsDropTarget(FALSE); _RegisterWithFontCache(FALSE); } m_hwndParent = hwndParent?hwndParent:g_hwndInit; ::SetParent(m_hwnd, m_hwndParent); if (hwndParent) ReLayout(); return S_OK; } // IMsoEnvelope::Resize HRESULT CNoteHdr::Resize(LPCRECT prc) { MoveWindow(m_hwnd, prc->left, prc->top, prc->right - prc->left, prc->bottom - prc->top, TRUE); return NOERROR; } // IMsoEnvelope::Show HRESULT CNoteHdr::Show(BOOL fShow) { ShowWindow(m_hwnd, fShow ? SW_SHOW : SW_HIDE); return NOERROR; } // IMsoEnvelope::SetHelpMode HRESULT CNoteHdr::SetHelpMode(BOOL fEnter) { return NOERROR; } // IMsoEnvelope::Save HRESULT CNoteHdr::Save(IStream* pstm, DWORD grfSave) { HRESULT hr = S_OK; IMimeMessage *pMsg = NULL; PERSISTHEADER rPersistHdr; if (pstm == NULL) return E_INVALIDARG; hr = WriteClassStm(pstm, CLSID_OEEnvelope); if (!FAILED(hr)) { ZeroMemory(&rPersistHdr, sizeof(PERSISTHEADER)); rPersistHdr.cbSize = sizeof(PERSISTHEADER); hr = pstm->Write(&rPersistHdr, sizeof(PERSISTHEADER), NULL); if (!FAILED(hr)) { hr = HrCreateMessage(&pMsg); if (!FAILED(hr)) { hr = Save(pMsg, 0); if (!FAILED(hr)) hr = pMsg->Save(pstm, FALSE); pMsg->Release(); } } } _ClearDirtyFlag(); return hr; } // IMsoEnvelope::GetAttach HRESULT CNoteHdr::GetAttach(const WCHAR* wszName,IStream** ppstm) { return NOERROR; } HRESULT CNoteHdr::SetAttach(const WCHAR* wszName, const WCHAR *wszCID, IStream **ppstm, DWORD *pgrfAttach) { IStream *pstm=0; HBODY hBody; LPWSTR pszCntTypeW=NULL; HRESULT hr; PROPVARIANT pv; if (!m_pMsgSend) return E_FAIL; IF_FAILEXIT(hr = MimeOleCreateVirtualStream(&pstm)); IF_FAILEXIT(hr = m_pMsgSend->AttachURL(NULL, NULL, 0, pstm, NULL, &hBody)); // strip off cid: header if (StrCmpNIW(wszCID, L"CID:", 4)==0) wszCID += 4; IF_FAILEXIT(hr = MimeOleSetBodyPropW(m_pMsgSend, hBody, PIDTOSTR(PID_HDR_CNTID), 0, wszCID)); IF_FAILEXIT(hr = MimeOleSetBodyPropW(m_pMsgSend, hBody, PIDTOSTR(STR_ATT_FILENAME), 0, wszName)); FindMimeFromData(NULL, wszName, NULL, NULL, NULL, 0, &pszCntTypeW, 0); pv.vt = pszCntTypeW ? VT_LPWSTR : VT_LPSTR; if (pszCntTypeW) pv.pwszVal = pszCntTypeW; else pv.pszVal = (LPSTR)STR_MIME_APPL_STREAM; // if FindMimeFromData fails use application/octect-stream IF_FAILEXIT(hr = m_pMsgSend->SetBodyProp(hBody, PIDTOSTR(PID_HDR_CNTTYPE), 0, &pv)); *ppstm = pstm; pstm->AddRef(); exit: ReleaseObj(pstm); return hr; } // IMsoEnvelope::NewAttach HRESULT CNoteHdr::NewAttach(const WCHAR* pwzName,DWORD grfAttach) { return NOERROR; } // IMsoEnvelope::SetFocus HRESULT CNoteHdr::SetFocus(DWORD grfFocus) { if (!m_rgHCI) return S_OK; if (grfFocus & ENV_FOCUS_TAB) { // reverse tab in from word, focus on well if visible or subject if (IsWindowVisible(GetDlgItem(m_hwnd, idwAttachWell))) ::SetFocus(GetDlgItem(m_hwnd, idwAttachWell)); else ::SetFocus(GetDlgItem(m_hwnd, idTXTSubject)); } else if (grfFocus & ENV_FOCUS_INITIAL) SetInitFocus(FALSE); else if (grfFocus & ENV_FOCUS_RESTORE && m_hwndLastFocus) ::SetFocus(m_hwndLastFocus); return NOERROR; } // IMsoEnvelope::GetHeaderInfo HRESULT CNoteHdr::GetHeaderInfo(ULONG dispid, DWORD grfHeader, void** pszData) { HRESULT hr = E_FAIL; if (!pszData) return E_INVALIDARG; *pszData = NULL; if (dispid == dispidSubject) hr = HrGetFieldText((LPWSTR*)pszData, idTXTSubject); return hr; } // IMsoEnvelope::SetHeaderInfo HRESULT CNoteHdr::SetHeaderInfo(ULONG dispid, const void *pv) { HRESULT hr = S_OK; LPSTR psz = NULL; switch (dispid) { case dispidSubject: HdrSetRichEditText(GetDlgItem(m_hwnd, idTXTSubject), (LPWSTR)pv, FALSE); break; case dispidSendBtnText: { IF_NULLEXIT(psz = PszToANSI(GetACP(), (LPWSTR)pv)); _SetButtonText(ID_SEND_NOW, psz); break; } } exit: MemFree(psz); return NOERROR; } // IMsoEnvelope::IsDirty HRESULT CNoteHdr::IsDirty() { if (m_fDirty || (m_lpAttMan && (m_lpAttMan->HrIsDirty()==S_OK))) return S_OK; else return S_FALSE; } // IMsoEnvelope::GetLastError HRESULT CNoteHdr::GetLastError(HRESULT hr, WCHAR __RPC_FAR *wszBuf, ULONG cchBuf) { DWORD ids; switch (hr) { case E_NOTIMPL: ids = idsNYIGeneral; break; default: ids = idsGenericError; } AthLoadStringW(ids, wszBuf, cchBuf); return S_OK; } // IMsoEnvelope::DoDebug HRESULT CNoteHdr::DoDebug(DWORD grfDebug) { return S_OK; } //////////////////////////////////////////////////////////////////////////////////////// // IMsoComponent::FDebugMessage BOOL CNoteHdr::FDebugMessage(HMSOINST hinst, UINT message, WPARAM wParam, LPARAM lParam) { return TRUE; } // IMsoComponent::FPreTranslateMessage BOOL CNoteHdr::FPreTranslateMessage(MSG *pMsg) { HWND hwnd; BOOL fShift; // Invalid ARgs if (NULL == pMsg) return FALSE; // check if it's US, or one of our children if (pMsg->hwnd != m_hwnd && !IsChild(m_hwnd, pMsg->hwnd)) return FALSE; if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_ESCAPE && GetFocus() == m_hwndToolbar && m_hwndLastFocus) { // when focus is inthe toolbar, we're not UIActive (cheaper than subclassing to catch WM_SETFOCUS\WM_KILLFOCUS // as toolbar doesn't send NM_SETFOCUS). So we special case ESCAPE to drop the focus from the toolbar ::SetFocus(m_hwndLastFocus); return TRUE; } // check to see if we are UIActive if (!m_fUIActive) return FALSE; // check and see if it's one of our accelerators if (::TranslateAcceleratorWrapW(m_hwnd, GetAcceleratorTable(), pMsg)) return TRUE; // handle tab-key here if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_TAB) { fShift = ( GetKeyState(VK_SHIFT ) & 0x8000) != 0; if (!fShift && (GetKeyState(VK_CONTROL) & 0x8000)) { // ctrl-TAB means focus to the toolbar ::SetFocus(m_hwndToolbar); return TRUE; } hwnd = _GetNextDlgTabItem(m_hwnd, pMsg->hwnd, fShift); if (hwnd != NULL) ::SetFocus(hwnd); else if (m_pEnvelopeSite) m_pEnvelopeSite->SetFocus(TRUE); return TRUE; } // pass the accelerators to the envelopesite if (m_pEnvelopeSite && (pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST) && m_pEnvelopeSite->TranslateAccelerators(pMsg)==S_OK) return TRUE; // see if it's a message for our child controls if (pMsg->message != WM_SYSCHAR && IsDialogMessageWrapW(m_hwnd, pMsg)) return TRUE; return FALSE; } // IMsoComponent::OnEnterState void CNoteHdr::OnEnterState(ULONG uStateID, BOOL fEnter) { return; } // IMsoComponent::OnAppActivate void CNoteHdr::OnAppActivate(BOOL fActive, DWORD dwOtherThreadID) { return; } // IMsoComponent::OnLoseActivation void CNoteHdr::OnLoseActivation() { return; } // IMsoComponent::OnActivationChange void CNoteHdr::OnActivationChange(IMsoComponent *pic, BOOL fSameComponent, const MSOCRINFO *pcrinfo, BOOL fHostIsActivating, const MSOCHOSTINFO *pchostinfo, DWORD dwReserved) { return; } // IMsoComponent::FDoIdle BOOL CNoteHdr::FDoIdle(DWORD grfidlef) { return FALSE; } // IMsoComponent::FContinueMessageLoop BOOL CNoteHdr::FContinueMessageLoop(ULONG uReason, void *pvLoopData, MSG *pMsgPeeked) { return FALSE; } // IMsoComponent::FQueryTerminate BOOL CNoteHdr::FQueryTerminate(BOOL fPromptUser) { return TRUE; } // IMsoComponent::Terminate void CNoteHdr::Terminate() { _RegisterWithComponentMgr(FALSE); if (m_hwnd) DestroyWindow(m_hwnd); } // IMsoComponent::HwndGetWindow HWND CNoteHdr::HwndGetWindow(DWORD dwWhich, DWORD dwReserved) { HWND hwnd = NULL; switch (dwWhich) { case msocWindowComponent: case msocWindowDlgOwner: hwnd = m_hwnd; break; case msocWindowFrameOwner: hwnd = GetParent(m_hwnd); break; case msocWindowFrameToplevel: { if (m_pEnvelopeSite) m_pEnvelopeSite->GetFrameWnd(&hwnd); return hwnd; } } return hwnd; } // HrUpdateCharSetFonts // // Purpose: Creates the controls on the header dialog // calculates and sets up all initial coordinates // // // Comments: // HRESULT CNoteHdr::HrUpdateCharSetFonts(HCHARSET hCharset, BOOL fUpdateFields) { PHCI phci; HWND hwnd; INT iHC; TCHAR sz[cchHeaderMax+1]; BOOL fDirty=m_fDirty; INETCSETINFO rCharset; HRESULT hr = E_FAIL; // Check Params Assert(hCharset); // No font cache, bummer if (!g_lpIFontCache) return E_FAIL; // Get Charset Information if (SUCCEEDED(MimeOleGetCharsetInfo(hCharset, &rCharset))) { HFONT hHeaderFont, hSystemFont; if ((m_hCharset != hCharset) || (0 == *m_szLastLang)) { *m_szLastLang = 0; GetMimeCharsetForTitle(hCharset, NULL, m_szLastLang, ARRAYSIZE(m_szLastLang) - 1, IsReadOnly()); // Save Charset m_hCharset = hCharset; } // If don't update fields, then just return if (!fUpdateFields) return S_OK; // Get charset charformat hHeaderFont = HGetCharSetFont(FNT_SYS_ICON, hCharset); hSystemFont = GetFont(FALSE); // Loop through header fields for (iHC=0; iHC<(int)m_cHCI; iHC++) { // Get info phci = &m_rgHCI[iHC]; hwnd = GetDlgItem(m_hwnd, phci->idEdit); //Assert(hwndRE); if (!hwnd) continue; switch (phci->dwFlags & (HCF_COMBO|HCF_ATTACH)) { case HCF_COMBO: case HCF_ATTACH: SendMessage(hwnd, WM_SETFONT, (WPARAM)hSystemFont, MAKELPARAM(TRUE, 0)); break; // richedit // REVIEW: Why are we only doing a request resize when we have the USECHARSET flag set??? case 0: if (phci->dwFlags & HCF_USECHARSET) { SetFontOnRichEdit(hwnd, hHeaderFont); SendMessage(hwnd, EM_REQUESTRESIZE, 0, 0); } else { SetFontOnRichEdit(hwnd, hSystemFont); } break; default: AssertSz(FALSE, "How did we get something that is combo and attach???"); break; } } // Don't let this make the note dirty if (fDirty) SetDirtyFlag(); else m_fDirty=FALSE; hr = S_OK; } return hr; } // // WMCreate // // Purpose: Creates the controls on the header dialog // calculates and sets up all initial coordinates // // // Comments: // BOOL CNoteHdr::WMCreate() { HWND hwnd; LONG lStyleFlags, lExStyleFlags, lMask; int cy, cx, cxButtons = ControlXBufferSize(); HFONT hFont; TOOLINFO ti; PHCI phci; RECT rc; CAddrWellCB *pawcb; CHARFORMAT cfHeaderCset; HRESULT hr; LPCWSTR pwszTitle = NULL; BOOL fSubjectField; Assert(g_cyFont); // should have been setup already if (m_pEnvelopeSite) { // if we are the office-envelope, create a toolbar if (_CreateEnvToolbar()) return FALSE; } cy = ControlYBufferSize() + m_dxTBOffset; cx = 0; if (S_OK != HrInitFieldList()) return FALSE; //BROKEN: using system charformat here as not CSET info with MIMEOLE // Get charset for cset { hFont = GetFont(FALSE); if (hFont != 0) { hr = FontToCharformat(hFont, &g_cfHeader); } hFont = HGetCharSetFont(FNT_SYS_ICON, m_hCharset); if (hFont != 0) { hr = FontToCharformat(hFont, &cfHeaderCset); if (FAILED(hr)) CopyMemory (&cfHeaderCset, &g_cfHeader, sizeof (CHARFORMAT)); } else CopyMemory (&cfHeaderCset, &g_cfHeader, sizeof (CHARFORMAT)); hFont = GetFont(FALSE); } // ~~~~ Do we need to be calling this with WrapW??? // Create a tooltip, if it doesn't already exist: m_hwndTT=CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, NULL, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,CW_USEDEFAULT, m_hwnd, (HMENU) NULL, g_hInst, NULL); if (!m_hwndTT) return FALSE; ti.cbSize=sizeof(TOOLINFO); ti.hwnd=m_hwnd; ti.hinst=g_hLocRes; ti.uFlags=TTF_IDISHWND|TTF_SUBCLASS; m_lpAttMan = new CAttMan(); if (!m_lpAttMan) return FALSE; if (m_lpAttMan->HrInit(m_hwnd, m_ntNote==OENA_READ, m_ntNote==OENA_FORWARD, !DwGetOption(OPT_SECURITY_ATTACHMENT))) return FALSE; for (int iHC=0; iHC<(int)m_cHCI; iHC++) { phci=&m_rgHCI[iHC]; BOOL fIsCombo = (HCF_COMBO & phci->dwFlags); BOOL fNeedsBorder = (phci->dwFlags & HCF_BORDER); int cyCtrlSize; // if header is optional, check setting if ((phci->dwFlags & HCF_OPTIONAL) && !DwGetOption(phci->dwOpt)) continue; if (phci->dwFlags & HCF_ATTACH) { // if we're not readonly, register ourselves as a drop target... if (!(phci->dwFlags & HCF_READONLY)) { hr = _RegisterAsDropTarget(TRUE); if (FAILED(hr)) return FALSE; } continue; } phci->height = GetControlSize(fNeedsBorder, 1); // Richedit if (!fIsCombo) { pwszTitle = GetREClassStringW(); cyCtrlSize = phci->height; lStyleFlags = WS_CHILD|WS_TABSTOP|WS_VISIBLE|ES_SAVESEL; lMask=ENM_KEYEVENTS|ENM_CHANGE|ENM_SELCHANGE|ENM_REQUESTRESIZE; if (phci->dwFlags & HCF_MULTILINE) { //lStyleFlags |= ES_MULTILINE|ES_WANTRETURN|WS_VSCROLL|ES_AUTOVSCROLL; lStyleFlags |= ES_MULTILINE|WS_VSCROLL|ES_AUTOVSCROLL; } else lStyleFlags |= ES_AUTOHSCROLL; } // Combo Box else { pwszTitle = L"ComboBox"; cyCtrlSize = GetControlSize(fNeedsBorder, NUM_COMBO_LINES); lStyleFlags = WS_CHILD|WS_TABSTOP|WS_VISIBLE|WS_VSCROLL| CBS_DROPDOWNLIST|CBS_HASSTRINGS|CBS_SORT; } if (phci->dwFlags & HCF_READONLY) lStyleFlags|=ES_READONLY; GetClientRect(m_hwnd, &rc); lExStyleFlags = fNeedsBorder ? WS_EX_NOPARENTNOTIFY|WS_EX_CLIENTEDGE : WS_EX_NOPARENTNOTIFY; // @hack [dhaws] {55073} Do RTL mirroring only in special richedit versions. fSubjectField = (idsSubjectField == phci->idsLabel); RichEditRTLMirroring(m_hwnd, fSubjectField, &lExStyleFlags, TRUE); // Regardless of mirroring, BiDi-Dates should be displayed RTL if(((phci->idsLabel == idsDateField) && IsBiDiCalendar())) lExStyleFlags |= WS_EX_RTLREADING; hwnd = CreateWindowExWrapW(lExStyleFlags, pwszTitle, NULL, lStyleFlags, cx, cy, rc.right, cyCtrlSize, m_hwnd, (HMENU)IntToPtr(phci->idEdit), g_hInst, 0 ); if (!hwnd) return FALSE; RichEditRTLMirroring(m_hwnd, fSubjectField, &lExStyleFlags, FALSE); if (0 == (phci->dwFlags & HCF_BORDER)) { SendMessage(hwnd, EM_SETBKGNDCOLOR, WPARAM(FALSE), LPARAM(GetSysColor(COLOR_BTNFACE))); } ti.uId = (UINT_PTR)hwnd; ti.lpszText = (LPTSTR)IntToPtr(phci->idsTT); SendMessage(m_hwndTT, TTM_ADDTOOL, 0, (LPARAM) &ti); // hang a pointer into the phci off each control SetWindowLongPtr(hwnd, GWLP_USERDATA, (LPARAM)phci); if (!fIsCombo) { LPRICHEDITOLE preole = NULL; ITextDocument *pDoc = NULL; SideAssert(SendMessage(hwnd, EM_GETOLEINTERFACE, NULL, (LPARAM)&preole)); phci->preole = preole; Assert(preole); if (SUCCEEDED(preole->QueryInterface(IID_ITextDocument, (LPVOID*)&pDoc))) phci->pDoc = pDoc; // This only happens with richedit 1.0 else phci->pDoc = NULL; // Set edit charformat if (phci->dwFlags & HCF_USECHARSET) SendMessage(hwnd, EM_SETCHARFORMAT, 0, (LPARAM)&cfHeaderCset); else SendMessage(hwnd, EM_SETCHARFORMAT, 0, (LPARAM)&g_cfHeader); if ((pawcb = new CAddrWellCB(!(phci->dwFlags&HCF_READONLY), phci->dwFlags&HCF_ADDRWELL))) { if (pawcb->FInit(hwnd)) SendMessage(hwnd, EM_SETOLECALLBACK, 0, (LPARAM)(IRichEditOleCallback *)pawcb); ReleaseObj(pawcb); } SendMessage(hwnd, EM_SETEVENTMASK, 0, lMask); g_lpfnREWndProc=(WNDPROC)SetWindowLongPtrAthW(hwnd, GWLP_WNDPROC, (LPARAM)EditSubClassProc); } else { CHAR szAccount[CCHMAX_ACCOUNT_NAME]; CHAR szAcctID[CCHMAX_ACCOUNT_NAME]; CHAR szDefault[CCHMAX_ACCOUNT_NAME]; CHAR szEmailAddress[CCHMAX_EMAIL_ADDRESS]; CHAR szEntry[ACCT_ENTRY_SIZE]; CHAR szDefaultEntry[ACCT_ENTRY_SIZE]; IImnEnumAccounts *pEnum=NULL; IImnAccount *pAccount=NULL; int i = 0; DWORD cAccounts = 0; LPSTR *ppszAcctIDs; *szDefault = 0; *szDefaultEntry = 0; // If default account isn't setup, this might fail, but doesn't matter. g_pAcctMan->GetDefaultAccountName(m_fMail?ACCT_MAIL:ACCT_NEWS, szDefault, ARRAYSIZE(szDefault)); hr = g_pAcctMan->Enumerate(m_fMail?SRV_MAIL:SRV_NNTP, &pEnum); if (SUCCEEDED(hr)) hr = pEnum->GetCount(&cAccounts); if (SUCCEEDED(hr) && cAccounts) { if (!MemAlloc((void**)&m_ppAccountIDs, cAccounts*sizeof(LPSTR))) hr = E_OUTOFMEMORY; } if (SUCCEEDED(hr)) { *szDefaultEntry = 0; ppszAcctIDs = m_ppAccountIDs; while(SUCCEEDED(pEnum->GetNext(&pAccount))) { *szAccount = 0; *szEmailAddress = 0; pAccount->GetPropSz(AP_ACCOUNT_NAME, szAccount, ARRAYSIZE(szAccount)); if (m_fMail) { pAccount->GetPropSz(AP_SMTP_EMAIL_ADDRESS, szEmailAddress, ARRAYSIZE(szEmailAddress)); wnsprintf(szEntry, ARRAYSIZE(szEntry), "%s (%s)", szEmailAddress, szAccount); } else { StrCpyN(szEntry, szAccount, ARRAYSIZE(szEntry)); } i = ComboBox_InsertString(hwnd, -1, szEntry); if (i != CB_ERR) { if (0 == lstrcmpi(szDefault, szAccount)) { StrCpyN(szDefaultEntry, szEntry, ARRAYSIZE(szDefaultEntry)); } if (SUCCEEDED(pAccount->GetPropSz(AP_ACCOUNT_ID, szAcctID, ARRAYSIZE(szAcctID)))) { DWORD cchSize = (lstrlen(szAcctID) + 1); if (MemAlloc((void**)ppszAcctIDs, cchSize * sizeof(CHAR))) { StrCpyN(*ppszAcctIDs, szAcctID, cchSize); } else { *ppszAcctIDs = NULL; } } else *ppszAcctIDs = NULL; SendMessage(hwnd, CB_SETITEMDATA, WPARAM(i), LPARAM(*ppszAcctIDs)); ppszAcctIDs++; m_cAccountIDs++; } // Release Account SafeRelease(pAccount); } AssertSz(m_cAccountIDs == cAccounts, "Why isn't num Ds = num accts?"); SafeRelease(pEnum); AssertSz(!pAccount, "The last account didn't get freed."); if (0 != *szDefaultEntry) { ComboBox_SelectString(hwnd, -1, szDefaultEntry); m_iCurrComboIndex = ComboBox_GetCurSel(hwnd); } else { ComboBox_SetCurSel(hwnd, 0); m_iCurrComboIndex = 0; } if (SUCCEEDED(HrGetAccountInHeader(&pAccount))) { ReplaceInterface(m_pAccount, pAccount); ReleaseObj(pAccount); } SendMessage(hwnd, WM_SETFONT, WPARAM(hFont), MAKELONG(TRUE,0)); } } } _RegisterWithFontCache(TRUE); HrOnOffVCard(); ReLayout(); return PostWMCreate(); // allow subclass to setup the controls once created... } // // HeaderWndProc // // Purpose: Main WNDPROC for header dialog // // Comments: // LRESULT CALLBACK CNoteHdr::ExtCNoteHdrWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { CNoteHdr *pnh = NULL; if (msg==WM_NCCREATE) { SetWndThisPtrOnCreate(hwnd, lParam); pnh=(CNoteHdr *)GetWndThisPtr(hwnd); if (!pnh) return -1; pnh->m_hwnd=hwnd; return pnh->WMCreate(); } pnh = (CNoteHdr *)GetWndThisPtr(hwnd); if (pnh) return pnh->CNoteHdrWndProc(hwnd, msg, wParam, lParam); else return DefWindowProcWrapW(hwnd, msg, wParam, lParam); } void CNoteHdr::RelayToolTip(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { MSG Msg; if (m_hwndTT != NULL) { Msg.lParam=lParam; Msg.wParam=wParam; Msg.message=msg; Msg.hwnd=hwnd; SendMessage(m_hwndTT, TTM_RELAYEVENT, 0, (LPARAM) (LPMSG) &Msg); } } LRESULT CALLBACK CNoteHdr::CNoteHdrWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { POINT pt; int newWidth; RECT rc; HFONT hFont=NULL; switch (msg) { case WM_HEADER_GETFONT: // update cached fornt for addrobj's if (g_lpIFontCache) g_lpIFontCache->GetFont(wParam ? FNT_SYS_ICON_BOLD:FNT_SYS_ICON, m_hCharset, &hFont); return (LRESULT)hFont; case HDM_TESTQUERYPRI: // hack for test team to query header's priority... return m_pri; case WM_DESTROY: OnDestroy(); break; case WM_NCDESTROY: OnNCDestroy(); break; case WM_CTLCOLORBTN: // make sure the buttons backgrounds are window-color so the ownerdraw // imagelists paint transparent OK return (LPARAM)GetSysColorBrush(COLOR_WINDOWFRAME); case WM_CONTEXTMENU: if (m_lpAttMan && m_lpAttMan->WMContextMenu(hwnd, msg, wParam, lParam)) return 0; break; case WM_MOUSEMOVE: { DWORD newButton = GetButtonUnderMouse(LOWORD(lParam), HIWORD(lParam)); if ((HDRCB_NO_BUTTON == m_dwClickedBtn) || (HDRCB_NO_BUTTON == newButton) || (m_dwClickedBtn == newButton)) if (newButton != m_dwCurrentBtn) { DOUTL(PAINTING_DEBUG_LEVEL, "Old button: %d, New Button: %d", m_dwCurrentBtn, newButton); if (HDRCB_NO_BUTTON == newButton) { DOUTL(PAINTING_DEBUG_LEVEL, "Leaving right button framing."); // Need to clear old button. InvalidateRect(m_hwnd, &m_rcCurrentBtn, FALSE); HeaderRelease(FALSE); } else { DOUTL(PAINTING_DEBUG_LEVEL, "Framing button."); if (HDRCB_NO_BUTTON == m_dwCurrentBtn) HeaderCapture(); else InvalidateRect(m_hwnd, &m_rcCurrentBtn, FALSE); GetButtonRect(newButton, &m_rcCurrentBtn); InvalidateRect(m_hwnd, &m_rcCurrentBtn, FALSE); } m_dwCurrentBtn = newButton; } RelayToolTip(hwnd, msg, wParam, lParam); break; } case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: { RECT rc; int x = LOWORD(lParam), y = HIWORD(lParam); HeaderCapture(); m_dwClickedBtn = GetButtonUnderMouse(x, y); if (m_dwClickedBtn != HDRCB_NO_BUTTON) { GetButtonRect(m_dwClickedBtn, &rc); InvalidateRect(m_hwnd, &rc, FALSE); } RelayToolTip(hwnd, msg, wParam, lParam); break; } case WM_LBUTTONUP: case WM_RBUTTONUP: { int x = LOWORD(lParam), y = HIWORD(lParam); DWORD iBtn = GetButtonUnderMouse(x, y); RelayToolTip(hwnd, msg, wParam, lParam); if (m_dwClickedBtn == iBtn) HandleButtonClicks(x, y, iBtn); m_dwClickedBtn = HDRCB_NO_BUTTON; HeaderRelease(FALSE); break; } case WM_PAINT: WMPaint(); break; case WM_SYSCOLORCHANGE: if (m_himl) { // remap the toolbar bitmap into the new color scheme ImageList_Destroy(m_himl); SendMessage(m_hwndToolbar, TB_SETIMAGELIST, 0, NULL); m_himl = LoadMappedToolbarBitmap(g_hLocRes, (fIsWhistler() ? ((GetCurColorRes() > 24) ? idb32SmBrowserHot : idbSmBrowserHot): idbNWSmBrowserHot), cxTBButton); SendMessage(m_hwndToolbar, TB_SETIMAGELIST, 0, (LPARAM)m_himl); } UpdateRebarBandColors(m_hwndRebar); // fall thro' case WM_WININICHANGE: case WM_DISPLAYCHANGE: case WM_QUERYNEWPALETTE: case WM_PALETTECHANGED: SendMessage(m_hwndRebar, msg, wParam, lParam); break; case WM_ERASEBKGND: return 1; case WM_SIZE: { STACK("WM_SIZE (width, heigth)", LOWORD(lParam), HIWORD(lParam)); if (m_fResizing) break; m_fResizing = TRUE; newWidth = LOWORD(lParam); SetPosOfControls(newWidth, FALSE); if (m_hwndRebar) { GetClientRect(m_hwndRebar, &rc); // resize the width of the toolbar if(rc.right != newWidth) SetWindowPos(m_hwndRebar, NULL, 0, 0, newWidth, 30, SETWINPOS_DEF_FLAGS|SWP_NOMOVE); } AssertSz(m_fResizing, "Someone re-entered me!!! Why is m_fResizing already false??"); m_fResizing = FALSE; break; } case WM_CLOSE: //prevent alt-f4 return 0; case WM_COMMAND: WMCommand(GET_WM_COMMAND_HWND(wParam, lParam), GET_WM_COMMAND_ID(wParam, lParam), GET_WM_COMMAND_CMD(wParam, lParam)); break; case WM_NOTIFY: return WMNotify(wParam, lParam); } return DefWindowProcWrapW(hwnd, msg, wParam, lParam); } void CNoteHdr::HeaderCapture() { if (0 == m_cCapture) m_hwndOldCapture = SetCapture(m_hwnd); m_cCapture++; } void CNoteHdr::HeaderRelease(BOOL fForce) { if (0 == m_cCapture) return; if (fForce) m_cCapture = 0; else m_cCapture--; if (0 == m_cCapture) { ReleaseCapture(); if (NULL != m_hwndOldCapture) { DOUTL(PAINTING_DEBUG_LEVEL, "Restoring old mouse events capture."); SetCapture(m_hwndOldCapture); m_hwndOldCapture = NULL; } } } BOOL CNoteHdr::WMNotify(WPARAM wParam, LPARAM lParam) { HWND hwnd=m_hwnd; int idCtl=(int)wParam; LPNMHDR pnmh=(LPNMHDR)lParam; TBNOTIFY *ptbn; LPTOOLTIPTEXT lpttt; int i; if (m_lpAttMan->WMNotify((int) wParam, pnmh)) return TRUE; switch (pnmh->code) { case RBN_CHEVRONPUSHED: { ITrackShellMenu* ptsm; CoCreateInstance(CLSID_TrackShellMenu, NULL, CLSCTX_INPROC_SERVER, IID_ITrackShellMenu, (LPVOID*)&ptsm); if (!ptsm) break; ptsm->Initialize(0, 0, 0, SMINIT_TOPLEVEL|SMINIT_VERTICAL); LPNMREBARCHEVRON pnmch = (LPNMREBARCHEVRON) pnmh; ptsm->SetObscured(m_hwndToolbar, NULL, SMSET_TOP); MapWindowPoints(m_hwndRebar, HWND_DESKTOP, (LPPOINT)&pnmch->rc, 2); POINTL pt = {pnmch->rc.left, pnmch->rc.right}; ptsm->Popup(m_hwndRebar, &pt, (RECTL*)&pnmch->rc, MPPF_BOTTOM); ptsm->Release(); break; } case EN_MSGFILTER: { // if we get a control-tab, then richedit snags this and inserts a // tab char, we hook the wm_keydown and never pass to richedit if (((MSGFILTER *)pnmh)->msg == WM_KEYDOWN && ((MSGFILTER *)pnmh)->wParam == VK_TAB && (GetKeyState(VK_CONTROL) & 0x8000)) return TRUE; break; } case ATTN_RESIZEPARENT: { RECT rc; GetClientRect(m_hwnd, &rc); SetPosOfControls(rc.right, TRUE); return TRUE; } case EN_REQUESTRESIZE: { REQRESIZE *presize=(REQRESIZE *)lParam; HWND hwndEdit = presize->nmhdr.hwndFrom; STACK("EN_REQUESTRESIZE (hwnd, width, heigth)", (DWORD_PTR)(presize->nmhdr.hwndFrom), presize->rc.right - presize->rc.left, presize->rc.bottom - presize->rc.top); if (S_FALSE != HrUpdateCachedHeight(hwndEdit, &presize->rc) && !m_fResizing) { RECT rc; DWORD dwMask = (DWORD) SendMessage(hwndEdit, EM_GETEVENTMASK, 0, 0); SendMessage(hwndEdit, EM_SETEVENTMASK, 0, dwMask & (~ENM_REQUESTRESIZE)); STACK("EN_REQUESTRESIZE after GrowControls"); GetClientRect(m_hwnd, &rc); SetPosOfControls(rc.right, FALSE); SendMessage(hwndEdit, EM_SETEVENTMASK, 0, dwMask); } return TRUE; } case NM_SETFOCUS: case NM_KILLFOCUS: // UIActivate/Deactivate for attachment manager if (m_lpAttMan && pnmh->hwndFrom == m_lpAttMan->Hwnd()) _UIActivate(pnmh->code == NM_SETFOCUS, pnmh->hwndFrom); break; case EN_SELCHANGE: { PHCI phci=(PHCI)GetWndThisPtr(pnmh->hwndFrom); if (phci) phci->dwACFlags &= ~AC_SELECTION; // update office toolbars if running as envelope if(m_pEnvelopeSite) m_pEnvelopeSite->DirtyToolbars(); // on a sel change, forward a note updatetoolbar to update the // cut|copy|paste buttons if (m_pHeaderSite) m_pHeaderSite->Update(); return TRUE; } case TTN_NEEDTEXT: // we use TTN_NEEDTEXT to show toolbar tips as we have different tips than toolbar-labels // because on the office-envelope toolbar only 2 buttons (send and bcc) have text next to the // buttons lpttt = (LPTOOLTIPTEXT) pnmh; lpttt->hinst = NULL; lpttt->lpszText = 0; for (i=0; i< ARRAYSIZE(c_rgTipLookup); i++) { if (c_rgTipLookup[i].idm == (int)lpttt->hdr.idFrom) { lpttt->hinst = g_hLocRes; lpttt->lpszText = MAKEINTRESOURCE(c_rgTipLookup[i].ids); break; } } break; case TBN_DROPDOWN: { ptbn = (TBNOTIFY *)lParam; if (ptbn->iItem == ID_SET_PRIORITY) { HMENU hMenuPopup; UINT i; hMenuPopup = LoadPopupMenu(IDR_PRIORITY_POPUP); if (hMenuPopup != NULL) { for (i = 0; i < 3; i++) CheckMenuItem(hMenuPopup, i, MF_UNCHECKED | MF_BYPOSITION); GetPriority(&i); Assert(i != priNone); CheckMenuItem(hMenuPopup, 2 - i, MF_CHECKED | MF_BYPOSITION); DoToolbarDropdown(hwnd, (LPNMHDR) lParam, hMenuPopup); DestroyMenu(hMenuPopup); } } break; } } return FALSE; } HRESULT CNoteHdr::WMCommand(HWND hwndCmd, int id, WORD wCmd) { HWND hwnd=m_hwnd; int i; UINT pri; if (m_lpAttMan && m_lpAttMan->WMCommand(hwndCmd, id, wCmd)) return S_OK; for (i=0; i<(int)m_cHCI; i++) if (m_rgHCI[i].idEdit==id) { switch (wCmd) { case EN_CHANGE: { if (m_fHandleChange) { BOOL fEmpty; PHCI phci = (PHCI)GetWndThisPtr(hwndCmd); char sz[cchHeaderMax+1]; DWORD dwMask = 0; RichEditProtectENChange(hwndCmd, &dwMask, TRUE); Assert(phci); fEmpty = (0 == GetRichEditTextLen(hwndCmd)); // if it has no text, see if it has object... if (fEmpty && phci->preole) fEmpty = (fEmpty && (0 == phci->preole->GetObjectCount())); if (phci->dwFlags & HCF_ADDRWELL) m_fAddressesChanged = TRUE; phci->fEmpty = fEmpty; SetDirtyFlag(); if (m_fAutoComplete && (m_rgHCI[i].dwFlags & HCF_ADDRWELL) && !IsReadOnly()) { if (NULL == m_pTable) { if (NULL == m_lpWab) HrCreateWabObject(&m_lpWab); if (m_lpWab) m_lpWab->HrGetPABTable(&m_pTable); } if (m_pTable) HrAutoComplete(hwndCmd, &m_rgHCI[i]); } RichEditProtectENChange(hwndCmd, &dwMask, FALSE); } } return S_OK; case CBN_SELCHANGE: { IImnAccount *pAcct = NULL; if (!m_fMail) { int newIndex = ComboBox_GetCurSel(hwndCmd); HWND hwndNews = GetDlgItem(m_hwnd, idADNewsgroups); // Don't need to warn if going to same account, or if there are no newgroups listed. if ((newIndex != m_iCurrComboIndex) && (0 < GetWindowTextLength(hwndNews))) { if (IDCANCEL == DoDontShowMeAgainDlg(m_hwnd, c_szDSChangeNewsServer, MAKEINTRESOURCE(idsAthena), MAKEINTRESOURCE(idsChangeNewsServer), MB_OKCANCEL)) { ComboBox_SetCurSel(hwndCmd, m_iCurrComboIndex); return S_OK; } else HdrSetRichEditText(hwndNews, c_wszEmpty, FALSE); } m_iCurrComboIndex = newIndex; } if (SUCCEEDED(HrGetAccountInHeader(&pAcct))) ReplaceInterface(m_pAccount, pAcct); ReleaseObj(pAcct); return S_OK; } case CBN_SETFOCUS: case EN_SETFOCUS: _UIActivate(TRUE, hwndCmd); return S_OK; case CBN_KILLFOCUS: case EN_KILLFOCUS: _UIActivate(FALSE, hwndCmd); return S_OK; } return S_FALSE; } switch (id) { case ID_PRIORITY_LOW: SetPriority(priLow); return S_OK; case ID_PRIORITY_NORMAL: SetPriority(priNorm); return S_OK; case ID_PRIORITY_HIGH: SetPriority(priHigh); return S_OK; case ID_SET_PRIORITY: GetPriority(&pri); pri++; if (pri > priHigh) pri = priLow; SetPriority(pri); return S_OK; case ID_SELECT_ALL: { HWND hwndFocus=GetFocus(); if (GetParent(hwndFocus)==m_hwnd) { // only if it's one of our kids.. Edit_SetSel(hwndFocus, 0, -1); return S_OK; } } break; case ID_CUT: if (FDoCutCopyPaste(WM_CUT)) return S_OK; break; case ID_NOTE_COPY: case ID_COPY: if (FDoCutCopyPaste(WM_COPY)) return S_OK; break; case ID_PASTE: if (FDoCutCopyPaste(WM_PASTE)) return S_OK; break; case ID_DELETE_VCARD: m_fVCard = FALSE; SetDirtyFlag(); HrOnOffVCard(); return S_OK; case ID_OPEN_VCARD: HrShowVCardProperties(m_hwnd); return S_OK; case ID_DIGITALLY_SIGN: case ID_ENCRYPT: HrHandleSecurityIDMs(ID_DIGITALLY_SIGN == id); return S_OK; case ID_ADDRESS_BOOK: HrViewContacts(); return S_OK; //this is for office use only case ID_CHECK_NAMES: HrCheckNames(FALSE, TRUE); return S_OK; //this is for office use only case ID_ENV_BCC: if (m_pEnvelopeSite) { ShowAdvancedHeaders(!m_fAdvanced); SetDwOption(OPT_MAILNOTEADVSEND, !!m_fAdvanced, NULL, NULL); // ~~~~ m_pHeaderSite is mutually exclusive to m_pEnvelopeSite //if (m_pHeaderSite) // m_pHeaderSite->Update(); return S_OK; } break; case ID_MESSAGE_OPTS: ShowEnvOptions(); return S_OK; case ID_SAVE_ATTACHMENTS: case ID_NOTE_SAVE_ATTACHMENTS: if (m_pHeaderSite) m_pHeaderSite->SaveAttachment(); return S_OK; // These next two should only be handled by the header if in the envelope case ID_SEND_MESSAGE: case ID_SEND_NOW: if (m_pEnvelopeSite) { m_fShowedUnicodeDialog = FALSE; m_iUnicodeDialogResult = 0; HrSend(); return S_OK; } default: if (id>=ID_ADDROBJ_OLE_FIRST && id <=ID_ADDROBJ_OLE_LAST) { DoNoteOleVerb(id-ID_ADDROBJ_OLE_FIRST); return S_OK; } } return S_FALSE; } HRESULT CNoteHdr::HrAutoComplete(HWND hwnd, PHCI pHCI) { CHARRANGE chrg, chrgCaret; LPWSTR pszPartial, pszSemiColon, pszComma; INT i, j, len, iTextLen; LPWSTR pszBuf=0; WCHAR szFound[cchMaxWab+1]; WCHAR sz; HRESULT hr = NOERROR; STACK("HrAutoComplete"); *szFound = 0; // If the IME is open, bail out if (0 < m_dwIMEStartCount) return hr; if (NULL==hwnd || NULL==m_pTable || NULL==pHCI) return hr; if (pHCI->dwACFlags&AC_IGNORE) return hr; SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&chrgCaret); if (chrgCaret.cpMin != chrgCaret.cpMax) return hr; if (S_OK != HrGetFieldText(&pszBuf, hwnd)) return hr; sz = pszBuf[chrgCaret.cpMin]; if (!(sz==0x0000 || sz==L' ' || sz==L';'|| sz==L',' || sz==L'\r')) goto cleanup; DOUTL(64, "HrAutoComplete- Didn't exit early"); pszBuf[chrgCaret.cpMin] = 0x0000; pszSemiColon = StrRChrIW(pszBuf, &pszBuf[lstrlenW(pszBuf)], L';'); pszComma = StrRChrIW(pszBuf, &pszBuf[lstrlenW(pszBuf)], L','); if (pszComma >= pszSemiColon) pszPartial = pszComma; else pszPartial = pszSemiColon; if (!pszPartial) pszPartial = pszBuf; else pszPartial++; //skip spaces and returns... while (*pszPartial==L' ' || *pszPartial==L'\r' || *pszPartial==L'\n') pszPartial++; if (NULL == *pszPartial) goto cleanup; //Certain richedits put in 0xfffc for an object, if our text is only that, it's no good if (*pszPartial==0xfffc && pszPartial[1]==0x0000) goto cleanup; len = lstrlenW(pszPartial); m_lpWab->SearchPABTable(m_pTable, pszPartial, szFound, ARRAYSIZE(szFound)); if (*szFound != 0) { chrg.cpMin = chrgCaret.cpMin; chrg.cpMax = chrg.cpMin + lstrlenW(szFound) - len; if (chrg.cpMin < chrg.cpMax) { RichEditExSetSel(hwnd, &chrgCaret); HdrSetRichEditText(hwnd, szFound + len, TRUE); SendMessage(hwnd, EM_SETMODIFY, (WPARAM)(UINT)TRUE, 0); RichEditExSetSel(hwnd, &chrg); pHCI->dwACFlags |= AC_SELECTION; } } cleanup: MemFree(pszBuf); return hr; } void CNoteHdr::WMPaint() { PAINTSTRUCT ps; HDC hdc, hdcMem; RECT rc; PHCI phci = m_rgHCI; HBITMAP hbmMem; int idc, cxHeader, cyHeader, cxLabel = ControlXBufferSize(), cyStatus, cyLeftButtonOffset = BUTTON_BUFFER, cxLabelWithBtn = cxLabel + CXOfButtonToLabel(); char sz[cchHeaderMax+1]; int cStatusBarLines = 0; BOOL fBold; HWND hwnd; if (!m_hwnd) return; STACK("WMPaint"); if (m_fFlagged || (priLow == m_pri) || (priHigh == m_pri) || (MARK_MESSAGE_NORMALTHREAD != m_MarkType)) cStatusBarLines++; if (m_lpAttMan->GetUnsafeAttachCount()) cStatusBarLines++; hdc = BeginPaint(m_hwnd, &ps); // **************** Init the background bitmap **************** hdcMem = CreateCompatibleDC(hdc); idc = SaveDC(hdcMem); GetClientRect(m_hwnd, &rc); cxHeader = rc.right; cyHeader = rc.bottom; hbmMem = CreateCompatibleBitmap(hdc, rc.right, rc.bottom); SelectObject(hdcMem, (HGDIOBJ)hbmMem); // **************** Clear the rect ***************** FillRect(hdcMem, &rc, GetSysColorBrush(COLOR_BTNFACE)); // **************** Setup the HDC ****************** fBold = IsReadOnly(); SetBkColor(hdcMem, GetSysColor(COLOR_BTNFACE)); // colour of header window SetBkMode(hdcMem, TRANSPARENT); SetTextColor(hdcMem, GetSysColor(COLOR_BTNTEXT)); SelectObject(hdcMem, GetFont(fBold)); // **************** Paint the left labels and buttons ************** // Center the buttons images if (g_cyFont > cyBtn) cyLeftButtonOffset += ((g_cyFont - cyBtn) / 2); for (int i = 0; (ULONG)i < m_cHCI; i++, phci++) { if (S_OK == HrFShowHeader(phci)) { if (HCF_HASBUTTON & phci->dwFlags) { TextOutW(hdcMem, cxLabelWithBtn, phci->cy + BUTTON_BUFFER, phci->sz, phci->strlen); ImageList_Draw(g_himlBtns, (HCF_ADDRBOOK & phci->dwFlags)?0:1, hdcMem, cxLabel, phci->cy + cyLeftButtonOffset, ILD_NORMAL); } else TextOutW(hdcMem, cxLabel, (HCF_BORDER & phci->dwFlags)? phci->cy + BUTTON_BUFFER: phci->cy, phci->sz, phci->strlen); } } // **************** Paint the status bar as needed ******************* if (cStatusBarLines > 0) { int cxStatusBtn = ControlXBufferSize() + 1, // 1 added for the border cyStatusBtn = m_dxTBOffset + cyBorder + 1, // 1 added for the border cyStatusBmp = cyStatusBtn, cNumButtons = 0; LPTSTR pszTitles[3]={0}; // Center the buttons images if (g_cyFont > cyBtn) cyStatusBmp += ((g_cyFont - cyBtn) / 2); // Fill the dark rect rc.top = m_dxTBOffset; rc.bottom = m_dxTBOffset + GetStatusHeight(cStatusBarLines); FillRect(hdcMem, &rc, GetSysColorBrush(COLOR_BTNSHADOW)); InflateRect(&rc, -1, -1); FillRect(hdcMem, &rc, GetSysColorBrush(COLOR_INFOBK)); // Set up the DC for the rest of the status bar SetBkColor(hdcMem, GetSysColor(COLOR_INFOBK)); // colour of header window SetTextColor(hdcMem, GetSysColor(COLOR_INFOTEXT)); SelectObject(hdcMem, GetFont(FALSE)); // Draw icons in status bar if (priLow == m_pri) { ImageList_Draw(g_himlStatus, 1, hdcMem, cxStatusBtn, cyStatusBmp+2, ILD_NORMAL); cxStatusBtn += cxFlagsDelta; pszTitles[cNumButtons++] = g_szStatLowPri; } else if (priHigh == m_pri) { ImageList_Draw(g_himlStatus, 0, hdcMem, cxStatusBtn, cyStatusBmp+2, ILD_NORMAL); cxStatusBtn += cxFlagsDelta; pszTitles[cNumButtons++] = g_szStatHighPri; } if (MARK_MESSAGE_WATCH == m_MarkType) { ImageList_Draw(g_himlStatus, 4, hdcMem, cxStatusBtn, cyStatusBmp+2, ILD_NORMAL); cxStatusBtn += cxFlagsDelta; pszTitles[cNumButtons++] = g_szStatWatched; } else if (MARK_MESSAGE_IGNORE == m_MarkType) { ImageList_Draw(g_himlStatus, 5, hdcMem, cxStatusBtn, cyStatusBmp+2, ILD_NORMAL); cxStatusBtn += cxFlagsDelta; pszTitles[cNumButtons++] = g_szStatIgnored; } if (m_fFlagged) { ImageList_Draw(g_himlStatus, 2, hdcMem, cxStatusBtn, cyStatusBmp+2, ILD_NORMAL); cxStatusBtn += cxFlagsDelta; pszTitles[cNumButtons++] = g_szStatFlagged; } if (m_lpAttMan->GetUnsafeAttachCount()) { ImageList_Draw(g_himlStatus, 6, hdcMem, cxStatusBtn, cyStatusBmp+2, ILD_NORMAL); cxStatusBtn += cxFlagsDelta; } if (cNumButtons > 0) { char szHeaderString[cchHeaderMax*4+1]; // Add an additional pixel for the text. cyStatusBtn++; switch (cNumButtons) { case 1: { wnsprintf(szHeaderString, ARRAYSIZE(szHeaderString), g_szStatFormat1, pszTitles[0]); TextOut(hdcMem, cxStatusBtn, cyStatusBtn, szHeaderString, lstrlen(szHeaderString)); break; } case 2: { wnsprintf(szHeaderString, ARRAYSIZE(szHeaderString), g_szStatFormat2, pszTitles[0], pszTitles[1]); TextOut(hdcMem, cxStatusBtn, cyStatusBtn, szHeaderString, lstrlen(szHeaderString)); break; } case 3: { wnsprintf(szHeaderString, ARRAYSIZE(szHeaderString), g_szStatFormat3, pszTitles[0], pszTitles[1], pszTitles[2]); TextOut(hdcMem, cxStatusBtn, cyStatusBtn, szHeaderString, lstrlen(szHeaderString)); break; } } cyStatusBtn += CYOfStatusLine() - 1; } if (m_lpAttMan->GetUnsafeAttachCount()) { char szHeaderString[cchHeaderMax*4+1]; // Add an additional pixel for the text. cyStatusBtn++; wnsprintf(szHeaderString, ARRAYSIZE(szHeaderString), g_szStatUnsafeAtt, m_lpAttMan->GetUnsafeAttachList()); TextOut(hdcMem, cxStatusBtn, cyStatusBtn, szHeaderString, lstrlen(szHeaderString)); } } // ************ Draw the right side buttons ************** if (m_fDigSigned || m_fEncrypted || m_fVCard) { int width = GetRightMargin(TRUE), cx = cxHeader - (ControlXBufferSize() + cxBtn), cy = BeginYPos() + BUTTON_BUFFER, yDiff = cyBtn + ControlYBufferSize() + 2*BUTTON_BUFFER; if (m_fDigSigned) { ImageList_Draw(g_himlSecurity, m_fSignTrusted?0:2, hdcMem, cx, cy, ILD_NORMAL); cy += yDiff; } if (m_fEncrypted) { ImageList_Draw(g_himlSecurity, m_fEncryptionOK?1:3, hdcMem, cx, cy, ILD_NORMAL); cy += yDiff; } if (m_fVCard) { ImageList_Draw(g_himlBtns, 2, hdcMem, cx, cy, ILD_NORMAL); } } // Draw active button edge if (HDRCB_NO_BUTTON != m_dwCurrentBtn) { DOUTL(PAINTING_DEBUG_LEVEL, "Framing button %d: (%d, %d) to (%d, %d)", m_dwCurrentBtn, m_rcCurrentBtn.left, m_rcCurrentBtn.top, m_rcCurrentBtn.right, m_rcCurrentBtn.bottom); if (HDRCB_NO_BUTTON == m_dwClickedBtn) DrawEdge(hdcMem, &m_rcCurrentBtn, BDR_RAISEDINNER, BF_TOPRIGHT | BF_BOTTOMLEFT); else DrawEdge(hdcMem, &m_rcCurrentBtn, BDR_SUNKENINNER, BF_TOPRIGHT | BF_BOTTOMLEFT); } BitBlt(hdc, 0, 0, cxHeader, cyHeader, hdcMem, 0, 0, SRCCOPY); RestoreDC(hdcMem, idc); DeleteObject(hbmMem); DeleteDC(hdcMem); EndPaint(m_hwnd, &ps); } HRESULT CNoteHdr::HrFillToolbarColor(HDC hdc) { HRESULT hr = NOERROR; RECT rc; if (!m_hwndToolbar) return hr; GetRealClientRect(m_hwndToolbar, &rc); FillRect(hdc, &rc, GetSysColorBrush(COLOR_3DFACE)); return hr; } HRESULT CNoteHdr::HrGetVCardName(LPTSTR pszName, DWORD cch) { HRESULT hr = E_FAIL; if (pszName == NULL || cch==0) goto error; *pszName = 0; if (m_fMail) GetOption(OPT_MAIL_VCARDNAME, pszName, cch); else GetOption(OPT_NEWS_VCARDNAME, pszName, cch); if (*pszName != 0) hr = NOERROR; error: return hr; } // turn on or off the vcard stamp. HRESULT CNoteHdr::HrOnOffVCard() { HRESULT hr = NOERROR; RECT rc; TOOLINFO ti = {0}; ti.cbSize = sizeof(TOOLINFO); ti.uFlags = 0; ti.uId = idVCardStamp; ti.hinst=g_hLocRes; ti.hwnd = m_hwnd; if (m_fVCardSave == m_fVCard) return hr; else m_fVCardSave = m_fVCard; if (m_fVCard) { ti.lpszText = (LPTSTR)idsTTVCardStamp; SendMessage(m_hwndTT, TTM_ADDTOOL, 0, (LPARAM) &ti); } else SendMessage(m_hwndTT, TTM_DELTOOL, 0, (LPARAM) &ti); InvalidateRightMargin(0); ReLayout(); return hr; } HRESULT CNoteHdr::HrGetVCardState(ULONG* pCmdf) { TCHAR szBuf[MAX_PATH]; HRESULT hr; // if OLECMDF_LATCHED is on, insert vcard menu should be checked. if (m_fVCard) *pCmdf |= OLECMDF_LATCHED; hr = HrGetVCardName(szBuf, sizeof(szBuf)); if (FAILED(hr)) // no vcard name selected { *pCmdf &= ~OLECMDF_ENABLED; *pCmdf &= ~OLECMDF_LATCHED; } else *pCmdf |= OLECMDF_ENABLED; return NOERROR; } HRESULT CNoteHdr::HrShowVCardCtxtMenu(int x, int y) { HMENU hPopup=0; HRESULT hr = E_FAIL; POINT pt; if (!m_fVCard) goto exit; // Pop up the context menu. hPopup = LoadPopupMenu(IDR_VCARD_POPUP); if (!hPopup) goto exit; if (IsReadOnly()) EnableMenuItem(hPopup, ID_DELETE_VCARD, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED); pt.x = x; pt.y = y; ClientToScreen(m_hwnd, &pt); TrackPopupMenuEx( hPopup, TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_RIGHTBUTTON, pt.x, pt.y, m_hwnd, NULL); hr = NOERROR; exit: if (hPopup) DestroyMenu(hPopup); return hr; } HRESULT CNoteHdr::HrShowVCardProperties(HWND hwnd) { HRESULT hr = NOERROR; LPWAB lpWab = NULL; TCHAR szName[MAX_PATH] = {0}; UINT cb = 0; if (IsReadOnly() && m_lpAttMan) return m_lpAttMan->HrShowVCardProp(); //else // return E_FAIL; hr = HrGetVCardName(szName, sizeof(szName)); if (FAILED(hr)) goto error; hr = HrCreateWabObject(&lpWab); if (FAILED(hr)) goto error; //load names into the combobox from personal address book hr = lpWab->HrEditEntry(hwnd, szName, ARRAYSIZE(szName)); if (FAILED(hr)) goto error; error: if (FAILED(hr) && hr!=MAPI_E_USER_CANCEL) AthMessageBoxW(hwnd, MAKEINTRESOURCEW(idsAthena), MAKEINTRESOURCEW(idsErrVCardProperties), NULL, MB_OK | MB_ICONEXCLAMATION); ReleaseObj(lpWab); return hr; } LRESULT CALLBACK CNoteHdr::IMESubClassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, PHCI phci) { CNoteHdr *pnh = NULL; HWND hwndParent = GetParent(hwnd); STACK("IMESubClassProc"); if (IsWindow(hwndParent)) { // Get the header class of the header window pnh = (CNoteHdr *)GetWndThisPtr(hwndParent); switch (msg) { case WM_IME_STARTCOMPOSITION: DOUTL(64, "WM_IME_STARTCOMPOSITION"); pnh->m_dwIMEStartCount++; break; case WM_IME_ENDCOMPOSITION: DOUTL(64, "WM_IME_ENDCOMPOSITION"); // Make sure we don't go negative. if (0 < pnh->m_dwIMEStartCount) { pnh->m_dwIMEStartCount--; } else { AssertSz(FALSE, "We just received an extra WM_IME_ENDCOMPOSITION"); DOUTL(64, "WM_IME_ENDCOMPOSITION, not expected"); } break; } } // Defer to the default window proc return CallWindowProcWrapW(g_lpfnREWndProc, hwnd, msg, wParam, lParam); } // bug #28379 // this is a hack to work around RichEd32 4.0 above bug in which // it did not syncronize the keyboard change in the child windows. // we use these global variable to keep track which keyboard // is using now. static HKL g_hCurrentKeyboardHandle = NULL ; static BOOL g_fBiDiSystem = (BOOL) GetSystemMetrics(SM_MIDEASTENABLED); static TCHAR g_chLastPressed = 0; LRESULT CALLBACK CNoteHdr::EditSubClassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; int idcKeep; PHCI phci; LRESULT lRet; CHARRANGE chrg; phci=(PHCI)GetWndThisPtr(hwnd); Assert(phci); Assert(g_lpfnREWndProc); if (phci && (phci->dwFlags&HCF_ADDRWELL)) { switch (msg) { case WM_IME_STARTCOMPOSITION: case WM_IME_ENDCOMPOSITION: return IMESubClassProc(hwnd, msg, wParam, lParam, phci); case WM_CUT: // if cutting a selection, make sure we don't autocomplete when we get the en_change goto cut; case WM_KEYDOWN: if (VK_BACK==wParam || VK_DELETE==wParam || ((GetKeyState(VK_CONTROL)&0x8000) && ('x'==wParam || 'X'==wParam))) { // if deleting a selection, make sure we don't autocomplete when we get the en_change cut: phci->dwACFlags |= AC_IGNORE; lRet = CallWindowProcWrapW(g_lpfnREWndProc, hwnd, msg, wParam, lParam); phci->dwACFlags &= ~AC_IGNORE; return lRet; } else if (phci->dwACFlags&AC_SELECTION && (VK_RETURN==wParam)) { SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&chrg); if (chrg.cpMin < chrg.cpMax) { chrg.cpMin = chrg.cpMax; SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&chrg); HdrSetRichEditText(hwnd, (',' == wParam) ? L", ": L"; ", TRUE); return 0; } } // bobn: brianv says we have to take this out... /*if ((g_dwBrowserFlags == 3) && (GetKeyState(VK_CONTROL)&0x8000) && (GetKeyState(VK_SHIFT)&0x8000)) { switch(wParam) { case 'R': g_chLastPressed = (g_chLastPressed == 0) ? 'R' : 0; break; case 'O': g_chLastPressed = (g_chLastPressed == 'R') ? 'O' : 0; break; case 'C': g_chLastPressed = (g_chLastPressed == 'O') ? 'C' : 0; break; case 'K': if (g_chLastPressed == 'C') g_dwBrowserFlags |= 4; g_chLastPressed = 0; break; } }*/ break; case WM_CHAR: // VK_RETURN is no longer sent as a WM_CHAR so we place it in the // WM_KEYDOWN. RAID 75444 if (phci->dwACFlags&AC_SELECTION && (wParam==',' || wParam==';')) { SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&chrg); if (chrg.cpMin < chrg.cpMax) { chrg.cpMin = chrg.cpMax; SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&chrg); HdrSetRichEditText(hwnd, (wParam==',') ? L", ": L"; ", TRUE); return 0; } } break; case WM_SETFOCUS: if(g_fBiDiSystem) { HKL hklUS = NULL; GetUSKeyboardLayout(&hklUS); ActivateKeyboardLayout(hklUS, 0); } break; } } // bug #28379 // this is a hack to work around RichEd32 4.0 above bug in which // it did not syncronize the keyboard change in the child windows. // we use these global variable to keep track which keyboard // is using now. //a-msadek; bug# 45709 // BiDi richedit uses WM_INPUTLANGCHANGE to determine reading order // This will make it confused causing Latin text displayed flipped if(!g_fBiDiSystem) { if (msg == WM_INPUTLANGCHANGE ) { if ( g_hCurrentKeyboardHandle && g_hCurrentKeyboardHandle != (HKL) lParam ) ActivateKeyboardLayout(g_hCurrentKeyboardHandle, 0 ); } if (msg == WM_INPUTLANGCHANGEREQUEST ) g_hCurrentKeyboardHandle = (HKL) lParam ; } // dispatch subject off to regular edit wndproc, and to & cc off to the RE wnd proc. return CallWindowProcWrapW(g_lpfnREWndProc, hwnd, msg, wParam, lParam); } void GetUSKeyboardLayout(HKL *phkl) { UINT cNumkeyboards = 0, i; HKL* phKeyboadList = NULL; HKL hKeyboardUS = NULL; // Let's check how many keyboard the system has cNumkeyboards = GetKeyboardLayoutList(0, phKeyboadList); phKeyboadList = (HKL*)LocalAlloc(LPTR, cNumkeyboards * sizeof(HKL)); cNumkeyboards = GetKeyboardLayoutList(cNumkeyboards, phKeyboadList); for (i = 0; i < cNumkeyboards; i++) { LANGID LangID = PRIMARYLANGID(LANGIDFROMLCID(LOWORD(phKeyboadList[i]))); if(LangID == LANG_ENGLISH) { *phkl = phKeyboadList[i]; break; } } if(phKeyboadList) { LocalFree((HLOCAL)phKeyboadList); } } HRESULT CNoteHdr::HrUpdateTooltipPos() { TOOLINFO ti; if (m_hwndTT) { /* ti.cbSize = sizeof(TOOLINFO); ti.hwnd = m_hwnd; ti.uId = idStamp; ::SetRect(&ti.rect, m_ptStamp.x, m_ptStamp.y, m_ptStamp.x + cxStamp, m_ptStamp.y + cyStamp); SendMessage(m_hwndTT, TTM_NEWTOOLRECT, 0, (LPARAM) &ti); if (m_fVCard) { ti.uFlags = 0; ti.uId = idVCardStamp; ti.lpszText = (LPTSTR) idsTTVCardStamp; if (m_pri!=priNone) //mail ::SetRect(&ti.rect, m_ptStamp.x, m_ptStamp.y*2+cyStamp, m_ptStamp.x + cxStamp, 2*(m_ptStamp.y+cyStamp)); else // news ::SetRect(&ti.rect, m_ptStamp.x, m_ptStamp.y, m_ptStamp.x + cxStamp, m_ptStamp.y + cyStamp); SendMessage(m_hwndTT, TTM_NEWTOOLRECT, 0, (LPARAM) &ti); }*/ } return NOERROR; } HRESULT CNoteHdr::HrInit(IMimeMessage *pMsg) { HWND hwnd; HRESULT hr=S_OK; if (m_hwnd) // already running return S_OK; if (!FInitRichEdit(TRUE)) return E_FAIL; if (!m_pEnvelopeSite) { Assert(m_hwndParent); hwnd=CreateWindowExWrapW( WS_EX_CONTROLPARENT|WS_EX_NOPARENTNOTIFY, WC_ATHHEADER, NULL, WS_VISIBLE|WS_CLIPSIBLINGS|WS_CLIPCHILDREN|WS_CHILD, 0,0,0,0, m_hwndParent, (HMENU)idcNoteHdr, g_hInst, (LPVOID)this ); } else { Assert(!m_hwnd); hr = HrOfficeInitialize(TRUE); if (FAILED(hr)) goto error; m_hwndParent = g_hwndInit; hwnd=CreateWindowExWrapW(WS_EX_CONTROLPARENT|WS_EX_NOPARENTNOTIFY, WC_ATHHEADER, NULL, WS_CLIPSIBLINGS|WS_CLIPCHILDREN|WS_CHILD, 0,0,0,0, m_hwndParent, (HMENU)idcNoteHdr, g_hInst, (LPVOID)this); if (!hwnd) { hr = E_FAIL; goto error; } m_ntNote = OENA_COMPOSE; m_fMail = TRUE; if (pMsg) hr = Load(pMsg); else hr = HrOfficeLoad(); if (FAILED(hr)) goto error; } if (!hwnd) { hr=E_OUTOFMEMORY; goto error; } m_hwnd = hwnd; m_fDirty=FALSE; error: return hr; } HRESULT CNoteHdr::HrOfficeInitialize(BOOL fInit) { HRESULT hr = E_FAIL; if (fInit) { hr = CoIncrementInit("CNoteHdr::HrOfficeInitialize", MSOEAPI_START_COMOBJECT, NULL, &m_hInitRef); if (FAILED(hr)) return hr; if (!FHeader_Init(TRUE)) return E_FAIL; m_fAutoComplete = TRUE; m_fDirty=FALSE; hr = _RegisterWithComponentMgr(TRUE); if (FAILED(hr)) return E_FAIL; m_fOfficeInit = TRUE; } else { if (m_hInitRef) CoDecrementInit("CNoteHdr::HrOfficeInitialize", &m_hInitRef); } return NOERROR; } void CNoteHdr::OnNCDestroy() { if (m_rgHCI) { MemFree(m_rgHCI); m_rgHCI = NULL; m_cHCI = 0; } _RegisterAsDropTarget(FALSE); _RegisterWithFontCache(FALSE); SafeRelease(m_pHeaderSite); SafeRelease(m_pEnvelopeSite); m_hwnd = NULL; } void CNoteHdr::OnDestroy() { HrFreeFieldList(); if (m_lpAttMan) m_lpAttMan->HrClose(); // release office interfaces if we get torn down _RegisterWithComponentMgr(FALSE); } HRESULT CNoteHdr::ShowAdvancedHeaders(BOOL fShow) { if (!!m_fAdvanced != fShow) { m_fAdvanced=fShow; ReLayout(); if (m_hwndToolbar) SendMessage(m_hwndToolbar, TB_CHECKBUTTON, ID_ENV_BCC, MAKELONG(!!m_fAdvanced, 0)); } return S_OK; } HRESULT CNoteHdr::HrFShowHeader(PHCI phci) { Assert(phci); if (phci->dwFlags & HCF_COMBO) { if (m_cAccountIDs < 2) return S_FALSE; else return S_OK; } if (phci->dwFlags & HCF_ATTACH) { if (!m_fStillLoading) { ULONG cAttMan = 0; HrGetAttachCount(&cAttMan); if (cAttMan) return S_OK; } return S_FALSE; } if (phci->dwFlags & HCF_ADVANCED) { if (IsReadOnly()) { // If it is a read note and CC is empty, don't show if (phci->fEmpty) return S_FALSE; } else // If is a send note and not suppose to show adv headers, don't show if (!m_fAdvanced) return S_FALSE; } if ((phci->dwFlags & HCF_OPTIONAL) && !DwGetOption(phci->dwOpt)) return S_FALSE; if (phci->dwFlags & HCF_HIDDEN) return S_FALSE; return S_OK; } // ================================================================================= // SzGetDisplaySec // returns the security enhancements and state of such for this message // Params: // OUT pidsLabel - if non-NULL, will contain the ids for the field name // Returns: // a built string giving information about the signature and/or encryption // ================================================================================= LPWSTR CNoteHdr::SzGetDisplaySec(LPMIMEMESSAGE pMsg, int *pidsLabel) { WCHAR szResource[CCHMAX_STRINGRES]; LPWSTR lpszLabel = NULL; DWORD cchSecurityField = 0; if (m_lpszSecurityField) { MemFree(m_lpszSecurityField); m_lpszSecurityField = NULL; } // check label first. if ((m_ntNote == OENA_READ) && pMsg) { HrGetLabelString(pMsg, &lpszLabel); } if (pidsLabel) *pidsLabel=idsSecurityField; UINT labelLen = 1; if(lpszLabel) { //Bug #101350 - lstrlenW will AV (and handle it) if passed a NULL labelLen += lstrlenW(lpszLabel); } // need to build string cchSecurityField = (2 * CCHMAX_STRINGRES + labelLen); if (!MemAlloc((LPVOID *)&m_lpszSecurityField, (cchSecurityField *sizeof(WCHAR)))) return NULL; *m_lpszSecurityField = L'\0'; // Example: "Digitally signed - signature unverifiable; Encrypted - Certificate is trusted" if (MST_SIGN_MASK & m_SecState.type) { AthLoadStringW(idsSecurityLineDigSign, szResource, ARRAYSIZE(szResource)); StrCpyNW(m_lpszSecurityField, szResource, cchSecurityField); if (IsSignTrusted(&m_SecState)) AthLoadStringW(idsSecurityLineSignGood, szResource, ARRAYSIZE(szResource)); else if (MSV_BADSIGNATURE & m_SecState.ro_msg_validity) AthLoadStringW(idsSecurityLineSignBad, szResource, ARRAYSIZE(szResource)); else if ((MSV_UNVERIFIABLE & m_SecState.ro_msg_validity) || (MSV_MALFORMEDSIG & m_SecState.ro_msg_validity)) AthLoadStringW(idsSecurityLineSignUnsure, szResource, ARRAYSIZE(szResource)); else if ((ATHSEC_NOTRUSTWRONGADDR & m_SecState.user_validity) && ((m_SecState.user_validity & ~ATHSEC_NOTRUSTWRONGADDR) == ATHSEC_TRUSTED) && (! m_SecState.ro_msg_validity)) { AthLoadStringW(idsSecurityLineSignPreProblem, szResource, ARRAYSIZE(szResource)); StrCatBuffW(m_lpszSecurityField, szResource, cchSecurityField); AthLoadStringW(idsSecurityLineSignMismatch, szResource, ARRAYSIZE(szResource)); } else if (((ATHSEC_TRUSTED != m_SecState.user_validity) && m_SecState.fHaveCert) || (MSV_EXPIRED_SIGNINGCERT & m_SecState.ro_msg_validity)) { AthLoadStringW(idsSecurityLineSignPreProblem, szResource, ARRAYSIZE(szResource)); if (ATHSEC_TRUSTED != m_SecState.user_validity) { int nNotTrust = 0; StrCatBuffW(m_lpszSecurityField, szResource, cchSecurityField); // ignore revokedness for now if (ATHSEC_NOTRUSTUNKNOWN & m_SecState.user_validity) { AthLoadStringW(idsSecurityLineSignUntrusted, szResource, ARRAYSIZE(szResource)); } else if(ATHSEC_NOTRUSTREVOKED & m_SecState.user_validity) { AthLoadStringW(idsSecurityLineSignRevoked, szResource, ARRAYSIZE(szResource)); nNotTrust = 1; } else if(ATHSEC_NOTRUSTOTHER & m_SecState.user_validity) { AthLoadStringW(idsSecurityLineSignOthers, szResource, ARRAYSIZE(szResource)); nNotTrust = 1; } else if(m_SecState.user_validity & ATHSEC_NOTRUSTWRONGADDR) { AthLoadStringW(idsSecurityLineSignMismatch, szResource, ARRAYSIZE(szResource)); nNotTrust = 1; } else // if(!(m_SecState.user_validity & ATHSEC_NOTRUSTNOTTRUSTED)) AthLoadStringW(idsSecurityLineSignDistrusted, szResource, ARRAYSIZE(szResource)); if((m_SecState.user_validity & ATHSEC_NOTRUSTNOTTRUSTED) && nNotTrust) { StrCatBuffW(m_lpszSecurityField, szResource, cchSecurityField); AthLoadStringW(idsSecurityLineListStr, szResource, ARRAYSIZE(szResource)); StrCatBuffW(m_lpszSecurityField, szResource, cchSecurityField); AthLoadStringW(idsSecurityLineSignDistrusted, szResource, ARRAYSIZE(szResource)); } if (MSV_EXPIRED_SIGNINGCERT & m_SecState.ro_msg_validity) { StrCatBuffW(m_lpszSecurityField, szResource, cchSecurityField); AthLoadStringW(idsSecurityLineListStr, szResource, ARRAYSIZE(szResource)); } } if (MSV_EXPIRED_SIGNINGCERT & m_SecState.ro_msg_validity) { StrCatBuffW(m_lpszSecurityField, szResource, cchSecurityField); AthLoadStringW(idsSecurityLineSignExpired, szResource, ARRAYSIZE(szResource)); } } else { AthLoadStringW(idsSecurityLineSignUnsure, szResource, ARRAYSIZE(szResource)); } StrCatBuffW(m_lpszSecurityField, szResource, cchSecurityField); if (MST_ENCRYPT_MASK & m_SecState.type) { AthLoadStringW(idsSecurityLineBreakStr, szResource, ARRAYSIZE(szResource)); StrCatBuffW(m_lpszSecurityField, szResource, cchSecurityField); } } if (MST_ENCRYPT_MASK & m_SecState.type) { AthLoadStringW(idsSecurityLineEncryption, szResource, ARRAYSIZE(szResource)); StrCatBuffW(m_lpszSecurityField, szResource, cchSecurityField); if (MSV_OK == (m_SecState.ro_msg_validity & MSV_ENCRYPT_MASK)) AthLoadStringW(idsSecurityLineEncGood, szResource, ARRAYSIZE(szResource)); else if (MSV_CANTDECRYPT & m_SecState.ro_msg_validity) AthLoadStringW(idsSecurityLineEncBad, szResource, ARRAYSIZE(szResource)); else if (MSV_ENC_FOR_EXPIREDCERT & m_SecState.ro_msg_validity) AthLoadStringW(idsSecurityLineEncExpired, szResource, ARRAYSIZE(szResource)); else { DOUTL(DOUTL_CRYPT, "CRYPT: bad encrypt state in SzGetDisplaySec"); szResource[0] = _T('\000'); } StrCatBuffW(m_lpszSecurityField, szResource, cchSecurityField); } if(lpszLabel != NULL) { AthLoadStringW(idsSecurityLineBreakStr, szResource, ARRAYSIZE(szResource)); StrCatBuffW(m_lpszSecurityField, szResource, cchSecurityField); StrCatBuffW(m_lpszSecurityField, lpszLabel, cchSecurityField); MemFree(lpszLabel); } return m_lpszSecurityField; } HRESULT CNoteHdr::HrClearUndoStack() { int iHC; HWND hwndRE; for (iHC=0; iHC<(int)m_cHCI; iHC++) { if (hwndRE = GetDlgItem(m_hwnd, m_rgHCI[iHC].idEdit)) SendMessage(hwndRE, EM_EMPTYUNDOBUFFER, 0, 0); } return S_OK; } // There are some cases where we don't wan't the resolve name to // be skipped. For example, a resolve name during a save will set // m_fAddressesChanged to be false. That is fine, except it doesn't // underline the addresses. So when the user tries to resolve the name // by doing the resolve name command, the name will appear not to // be resolved. In this case, we don't want the next call to HrCheckNames // to be skipped. HRESULT CNoteHdr::HrCheckNames(BOOL fSilent, BOOL fSetCheckedFlag) { HRESULT hr; if (!m_fAddressesChanged) return S_OK; if (m_fPoster && (OENA_READ != m_ntNote)) { //We need to setmodify the cc field. //We need to do this because this field is not typed in by the user. Edit_SetModify(GetDlgItem(m_hwnd, idADCc), TRUE); } hr = m_pAddrWells->HrCheckNames(m_hwnd, fSilent ? CNF_DONTRESOLVE : 0); if (SUCCEEDED(hr)) { if (m_lpWabal == NULL) hr = hrNoRecipients; else { ADRINFO AdrInfo; if (!m_lpWabal->FGetFirst(&AdrInfo)) hr = hrNoRecipients; } if (SUCCEEDED(hr) && fSetCheckedFlag) m_fAddressesChanged = FALSE; } return hr; } HRESULT CNoteHdr::HrCheckGroups(BOOL fPosting) { HRESULT hr = S_OK; BOOL fFailed = FALSE; ULONG cReplyTo=0; ADRINFO adrInfo; BOOL fOneOrMoreNames = FALSE; BOOL fMoreNames = FALSE; TCHAR szAcctID[CCHMAX_ACCOUNT_NAME]; FOLDERID idServer = FOLDERID_INVALID; if (!m_pAccount) return E_FAIL; m_pAccount->GetPropSz(AP_ACCOUNT_ID, szAcctID, sizeof(szAcctID)); // find the parent folder id of the account hr = g_pStore->FindServerId(szAcctID, &idServer); if (FAILED(hr)) return hr; // check the group names... hr = ResolveGroupNames(m_hwnd, idADNewsgroups, idServer, FALSE, &fMoreNames); fOneOrMoreNames = fMoreNames; fFailed = FAILED(hr); // Check followup names hr = ResolveGroupNames(m_hwnd, idTXTFollowupTo, idServer, TRUE, &fMoreNames); fOneOrMoreNames = (fOneOrMoreNames || fMoreNames); fFailed = fFailed || FAILED(hr); if (!fOneOrMoreNames) return hrNoRecipients; if (fPosting) { // make sure there is only one reply-to person, in the wabal if (m_lpWabal->FGetFirst(&adrInfo)) do if (adrInfo.lRecipType == MAPI_REPLYTO) cReplyTo++; while (m_lpWabal->FGetNext(&adrInfo)); if (cReplyTo>1) { // this is not cool. Don't allow then to post... AthMessageBoxW(m_hwnd, MAKEINTRESOURCEW(idsAthenaNews), MAKEINTRESOURCEW(idsErrOnlyOneReplyTo), NULL, MB_OK); return hrTooManyReplyTo; } } if (fPosting && fFailed) { if (IDYES == AthMessageBoxW(m_hwnd, MAKEINTRESOURCEW(idsAthenaNews), MAKEINTRESOURCEW(idsIgnoreResolveError), 0, MB_ICONEXCLAMATION |MB_YESNO)) hr = S_OK; else hr = MAPI_E_USER_CANCEL; } return hr; } HRESULT CNoteHdr::ResolveGroupNames(HWND hwnd, int idField, FOLDERID idServer, BOOL fPosterAllowed, BOOL *fOneOrMoreNames) { HRESULT hr = S_OK; FOLDERINFO Folder; int nResolvedNames = 0; AssertSz((idServer != FOLDERID_INVALID), TEXT("ResolveGroupNames: [ARGS] No account folder")); // Now loop through the group names and see if they all exist. First make // a copy of the string since strtok is destructive. LPWSTR pwszBuffer = NULL; LPSTR pszBuffer = NULL; DWORD dwType; LONG lIndex, cchBufLen, lIter = 0; TCHAR szPrompt[CCHMAX_STRINGRES]; LPTSTR psz = NULL, pszTok = NULL, pszToken = NULL; // HrGetFieldText will return S_FALSE if no text hr = HrGetFieldText(&pwszBuffer, idField); if (S_OK != hr) return hr; IF_NULLEXIT(pszBuffer = PszToANSI(GetACP(), pwszBuffer)); psz = pszBuffer; // Check group name while (*psz && IsSpace(psz)) psz = CharNext(psz); if(!(*psz)) { hr = S_FALSE; goto exit; } else psz = NULL; pszTok = pszBuffer; pszToken = StrTokEx(&pszTok, GRP_DELIMITERS); while (NULL != pszToken) { if (!fPosterAllowed || (fPosterAllowed && 0 != lstrcmpi(pszToken, c_szPosterKeyword))) { ZeroMemory(&Folder, sizeof(Folder)); // See if the Folder Already Exists Folder.idParent = idServer; Folder.pszName = (LPSTR)pszToken; // Try to find in the index if (DB_S_FOUND == g_pStore->FindRecord(IINDEX_ALL, COLUMNS_ALL, &Folder, NULL)) { // Check to see if this newsgroup allows posting. if (Folder.dwFlags & FOLDER_NOPOSTING) { psz = AthLoadString(idsErrNewsgroupNoPosting, 0, 0); wnsprintf(szPrompt, ARRAYSIZE(szPrompt), psz, pszToken, pszToken); AthFreeString(psz); AthMessageBox(hwnd, MAKEINTRESOURCE(idsAthenaNews), szPrompt, 0, MB_ICONSTOP | MB_OK); hr = E_FAIL; } if (Folder.dwFlags & FOLDER_BLOCKED) { psz = AthLoadString(idsErrNewsgroupBlocked, 0, 0); wnsprintf(szPrompt, ARRAYSIZE(szPrompt), psz, pszToken, pszToken); AthFreeString(psz); AthMessageBox(hwnd, MAKEINTRESOURCE(idsAthenaNews), szPrompt, 0, MB_ICONSTOP | MB_OK); hr = E_FAIL; } else nResolvedNames++; // Free g_pStore->FreeRecord(&Folder); } else { psz = AthLoadString(idsErrCantResolveGroup, 0, 0); wnsprintf(szPrompt, ARRAYSIZE(szPrompt), psz, pszToken); AthFreeString(psz); AthMessageBox(hwnd, MAKEINTRESOURCE(idsAthenaNews), szPrompt, 0, MB_ICONSTOP | MB_OK); hr = E_FAIL; } } pszToken = StrTokEx(&pszTok, GRP_DELIMITERS); } exit: MemFree(pszBuffer); MemFree(pwszBuffer); *fOneOrMoreNames = ((nResolvedNames > 0) ? TRUE : FALSE); return (hr); } HRESULT CNoteHdr::HrGetFieldText(LPWSTR* ppszText, int idHdrCtrl) { HWND hwnd = GetDlgItem(m_hwnd, idHdrCtrl); return HrGetFieldText(ppszText, hwnd); } HRESULT CNoteHdr::HrGetFieldText(LPWSTR* ppszText, HWND hwnd) { DWORD cch; cch = GetRichEditTextLen(hwnd) + 1; if (1 == cch) return (S_FALSE); if (!MemAlloc((LPVOID*) ppszText, cch * sizeof(WCHAR))) return (E_OUTOFMEMORY); HdrGetRichEditText(hwnd, *ppszText, cch, FALSE); return (S_OK); } HRESULT CNoteHdr::HrAddSender() { ULONG uPos=0; ADRINFO adrInfo; LPADRINFO lpAdrInfo=0; LPWAB lpWab; HRESULT hr=E_FAIL; if (m_lpWabal->FGetFirst(&adrInfo)) do if (adrInfo.lRecipType==MAPI_ORIG) { lpAdrInfo=&adrInfo; break; } while (m_lpWabal->FGetNext(&adrInfo)); if (lpAdrInfo && !FAILED (HrCreateWabObject (&lpWab))) { hr=lpWab->HrAddToWAB(m_hwnd, lpAdrInfo); lpWab->Release (); } if (FAILED(hr) && hr!=MAPI_E_USER_CANCEL) { if (hr==MAPI_E_COLLISION) AthMessageBoxW (m_hwnd, MAKEINTRESOURCEW(idsAthenaMail), MAKEINTRESOURCEW(idsErrAddrDupe), NULL, MB_OK); else AthMessageBoxW (m_hwnd, MAKEINTRESOURCEW(idsAthenaMail), MAKEINTRESOURCEW(idsErrAddToWAB), NULL, MB_OK); } return NOERROR; } HRESULT CNoteHdr::HrAddAllOnToList() { ADRINFO adrInfo; LPWAB lpWab; HRESULT hr = S_OK; if (m_lpWabal->FGetFirst(&adrInfo)) { hr = HrCreateWabObject(&lpWab); if (SUCCEEDED(hr)) { do { if (MAPI_TO == adrInfo.lRecipType) { hr = lpWab->HrAddToWAB(m_hwnd, &adrInfo); if (MAPI_E_COLLISION == hr) { hr = S_OK; AthMessageBoxW (m_hwnd, MAKEINTRESOURCEW(idsAthenaMail), MAKEINTRESOURCEW(idsErrAddrDupe), NULL, MB_OK); } } } while (SUCCEEDED(hr) && m_lpWabal->FGetNext(&adrInfo)); } lpWab->Release(); } if (FAILED(hr) && (MAPI_E_USER_CANCEL != hr)) AthMessageBoxW (m_hwnd, MAKEINTRESOURCEW(idsAthenaMail), MAKEINTRESOURCEW(idsErrAddToWAB), NULL, MB_OK); return hr; } HRESULT CNoteHdr::HrInitFieldList() { PHCI pHCI, pLoopHCI; INT size; BOOL fReadOnly = IsReadOnly(); if (m_fMail) { if (fReadOnly) { pHCI = rgMailHeaderRead; size = sizeof(rgMailHeaderRead); } else { pHCI = rgMailHeaderSend; size = sizeof(rgMailHeaderSend); } } else { if (fReadOnly) { pHCI = rgNewsHeaderRead; size = sizeof(rgNewsHeaderRead); } else { pHCI = rgNewsHeaderSend; size = sizeof(rgNewsHeaderSend); } } // Setup the labels pLoopHCI = pHCI; m_cHCI = size/sizeof(HCI); for (ULONG i = 0; i < m_cHCI; i++, pLoopHCI++) { if (0 == pLoopHCI->strlen) { AthLoadStringW(pLoopHCI->idsLabel, pLoopHCI->sz, cchHeaderMax+1); pLoopHCI->strlen = lstrlenW(pLoopHCI->sz); } if ((0 == pLoopHCI->strlenEmpty) && (0 != pLoopHCI->idsEmpty)) { AthLoadStringW(pLoopHCI->idsEmpty, pLoopHCI->szEmpty, cchHeaderMax+1); pLoopHCI->strlenEmpty = lstrlenW(pLoopHCI->szEmpty); } } if (NULL != MemAlloc((LPVOID *)&m_rgHCI, size)) CopyMemory(m_rgHCI, pHCI, size); else return E_OUTOFMEMORY; m_cxLeftMargin = _GetLeftMargin(); return S_OK; } int CNoteHdr::_GetLeftMargin() { PHCI pLoopHCI = m_rgHCI; INT size; int cxButtons = ControlXBufferSize(); HDC hdc = GetDC(m_hwnd); HFONT hfontOld; ULONG cxEditMarginCur = 0, cxEditMaxMargin = 0; SIZE rSize; BOOL fReadOnly = IsReadOnly(); // Setup the labels hfontOld=(HFONT)SelectObject(hdc, GetFont(fReadOnly)); for (ULONG i = 0; i < m_cHCI; i++, pLoopHCI++) { AssertSz(pLoopHCI->strlen, "Haven't set the strings yet."); GetTextExtentPoint32AthW(hdc, pLoopHCI->sz, pLoopHCI->strlen, &rSize, NOFLAGS); cxEditMarginCur = rSize.cx + PaddingOfLabels(); if (pLoopHCI->dwFlags & HCF_HASBUTTON) cxEditMarginCur += CXOfButtonToLabel(); if (cxEditMarginCur > cxEditMaxMargin) cxEditMaxMargin = cxEditMarginCur; } SelectObject(hdc, hfontOld); ReleaseDC(m_hwnd, hdc); return cxEditMaxMargin; } HRESULT CNoteHdr::HrFreeFieldList() { if (m_rgHCI) { for (int i=0; i<(int)m_cHCI; i++) { // You must free the pDoc before the preole or fault! (RICHED 2.0) SafeRelease(m_rgHCI[i].pDoc); SafeRelease(m_rgHCI[i].preole); } } return NOERROR; } static WELLINIT rgWellInitMail[]= { {idADTo, MAPI_TO}, {idADCc, MAPI_CC}, {idADFrom, MAPI_ORIG}, {idADBCc, MAPI_BCC} }; static WELLINIT rgWellInitNews[]= { {idADFrom, MAPI_ORIG}, {idADCc, MAPI_TO}, {idADReplyTo, MAPI_REPLYTO} }; BOOL CNoteHdr::PostWMCreate() { HWND hwnd; HWND hwndWells[4]; ULONG ulRecipType[4]; ULONG cWells=0; PWELLINIT pWI; INT size; INT i; if (hwnd=GetDlgItem(m_hwnd, idTXTSubject)) SendMessage(hwnd, EM_LIMITTEXT,cchMaxSubject,0); if (m_fMail) { pWI = rgWellInitMail; size = ARRAYSIZE(rgWellInitMail); } else { pWI = rgWellInitNews; size = ARRAYSIZE(rgWellInitNews); } for (i=0; iHrInit(cWells, hwndWells, ulRecipType))) return FALSE; return TRUE; } HRESULT CNoteHdr::HrSetMailRecipients(LPMIMEMESSAGE pMsg) { ADRINFO rAdrInfo; HRESULT hr = NOERROR; IImnEnumAccounts *pEnumAccounts = NULL; LPWABAL lpWabal = NULL; BOOL fAdvanced = FALSE; AssertSz(OENA_REPLYTONEWSGROUP != m_ntNote, "Shouldn't get a REPLYTONEWSGROUP in a mail note."); SafeRelease(m_lpWabal); // Set initial state of wabals to use switch (m_ntNote) { case OENA_READ: case OENA_WEBPAGE: case OENA_STATIONERY: IF_FAILEXIT(hr = HrGetWabalFromMsg(pMsg, &m_lpWabal)); break; case OENA_COMPOSE: case OENA_REPLYTOAUTHOR: case OENA_REPLYALL: IF_FAILEXIT(hr = HrGetWabalFromMsg(pMsg, &lpWabal)); IF_FAILEXIT(hr = HrCreateWabalObject(&m_lpWabal)); break; case OENA_FORWARD: case OENA_FORWARDBYATTACH: IF_FAILEXIT(hr = HrCreateWabalObject(&m_lpWabal)); break; } // Actually set recipients now. switch (m_ntNote) { case OENA_COMPOSE: { #pragma prefast(suppress:11, "noise") BOOL fMoreIterations = lpWabal->FGetFirst(&rAdrInfo); while (fMoreIterations) { if (rAdrInfo.lRecipType != MAPI_ORIG) { hr = m_lpWabal->HrAddEntry(&rAdrInfo); if (FAILED(hr)) break; } fMoreIterations = lpWabal->FGetNext(&rAdrInfo); } break; } case OENA_REPLYTOAUTHOR: case OENA_REPLYALL: { BOOL fNeedOriginatorItems = TRUE; BOOL fMoreIterations; // Add items to To: line from the ReplyTo Field fMoreIterations = lpWabal->FGetFirst (&rAdrInfo); while (fMoreIterations) { if (rAdrInfo.lRecipType==MAPI_REPLYTO) { Assert (rAdrInfo.lpwszAddress); fNeedOriginatorItems = FALSE; rAdrInfo.lRecipType=MAPI_TO; IF_FAILEXIT(hr = m_lpWabal->HrAddEntry(&rAdrInfo)); } fMoreIterations = lpWabal->FGetNext (&rAdrInfo); } // If we don't need to add the MAPI_ORIG and we are not trying to reply to all, then we are done if (!fNeedOriginatorItems && (OENA_REPLYALL != m_ntNote)) break; // Raid-35976: Unable to open message window with no accounts configured // Get an SMTP account enumerator Assert(g_pAcctMan); if (g_pAcctMan && (OENA_REPLYALL == m_ntNote)) g_pAcctMan->Enumerate(SRV_SMTP|SRV_HTTPMAIL, &pEnumAccounts); // Add the following items to the To line // 1) If there were no ReplyTo items, then fill from the Orig field // 2) If is ReplyToAll, then fill from the To and CC line fMoreIterations = lpWabal->FGetFirst (&rAdrInfo); while (fMoreIterations) { // No replyto people were added, and this is a MAPI_ORIG if (fNeedOriginatorItems && rAdrInfo.lRecipType == MAPI_ORIG) { rAdrInfo.lRecipType=MAPI_TO; IF_FAILEXIT(hr = m_lpWabal->HrAddEntry(&rAdrInfo)); } // pEnumAccounts will only be set if ReplyToAll // If ReplyToAll, then add the CC and To line entries to the To field else if (pEnumAccounts && (rAdrInfo.lRecipType == MAPI_TO || rAdrInfo.lRecipType == MAPI_CC)) { BOOL fIsSendersAccount = FALSE; TCHAR szEmailAddress[CCHMAX_EMAIL_ADDRESS]; Assert (rAdrInfo.lpwszAddress); pEnumAccounts->Reset(); // See if rAdrInfo.lpszAddress exist as one of the user's Send Email Addresses while (!fIsSendersAccount) { IImnAccount *pAccount = NULL; hr = pEnumAccounts->GetNext(&pAccount); if (hr == E_EnumFinished || FAILED(hr)) break; if (SUCCEEDED(pAccount->GetPropSz(AP_SMTP_EMAIL_ADDRESS, szEmailAddress, ARRAYSIZE(szEmailAddress)))) { LPWSTR pwszAddress = NULL; IF_NULLEXIT(pwszAddress = PszToUnicode(CP_ACP, szEmailAddress)); if (0 == StrCmpIW(rAdrInfo.lpwszAddress, pwszAddress)) fIsSendersAccount = TRUE; MemFree(pwszAddress); } pAccount->Release(); } // Reset hr hr = S_OK; // Add the account if it isn't from the sender if (!fIsSendersAccount) { if (0 != StrCmpW(rAdrInfo.lpwszAddress, L"Undisclosed Recipients")) { // only include recipient on ReplyAll if it's not the sender... IF_FAILEXIT(hr = m_lpWabal->HrAddEntry(&rAdrInfo)); } } } fMoreIterations = lpWabal->FGetNext(&rAdrInfo); } } } Assert (m_lpWabal); // For the send note case, make sure that resolved addresses are valid. // If display name and email address are the same, UnresolveOneOffs() will clear // the email address to force a real resolve. if (OENA_COMPOSE == m_ntNote || OENA_WEBPAGE == m_ntNote || OENA_STATIONERY == m_ntNote) m_lpWabal->UnresolveOneOffs(); m_lpWabal->HrResolveNames(NULL, FALSE); Assert(m_pAddrWells); m_pAddrWells->HrSetWabal(m_lpWabal); m_pAddrWells->HrDisplayWells(m_hwnd); if (OENA_READ == m_ntNote) fAdvanced = DwGetOption(OPT_MAILNOTEADVREAD); else { fAdvanced = DwGetOption(OPT_MAILNOTEADVSEND); // Need to make sure that if we are in a compose note, that we check to see // if we added a bcc without setting the advanced headers. If this is the case, // then show the advanced headers for this note. if (!fAdvanced && (0 < GetRichEditTextLen(GetDlgItem(m_hwnd, idADBCc)))) fAdvanced = TRUE; } // BUG: 31217: showadvanced has to be the last thing we call after modifying the // well contents ShowAdvancedHeaders(fAdvanced); exit: // Cleanup ReleaseObj(lpWabal); ReleaseObj(pEnumAccounts); return hr; } HRESULT CNoteHdr::HrSetupNote(LPMIMEMESSAGE pMsg) { HWND hwnd; WCHAR wsz[cchMaxSubject+1]; LPWSTR psz = NULL; PROPVARIANT rVariant; HRESULT hr = NOERROR; if (!pMsg) return E_INVALIDARG; MimeOleGetBodyPropW(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_SUBJECT), NOFLAGS, &psz); HdrSetRichEditText(GetDlgItem(m_hwnd, idTXTSubject), psz, FALSE); *wsz=0; rVariant.vt = VT_FILETIME; pMsg->GetProp(PIDTOSTR(PID_ATT_SENTTIME), 0, &rVariant); AthFileTimeToDateTimeW(&rVariant.filetime, wsz, ARRAYSIZE(wsz), DTM_LONGDATE|DTM_NOSECONDS); HdrSetRichEditText(GetDlgItem(m_hwnd, idTXTDate), wsz, FALSE); MemFree(psz); return hr; } HRESULT CNoteHdr::HrSetPri(LPMIMEMESSAGE pMsg) { UINT pri=priNorm; PROPVARIANT rVariant; Assert(pMsg); rVariant.vt = VT_UI4; if (SUCCEEDED(pMsg->GetProp(PIDTOSTR(PID_ATT_PRIORITY), 0, &rVariant))) { if (rVariant.ulVal == IMSG_PRI_HIGH) pri=priHigh; else if (rVariant.ulVal == IMSG_PRI_LOW) pri=priLow; } return SetPriority(pri); } HRESULT CNoteHdr::HrAutoAddToWAB() { LPWAB lpWab=0; LPWABAL lpWabal=0; HRESULT hr; ADRINFO adrInfo; if (!m_lpWabal) return S_OK; if (!DwGetOption(OPT_MAIL_AUTOADDTOWABONREPLY)) return S_OK; IF_FAILEXIT(hr=HrCreateWabObject(&lpWab)); // when this is called, m_lpWabal contains everyone on the to: and cc: line // for a reply/reply all. We will add all these people to the WAB, ignoring any // clashes or failures // Add Sender if email and displayname are not the same. // if so then there's no username so little point in adding. if (m_lpWabal->FGetFirst(&adrInfo)) do { // IE5.#2568: we now just add to the WAB regardless of // email and dispname being the same. // if (lstrcmp(adrInfo.lpszDisplay, adrInfo.lpszAddress)!=0) lpWab->HrAddNewEntry(adrInfo.lpwszDisplay, adrInfo.lpwszAddress); } while (m_lpWabal->FGetNext(&adrInfo)); exit: ReleaseObj(lpWab); return hr; } HRESULT CNoteHdr::HrOfficeLoad() { HRESULT hr = NOERROR; m_fSkipLayout = FALSE; if (!m_hCharset) { if (g_hDefaultCharsetForMail==NULL) ReadSendMailDefaultCharset(); m_hCharset = g_hDefaultCharsetForMail; } if (m_hCharset) HrUpdateCharSetFonts(m_hCharset, FALSE); SafeRelease(m_lpWabal); hr = HrCreateWabalObject(&m_lpWabal); if (SUCCEEDED(hr)) { Assert(m_pAddrWells); m_pAddrWells->HrSetWabal(m_lpWabal); ShowAdvancedHeaders(DwGetOption(OPT_MAILNOTEADVSEND)); m_fStillLoading = FALSE; } return hr; } void CNoteHdr::SetReferences(LPMIMEMESSAGE pMsg) { LPWSTR lpszRefs = 0; SafeMemFree(m_pszRefs); MimeOleGetBodyPropW(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_REFS), NOFLAGS, &lpszRefs); switch (m_ntNote) { case OENA_REPLYALL: case OENA_REPLYTOAUTHOR: case OENA_REPLYTONEWSGROUP: { LPWSTR lpszMsgId = 0; MimeOleGetBodyPropW(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_MESSAGEID), NOFLAGS, &lpszMsgId); if (lpszMsgId) HrCreateReferences(lpszRefs, lpszMsgId, &m_pszRefs); SafeMimeOleFree(lpszMsgId); break; } case OENA_READ: case OENA_WEBPAGE: case OENA_STATIONERY: case OENA_COMPOSE: // hold on to the reference line for a send-note, so we can repersist if saving in drafts if (lpszRefs) m_pszRefs = PszDupW(lpszRefs); break; default: break; } SafeMimeOleFree(lpszRefs); } HRESULT CNoteHdr::HrSetNewsRecipients(LPMIMEMESSAGE pMsg) { HRESULT hr = S_OK; LPWSTR pwszNewsgroups = 0, pwszCC = 0, pwszSetNewsgroups = 0; TCHAR szApproved[CCHMAX_EMAIL_ADDRESS]; HWND hwnd; AssertSz(OENA_REPLYTOAUTHOR != m_ntNote, "Shouldn't get a REPLYTOAUTHOR in a news note."); AssertSz(OENA_FORWARD != m_ntNote, "Shouldn't get a FORWARD in a news note."); AssertSz(OENA_FORWARDBYATTACH != m_ntNote, "Shouldn't get a FORWARDBYATTACH in a news note."); *szApproved = 0; if (m_pAccount && DwGetOption(OPT_NEWSMODERATOR)) { if (FAILED(m_pAccount->GetPropSz(AP_NNTP_REPLY_EMAIL_ADDRESS, szApproved, ARRAYSIZE(szApproved))) || (0 == *szApproved)) m_pAccount->GetPropSz(AP_NNTP_EMAIL_ADDRESS, szApproved, ARRAYSIZE(szApproved)); } MimeOleGetBodyPropW(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_NEWSGROUPS), NOFLAGS, &pwszNewsgroups); switch (m_ntNote) { case OENA_READ: { LPWSTR lpszOrg = 0; MimeOleGetBodyPropW(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_ORG), NOFLAGS, &lpszOrg); HdrSetRichEditText(GetDlgItem(m_hwnd, idTXTOrg), lpszOrg, FALSE); SafeMimeOleFree(lpszOrg); } // Fall through case OENA_WEBPAGE: case OENA_STATIONERY: case OENA_COMPOSE: { LPWSTR lpszFollowup = 0, lpszDist = 0, lpszKeywords = 0; MimeOleGetBodyPropW(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_FOLLOWUPTO), NOFLAGS, &lpszFollowup); MimeOleGetBodyPropW(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_DISTRIB), NOFLAGS, &lpszDist); MimeOleGetBodyPropW(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_KEYWORDS), NOFLAGS, &lpszKeywords); pwszSetNewsgroups = pwszNewsgroups; HdrSetRichEditText(GetDlgItem(m_hwnd, idTXTFollowupTo), lpszFollowup, FALSE); HdrSetRichEditText(GetDlgItem(m_hwnd, idTXTDistribution), lpszDist, FALSE); HdrSetRichEditText(GetDlgItem(m_hwnd, idTXTKeywords), lpszKeywords, FALSE); MemFree(lpszFollowup); MemFree(lpszDist); MemFree(lpszKeywords); break; } case OENA_REPLYALL: case OENA_REPLYTONEWSGROUP: { LPSTR pszGroupsFree = 0; if (SUCCEEDED(ParseFollowup(pMsg, &pszGroupsFree, &m_fPoster))) { if (pszGroupsFree) { SafeMemFree(pwszNewsgroups); IF_NULLEXIT(pwszNewsgroups = PszToUnicode(CP_ACP, pszGroupsFree)); } pwszSetNewsgroups = pwszNewsgroups; } else pwszSetNewsgroups = pwszNewsgroups; Assert(pwszSetNewsgroups); if ((OENA_REPLYALL == m_ntNote) || m_fPoster) { MimeOleGetBodyPropW(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_REPLYTO), NOFLAGS, &pwszCC); if (!pwszCC) MimeOleGetBodyPropW(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_FROM), NOFLAGS, &pwszCC); } break; } } // set common fields HdrSetRichEditText(GetDlgItem(m_hwnd, idADNewsgroups), pwszSetNewsgroups, FALSE); // set read note / send note specific fields if (OENA_READ != m_ntNote) SetDlgItemText(m_hwnd, idADApproved, szApproved); // set up the recipients hr = HrSetNewsWabal(pMsg, pwszCC); // BUG: 31217: showadvanced has to be the last thing we call after modifying the // well contents ShowAdvancedHeaders(DwGetOption(m_ntNote == OENA_READ ? OPT_NEWSNOTEADVREAD : OPT_NEWSNOTEADVSEND)); exit: MemFree(pwszNewsgroups); MemFree(pwszCC); return hr; } HRESULT CNoteHdr::FullHeadersShowing(void) { return m_fAdvanced ? S_OK : S_FALSE; } HRESULT CNoteHdr::HrNewsSave(LPMIMEMESSAGE pMsg, CODEPAGEID cpID, BOOL fCheckConflictOnly) { HRESULT hr = S_OK; WCHAR wsz[256]; WCHAR *pwszTrim; BOOL fSenderOk = FALSE, fSetMessageAcct = TRUE; PROPVARIANT rVariant; SYSTEMTIME st; HWND hwnd; PROPVARIANT rUserData; BOOL fConflict = FALSE; if (fCheckConflictOnly) { HdrGetRichEditText(GetDlgItem(m_hwnd, idADNewsgroups), wsz, ARRAYSIZE(wsz), FALSE); pwszTrim = strtrimW(wsz); if (*pwszTrim) { IF_FAILEXIT(hr = HrSafeToEncodeToCP(pwszTrim, cpID)); if (MIME_S_CHARSET_CONFLICT == hr) goto exit; } HdrGetRichEditText(GetDlgItem(m_hwnd, idTXTFollowupTo), wsz, ARRAYSIZE(wsz), FALSE); pwszTrim = strtrimW(wsz); if (*pwszTrim) { IF_FAILEXIT(hr = HrSafeToEncodeToCP(pwszTrim, cpID)); if (MIME_S_CHARSET_CONFLICT == hr) goto exit; } HdrGetRichEditText(GetDlgItem(m_hwnd, idTXTDistribution), wsz, ARRAYSIZE(wsz), FALSE); pwszTrim = strtrimW(wsz); if (*pwszTrim) { IF_FAILEXIT(hr = HrSafeToEncodeToCP(pwszTrim, cpID)); if (MIME_S_CHARSET_CONFLICT == hr) goto exit; } HdrGetRichEditText(GetDlgItem(m_hwnd, idTXTKeywords), wsz, ARRAYSIZE(wsz), FALSE); pwszTrim = strtrimW(wsz); if (*pwszTrim) { IF_FAILEXIT(hr = HrSafeToEncodeToCP(pwszTrim, cpID)); if (MIME_S_CHARSET_CONFLICT == hr) goto exit; } if (hwnd = GetDlgItem(m_hwnd, idADApproved)) { HdrGetRichEditText(hwnd, wsz, ARRAYSIZE(wsz), FALSE); pwszTrim = strtrimW(wsz); if (*pwszTrim) { IF_FAILEXIT(hr = HrSafeToEncodeToCP(pwszTrim, cpID)); if (MIME_S_CHARSET_CONFLICT == hr) goto exit; } } if (hwnd = GetDlgItem(m_hwnd, idTxtControl)) { HdrGetRichEditText(hwnd, wsz, ARRAYSIZE(wsz), FALSE); pwszTrim = strtrimW(wsz); if (*pwszTrim) { IF_FAILEXIT(hr = HrSafeToEncodeToCP(pwszTrim, cpID)); if (MIME_S_CHARSET_CONFLICT == hr) goto exit; } } } else { // ************************ // This portion only happens on save, so don't try to do for fCheckConflictOnly // Anything not in this section had better be mirrored in the fCheckConflictOnly block above // Place any ascii only stuff here. // end of save only portion. // ************************* HdrGetRichEditText(GetDlgItem(m_hwnd, idADNewsgroups), wsz, ARRAYSIZE(wsz), FALSE); pwszTrim = strtrimW(wsz); if (*pwszTrim) { // Bug #22455 - Make sure we strip spaces etc from between newsgroups _ValidateNewsgroups(pwszTrim); IF_FAILEXIT(hr = MimeOleSetBodyPropW(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_NEWSGROUPS), NOFLAGS, pwszTrim)); } HdrGetRichEditText(GetDlgItem(m_hwnd, idTXTFollowupTo), wsz, ARRAYSIZE(wsz), FALSE); pwszTrim = strtrimW(wsz); if (*pwszTrim) { IF_FAILEXIT(hr = MimeOleSetBodyPropW(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_FOLLOWUPTO), NOFLAGS, pwszTrim)); } HdrGetRichEditText(GetDlgItem(m_hwnd, idTXTDistribution), wsz, ARRAYSIZE(wsz), FALSE); pwszTrim = strtrimW(wsz); if (*pwszTrim) { IF_FAILEXIT(hr = MimeOleSetBodyPropW(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_DISTRIB), NOFLAGS, pwszTrim)); } HdrGetRichEditText(GetDlgItem(m_hwnd, idTXTKeywords), wsz, ARRAYSIZE(wsz), FALSE); pwszTrim = strtrimW(wsz); if (*pwszTrim) { IF_FAILEXIT(hr = MimeOleSetBodyPropW(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_KEYWORDS), NOFLAGS, pwszTrim)); } if (hwnd = GetDlgItem(m_hwnd, idADApproved)) { HdrGetRichEditText(hwnd, wsz, ARRAYSIZE(wsz), FALSE); pwszTrim = strtrimW(wsz); if (*pwszTrim) { IF_FAILEXIT(hr = MimeOleSetBodyPropW(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_APPROVED), NOFLAGS, pwszTrim)); } } if (hwnd = GetDlgItem(m_hwnd, idTxtControl)) { HdrGetRichEditText(hwnd, wsz, ARRAYSIZE(wsz), FALSE); pwszTrim = strtrimW(wsz); if (*pwszTrim) { IF_FAILEXIT(hr = MimeOleSetBodyPropW(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_CONTROL), NOFLAGS, pwszTrim)); } } } exit: return hr; } HRESULT CNoteHdr::HrSetNewsWabal(LPMIMEMESSAGE pMsg, LPWSTR pwszCC) { HRESULT hr = S_OK; LPWABAL lpWabal = NULL; ADDRESSLIST addrList = { 0 }; LPWSTR pwszEmail = NULL; IMimeMessageW *pMsgW = NULL; SafeRelease(m_lpWabal); if (OENA_READ == m_ntNote) { // for a read note, just take the wabal from the message IF_FAILEXIT(hr = HrGetWabalFromMsg(pMsg, &m_lpWabal)); } else { TCHAR szReplyAddr[CCHMAX_EMAIL_ADDRESS]; TCHAR szEmailAddr[CCHMAX_EMAIL_ADDRESS]; // for a compose note, or a reply note we need to do some munging, so create a new wabal IF_FAILEXIT(hr = HrCreateWabalObject(&m_lpWabal)); if (OENA_COMPOSE == m_ntNote) { ADRINFO rAdrInfo; IF_FAILEXIT(hr = HrGetWabalFromMsg(pMsg, &lpWabal)); // just copy everything except From: and ReplyTo: because we'll add those later if (lpWabal->FGetFirst(&rAdrInfo)) { do { if (rAdrInfo.lRecipType != MAPI_ORIG && rAdrInfo.lRecipType != MAPI_REPLYTO) IF_FAILEXIT(hr = m_lpWabal->HrAddEntry(&rAdrInfo)); } while (lpWabal->FGetNext(&rAdrInfo)); } } // add replyto if necessary if (m_pAccount) { if (SUCCEEDED(m_pAccount->GetPropSz(AP_NNTP_REPLY_EMAIL_ADDRESS, szReplyAddr, ARRAYSIZE(szReplyAddr))) && *szReplyAddr && SUCCEEDED(m_pAccount->GetPropSz(AP_NNTP_EMAIL_ADDRESS, szEmailAddr, ARRAYSIZE(szEmailAddr))) && lstrcmpi(szReplyAddr, szEmailAddr)) { TCHAR szName[CCHMAX_DISPLAY_NAME]; if (SUCCEEDED(m_pAccount->GetPropSz(AP_NNTP_DISPLAY_NAME, szName, ARRAYSIZE(szName)))) IF_FAILEXIT(hr = m_lpWabal->HrAddEntryA(szName, szReplyAddr, MAPI_REPLYTO)); else IF_FAILEXIT(hr = m_lpWabal->HrAddEntryA(szReplyAddr, szReplyAddr, MAPI_REPLYTO)); } } //Bug# 79066 if ((OENA_REPLYALL == m_ntNote) || m_fPoster) { if (FAILED(MimeOleParseRfc822AddressW(IAT_REPLYTO, pwszCC, &addrList))) { IF_FAILEXIT(hr = MimeOleParseRfc822AddressW(IAT_FROM, pwszCC, &addrList)); } IF_NULLEXIT(pwszEmail = PszToUnicode(CP_ACP, addrList.prgAdr->pszEmail)); IF_FAILEXIT(hr = m_lpWabal->HrAddEntry(addrList.prgAdr->pszFriendlyW, pwszEmail, MAPI_TO)); } } // For the send note case, make sure that resolved addresses are valid. // If display name and email address are the same, UnresolveOneOffs() will clear // the email address to force a real resolve. if ((OENA_COMPOSE == m_ntNote) || (OENA_WEBPAGE == m_ntNote) || OENA_STATIONERY == m_ntNote) m_lpWabal->UnresolveOneOffs(); m_lpWabal->HrResolveNames(NULL, FALSE); Assert(m_pAddrWells); if (SUCCEEDED(hr = m_pAddrWells->HrSetWabal(m_lpWabal))) hr = m_pAddrWells->HrDisplayWells(m_hwnd); exit: if (g_pMoleAlloc) { if (addrList.cAdrs) g_pMoleAlloc->FreeAddressList(&addrList); } ReleaseObj(lpWabal); MemFree(pwszEmail); ReleaseObj(pMsgW); return hr; } HRESULT CNoteHdr::HrSetReplySubject(LPMIMEMESSAGE pMsg, BOOL fReply) { WCHAR szNewSubject[cchMaxSubject+1]; LPWSTR pszNorm = NULL; int cchPrefix; LPCWSTR lpwReFwd = NULL; MimeOleGetBodyPropW(pMsg, HBODY_ROOT, STR_ATT_NORMSUBJ, NOFLAGS, &pszNorm); if (!!DwGetOption(OPT_HARDCODEDHDRS)) { //Use english strings and not from resources lpwReFwd = fReply ? c_wszRe : c_wszFwd; StrCpyNW(szNewSubject, lpwReFwd, cchMaxSubject); } else { // pull in the new prefix from resource... AthLoadStringW(fReply?idsPrefixReply:idsPrefixForward, szNewSubject, cchMaxSubject); } cchPrefix = lstrlenW(szNewSubject); Assert(cchPrefix); if (pszNorm) { StrCpyNW(szNewSubject+cchPrefix, pszNorm, min(lstrlenW(pszNorm), cchMaxSubject-cchPrefix)+1); SafeMimeOleFree(pszNorm); } HdrSetRichEditText(GetDlgItem(m_hwnd, idTXTSubject), szNewSubject, FALSE); return NOERROR; } #define FIsDelimiter(_ch) (_ch==L';' || _ch==L',' || _ch==L' ' || _ch==L'\r' || _ch==L'\n' || _ch == L'\t') void _ValidateNewsgroups(LPWSTR pszGroups) { LPWSTR pszDst = pszGroups; BOOL fInGroup = FALSE; WCHAR ch; Assert(pszGroups); while (ch = *pszGroups++) { if (FIsDelimiter(ch)) { if (fInGroup) { while ((ch = *pszGroups) && FIsDelimiter(ch)) pszGroups++; if (ch) *pszDst++ = L','; fInGroup = FALSE; } } else { *pszDst++ = ch; fInGroup = TRUE; } } *pszDst = 0; } HRESULT CNoteHdr::HrQueryToolbarButtons(DWORD dwFlags, const GUID *pguidCmdGroup, OLECMD* pOleCmd) { pOleCmd->cmdf = 0; if (NULL == pguidCmdGroup) { switch (pOleCmd->cmdID) { case OLECMDID_CUT: pOleCmd->cmdf = QS_ENABLED(dwFlags&edfEditHasSelAndIsRW); break; case OLECMDID_PASTE: pOleCmd->cmdf = QS_ENABLED(dwFlags&edfPaste); break; case OLECMDID_SELECTALL: pOleCmd->cmdf = QS_ENABLED(TRUE); break; case OLECMDID_COPY: pOleCmd->cmdf = QS_ENABLED(dwFlags&edfEditHasSel); break; case OLECMDID_UNDO: pOleCmd->cmdf = QS_ENABLED(dwFlags&edfUndo); break; } } else if (IsEqualGUID(CMDSETID_OutlookExpress, *pguidCmdGroup)) { switch (pOleCmd->cmdID) { case ID_CUT: pOleCmd->cmdf = QS_ENABLED(dwFlags&edfEditHasSelAndIsRW); break; case ID_PASTE: pOleCmd->cmdf = QS_ENABLED(dwFlags&edfPaste); break; case ID_SELECT_ALL: pOleCmd->cmdf = QS_ENABLED(TRUE); break; case ID_NOTE_COPY: case ID_COPY: pOleCmd->cmdf = QS_ENABLED(dwFlags&edfEditHasSel); break; case ID_UNDO: pOleCmd->cmdf = QS_ENABLED(dwFlags&edfUndo); break; } } return NOERROR; } void CNoteHdr::OnButtonClick(int idBtn) { UINT cch; LPTSTR pszGroups; //CPickGroupDlg* ppgd; switch (idBtn) { case idbtnTo: if (m_fMail) HrPickNames(0); else HrPickGroups(idADNewsgroups, FALSE); break; case idbtnFollowup: HrPickGroups(idTXTFollowupTo, TRUE); break; case idbtnCc: if (m_fMail) HrPickNames(1); else HrPickNames(0); break; case idbtnBCc: HrPickNames(2); break; case idbtnReplyTo: HrPickNames(1); break; } } void CNoteHdr::HrPickGroups(int idWell, BOOL fFollowUpTo) { UINT cch; DWORD cServer = 0; HWND hwnd; LPSTR pszGroups=NULL; LPWSTR pwszGroups=NULL; CPickGroupDlg *ppgd; CHAR szAccount[CCHMAX_ACCOUNT_NAME]; g_pAcctMan->GetAccountCount(ACCT_NEWS, &cServer); // BUGBUG Sometimes m_pAccount is an IMAP server, so we want to also // test that we have at least one news server. This is a known problem // that was punted a long time ago. if (!m_pAccount || !cServer) { AthMessageBoxW (m_hwnd, MAKEINTRESOURCEW(idsAthenaMail), MAKEINTRESOURCEW(idsErrConfigureServer), NULL, MB_OK); return; } hwnd = GetDlgItem(m_hwnd, idWell); if (S_OK == HrGetFieldText(&pwszGroups, hwnd)) { // Since this function doesn't fail, just make sure that we // don't do anything funky when PszToANSI and PszToUnicode fails. pszGroups = PszToANSI(GetACP(), pwszGroups); } ppgd = new CPickGroupDlg; if (ppgd) { FOLDERID idServer = FOLDERID_INVALID; m_pAccount->GetPropSz(AP_ACCOUNT_ID, szAccount, sizeof(szAccount)); // find the parent folder id of the account if (SUCCEEDED(g_pStore->FindServerId(szAccount, &idServer)) && ppgd->FCreate(m_hwnd, idServer, &pszGroups, fFollowUpTo) && pszGroups) { SafeMemFree(pwszGroups); pwszGroups = PszToUnicode(CP_ACP, pszGroups); HdrSetRichEditText(hwnd, pwszGroups != NULL ? pwszGroups : c_wszEmpty, FALSE); } ppgd->Release(); } MemFree(pwszGroups); MemFree(pszGroups); } HRESULT CNoteHdr::HrPickNames(int iwell) { HRESULT hr = NOERROR; if (IsReadOnly()) return hr; Assert(m_lpWabal); Assert(m_pAddrWells); //We need to setmodify so that it is marked as dirty. In a normal case, //the user would have typed in and hence set modify would have happenned automatically if (m_fPoster) { Edit_SetModify(GetDlgItem(m_hwnd, idADCc), TRUE); } hr=m_pAddrWells->HrSelectNames(m_hwnd, iwell, m_fMail?FALSE:TRUE); if (SUCCEEDED(hr)) { // Check to see if need to show advanced headers. if (0 < GetRichEditTextLen(GetDlgItem(m_hwnd, idADBCc))) ShowAdvancedHeaders(TRUE); } else if (hr!=MAPI_E_USER_CANCEL) AthMessageBoxW (m_hwnd, MAKEINTRESOURCEW(idsAthenaMail), MAKEINTRESOURCEW(idsErrPickNames), NULL, MB_OK); return hr; } HRESULT CNoteHdr::HrGetAccountInHeader(IImnAccount **ppAcct) { HRESULT hr = E_FAIL; IImnAccount *pAcct = NULL; ULONG cAccount = 0; HWND hwndCombo = GetDlgItem(m_hwnd, idFromCombo); // If the combo box is being used then get the account info from it. if (SUCCEEDED(g_pAcctMan->GetAccountCount(m_fMail?ACCT_MAIL:ACCT_NEWS, &cAccount)) && (cAccount > 1) && hwndCombo) { LPSTR szAcctID = NULL; ULONG i = ComboBox_GetCurSel(hwndCombo); szAcctID = (LPSTR)SendMessage(hwndCombo, CB_GETITEMDATA, WPARAM(i), 0); hr = g_pAcctMan->FindAccount(AP_ACCOUNT_ID, szAcctID, &pAcct); } // Get default account from MsgSite if (FAILED(hr) && m_pHeaderSite) { IOEMsgSite *pMsgSite = NULL; IServiceProvider *pServ = NULL; hr = m_pHeaderSite->QueryInterface(IID_IServiceProvider, (LPVOID*)&pServ); if (SUCCEEDED(hr)) { hr = pServ->QueryService(IID_IOEMsgSite, IID_IOEMsgSite, (LPVOID*)&pMsgSite); pServ->Release(); } if (SUCCEEDED(hr)) { hr = pMsgSite->GetDefaultAccount(m_fMail?ACCT_MAIL:ACCT_NEWS, &pAcct); pMsgSite->Release(); } } // Get global default. Used in failure case and in Envelope (WordMail, etc) case if (FAILED(hr)) hr = g_pAcctMan->GetDefaultAccount(m_fMail?ACCT_MAIL:ACCT_NEWS, &pAcct); if (SUCCEEDED(hr)) { AssertSz(pAcct, "How is it that we succeeded, yet we don't have an account???"); ReplaceInterface((*ppAcct), pAcct); } else if (E_FAIL == hr) hr = HR_E_COULDNOTFINDACCOUNT; ReleaseObj(pAcct); return hr; } HRESULT CNoteHdr::HrFillMessage(IMimeMessage *pMsg) { IUnknown *punk; IPersistMime *pPM = NULL; HRESULT hr; if (m_pEnvelopeSite) punk = m_pEnvelopeSite; else punk = m_pHeaderSite; AssertSz(punk, "You need either a HeaderSite or an EnvelopeSite"); hr = punk->QueryInterface(IID_IPersistMime, (LPVOID*)&pPM); if (SUCCEEDED(hr)) { hr = pPM->Save(pMsg, 0); ReleaseObj(pPM); if (hr == MAPI_E_USER_CANCEL) goto Exit; } else // If can't get a IPersistMime, need to fake the save through the m_pEnvelopeSite // The only time the QI for IPersistMime doesn't work is if you have an m_pEnvelopeSite // that doesn't support IPersistMime. If you have a m_pHeaderSite, QI should always work. { LPSTREAM pstm; HBODY hBodyHtml = 0; AssertSz(m_pEnvelopeSite, "If the QI didn't work, then must be an envelope site."); // We need to select the charset before we save the message pMsg->SetCharset(m_hCharset, CSET_APPLY_ALL); hr = Save(pMsg, 0); if (FAILED(hr)) goto Exit; // Word will call our GetAttach function during this call to GetBody so save m_pMsgSend // so that we can inline attaches that Word sends to us. m_pMsgSend = pMsg; if (SUCCEEDED(_GetMsoBody(ENV_BODY_HTML, &pstm))) { pMsg->SetTextBody(TXT_HTML, IET_INETCSET, NULL, pstm, &hBodyHtml); pstm->Release(); } if (SUCCEEDED(_GetMsoBody(ENV_BODY_TEXT, &pstm))) { pMsg->SetTextBody(TXT_PLAIN, IET_INETCSET, hBodyHtml, pstm, NULL); pstm->Release(); } m_pMsgSend = NULL; } Exit: return hr; } HRESULT CNoteHdr::_GetMsoBody(ULONG uBody, LPSTREAM *ppstm) { LPSTREAM pstm=NULL; HRESULT hr; *ppstm = NULL; IF_FAILEXIT(hr = MimeOleCreateVirtualStream(&pstm)); IF_FAILEXIT(hr = m_pEnvelopeSite->GetBody(pstm, uCodePageFromCharset(m_hCharset), uBody)); *ppstm = pstm; pstm = NULL; exit: ReleaseObj(pstm); return hr; } #ifdef YST // this check produced a 4 bugs in OE 5.01 and 5.5 and I disaable it (YST) HRESULT CNoteHdr::_CheckMsoBodyCharsetConflict(CODEPAGEID cpID) { HRESULT hr = S_OK; LPSTREAM pstm = NULL; BSTR bstrText = NULL; ULONG cbToRead = 0, cbRead = 0; IF_FAILEXIT(hr = MimeOleCreateVirtualStream(&pstm)); hr = m_pEnvelopeSite->GetBody(pstm, CP_UNICODE, ENV_BODY_TEXT); // bobn; Raid 81900; 6/30/99 // Excel (and powerpoint?) don't have a text body. // Check that there is an HTML body and we can have // it in unicode. if(FAILED(hr)) IF_FAILEXIT(hr = m_pEnvelopeSite->GetBody(pstm, CP_UNICODE, ENV_BODY_HTML)); IF_FAILEXIT(hr = HrIStreamToBSTR(CP_UNICODE, pstm, &bstrText)); hr = HrSafeToEncodeToCP((LPWSTR)bstrText, cpID); exit: SysFreeString(bstrText); ReleaseObj(pstm); return hr; } #endif //YST HRESULT CNoteHdr::HrCheckSendInfo() { HRESULT hr; BOOL fOneOrMoreGroups = FALSE, fOneOrMoreNames = FALSE; hr = HrCheckNames(FALSE, TRUE); if (FAILED(hr)) { if ((MAPI_E_USER_CANCEL != hr) && (hrNoRecipients != hr)) hr = hrBadRecipients; if (hrNoRecipients != hr) goto Exit; } else fOneOrMoreNames = TRUE; // If we didn't find any email recipients, don't need to check if valid. if (SUCCEEDED(hr) && m_lpWabal) hr = m_lpWabal->IsValidForSending(); // Only check groups if: // 1- Have succeeded to this point or didn't have any email recipients // 2- In a news header if ((SUCCEEDED(hr) || (hrNoRecipients == hr)) && !m_fMail) { hr = HrCheckGroups(TRUE); if (SUCCEEDED(hr)) fOneOrMoreGroups = TRUE; } if (FAILED(hr)) goto Exit; hr = HrCheckSubject(!fOneOrMoreGroups); if (FAILED(hr)) goto Exit; // TODO: if (m_pHeaderSite && m_pHeaderSite->IsHTML() == S_OK) { // if a HTML message, then let's make sure there's no plain-text recipients if (fOneOrMoreNames) { hr = HrIsCoolToSendHTML(); if (hr == S_FALSE && m_pHeaderSite) // send plain-text only... m_pHeaderSite->SetHTML(FALSE); } if (fOneOrMoreGroups && (IDCANCEL == DoDontShowMeAgainDlg(m_hwnd, c_szDSHTMLNewsWarning, MAKEINTRESOURCE(idsAthena), MAKEINTRESOURCE(idsErrHTMLInNewsIsBad), MB_OKCANCEL))) hr = MAPI_E_USER_CANCEL; } Exit: return hr; } HRESULT CNoteHdr::HrSend(void) { HRESULT hr; IMimeMessage *pMsg = NULL; IOEMsgSite *pMsgSite = NULL; if (m_pEnvelopeSite) { // With the envelope site, must check to see if things set up at this point to use mail hr = ProcessICW(m_hwnd, FOLDER_LOCAL, TRUE); if (hr == S_FALSE) // user cancelled out of config wizard so we can't continue hr = MAPI_E_USER_CANCEL; if (FAILED(hr)) goto error; m_fSendImmediate = TRUE; } hr = HrCreateMessage(&pMsg); if (FAILED(hr)) goto error; // The only case where this will happen is if no accounts are configured. Just to make // sure, call the ICW and then try to get the default account. if (!m_pAccount) { hr = ProcessICW(m_hwnd, m_fMail ? FOLDER_LOCAL : FOLDER_NEWS, TRUE); if (FAILED(hr)) goto error; if (FAILED(g_pAcctMan->GetDefaultAccount(m_fMail?ACCT_MAIL:ACCT_NEWS, &m_pAccount))) { hr = HR_E_COULDNOTFINDACCOUNT; goto error; } } hr = HrCheckSendInfo(); if (FAILED(hr)) goto error; // Does IPersistMime save stuff hr = HrFillMessage(pMsg); if (FAILED(hr)) goto error; if (m_pHeaderSite) { IOEMsgSite *pMsgSite = NULL; IServiceProvider *pServ = NULL; hr = m_pHeaderSite->QueryInterface(IID_IServiceProvider, (LPVOID*)&pServ); if (SUCCEEDED(hr)) { hr = pServ->QueryService(IID_IOEMsgSite, IID_IOEMsgSite, (LPVOID*)&pMsgSite); pServ->Release(); } if (SUCCEEDED(hr)) { if (!m_fMail && IsReplyNote() && !DwGetDontShowAgain(c_szDSReplyNews)) { LRESULT id = DoDontShowMeAgainDlg(m_hwnd, c_szDSReplyNews, MAKEINTRESOURCE(idsPostNews), MAKEINTRESOURCE(idsReplyToNewsGroup), MB_YESNO); if (IDNO == id || IDCANCEL == id) hr = hrUserCancel; else hr = pMsgSite->SendToOutbox(pMsg, m_fSendImmediate, m_pHeaderSite); } else { hr = pMsgSite->SendToOutbox(pMsg, m_fSendImmediate, m_pHeaderSite); } pMsgSite->Release(); } } // We are in office Envelope else { COEMsgSite *pMsgSite = NULL; CStoreCB *pCB = NULL; pMsgSite = new COEMsgSite(); if (!pMsgSite) hr = E_OUTOFMEMORY; pCB = new CStoreCB; if (!pCB) hr = E_OUTOFMEMORY; if (SUCCEEDED(hr)) hr = pCB->Initialize(m_hwndParent, MAKEINTRESOURCE(idsSendingToOutbox), TRUE); if (SUCCEEDED(hr)) { INIT_MSGSITE_STRUCT rInitStruct; rInitStruct.dwInitType = OEMSIT_MSG; rInitStruct.folderID = FOLDERID_INVALID; rInitStruct.pMsg = pMsg; hr = pMsgSite->Init(&rInitStruct); } if (SUCCEEDED(hr)) hr = pMsgSite->SetStoreCallback(pCB); if (SUCCEEDED(hr)) { hr = pMsgSite->SendToOutbox(pMsg, m_fSendImmediate, m_pHeaderSite); if (E_PENDING == hr) hr = pCB->Block(); pCB->Close(); } if (SUCCEEDED(hr)) { m_pEnvelopeSite->CloseNote(ENV_CLOSE_SEND); ShowWindow(m_hwnd, SW_HIDE); } if (pMsgSite) { pMsgSite->Close(); pMsgSite->Release(); } ReleaseObj(pCB); } error: if (FAILED(hr)) { int idsErr = -1; m_fSecurityInited = FALSE; switch (hr) { case hrNoRecipients: if(!m_fMail) hr = HR_E_POST_WITHOUT_NEWS; // idsErr = idsErrPostWithoutNewsgroup; break; case HR_E_COULDNOTFINDACCOUNT: if(!m_fMail) hr = HR_E_CONFIGURE_SERVER; //idsErr = idsErrConfigureServer; break; case HR_E_ATHSEC_FAILED: case hrUserCancel: case MAPI_E_USER_CANCEL: idsErr = 0; break; case HR_E_ATHSEC_NOCERTTOSIGN: case MIME_E_SECURITY_NOSIGNINGCERT: idsErr = 0; if(DialogBoxParam(g_hLocRes, MAKEINTRESOURCE(iddErrSecurityNoSigningCert), m_hwnd, ErrSecurityNoSigningCertDlgProc, NULL) == idGetDigitalIDs) GetDigitalIDs(m_pAccount); break; default: // idsErr = m_fMail?idsErrSendMail:NULL; // ~~~ Should we have a default for news? break; } if (idsErr != 0) { AthErrorMessageW(m_hwnd, MAKEINTRESOURCEW(idsAthena), MAKEINTRESOURCEW(idsErrSendMail), hr); if ((hr == hrNoRecipients) || (hr == HR_E_POST_WITHOUT_NEWS)) SetInitFocus(FALSE); } } ReleaseObj(pMsg); return hr; } HRESULT CNoteHdr::HrCheckSubject(BOOL fMail) { HWND hwnd; if ((hwnd=GetDlgItem(m_hwnd, idTXTSubject)) && GetRichEditTextLen(hwnd)==0) { if (IDCANCEL == DoDontShowMeAgainDlg(m_hwnd, fMail?c_szRegMailEmptySubj:c_szRegNewsEmptySubj, MAKEINTRESOURCE(idsAthena), MAKEINTRESOURCE(fMail?idsWarnMailEmptySubj:idsWarnNewsEmptySubj), MB_OKCANCEL)) { ::SetFocus(hwnd); return MAPI_E_USER_CANCEL; } } return NOERROR; } HRESULT CNoteHdr::HrIsCoolToSendHTML() { HRESULT hr=S_OK; ADRINFO adrInfo; BOOL fPlainText=FALSE; int id; // check for plaintext people if (m_lpWabal->FGetFirst(&adrInfo)) { do { if (adrInfo.fPlainText) { fPlainText=TRUE; break; } } while (m_lpWabal->FGetNext(&adrInfo)); } if (fPlainText) { id = (int) DialogBox(g_hLocRes, MAKEINTRESOURCE(iddPlainRecipWarning), m_hwnd, _PlainWarnDlgProc); if (id == IDNO) return S_FALSE; else if (id == IDCANCEL) return MAPI_E_USER_CANCEL; else return S_OK; } return hr; } INT_PTR CALLBACK _PlainWarnDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { int id; switch (msg) { case WM_INITDIALOG: CenterDialog(hwnd); return TRUE; case WM_COMMAND: id = GET_WM_COMMAND_ID(wParam, lParam); if (id == IDYES || id == IDNO || id == IDCANCEL) { EndDialog(hwnd, id); break; } } return FALSE; } static HACCEL g_hAccelMailSend=0; // This should only get called from the envelope as a send note HACCEL CNoteHdr::GetAcceleratorTable() { Assert(!IsReadOnly()); Assert(m_pEnvelopeSite); if (!g_hAccelMailSend) g_hAccelMailSend = LoadAccelerators(g_hLocRes, MAKEINTRESOURCE(IDA_SEND_HDR_ACCEL)); return g_hAccelMailSend; } HRESULT CNoteHdr::HrInitSecurityOptions(LPMIMEMESSAGE pMsg, ULONG ulSecurityType) { HRESULT hr; if (!m_fSecurityInited) { if (SUCCEEDED(hr = ::HrInitSecurityOptions(pMsg, ulSecurityType))) m_fSecurityInited = TRUE; } else hr = S_OK; return hr; } HRESULT CNoteHdr::HrHandleSecurityIDMs(BOOL fDigSign) { IMimeBody *pBody; PROPVARIANT var; HRESULT hr; if (fDigSign) m_fDigSigned = !m_fDigSigned; else m_fEncrypted = !m_fEncrypted; if(m_fForceEncryption && m_fDigSigned) m_fEncrypted = TRUE; hr = HrUpdateSecurity(); return hr; } HRESULT CNoteHdr::HrInitSecurity() { HRESULT hr = S_OK; // Constructor set these flags to false so don't need to handle else case if (OENA_READ != m_ntNote && m_fMail) { m_fDigSigned = DwGetOption(OPT_MAIL_DIGSIGNMESSAGES); m_fEncrypted = DwGetOption(OPT_MAIL_ENCRYPTMESSAGES); } return hr; } HRESULT CNoteHdr::HrUpdateSecurity(LPMIMEMESSAGE pMsg) { RECT rc; HRESULT hr = NOERROR; LPWSTR psz = NULL; HWND hEdit; switch (m_ntNote) { case OENA_READ: case OENA_REPLYTOAUTHOR: case OENA_REPLYTONEWSGROUP: case OENA_REPLYALL: case OENA_FORWARD: case OENA_FORWARDBYATTACH: if (pMsg) { CleanupSECSTATE(&m_SecState); HrGetSecurityState(pMsg, &m_SecState, NULL); m_fDigSigned = IsSigned(m_SecState.type); m_fEncrypted = IsEncrypted(m_SecState.type); // RAID 12243. Added these two flags for broken and untrusted messages if(m_ntNote == OENA_READ) { m_fSignTrusted = IsSignTrusted(&m_SecState); m_fEncryptionOK = IsEncryptionOK(&m_SecState); } } break; case OENA_COMPOSE: if (pMsg) { // Make certain that the highest security of (current message, option defaults) is applied. // CleanupSECSTATE(&m_SecState); HrGetSecurityState(pMsg, &m_SecState, NULL); if (! m_fDigSigned) { m_fDigSigned = IsSigned(m_SecState.type); } if (! m_fEncrypted) { m_fEncrypted = IsEncrypted(m_SecState.type); } } break; default: // do nothing break; } hEdit = GetDlgItem(m_hwnd, idSecurity); if (hEdit) { PHCI phci = (HCI*)GetWindowLongPtr(hEdit, GWLP_USERDATA); // BUG 17788: need to set the text even if it is null // since that will delete old security line text. psz = SzGetDisplaySec(pMsg, NULL); HdrSetRichEditText(hEdit, psz, FALSE); phci->fEmpty = (0 == *psz); } m_fThisHeadDigSigned = m_fDigSigned; m_fThisHeadEncrypted = m_fEncrypted; // if(!m_fDigSigned) // m_fForceEncryption = FALSE; InvalidateRightMargin(0); ReLayout(); if (m_pHeaderSite) m_pHeaderSite->Update(); if (m_hwndToolbar) { Assert(m_pEnvelopeSite); if (m_fDigSigned) SendMessage(m_hwndToolbar, TB_SETSTATE, ID_DIGITALLY_SIGN, MAKELONG(TBSTATE_ENABLED | TBSTATE_PRESSED, 0)); else SendMessage(m_hwndToolbar, TB_SETSTATE, ID_DIGITALLY_SIGN, MAKELONG(TBSTATE_ENABLED, 0)); if(m_fForceEncryption && m_fDigSigned) SendMessage(m_hwndToolbar, TB_SETSTATE, ID_ENCRYPT, MAKELONG(TBSTATE_PRESSED, 0)); else if (m_fEncrypted) SendMessage(m_hwndToolbar, TB_SETSTATE, ID_ENCRYPT, MAKELONG(TBSTATE_ENABLED | TBSTATE_PRESSED, 0)); else SendMessage(m_hwndToolbar, TB_SETSTATE, ID_ENCRYPT, MAKELONG(TBSTATE_ENABLED, 0)); } return hr; } HRESULT CNoteHdr::HrSaveSecurity(LPMIMEMESSAGE pMsg) { HRESULT hr; ULONG ulSecurityType = MST_CLASS_SMIME_V1; if (m_fDigSigned) ulSecurityType |= ((DwGetOption(OPT_OPAQUE_SIGN)) ? MST_THIS_BLOBSIGN : MST_THIS_SIGN); else ulSecurityType &= ~((DwGetOption(OPT_OPAQUE_SIGN)) ? MST_THIS_BLOBSIGN : MST_THIS_SIGN); if (m_fEncrypted) ulSecurityType |= MST_THIS_ENCRYPT; else ulSecurityType &= ~MST_THIS_ENCRYPT; hr = HrInitSecurityOptions(pMsg, ulSecurityType); return hr; } BOOL CNoteHdr::IsReadOnly() { if (m_ntNote==OENA_READ) return TRUE; else return FALSE; } HRESULT CNoteHdr::HrViewContacts() { LPWAB lpWab; if (!FAILED (HrCreateWabObject (&lpWab))) { // launch wab in modal-mode if a) container is modal or b) running as office envelope lpWab->HrBrowse (m_hwnd, m_fOfficeInit ? TRUE : (m_pHeaderSite ? (m_pHeaderSite->IsModal() == S_OK) : FALSE)); lpWab->Release (); } else AthMessageBoxW(m_hwnd, MAKEINTRESOURCEW(idsAthenaMail), MAKEINTRESOURCEW(idsGeneralWabError), NULL, MB_OK); return NOERROR; } BOOL CNoteHdr::FDoCutCopyPaste(int wmCmd) { HWND hwndFocus=GetFocus(); // only if it's one of our kids.. if (GetParent(hwndFocus)==m_hwnd) { SendMessage(hwndFocus, wmCmd, 0, 0); return TRUE; } return FALSE; } HRESULT CNoteHdr::GetTabStopArray(HWND *rgTSArray, int *pcArrayCount) { Assert(rgTSArray); Assert(pcArrayCount); int *array; int cCount; if (m_fMail) { if (IsReadOnly()) { array = rgIDTabOrderMailRead; cCount = sizeof(rgIDTabOrderMailRead)/sizeof(int); } else { array = rgIDTabOrderMailSend; cCount = sizeof(rgIDTabOrderMailSend)/sizeof(int); } } else { if (IsReadOnly()) { array = rgIDTabOrderNewsRead; cCount = sizeof(rgIDTabOrderNewsRead)/sizeof(int); } else { array = rgIDTabOrderNewsSend; cCount = sizeof(rgIDTabOrderNewsSend)/sizeof(int); } } AssertSz(cCount <= *pcArrayCount, "Do you need to change MAX_HEADER_COMP in note.h?"); for (int i = 0; i < cCount; i++) *rgTSArray++ = GetDlgItem(m_hwnd, *array++); *pcArrayCount = cCount; return S_OK; } HRESULT CNoteHdr::SetFlagState(MARK_TYPE markType) { BOOL fDoRelayout = FALSE; switch (markType) { case MARK_MESSAGE_FLAGGED: case MARK_MESSAGE_UNFLAGGED: { BOOL fFlagged = (MARK_MESSAGE_FLAGGED == markType); if (m_fFlagged != fFlagged) { fDoRelayout = TRUE; m_fFlagged = fFlagged; } break; } case MARK_MESSAGE_WATCH: case MARK_MESSAGE_IGNORE: case MARK_MESSAGE_NORMALTHREAD: if (m_MarkType != markType) { fDoRelayout = TRUE; m_MarkType = markType; } break; } if (fDoRelayout) { InvalidateStatus(); ReLayout(); if (m_pHeaderSite) m_pHeaderSite->Update(); } return S_OK; } HRESULT CNoteHdr::ShowEnvOptions() { nyi("Header options are not implemented yet."); return S_OK; } void CNoteHdr::ReLayout() { RECT rc; if (m_fSkipLayout) return; GetClientRect(m_hwnd, &rc); SetPosOfControls(rc.right, TRUE); InvalidateRect(m_hwnd, &rc, TRUE); DOUTL(PAINTING_DEBUG_LEVEL, "STATE Invalidating:(%d,%d) for (%d,%d)", rc.left, rc.top, rc.right, rc.bottom); } //IDropTarget HRESULT CNoteHdr::DragEnter(LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) { LPENUMFORMATETC penum = NULL; HRESULT hr; FORMATETC fmt; ULONG ulCount = 0; if (m_lpAttMan->HrIsDragSource() == S_OK) { *pdwEffect=DROPEFFECT_NONE; return S_OK; } if (!pdwEffect || !pDataObj) return E_INVALIDARG; m_dwEffect = DROPEFFECT_NONE; // lets get the enumerator from the IDataObject, and see if the format we take is // available hr = pDataObj->EnumFormatEtc(DATADIR_GET, &penum); if (SUCCEEDED(hr) && penum) { hr = penum->Reset(); while (SUCCEEDED(hr=penum->Next(1, &fmt, &ulCount)) && ulCount) { if ( fmt.cfFormat==CF_HDROP || fmt.cfFormat==CF_FILEDESCRIPTORA || fmt.cfFormat==CF_FILEDESCRIPTORW) { // we take either a CF_FILEDESCRIPTOR from the shell, or a CF_HDROP... //by default, or a move if the shift key is down if ( (*pdwEffect) & DROPEFFECT_COPY ) m_dwEffect = DROPEFFECT_COPY; if ( ((*pdwEffect) & DROPEFFECT_MOVE) && (grfKeyState & MK_SHIFT)) m_dwEffect=DROPEFFECT_MOVE; // IE3 gives us a link // if ONLY link is specified, default to a copy if (*pdwEffect == DROPEFFECT_LINK) m_dwEffect=DROPEFFECT_LINK; m_cfAccept=fmt.cfFormat; if (m_cfAccept==CF_FILEDESCRIPTORW) // this is the richest format we take, if we find one of these, no point looking any break; // further... } } } ReleaseObj(penum); *pdwEffect = m_dwEffect; m_grfKeyState = grfKeyState; return S_OK; } HRESULT CNoteHdr::DragOver(DWORD grfKeyState,POINTL pt, DWORD *pdwEffect) { if (m_lpAttMan->HrIsDragSource() == S_OK) { *pdwEffect=DROPEFFECT_NONE; return S_OK; } if ( m_dwEffect == DROPEFFECT_NONE) // we're not taking drops at all... { *pdwEffect = m_dwEffect; return NOERROR; } // Cool, we've accepted the drag this far... now we // have to watch to see if it turns into a copy or move... // as before, take the copy as default or move if the // shft key is down if ((*pdwEffect)&DROPEFFECT_COPY) m_dwEffect=DROPEFFECT_COPY; if (((*pdwEffect)&DROPEFFECT_MOVE)&& (grfKeyState&MK_SHIFT)) m_dwEffect=DROPEFFECT_MOVE; if (*pdwEffect==DROPEFFECT_LINK) // if it's link ONLY, like IE3 gives, then fine... m_dwEffect=DROPEFFECT_LINK; *pdwEffect &= m_dwEffect; m_grfKeyState=grfKeyState; return NOERROR; } HRESULT CNoteHdr::DragLeave() { return NOERROR; } HRESULT CNoteHdr::Drop(LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) { HRESULT hr = E_FAIL; FORMATETC fmte = {m_cfAccept, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; STGMEDIUM medium; *pdwEffect = m_dwEffect; if ( m_dwEffect != DROPEFFECT_NONE ) { // If this is us sourcing the drag, just bail. We may want to save the // points of the icons. // if (m_lpAttMan->HrIsDragSource() == S_OK) { *pdwEffect=DROPEFFECT_NONE; return S_OK; } if ( (m_grfKeyState & MK_RBUTTON) && m_lpAttMan->HrGetRequiredAction(pdwEffect, pt)) return E_FAIL; if (pDataObj && SUCCEEDED(pDataObj->GetData(&fmte, &medium))) { if (m_cfAccept==CF_HDROP) { HDROP hdrop=(HDROP)GlobalLock(medium.hGlobal); hr=m_lpAttMan->HrDropFiles(hdrop, (*pdwEffect)&DROPEFFECT_LINK); GlobalUnlock(medium.hGlobal); } else if (m_cfAccept==CF_FILEDESCRIPTORA || m_cfAccept==CF_FILEDESCRIPTORW) { // all file descriptors are copy|more, link makes no sense, as they are are // memory object, ie. non-existent in fat. hr=m_lpAttMan->HrDropFileDescriptor(pDataObj, FALSE); } #ifdef DEBUG else AssertSz(0, "how did this clipformat get accepted??"); #endif if (medium.pUnkForRelease) medium.pUnkForRelease->Release(); else GlobalFree(medium.hGlobal); } } return hr; } HRESULT CNoteHdr::HrGetAttachCount(ULONG *pcAttach) { return m_lpAttMan->HrGetAttachCount(pcAttach); } HRESULT CNoteHdr::HrIsDragSource() { return m_lpAttMan->HrIsDragSource(); } HRESULT CNoteHdr::UnloadAll() { if (m_lpAttMan) { m_lpAttMan->HrUnload(); m_lpAttMan->HrClearDirtyFlag(); } for (int i=0; i<(int)m_cHCI; i++) { if (0 == (m_rgHCI[i].dwFlags & HCF_ATTACH)) { if (0 == (m_rgHCI[i].dwFlags & HCF_COMBO)) HdrSetRichEditText(GetDlgItem(m_hwnd, m_rgHCI[i].idEdit), c_wszEmpty, FALSE); else SetWindowText(GetDlgItem(m_hwnd, m_rgHCI[i].idEdit), ""); } } m_fDirty = FALSE; m_pri = priNorm; return S_OK; } void CNoteHdr::SetDirtyFlag() { if (!m_fStillLoading) { m_fDirty = TRUE; if (m_pEnvelopeSite) m_pEnvelopeSite->OnPropChange(dispidSomething); } } void CNoteHdr::SetPosOfControls(int headerWidth, BOOL fChangeVisibleStates) { int cx, cy, cyDirty, cyLabelDirty, oldWidth = 0, windowPosFlags = SETWINPOS_DEF_FLAGS, editWidth = headerWidth - m_cxLeftMargin - GetRightMargin(FALSE); RECT rc; HWND hwnd; PHCI phci = m_rgHCI; BOOL fRePosition = FALSE; if ((headerWidth < 5) || (m_fSkipLayout)) return; STACK("SetPosOfControls (header width, edit width)", headerWidth, editWidth); // size the dialog GetClientRect(m_hwnd, &rc); cyDirty = rc.bottom; cyLabelDirty = rc.bottom; if (fChangeVisibleStates) windowPosFlags |= SWP_SHOWWINDOW; cy = BeginYPos(); for (int i=0; i<(int)m_cHCI; i++, phci++) { hwnd = GetDlgItem(m_hwnd, phci->idEdit); if (hwnd) { if (S_OK == HrFShowHeader(phci)) { int newLabelCY = (phci->dwFlags & HCF_BORDER) ? cy + 2*cyBorder : cy; BOOL fLabelMoved = FALSE; if (phci->cy != cy) { int smcy = ((INVALID_PHCI_Y != phci->cy) && (phci->cy < cy)) ? phci->cy : cy; if (cyLabelDirty > smcy) cyLabelDirty = smcy; phci->cy = cy; fLabelMoved = TRUE; } // Is an attachment if (HCF_ATTACH & phci->dwFlags) { DWORD cyAttMan = 0; RECT rc; m_lpAttMan->HrGetHeight(editWidth, &cyAttMan); if (cyAttMan > MAX_ATTACH_PIXEL_HEIGHT) cyAttMan = MAX_ATTACH_PIXEL_HEIGHT; cyAttMan += 4*cyBorder; cyDirty = cy; rc.left = m_cxLeftMargin; rc.right = m_cxLeftMargin + editWidth; rc.top = cy; rc.bottom = cy + cyAttMan; m_lpAttMan->HrSetSize(&rc); if ((cyAttMan != (DWORD)phci->height) && (cyDirty > cy)) cyDirty = cy; AssertSz(cyAttMan != 0, "Setting this to zero would be a bummer..."); phci->height = cyAttMan; cy += cyAttMan + ControlYBufferSize(); } // Is either an edit or combo else { int newHeight = phci->height, ctrlHeight = GetCtrlHeight(hwnd); oldWidth = GetCtrlWidth(hwnd); if (HCF_COMBO & phci->dwFlags) { if (ctrlHeight != newHeight) { fRePosition = TRUE; phci->height = ctrlHeight; newHeight = GetControlSize(TRUE, NUM_COMBO_LINES); } else { fRePosition = fRePosition || fLabelMoved || (oldWidth != editWidth); if (fRePosition) newHeight = GetControlSize(TRUE, NUM_COMBO_LINES); } } else { fRePosition = fRePosition || fLabelMoved || (oldWidth != editWidth) || (ctrlHeight != newHeight); } if (fRePosition) { SetWindowPos(hwnd, NULL, m_cxLeftMargin, cy, editWidth, newHeight, windowPosFlags); // RAID 81136: The above SetWindowPos might change the width in such a way // that the height now needs to change. We detect this condition below and // cause another resize to handle the needed height change. This, of course, // is only valid with the richedits. if ((newHeight != phci->height) && (0 == (HCF_COMBO & phci->dwFlags))) { SetWindowPos(hwnd, NULL, m_cxLeftMargin, cy, editWidth, phci->height, windowPosFlags); } if (cyDirty > cy) cyDirty = cy; if (fLabelMoved) InvalidateRect(hwnd, NULL, FALSE); } cy += phci->height + ControlYBufferSize(); } } else { phci->cy = INVALID_PHCI_Y; if (fChangeVisibleStates) SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_HIDEWINDOW); } } } DOUTL(RESIZING_DEBUG_LEVEL, "STATE resizing header (headerwidth=%d, cy=%d)", headerWidth, cy); // don't send a poschanging, as we did all the work here, plus invalidation... SetWindowPos(m_hwnd, NULL, NULL, NULL, headerWidth, cy, SETWINPOS_DEF_FLAGS|SWP_NOMOVE|SWP_DRAWFRAME|SWP_FRAMECHANGED); // notify the parent to resize the note... if (m_pHeaderSite) m_pHeaderSite->Resize(); if (m_pEnvelopeSite) { m_pEnvelopeSite->RequestResize(&cy); } GetRealClientRect(m_hwnd, &rc); // Dirty the labels region if (rc.bottom != cyLabelDirty) { rc.top = cyLabelDirty; rc.right = m_cxLeftMargin; rc.left = 0; InvalidateRect(m_hwnd, &rc, TRUE); DOUTL(PAINTING_DEBUG_LEVEL, "STATE Invalidating:(%d,%d) for (%d,%d)", rc.left, rc.top, rc.right, rc.bottom); } // Dirty the right margin if needed. if (editWidth != oldWidth) { int rightMargin = (editWidth > oldWidth) ? editWidth - oldWidth : 0; InvalidateRightMargin(rightMargin); } #ifdef DEBUG DEBUGDumpHdr(m_hwnd, m_cHCI, m_rgHCI); #endif } void CNoteHdr::InvalidateRightMargin(int additionalWidth) { RECT rc; GetClientRect(m_hwnd, &rc); rc.left = rc.right - GetRightMargin(TRUE) - additionalWidth; InvalidateRect(m_hwnd, &rc, TRUE); DOUTL(PAINTING_DEBUG_LEVEL, "STATE Invalidating:(%d,%d) for (%d,%d)", rc.left, rc.top, rc.right, rc.bottom); } HRESULT CNoteHdr::HrUpdateCachedHeight(HWND hwndEdit, RECT *prc) { int cyGrow, cLines = (int) SendMessage(hwndEdit, EM_GETLINECOUNT, 0, 0); BOOL fIncludeEdges = WS_EX_CLIENTEDGE & GetWindowLong(hwndEdit, GWL_EXSTYLE); PHCI phci = (HCI*)GetWindowLongPtr(hwndEdit, GWLP_USERDATA); if (prc->bottom < 0 || prc->top < 0) return S_FALSE; STACK("HrUpdateCachedHeight. Desired lines", cLines); // Only allow between 1 and MAX_RICHEDIT_LINES lines if (cLines < 1) cLines = 1; else if (cLines > MAX_RICHEDIT_LINES) cLines = MAX_RICHEDIT_LINES; DOUTL(RESIZING_DEBUG_LEVEL, "STATE Actual lines=%d", cLines); // Figure out how many pixels cLines lines is cyGrow = GetControlSize(fIncludeEdges, cLines); // If these are different, then change is needed if (cyGrow != GetCtrlHeight(hwndEdit)) phci->height = cyGrow; else return S_FALSE; return S_OK; } void CNoteHdr::ShowControls() { PHCI phci = m_rgHCI; STACK("ShowControls"); for (int i=0; i<(int)m_cHCI; i++, phci++) { HWND hwnd; BOOL fHide; fHide = (S_FALSE == HrFShowHeader(phci)); hwnd = GetDlgItem(m_hwnd, phci->idEdit); if (hwnd) ShowWindow(hwnd, fHide?SW_HIDE:SW_SHOW); } } int CNoteHdr::GetRightMargin(BOOL fMax) { int margin = ControlXBufferSize(); if (fMax || m_fDigSigned || m_fEncrypted || m_fVCard) margin += margin + cxBtn; return margin; } // prc is in and out DWORD CNoteHdr::GetButtonUnderMouse(int x, int y) { int resultButton = HDRCB_NO_BUTTON; PHCI phci = m_rgHCI; // Is it in the labels? if ((x > int(ControlXBufferSize() - BUTTON_BUFFER)) && (x < int(m_cxLeftMargin - ControlXBufferSize() + BUTTON_BUFFER))) { for (int i=0; i<(int)m_cHCI; i++, phci++) { // Only check labels that have buttons that are showing if ((0 != (phci->dwFlags & HCF_HASBUTTON)) && (INVALID_PHCI_Y != phci->cy)) { if (y < (phci->cy)) break; if (y < (phci->cy + 2*BUTTON_BUFFER + g_cyLabelHeight)) { resultButton = i; break; } } } } else // Is one of the right side buttons? { int width = GetCtrlWidth(m_hwnd), xBuffSize = ControlXBufferSize(), yBuffSize = ControlYBufferSize(); // Are we in the correct x range? if ((x > (width - (xBuffSize + cxBtn + BUTTON_BUFFER))) && (x < width - xBuffSize + BUTTON_BUFFER)) { BOOL rgBtnStates[] = {BUTTON_STATES}; BOOL rgUseButton[] = {BUTTON_USE_IN_COMPOSE}; BOOL fReadOnly = IsReadOnly(); int cy = BeginYPos(); for (int i = 0; i < ARRAYSIZE(rgBtnStates); i++) { if (rgBtnStates[i]) { if (y < cy) break; if (y < (cy + cyBtn + 2*BUTTON_BUFFER)) { if (fReadOnly || rgUseButton[i]) resultButton = g_rgBtnInd[i]; break; } cy += cyBtn + 2*BUTTON_BUFFER + yBuffSize; } } } } return resultButton; } void CNoteHdr::GetButtonRect(DWORD iBtn, RECT *prc) { // Do we already have the rect? if (iBtn == m_dwCurrentBtn) { CopyRect(prc, &m_rcCurrentBtn); return; } // Buttons on the left hand side of the header if (ButtonInLabels(iBtn)) { AssertSz(iBtn < m_cHCI, "We are about to access an invalid element..."); int cyBegin = BeginYPos(); prc->top = m_rgHCI[iBtn].cy; prc->bottom = m_rgHCI[iBtn].cy + g_cyLabelHeight + 2*BUTTON_BUFFER; prc->left = ControlXBufferSize() - BUTTON_BUFFER; prc->right = (m_cxLeftMargin - ControlXBufferSize()) + BUTTON_BUFFER; DOUTL(PAINTING_DEBUG_LEVEL, "STATE Set New Button Frame for button (btn:%d):(%d,%d) to (%d,%d)", iBtn, prc->left, prc->top, prc->right, prc->bottom); } // Buttons on the right hand side. else { RECT rc; int cx = GetCtrlWidth(m_hwnd) - (ControlXBufferSize() + cxBtn), cy = BeginYPos(), yBuffSize = cyBtn + ControlYBufferSize() + 2*BUTTON_BUFFER; BOOL rgBtnStates[] = {BUTTON_STATES}; prc->left = cx - BUTTON_BUFFER; prc->right = cx + cxBtn + BUTTON_BUFFER; for (int i = 0; i < ARRAYSIZE(rgBtnStates); i++) { if (g_rgBtnInd[i] == iBtn) { prc->top = cy; prc->bottom = cy + cyBtn + 2*BUTTON_BUFFER; DOUTL(PAINTING_DEBUG_LEVEL, "STATE Set New Button Frame for button (btn:%d):(%d,%d) to (%d,%d)", iBtn, prc->left, prc->top, prc->right, prc->bottom); return; } else if (rgBtnStates[i]) cy += yBuffSize; } } } int CNoteHdr::BeginYPos() { int beginBuffer = m_dxTBOffset; int cLines = 0; if (m_fFlagged || (priLow == m_pri) || (priHigh == m_pri) || (MARK_MESSAGE_NORMALTHREAD != m_MarkType)) cLines++; if (m_lpAttMan->GetUnsafeAttachCount()) cLines++; if (cLines) beginBuffer += GetStatusHeight(cLines) + g_cyFont/2; return beginBuffer; } void CNoteHdr::HandleButtonClicks(int x, int y, int iBtn) { m_dwCurrentBtn = HDRCB_NO_BUTTON; m_dwClickedBtn = HDRCB_NO_BUTTON; HeaderRelease(TRUE); InvalidateRect(m_hwnd, &m_rcCurrentBtn, FALSE); if (HDRCB_NO_BUTTON == iBtn) return; switch (iBtn) { case HDRCB_VCARD: HrShowVCardCtxtMenu(x, y); break; case HDRCB_SIGNED: case HDRCB_ENCRYPT: { HrShowSecurityProperty(m_hwnd, m_pMsg); break; } // This is an index into the labels default: OnButtonClick(m_rgHCI[iBtn].idBtn); break; } } void CNoteHdr::InvalidateStatus() { RECT rc; GetClientRect(m_hwnd, &rc); rc.bottom = BeginYPos(); InvalidateRect(m_hwnd, &rc, TRUE); DOUTL(PAINTING_DEBUG_LEVEL, "STATE Invalidating:(%d,%d) for (%d,%d)", rc.left, rc.top, rc.right, rc.bottom); } HRESULT CNoteHdr::_CreateEnvToolbar() { UINT i; RECT rc; TCHAR szRes[CCHMAX_STRINGRES]; REBARBANDINFO rbbi; POINT ptIdeal = {0}; // ~~~~ Do we need to do a WrapW here???? // create REBAR so we can show toolbar chevrons m_hwndRebar = CreateWindowEx(0, REBARCLASSNAME, NULL, WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NOPARENTALIGN, 0, 0, 100, 136, m_hwnd, NULL, g_hInst, NULL); if (!m_hwndRebar) return E_OUTOFMEMORY; SendMessage(m_hwndRebar, RB_SETTEXTCOLOR, 0, (LPARAM)GetSysColor(COLOR_BTNTEXT)); SendMessage(m_hwndRebar, RB_SETBKCOLOR, 0, (LPARAM)GetSysColor(COLOR_BTNFACE)); //SendMessage(m_hwndRebar, RB_SETEXTENDEDSTYLE, RBS_EX_OFFICE9, RBS_EX_OFFICE9); SendMessage(m_hwndRebar, CCM_SETVERSION, COMCTL32_VERSION, 0); // ~~~~ Do we need to do a WrapW here???? m_hwndToolbar = CreateWindowEx(WS_EX_TOOLWINDOW, TOOLBARCLASSNAME, NULL, WS_CHILD|WS_CLIPCHILDREN|WS_VISIBLE|CCS_NOPARENTALIGN|CCS_NODIVIDER| TBSTYLE_TOOLTIPS|TBSTYLE_FLAT|TBSTYLE_LIST, 0, 0, 0, 0, m_hwndRebar, NULL, g_hInst, NULL); if (!m_hwndToolbar) return E_OUTOFMEMORY; // set style on toolbar SendMessage(m_hwndToolbar, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_DRAWDDARROWS); SendMessage(m_hwndToolbar, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0); SendMessage(m_hwndToolbar, TB_ADDBUTTONS, (WPARAM)ARRAYSIZE(c_btnsOfficeEnvelope), (LPARAM)c_btnsOfficeEnvelope); // set the normal imagelist, office toolbar has ONE only as it's always in Color m_himl = LoadMappedToolbarBitmap(g_hLocRes, (fIsWhistler() ? ((GetCurColorRes() > 24) ? idb32SmBrowserHot : idbSmBrowserHot): idbNWSmBrowserHot), cxTBButton); if (!m_himl) return E_OUTOFMEMORY; SendMessage(m_hwndToolbar, TB_SETIMAGELIST, 0, (LPARAM)m_himl); SendMessage(m_hwndToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(cxTBButton, cxTBButton)); // Add text to the Bcc btn. The Send btn is taken care of in the Init _SetButtonText(ID_ENV_BCC, MAKEINTRESOURCE(idsEnvBcc)); GetClientRect(m_hwndToolbar, &rc); // get the IDEALSIZE of the toolbar SendMessage(m_hwndToolbar, TB_GETIDEALSIZE, FALSE, (LPARAM)&ptIdeal); // insert a band ZeroMemory(&rbbi, sizeof(rbbi)); rbbi.cbSize = sizeof(REBARBANDINFO); rbbi.fMask = RBBIM_SIZE | RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_IDEALSIZE | RBBIM_STYLE; rbbi.fStyle = RBBS_USECHEVRON; rbbi.cx = 0; rbbi.hwndChild = m_hwndToolbar; rbbi.cxMinChild = 0; rbbi.cyMinChild = rc.bottom; rbbi.cxIdeal = ptIdeal.x; SendMessage(m_hwndRebar, RB_INSERTBAND, (UINT)-1, (LPARAM)(LPREBARBANDINFO)&rbbi); // set the toolbar offset m_dxTBOffset = rc.bottom; return S_OK; } HRESULT CNoteHdr::_LoadFromStream(IStream *pstm) { HRESULT hr; IMimeMessage *pMsg; IStream *pstmTmp, *pstmMsg; PERSISTHEADER rPersist; ULONG cbRead; CLSID clsid; if (pstm == NULL) return E_INVALIDARG; HrRewindStream(pstm); // make sure it's our GUID if (ReadClassStm(pstm, &clsid)!=S_OK || !IsEqualCLSID(clsid, CLSID_OEEnvelope)) return E_FAIL; // make sure the persistent header is the correct version hr = pstm->Read(&rPersist, sizeof(PERSISTHEADER), &cbRead); if (hr != S_OK || cbRead != sizeof(PERSISTHEADER) || rPersist.cbSize != sizeof(PERSISTHEADER)) return E_FAIL; // read the message hr = HrCreateMessage(&pMsg); if (!FAILED(hr)) { hr = MimeOleCreateVirtualStream(&pstmMsg); if (!FAILED(hr)) { // MimeOle always rewinds the stream we give it, so we have to copy the // message from our persistent stream into another stream hr = HrCopyStream(pstm, pstmMsg, NULL); if (!FAILED(hr)) { hr = pMsg->Load(pstmMsg); if (!FAILED(hr)) { hr = Load(pMsg); if (!FAILED(hr)) { // BUG: as we use an empty message to persist data for office envelope and empty mime-body can be // considers a text/plain body part. We need to make sure we mark this as RENDERED before loading // any attachments if (pMsg->GetTextBody(TXT_PLAIN, IET_DECODED, &pstmTmp, NULL)==S_OK) pstmTmp->Release(); hr = OnDocumentReady(pMsg); } } } pstmMsg->Release(); } pMsg->Release(); } return hr; } HRESULT CNoteHdr::_SetButtonText(int idmCmd, LPSTR pszText) { TBBUTTONINFO tbi; TCHAR szRes[CCHMAX_STRINGRES]; ZeroMemory(&tbi, sizeof(TBBUTTONINFO)); tbi.cbSize = sizeof(TBBUTTONINFO); tbi.dwMask = TBIF_TEXT | TBIF_STYLE; tbi.fsStyle = TBSTYLE_BUTTON | TBSTYLE_AUTOSIZE; if (IS_INTRESOURCE(pszText)) { // its a string resource id LoadString(g_hLocRes, PtrToUlong(pszText), szRes, sizeof(szRes)); pszText = szRes; } tbi.pszText = pszText; tbi.cchText = lstrlen(pszText); SendMessage(m_hwndToolbar, TB_SETBUTTONINFO, idmCmd, (LPARAM) &tbi); return S_OK; } HRESULT CNoteHdr::_ConvertOfficeCmdIDToOE(LPDWORD pdwCmdId) { static const CMDMAPING rgCmdMap[] = { {cmdidSend, MSOEENVCMDID_SEND}, {cmdidCheckNames, MSOEENVCMDID_CHECKNAMES}, {cmdidAttach, MSOEENVCMDID_ATTACHFILE}, {cmdidSelectNames, MSOEENVCMDID_SELECTRECIPIENTS}, {cmdidFocusTo, MSOEENVCMDID_FOCUSTO}, {cmdidFocusCc, MSOEENVCMDID_FOCUSCC}, {cmdidFocusSubject, MSOEENVCMDID_FOCUSSUBJ} }; for (int i=0; iOnUIActivate(); if (m_pMsoComponentMgr) m_pMsoComponentMgr->FOnComponentActivate(m_dwComponentMgrID); if (m_pEnvelopeSite) { m_pEnvelopeSite->OnEnvSetFocus(); m_pEnvelopeSite->DirtyToolbars(); } } else { // store focus if decativating m_hwndLastFocus = hwndFocus; if (m_pHeaderSite) m_pHeaderSite->OnUIDeactivate(FALSE); } return S_OK; } HWND CNoteHdr::_GetNextDlgTabItem(HWND hwndDlg, HWND hwndFocus, BOOL fShift) { int i, j, idFocus = GetDlgCtrlID(hwndFocus), iFocus; LONG lStyle; HWND hwnd; // find current pos for (i=0; i=0; j--) { hwnd = GetDlgItem(hwndDlg, rgIDTabOrderMailSend[j]); AssertSz(hwnd, "something broke"); if (hwnd) { lStyle = GetWindowLong(hwnd, GWL_STYLE); if ((lStyle & WS_VISIBLE) && (lStyle & WS_TABSTOP) && !(lStyle & WS_DISABLED)) return GetDlgItem(hwndDlg, rgIDTabOrderMailSend[j]); } } } else { // forwards tab for (j=i+1; jHrClearDirtyFlag(); return S_OK; } HRESULT CNoteHdr::_RegisterAsDropTarget(BOOL fOn) { HRESULT hr=S_OK; if (fOn) { // already registered if (!m_fDropTargetRegister) { hr = CoLockObjectExternal((LPDROPTARGET)this, TRUE, FALSE); if (FAILED(hr)) goto error; hr = RegisterDragDrop(m_hwnd, (LPDROPTARGET)this); if (FAILED(hr)) goto error; m_fDropTargetRegister=TRUE; } } else { // nothing to do if (m_fDropTargetRegister) { RevokeDragDrop(m_hwnd); CoLockObjectExternal((LPUNKNOWN)(LPDROPTARGET)this, FALSE, TRUE); m_fDropTargetRegister = FALSE; } } error: return hr; } HRESULT CNoteHdr::_RegisterWithFontCache(BOOL fOn) { Assert(g_pFieldSizeMgr); if (fOn) { if (0 == m_dwFontNotify) g_pFieldSizeMgr->Advise((IUnknown*)(IFontCacheNotify*)this, &m_dwFontNotify); } else { if (m_dwFontNotify) { g_pFieldSizeMgr->Unadvise(m_dwFontNotify); m_dwFontNotify = NULL; } } return S_OK; } HRESULT CNoteHdr::_RegisterWithComponentMgr(BOOL fOn) { MSOCRINFO crinfo; IServiceProvider *pSP; if (fOn) { // not registered, so get a component msgr interface and register ourselves if (m_pMsoComponentMgr == NULL) { // negotiate an component msgr from the host if (m_pEnvelopeSite && m_pEnvelopeSite->QueryInterface(IID_IServiceProvider, (LPVOID *)&pSP)==S_OK) { pSP->QueryService(IID_IMsoComponentManager, IID_IMsoComponentManager, (LPVOID *)&m_pMsoComponentMgr); pSP->Release(); } // if not host-provided, try and obtain from LoadLibrary on office dll if (!m_pMsoComponentMgr && FAILED(MsoFGetComponentManager(&m_pMsoComponentMgr))) return E_FAIL; Assert (m_pMsoComponentMgr); crinfo.cbSize = sizeof(MSOCRINFO); crinfo.uIdleTimeInterval = 3000; crinfo.grfcrf = msocrfPreTranslateAll; crinfo.grfcadvf = msocadvfRedrawOff; if (!m_pMsoComponentMgr->FRegisterComponent((IMsoComponent*) this, &crinfo, &m_dwComponentMgrID)) return E_FAIL; } } else { if (m_pMsoComponentMgr) { m_pMsoComponentMgr->FRevokeComponent(m_dwComponentMgrID); m_pMsoComponentMgr->Release(); m_pMsoComponentMgr = NULL; m_dwComponentMgrID = 0; } } return S_OK; } HRESULT ParseFollowup(LPMIMEMESSAGE pMsg, LPTSTR* ppszGroups, BOOL* pfPoster) { LPTSTR pszToken, pszTok; BOOL fFirst = TRUE, fPoster = FALSE; int cchFollowup; LPSTR lpszFollowup=0; ADDRESSLIST addrList={0}; HRESULT hr = S_OK; *ppszGroups = NULL; if (!pMsg) return E_INVALIDARG; if (FAILED(MimeOleGetBodyPropA(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_FOLLOWUPTO), NOFLAGS, &lpszFollowup))) return E_FAIL; cchFollowup = lstrlen(lpszFollowup) + 1; if (!MemAlloc((LPVOID*) ppszGroups, sizeof(TCHAR) * cchFollowup)) { hr = E_OUTOFMEMORY; goto exit; } **ppszGroups = 0; // WARNING: we about to trash lpszFollowup with strtok... // Walk through the string parsing out the tokens pszTok = lpszFollowup; pszToken = StrTokEx(&pszTok, GRP_DELIMITERS); while (NULL != pszToken) { // Want to add all items except Poster (c_szPosterKeyword) if (0 == lstrcmpi(pszToken, c_szPosterKeyword)) fPoster = TRUE; else { if (!fFirst) { StrCatBuff(*ppszGroups, g_szComma, cchFollowup); } else fFirst = FALSE; StrCatBuff(*ppszGroups, pszToken, cchFollowup); } pszToken = StrTokEx(&pszTok, GRP_DELIMITERS); } *pfPoster = fPoster; exit: SafeMimeOleFree(lpszFollowup); if (**ppszGroups == 0) { MemFree(*ppszGroups); *ppszGroups = NULL; } return hr; } //*************************************************** CFieldSizeMgr::CFieldSizeMgr(IUnknown *pUnkOuter) : CPrivateUnknown(pUnkOuter) { TraceCall("CFieldSizeMgr::CFieldSizeMgr"); m_pAdviseRegistry = NULL; m_fFontsChanged = FALSE; m_dwFontNotify = 0; InitializeCriticalSection(&m_rAdviseCritSect); } //*************************************************** CFieldSizeMgr::~CFieldSizeMgr() { IConnectionPoint *pCP = NULL; TraceCall("CFieldSizeMgr::~CFieldSizeMgr"); EnterCriticalSection(&m_rAdviseCritSect); if (m_pAdviseRegistry) m_pAdviseRegistry->Release(); LeaveCriticalSection(&m_rAdviseCritSect); if (g_lpIFontCache) { if (SUCCEEDED(g_lpIFontCache->QueryInterface(IID_IConnectionPoint, (LPVOID*)&pCP))) { pCP->Unadvise(m_dwFontNotify); pCP->Release(); } } DeleteCriticalSection(&m_rAdviseCritSect); } //*************************************************** HRESULT CFieldSizeMgr::OnPreFontChange(void) { DWORD cookie = 0; IFontCacheNotify* pCurr; IUnknown* pTempCurr; TraceCall("CFieldSizeMgr::OnPreFontChange"); EnterCriticalSection(&m_rAdviseCritSect); while(SUCCEEDED(m_pAdviseRegistry->GetNext(LD_FORWARD, &pTempCurr, &cookie))) { if (SUCCEEDED(pTempCurr->QueryInterface(IID_IFontCacheNotify, (LPVOID *)&pCurr))) { pCurr->OnPreFontChange(); pCurr->Release(); } pTempCurr->Release(); } LeaveCriticalSection(&m_rAdviseCritSect); return S_OK; } //*************************************************** HRESULT CFieldSizeMgr::OnPostFontChange(void) { DWORD cookie = 0; IFontCacheNotify* pCurr; IUnknown* pTempCurr; TraceCall("CFieldSizeMgr::OnPostFontChange"); ResetGlobalSizes(); EnterCriticalSection(&m_rAdviseCritSect); while(SUCCEEDED(m_pAdviseRegistry->GetNext(LD_FORWARD, &pTempCurr, &cookie))) { if (SUCCEEDED(pTempCurr->QueryInterface(IID_IFontCacheNotify, (LPVOID *)&pCurr))) { pCurr->OnPostFontChange(); pCurr->Release(); } pTempCurr->Release(); } LeaveCriticalSection(&m_rAdviseCritSect); return S_OK; } //*************************************************** HRESULT CFieldSizeMgr::GetConnectionInterface(IID *pIID) { return E_NOTIMPL; } //*************************************************** HRESULT CFieldSizeMgr::GetConnectionPointContainer(IConnectionPointContainer **ppCPC) { *ppCPC = NULL; return E_NOTIMPL; } //*************************************************** HRESULT CFieldSizeMgr::EnumConnections(IEnumConnections **ppEnum) { *ppEnum = NULL; return E_NOTIMPL; } //*************************************************** HRESULT CFieldSizeMgr::Advise(IUnknown *pUnkSink, DWORD *pdwCookie) { TraceCall("CFieldSizeMgr::Advise"); EnterCriticalSection(&m_rAdviseCritSect); HRESULT hr = m_pAdviseRegistry->AddItem(pUnkSink, pdwCookie); LeaveCriticalSection(&m_rAdviseCritSect); return hr; } //*************************************************** HRESULT CFieldSizeMgr::Unadvise(DWORD dwCookie) { TraceCall("CFieldSizeMgr::Unadvise"); EnterCriticalSection(&m_rAdviseCritSect); HRESULT hr = m_pAdviseRegistry->RemoveItem(dwCookie); LeaveCriticalSection(&m_rAdviseCritSect); return hr; } //*************************************************** int CFieldSizeMgr::GetScalingFactor(void) { int iScaling = 100; UINT cp; cp = GetACP(); if((932 == cp) || (936 == cp) || (950 == cp) || (949 == cp) || (((1255 == cp) || (1256 == cp)) && (VER_PLATFORM_WIN32_NT != g_OSInfo.dwPlatformId))) iScaling = 115; return iScaling; } //*************************************************** void CFieldSizeMgr::ResetGlobalSizes(void) { HDC hdc; HFONT hfontOld, hfont; TEXTMETRIC tm; int oldcyFont = g_cyFont, oldLabelHeight = g_cyLabelHeight, cyScaledFont; TraceCall("CFieldSizeMgr::ResetGlobalSizes"); // calc height of edit, based on font we're going to put in it... hdc=GetDC(NULL); hfont = GetFont(FALSE); hfontOld=(HFONT)SelectObject(hdc, hfont); // Hopefully charset fonts are about the same size ???!!! g_cfHeader.cbSize = sizeof(CHARFORMAT); FontToCharformat(hfont, &g_cfHeader); GetTextMetrics(hdc, &tm); DOUTL(16, "tmHeight=%d tmAscent=%d tmDescent=%d tmInternalLeading=%d tmExternalLeading=%d\n", tm.tmHeight, tm.tmAscent, tm.tmDescent, tm.tmInternalLeading, tm.tmExternalLeading); SelectObject(hdc, hfontOld); cyScaledFont = (tm.tmHeight + tm.tmExternalLeading) * GetScalingFactor(); if((cyScaledFont%100) >= 50) cyScaledFont += 100; g_cyFont = (cyScaledFont / 100); g_cyLabelHeight = (g_cyFont < cyBtn) ? cyBtn : g_cyFont; DOUTL(GEN_HEADER_DEBUG_LEVEL,"cyFont=%d", g_cyFont); ReleaseDC(NULL, hdc); m_fFontsChanged = ((oldcyFont != g_cyFont) || (oldLabelHeight != g_cyLabelHeight)); } //*************************************************** HRESULT CFieldSizeMgr::Init(void) { HRESULT hr = S_OK; IConnectionPoint *pCP = NULL; TraceCall("CFieldSizeMgr::Init"); ResetGlobalSizes(); EnterCriticalSection(&m_rAdviseCritSect); IF_FAILEXIT(hr = IUnknownList_CreateInstance(&m_pAdviseRegistry)); IF_FAILEXIT(hr = m_pAdviseRegistry->Init(NULL, 0, 0)); // We don't want to fail if the font cache is not created. That just means // that the fonts won't be changed. if (g_lpIFontCache) { IF_FAILEXIT(hr = g_lpIFontCache->QueryInterface(IID_IConnectionPoint, (LPVOID*)&pCP)); IF_FAILEXIT(hr = pCP->Advise((IUnknown*)(IFontCacheNotify*)this, &m_dwFontNotify)); } exit: ReleaseObj(pCP); LeaveCriticalSection(&m_rAdviseCritSect); return hr; } //*************************************************** HRESULT CFieldSizeMgr::PrivateQueryInterface(REFIID riid, LPVOID *lplpObj) { TraceCall("CFieldSizeMgr::PrivateQueryInterface"); if(!lplpObj) return E_INVALIDARG; *lplpObj = NULL; if (IsEqualIID(riid, IID_IFontCacheNotify)) *lplpObj = (LPVOID)(IFontCacheNotify *)this; else if (IsEqualIID(riid, IID_IConnectionPoint)) *lplpObj = (LPVOID)(IConnectionPoint *)this; else { return E_NOINTERFACE; } AddRef(); return S_OK; }