|
|
/*
* w e l l s . c p p * * Purpose: * implments name checking and stuff for the wells * * Author:brettm * * Ported to C++ and modified for Athena from Capone src */ #include <pch.hxx>
#include <resource.h>
#include <richedit.h>
#include <ipab.h>
#include <addrlist.h>
#include "addrobj.h"
#include "wells.h"
#include "header.h"
#include <ourguid.h>
ASSERTDATA
HRESULT CAddrWells::HrInit(ULONG cWells, HWND *rgHwnd, ULONG *rgRecipType) { if(cWells<=0 || rgHwnd==NULL || rgRecipType==NULL) return E_INVALIDARG;
Assert(m_rgHwnd==NULL); Assert(m_rgRecipType==NULL); Assert(m_cWells==0); if(!MemAlloc((LPVOID *)&m_rgHwnd, sizeof(HWND)*cWells)) return E_OUTOFMEMORY;
if(!MemAlloc((LPVOID *)&m_rgRecipType, sizeof(ULONG)*cWells)) return E_OUTOFMEMORY;
CopyMemory(m_rgHwnd, rgHwnd, sizeof(HWND)*cWells); CopyMemory(m_rgRecipType, rgRecipType, sizeof(ULONG)*cWells); m_cWells=cWells; return NOERROR; }
HRESULT CAddrWells::HrSetWabal(LPWABAL lpWabal) { Assert(lpWabal);
if(!lpWabal) return E_INVALIDARG; ReleaseObj(m_lpWabal); m_lpWabal=lpWabal; m_lpWabal->AddRef(); return NOERROR; }
HRESULT CAddrWells::HrCheckNames(HWND hwnd, ULONG uFlags) { HRESULT hr=NOERROR; ULONG ulWell; HCURSOR hcur; BOOL fDirty=FALSE; if(!m_lpWabal) return E_FAIL;
// This optimization will only occur in the office envelope
// on autosave. In most cases, the ResolveNames in the header
// will stop before calling down to this level. For the other
// minority cases, we should leave this code in.
for(ulWell=0; ulWell<m_cWells; ulWell++) if(Edit_GetModify(m_rgHwnd[ulWell])) { fDirty=TRUE; break; }
if(!fDirty) return NOERROR; hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
// clear the current list
m_lpWabal->Reset();
for(ulWell=0; ulWell<m_cWells; ulWell++) if(Edit_GetModify(m_rgHwnd[ulWell])) hr=HrAddNamesToList(m_rgHwnd[ulWell], m_rgRecipType[ulWell]);
if(!(uFlags&CNF_DONTRESOLVE)) { if(uFlags&CNF_SILENTRESOLVEUI) hr=m_lpWabal->HrResolveNames(NULL, FALSE); else hr=m_lpWabal->HrResolveNames(hwnd, TRUE); HrDisplayWells(hwnd); }
if(hcur) SetCursor(hcur);
return hr; }
HRESULT CAddrWells::HrDisplayWells(HWND hwnd) { HRESULT hr=E_FAIL; HCURSOR hcursor; HWND hwndBlock; ULONG ulWell; if (m_lpWabal) { hcursor = SetCursor(LoadCursor(NULL, IDC_WAIT)); // brettm: hack taken from Capone. LockUpdateWindow doesn't work for the
// richedit, so we block paints by covering the edit controls with a
// paint-swallowing window until we're done...
hwndBlock=HwndStartBlockingPaints(hwnd); // empty the wells...
for(ulWell=0; ulWell<m_cWells; ulWell++) SetWindowText(m_rgHwnd[ulWell], NULL); hr=HrAddRecipientsToWells(); StopBlockingPaints(hwndBlock); if (hcursor) SetCursor(hcursor); } return hr; }
CAddrWells::CAddrWells() { m_lpWabal = 0; m_rgHwnd = NULL; m_rgRecipType = NULL; m_cWells = 0; };
CAddrWells::~CAddrWells() { ReleaseObj(m_lpWabal); if(m_rgRecipType) MemFree(m_rgRecipType); if(m_rgHwnd) MemFree(m_rgHwnd); };
HRESULT CAddrWells::HrAddNamesToList(HWND hwndWell, LONG lRecipType) { ULONG iOb; ULONG cOb; REOBJECT reobj = {0}; HRESULT hr; PHCI phci; LPRICHEDITOLE preole; LPPERSIST ppersist = NULL; LPWSTR pwszText = NULL; DWORD cch;
Assert(IsWindow(hwndWell));
// if the edit is not dirty, we're done
if(!Edit_GetModify(hwndWell)) return S_OK;
phci = (HCI*)GetWindowLongPtr(hwndWell, GWLP_USERDATA); Assert(phci);
preole = phci->preole; Assert(preole);
m_hwndWell = hwndWell; m_cchBuf = 0; m_fTruncated = FALSE; m_lRecipType = lRecipType;
reobj.cbStruct = sizeof(reobj);
cOb = preole->GetObjectCount(); for (iOb = 0; iOb < cOb; iOb++) { LPADRINFO pAdrInfo=NULL; IF_FAILEXIT(hr = preole->GetObject(iOb, &reobj, REO_GETOBJ_POLEOBJ)); IF_FAILEXIT(hr = reobj.poleobj->QueryInterface(IID_IPersist, (LPVOID *)&ppersist)); #ifdef DEBUG
AssertValidAddrObject(reobj.poleobj); #endif
// HrGetAdrInfo doesn't alloc memory.
IF_FAILEXIT(hr = ((CAddrObj *)ppersist)->HrGetAdrInfo(&pAdrInfo)); // set the new recipient type...
pAdrInfo->lRecipType=lRecipType; IF_FAILEXIT(hr = m_lpWabal->HrAddEntry(pAdrInfo));
SafeRelease(ppersist); SafeRelease(reobj.poleobj); } // now we add in all the unresolved names...
cch = GetRichEditTextLen(m_hwndWell) + 1; if (0 == cch) return (S_FALSE);
IF_NULLEXIT(MemAlloc((LPVOID*)&pwszText, cch * sizeof(WCHAR)));
GetRichEditText(m_hwndWell, pwszText, cch, FALSE, phci->pDoc);
hr = UnresolvedText(pwszText, cch - 1); // Add whatever is left after the last semicolon
if (SUCCEEDED(hr)) HrAddUnresolvedName(); exit: if(m_fTruncated) // warn if we trucated an address
MessageBeep(MB_OK); ReleaseObj(reobj.poleobj); ReleaseObj(ppersist); MemFree(pwszText); return hr; }
HRESULT CAddrWells::OnFontChange() { ULONG ulWell;
for(ulWell=0; ulWell<m_cWells; ulWell++) _UpdateFont(m_rgHwnd[ulWell]);
return S_OK; }
HRESULT CAddrWells::_UpdateFont(HWND hwndWell) { ULONG iOb; ULONG cOb; REOBJECT rObject={0}; IRichEditOle *pREOle; IOleInPlaceSite *pIPS; LPPERSIST pPersist = NULL;
rObject.cbStruct = sizeof(REOBJECT);
// walk the ole objects and send them an font-update
if (SendMessage(hwndWell, EM_GETOLEINTERFACE, 0, (LPARAM) &pREOle)) { cOb = pREOle->GetObjectCount();
for (iOb = 0; iOb < cOb; iOb++) { if (pREOle->GetObject(iOb, &rObject, REO_GETOBJ_POLEOBJ)==S_OK) { if (rObject.poleobj->QueryInterface(IID_IPersist, (LPVOID *)&pPersist)==S_OK) { ((CAddrObj *)pPersist)->OnFontChange(); pPersist->Release(); } rObject.poleobj->Release(); } } pREOle->Release(); } InvalidateRect(hwndWell, NULL, TRUE); return S_OK; }
HRESULT CAddrWells::HrAddUnresolvedName() { HRESULT hr = S_OK; // strip any trailing white-space
while(m_cchBuf > 0 && (m_rgwch[m_cchBuf - 1] == L' ' || m_rgwch[m_cchBuf - 1] == L'\t')) --m_cchBuf;
if (m_cchBuf) { // there is something in the buffer...
m_rgwch[m_cchBuf] = L'\0'; hr = m_lpWabal->HrAddUnresolved(m_rgwch, m_lRecipType); m_cchBuf = 0; } return hr; }
HRESULT CAddrWells::UnresolvedText(LPWSTR pwszText, LONG cch) { HRESULT hr = S_OK;
// The algorithm below will strip spaces off of the
// beginning and end of each name
while (cch) { cch--; // On some versions of richedit, 0xfffc is inserted in the text
// where there is a addrObj present. So just skip over that.
if ((L'\t' == *pwszText) || (0xfffc == *pwszText)) *pwszText = L' '; if (*pwszText == L';' || *pwszText == L'\r'|| *pwszText == L',') { hr = HrAddUnresolvedName(); if (S_OK != hr) goto err; } else { if ((*pwszText != L' ' && *pwszText != L'\n' && *pwszText != L'\r') || m_cchBuf > 0) { if (m_cchBuf < ARRAYSIZE(m_rgwch) - 1) m_rgwch[m_cchBuf++] = *pwszText; else // Truncation has occurred so I want to beep
m_fTruncated = TRUE; } } ++pwszText; } err: return hr; }
enum { mapiTo=0, mapiCc, mapiFrom, mapiReplyTo, mapiBcc, mapiMax };
HRESULT CAddrWells::HrAddRecipientsToWells() { HRESULT hr; ADRINFO AdrInfo; HWND hwnd; HWND hwndMap[mapiMax]={0}; ULONG ulWell; Assert(m_lpWabal); // walk the list of entries, and add them to the well...
// build mapping to MAPI_TO -> hwnd if available to make the lookup quicker..
for(ulWell=0; ulWell<m_cWells; ulWell++) { switch(m_rgRecipType[ulWell]) { case MAPI_TO: hwndMap[mapiTo]=m_rgHwnd[ulWell]; break; case MAPI_CC: hwndMap[mapiCc]=m_rgHwnd[ulWell]; break; case MAPI_BCC: hwndMap[mapiBcc]=m_rgHwnd[ulWell]; break; case MAPI_REPLYTO: hwndMap[mapiReplyTo]=m_rgHwnd[ulWell]; break; case MAPI_ORIG: hwndMap[mapiFrom]=m_rgHwnd[ulWell]; break; } } if(m_lpWabal->FGetFirst(&AdrInfo)) { do { hwnd=0; switch(AdrInfo.lRecipType) { case MAPI_TO: hwnd=hwndMap[mapiTo]; break; case MAPI_CC: hwnd=hwndMap[mapiCc]; break; case MAPI_ORIG: hwnd=hwndMap[mapiFrom]; break; case MAPI_BCC: hwnd=hwndMap[mapiBcc]; break; case MAPI_REPLYTO: hwnd=hwndMap[mapiReplyTo]; break; default: AssertSz(0, "Unsupported RECIPTYPE in AdrList"); } if(hwnd && IsWindow(hwnd)) { hr = HrAddRecipientToWell(hwnd, &AdrInfo, TRUE); if(FAILED(hr)) return hr; } } while(m_lpWabal->FGetNext(&AdrInfo)); } return NOERROR; }
/*
* HrAddRecipientToWell * * Purpose: * This function adds a recipient to a recipient well. * * Parameters: * hwndEdit hwnd of the recipient well to add the * recipient to * pae pointer to an ADRENTRY * fAddSemi whether to add a semicolon between entries * fCopyEntry whether to copy the ADRENTRY or just use it * * Returns: * scode */ HRESULT HrAddRecipientToWell(HWND hwndEdit, LPADRINFO lpAdrInfo, BOOL fAddSemi) { HRESULT hr = S_OK; CAddrObj *pAddrObj = NULL; INT cch; REOBJECT reobj = {0}; PHCI phci; LPRICHEDITOLE preole;
Assert(IsWindow(hwndEdit)); Assert(lpAdrInfo);
phci = (HCI*)GetWindowLongPtr(hwndEdit, GWLP_USERDATA); Assert(phci);
preole = phci->preole; Assert(preole);
if(lpAdrInfo->fResolved) { // Initialize the object information structure
reobj.cbStruct = sizeof(reobj); reobj.cp = REO_CP_SELECTION; reobj.clsid = CLSID_AddrObject; reobj.dwFlags = REO_BELOWBASELINE|REO_INVERTEDSELECT| REO_DYNAMICSIZE|REO_DONTNEEDPALETTE; reobj.dvaspect = DVASPECT_CONTENT; IF_FAILEXIT(hr = preole->GetClientSite(&reobj.polesite)); IF_NULLEXIT(pAddrObj = new CAddrObj()); IF_FAILEXIT(hr = pAddrObj->HrSetAdrInfo(lpAdrInfo)); } if (fAddSemi && (cch = GetRichEditTextLen(hwndEdit))) { Edit_SetSel(hwndEdit, cch, cch); HdrSetRichEditText(hwndEdit, L"; ", TRUE); } if (!lpAdrInfo->fResolved) { // Its an unresolved name
AssertSz(lpAdrInfo->lpwszDisplay, "Recipient must have a Display Name"); HdrSetRichEditText(hwndEdit, lpAdrInfo->lpwszDisplay, TRUE); } else { // Its a resolved name
IF_FAILEXIT(hr = pAddrObj->QueryInterface(IID_IOleObject, (LPVOID *)&reobj.poleobj)); IF_FAILEXIT(hr = reobj.poleobj->SetClientSite(reobj.polesite)); IF_FAILEXIT(hr = preole->InsertObject(&reobj)); } exit: ReleaseObj(reobj.poleobj); ReleaseObj(reobj.polesite); ReleaseObj(pAddrObj); return hr; }
HRESULT CAddrWells::HrSelectNames(HWND hwnd, int iFocus, BOOL fNews) { HRESULT hr; ULONG ulWell;
m_lpWabal->Reset();
for(ulWell=0; ulWell<m_cWells; ulWell++) if(Edit_GetModify(m_rgHwnd[ulWell])) hr=HrAddNamesToList(m_rgHwnd[ulWell], m_rgRecipType[ulWell]);
hr=m_lpWabal->HrPickNames(hwnd, m_rgRecipType, m_cWells, iFocus, fNews); if(FAILED(hr)) goto error;
hr=HrDisplayWells(hwnd); if(FAILED(hr)) goto error;
error: return hr; }
|