/* * 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 #include #include #include #include #include "addrobj.h" #include "wells.h" #include "header.h" #include 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; ulWellReset(); for(ulWell=0; ulWellHrResolveNames(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; ulWellpreole; 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; ulWellGetObjectCount(); 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; ulWellFGetFirst(&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; ulWellHrPickNames(hwnd, m_rgRecipType, m_cWells, iFocus, fNews); if(FAILED(hr)) goto error; hr=HrDisplayWells(hwnd); if(FAILED(hr)) goto error; error: return hr; }