Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1472 lines
42 KiB

// badata.cpp: implementation of the CAddressBook class.
// WAB & Messenger integration to OE
// Created 04/20/98 by YST
//
//////////////////////////////////////////////////////////////////////
#include "pch.hxx"
#include <shfusion.h>
#include "bactrl.h"
#include "badata.h"
#include "baui.h"
#include "baprop.h"
#include "ourguid.h"
#include "mapiguid.h"
#include "shlwapip.h"
#include "ipab.h"
#include "multiusr.h"
#include "demand.h"
#include "secutil.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Defines for the various MAPI Tables we request from the WAB
//////////////////////////////////////////////////////////////////////
#define MAX_QUERY_SIZE 1000
// Here are some private properties that the WAB stores. If WAB ever
// changes any of these we're in trouble.
#define WAB_INTERNAL_BASE 0x6600
#define PR_WAB_LDAP_SERVER PROP_TAG(PT_TSTRING, WAB_INTERNAL_BASE + 1)
#define PR_WAB_RESOLVE_FLAG PROP_TAG(PT_BOOLEAN, WAB_INTERNAL_BASE + 2)
// This BA's private GUID:
// {2BAD7EE0-36AB-11d1-9BAC-00A0C91F9C8B}
static const GUID WAB_ExtBAGuid =
{ 0x2bad7ee0, 0x36ab, 0x11d1, { 0x9b, 0xac, 0x0, 0xa0, 0xc9, 0x1f, 0x9c, 0x8b } };
static const LPTSTR lpMsgrPropNames[] =
{
"MsgrID"
};
enum _MsgrTags
{
MsgrID = 0,
msgrMax
};
ULONG MsgrPropTags[msgrMax];
ULONG PR_MSGR_DEF_ID = 0;
// These two define the table we request from the WAB when showing the
// contents of the local address book.
enum {
ieidPR_DISPLAY_NAME = 0,
ieidPR_ENTRYID,
ieidPR_OBJECT_TYPE,
ieidPR_MSGR_DEF_ID,
// ieidPR_BUSINESS_TELEPHONE_NUMBER,
ieidPR_EMAIL_ADDRESS,
ieidPR_USER_X509_CERTIFICATE,
ieidPR_RECORD_KEY,
ieidMax
};
static SizedSPropTagArray(ieidMax, ptaEid)=
{
ieidMax,
{
PR_DISPLAY_NAME,
PR_ENTRYID,
PR_OBJECT_TYPE,
PR_MSGR_DEF_ID,
// PR_BUSINESS_TELEPHONE_NUMBER,
PR_EMAIL_ADDRESS,
PR_USER_X509_CERTIFICATE,
PR_RECORD_KEY
}
};
// These two define the table we request to see which LDAP servers should
// be resolved against.
enum {
irnPR_OBJECT_TYPE = 0,
irnPR_WAB_RESOLVE_FLAG,
irnPR_ENTRYID,
irnPR_DISPLAY_NAME,
irnMax
};
static const SizedSPropTagArray(irnMax, irnColumns) =
{
irnMax,
{
PR_OBJECT_TYPE,
PR_WAB_RESOLVE_FLAG,
PR_ENTRYID,
PR_DISPLAY_NAME,
}
};
enum {
icrPR_DEF_CREATE_MAILUSER = 0,
icrPR_DEF_CREATE_DL,
icrMax
};
const SizedSPropTagArray(icrMax, ptaCreate)=
{
icrMax,
{
PR_DEF_CREATE_MAILUSER,
PR_DEF_CREATE_DL,
}
};
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CAddressBookData::CAddressBookData()
{
m_pWABObject = NULL;
m_hInstWAB = NULL;
m_pAdrBook = NULL;
m_ulConnection = 0;
}
CAddressBookData::~CAddressBookData()
{
// Release the Address Book pointer
if (m_pAdrBook)
m_pAdrBook->Release();
// Release the WAB object
if (m_pWABObject)
m_pWABObject->Release();
if (m_hInstWAB)
FreeLibrary(m_hInstWAB);
}
//
// FUNCTION: CAddressBookData::OpenWabFile()
//
// PURPOSE: Finds the WAB DLL, loads the DLL, and opens the WAB.
//
HRESULT CAddressBookData::OpenWabFile(void)
{
TCHAR szDll[MAX_PATH];
TCHAR szExpanded[MAX_PATH];
DWORD dwType = 0;
LPTSTR psz = szDll;
ULONG cbData = sizeof(szDll);
HKEY hKey = NULL;
HRESULT hr = E_FAIL;
LPWABOPEN lpfnWABOpen;
// Initialize the path string
*szDll = '\0';
// First look under the default WAB DLL path location in the Registry.
// WAB_DLL_PATH_KEY is defined in wabapi.h
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, WAB_DLL_PATH_KEY, 0, KEY_READ, &hKey))
{
if (ERROR_SUCCESS == RegQueryValueEx(hKey, _T(""), NULL, &dwType, (LPBYTE) szDll, &cbData))
if (REG_EXPAND_SZ == dwType)
{
ExpandEnvironmentStrings(szDll, szExpanded, ARRAYSIZE(szExpanded));
psz = szExpanded;
}
RegCloseKey(hKey);
}
// If the registry thing came up blank, then do a LoadLibrary on wab32.dll
m_hInstWAB = LoadLibrary((lstrlen(psz)) ? (LPCTSTR) psz : (LPCTSTR) WAB_DLL_NAME);
if (m_hInstWAB)
{
// If we've got the DLL, then get the entry point
lpfnWABOpen = (LPWABOPEN) GetProcAddress(m_hInstWAB, "WABOpen");
if (lpfnWABOpen)
{
WAB_PARAM wp = {0};
wp.cbSize = sizeof(WAB_PARAM);
wp.guidPSExt = CLSID_OEBAControl;
wp.ulFlags = (g_dwAthenaMode & MODE_NEWSONLY) ? WAB_ENABLE_PROFILES : WAB_ENABLE_PROFILES | WAB_USE_OE_SENDMAIL;
hr = lpfnWABOpen(&m_pAdrBook, &m_pWABObject, &wp, 0);
}
}
return (hr);
}
//
// FUNCTION: CAddressBookData::LoadWabContents()
//
// PURPOSE: Loads the contents of the WAB into the provided ListView control.
//
// PARAMETERS:
// [in] ctlList - Pointer to the ListView control to load the WAB into.
//
HRESULT CAddressBookData::LoadWabContents(CContainedWindow& ctlList, CMsgrAb *pSink)
{
ULONG ulObjType = 0;
LPMAPITABLE lpAB = NULL;
LPTSTR *lppszArray = NULL;
ULONG cRows = 0;
LPSRowSet lpRow = NULL;
LPSRowSet lpRowAB = NULL;
LPABCONT lpContainer = NULL;
int cNumRows = 0;
int nRows = 0;
HRESULT hr = E_FAIL;
ULONG lpcbEID;
LPENTRYID lpEID = NULL;
LPSRowSet pSRowSet = NULL;
Assert(m_pAdrBook);
if (!m_pAdrBook)
return E_UNEXPECTED;
// Get the entryid of the root PAB container
hr = m_pAdrBook->GetPAB(&lpcbEID, &lpEID);
if(!PR_MSGR_DEF_ID)
InitNamedProps();
// Open the root PAB container. This is where all the WAB contents reside.
ulObjType = 0;
hr = m_pAdrBook->OpenEntry(lpcbEID,
(LPENTRYID)lpEID,
NULL,
0,
&ulObjType,
(LPUNKNOWN *) &lpContainer);
if(HR_FAILED(hr))
goto exit;
if(pSink)
m_pAB = pSink;
if (pSink && !m_ulConnection)
m_pAdrBook->Advise(lpcbEID, lpEID, fnevObjectModified, (IMAPIAdviseSink *) pSink, &m_ulConnection);
// Get a contents table of all the contents in the WABs root container.
hr = lpContainer->GetContentsTable(WAB_PROFILE_CONTENTS /*0*/, &lpAB);
if(HR_FAILED(hr))
goto exit;
// Order the columns in the ContentsTable to conform to the ones we want
// - which are mainly DisplayName, EntryID and ObjectType. The table is
// guaranteed to set the columns in the order requested.
Assert(PR_MSGR_DEF_ID);
ptaEid.aulPropTag[ieidPR_MSGR_DEF_ID] = PR_MSGR_DEF_ID;
hr = lpAB->SetColumns((LPSPropTagArray) &ptaEid, 0);
if(HR_FAILED(hr))
goto exit;
// Reset to the beginning of the table
hr = lpAB->SeekRow(BOOKMARK_BEGINNING, 0, NULL);
if(HR_FAILED(hr))
goto exit;
// If we got this far, we have a populated table. We can query the rows
// now.
hr = _QueryAllRows(lpAB, NULL, NULL, NULL, MAX_QUERY_SIZE, &pSRowSet);
if (FAILED(hr) || !pSRowSet)
goto exit;
// Fill the provided ListView with this table
_FillListFromTable(ctlList, pSRowSet);
exit:
if (lpEID)
m_pWABObject->FreeBuffer(lpEID);
if (pSRowSet)
_FreeProws(pSRowSet);
if (lpContainer)
lpContainer->Release();
if (lpAB)
lpAB->Release();
return hr;
}
HRESULT CAddressBookData::DoLDAPSearch(LPTSTR pszText, CContainedWindow& ctlList)
{
// Build a restriction based on the given text
SRestriction SRes;
if (SUCCEEDED(_GetLDAPSearchRestriction(pszText, &SRes)))
{
// Figure out what the entry ID is for the LDAP container
ULONG cbEntryID = 0;
LPENTRYID pEntryID = 0;
if (SUCCEEDED(_GetLDAPContainer(&cbEntryID, &pEntryID)))
{
// Perform the search
SORT_INFO si = {0, 0};
_GetLDAPContentsList(cbEntryID, pEntryID, si, &SRes, ctlList);
if (pEntryID)
m_pWABObject->FreeBuffer(pEntryID);
}
if (SRes.res.resAnd.lpRes)
m_pWABObject->FreeBuffer(SRes.res.resAnd.lpRes);
}
return (S_OK);
}
void CAddressBookData::_FreeProws(LPSRowSet prows)
{
if (prows)
{
for (ULONG irow = 0; irow < prows->cRows; ++irow)
m_pWABObject->FreeBuffer(prows->aRow[irow].lpProps);
m_pWABObject->FreeBuffer(prows);
}
}
//
// FUNCTION: CAddressBookData::_MergeRowSets()
//
// PURPOSE: Merges prows with *pprowsDst, reallocating *pprowsDst if
// necessary. Destroys the container portion of prows (but not
// the individual rows it contains).
//
// PARAMETERS:
// [in] prows - source set of rows
// [in, out] *pprowsDst - set of rows to merge the prows into
//
// RETURN VALUE:
// HRESULT
//
HRESULT CAddressBookData::_MergeRowSets(LPSRowSet prows, LPSRowSet FAR *pprowsDst)
{
SCODE sc = S_OK;
LPSRowSet prowsT;
UINT crowsSrc;
UINT crowsDst;
_ASSERTE(!IsBadWritePtr(pprowsDst, sizeof(LPSRowSet)));
_ASSERTE(prows);
// If the table is completely empty we want to return this.
if (!*pprowsDst || (*pprowsDst)->cRows == 0)
{
m_pWABObject->FreeBuffer(*pprowsDst);
*pprowsDst = prows;
prows = NULL; // Don't free it!
goto exit;
}
if (prows->cRows == 0)
{
goto exit;
}
// OK, now we know there are rows in both rowsets, we have to do a real
// merge.
crowsSrc = (UINT) prows->cRows;
crowsDst = (UINT) (*pprowsDst)->cRows; // handle 0
if (FAILED(sc = m_pWABObject->AllocateBuffer(CbNewSRowSet(crowsSrc + crowsDst), (LPVOID*) &prowsT)))
goto exit;
if (crowsDst)
CopyMemory(prowsT->aRow, (*pprowsDst)->aRow, crowsDst * sizeof(SRow));
CopyMemory(&prowsT->aRow[crowsDst], prows->aRow, crowsSrc * sizeof(SRow));
prowsT->cRows = crowsSrc + crowsDst;
m_pWABObject->FreeBuffer(*pprowsDst);
*pprowsDst = prowsT;
exit:
// if (prows)
// m_pWABObject->FreeBuffer(&prows);
return ResultFromScode(sc);
}
/*
- HrQueryAllRows
-
* Purpose:
* Retrieves all rows from an IMAPITable interface up to a set
* maximum. It will optionally set the column set, sort order,
* and restriction on the table before querying.
*
* If the table is empty, an SRowSet with zero rows is
* returned (just like QueryRows).
*
* The seek position of the table is undefined both before and
* after this call.
*
* If the function fails with an error other than
* MAPI_E_NOT_ENOUGH_MEMORY, extended error information is
* available through the table interface.
*
* Arguments:
* ptable in the table interface to query
* ptaga in if not NULL, column set for the table
* pres in if not NULL, restriction to be applied
* psos in if not NULL, sort order to be applied
* crowsMax in if nonzero, limits the number of rows
* to be returned.
* pprows out all rows of the table
*
* Returns:
* HRESULT. Extended error information normally is in the
* table.
*
* Side effects:
* Seek position of table is undefined.
*
* Errors:
* MAPI_E_TABLE_TOO_BIG if the table contains more than
* cRowsMax rows.
*/
HRESULT CAddressBookData::_QueryAllRows(LPMAPITABLE ptable,
LPSPropTagArray ptaga,
LPSRestriction pres,
LPSSortOrderSet psos,
LONG crowsMax,
LPSRowSet FAR *pprows)
{
HRESULT hr;
LPSRowSet prows = NULL;
UINT crows = 0;
LPSRowSet prowsT=NULL;
UINT crowsT;
*pprows = NULL;
// Set up the table, if the corresponding setup parameter is present.
if (ptaga && FAILED(hr = ptable->SetColumns(ptaga, TBL_BATCH)))
goto exit;
if (pres && FAILED(hr = ptable->Restrict(pres, TBL_BATCH)))
goto exit;
if (psos && FAILED(hr = ptable->SortTable(psos, TBL_BATCH)))
goto exit;
// Set position to beginning of the table.
if (FAILED(hr = ptable->SeekRow(BOOKMARK_BEGINNING, 0, NULL)))
goto exit;
if (crowsMax == 0)
crowsMax = 0xffffffff;
for (;;)
{
prowsT = NULL;
// Retrieve some rows. Ask for the limit.
hr = ptable->QueryRows(crowsMax, 0, &prowsT);
if (FAILED(hr))
{
// Note: the failure may actually have happened during one of the
// setup calls, since we set TBL_BATCH.
goto exit;
}
_ASSERTE(prowsT->cRows <= 0xFFFFFFFF);
crowsT = (UINT) prowsT->cRows;
// Did we get more rows than caller can handle?
if ((LONG) (crowsT + (prows ? prows->cRows : 0)) > crowsMax)
{
hr = ResultFromScode(MAPI_E_TABLE_TOO_BIG);
//_FreeProws(prowsT);
goto exit;
}
// Add the rows just retrieved into the set we're building.
//
// NOTE: this handles boundary conditions including either row set is
// empty.
//
// NOTE: the merge destroys prowsT.
if (FAILED(hr = _MergeRowSets(prowsT, &prows)))
goto exit;
// Did we hit the end of the table? Unfortunately, we have to ask twice
// before we know.
if (crowsT == 0)
break;
}
if(prows->cRows != 0)
*pprows = prows;
exit:
if (prowsT)
_FreeProws(prowsT);
if (FAILED(hr))
_FreeProws(prows);
return hr;
}
HRESULT CAddressBookData::_GetLDAPContainer(ULONG *pcbEntryID, LPENTRYID *ppEntryID)
{
ULONG ulObjectType = 0;
IABContainer *pRoot = 0;
LPMAPITABLE pRootTable = 0;
HRESULT hr = S_OK;
// Get the root Address Book container
hr = m_pAdrBook->OpenEntry(0, NULL, NULL, 0, &ulObjectType, (LPUNKNOWN *) &pRoot);
if (FAILED(hr))
goto exit;
// From the address book container, get a table of it's contents
hr = pRoot->GetContentsTable(0, &pRootTable);
if (FAILED(hr))
goto exit;
// Set the columns
pRootTable->SetColumns((LPSPropTagArray) &irnColumns, 0);
// Build a restriction to only display LDAP servers that we're supposed
// to resolve against.
SRestriction resAnd[2]; // 0 = LDAP, 1 = ResolveFlag
SRestriction resLDAPResolve;
SPropValue ResolveFlag;
// Restrict: Only show LDAP containers with Resolve TRUE
resAnd[0].rt = RES_EXIST;
resAnd[0].res.resExist.ulReserved1 = 0;
resAnd[0].res.resExist.ulReserved2 = 0;
resAnd[0].res.resExist.ulPropTag = PR_WAB_LDAP_SERVER;
ResolveFlag.ulPropTag = PR_WAB_RESOLVE_FLAG;
ResolveFlag.Value.b = TRUE;
resAnd[1].rt = RES_PROPERTY;
resAnd[1].res.resProperty.relop = RELOP_EQ;
resAnd[1].res.resProperty.ulPropTag = PR_WAB_RESOLVE_FLAG;
resAnd[1].res.resProperty.lpProp = &ResolveFlag;
resLDAPResolve.rt = RES_AND;
resLDAPResolve.res.resAnd.cRes = 2;
resLDAPResolve.res.resAnd.lpRes = resAnd;
// Apply the restruction
hr = pRootTable->Restrict(&resLDAPResolve, 0);
if (HR_FAILED(hr))
goto exit;
// We're going to just blindly grab the first item in this table as the
// LDAP container we're going to use.
LPSRowSet pRowSet;
hr = pRootTable->QueryRows(1, 0, &pRowSet);
if (FAILED(hr))
goto exit;
// Grab the size of the entry id
*pcbEntryID = pRowSet->aRow[0].lpProps[irnPR_ENTRYID].Value.bin.cb;
// Make a copy of the entry id
hr = m_pWABObject->AllocateBuffer(*pcbEntryID, (LPVOID *) ppEntryID);
if (FAILED(hr))
goto exit;
CopyMemory(*ppEntryID, pRowSet->aRow[0].lpProps[irnPR_ENTRYID].Value.bin.lpb,
*pcbEntryID);
exit:
if (pRootTable)
pRootTable->Release();
if (pRoot)
pRoot->Release();
if (pRowSet)
_FreeProws(pRowSet);
return (hr);
}
HRESULT CAddressBookData::_GetLDAPSearchRestriction(LPTSTR pszText, LPSRestriction lpSRes)
{
SRestriction SRes = { 0 };
LPSRestriction lpPropRes = NULL;
ULONG ulcPropCount = 0;
HRESULT hr = E_FAIL;
ULONG i = 0;
SCODE sc = ERROR_SUCCESS;
LPSPropValue lpPropArray = NULL;
if (!lstrlen(pszText))
{
ATLTRACE(_T("No Search Props"));
goto exit;
}
lpSRes->rt = RES_AND;
lpSRes->res.resAnd.cRes = 1;
// Allocate a buffer for the restriction
lpSRes->res.resAnd.lpRes = NULL;
sc = m_pWABObject->AllocateBuffer(1 * sizeof(SRestriction),
(LPVOID *) &(lpSRes->res.resAnd.lpRes));
if (S_OK != sc || !(lpSRes->res.resAnd.lpRes))
{
ATLTRACE("MAPIAllocateBuffer Failed");
hr = MAPI_E_NOT_ENOUGH_MEMORY;
goto exit;
}
lpPropRes = lpSRes->res.resAnd.lpRes;
// Create the first part of the OR clause
lpPropRes[0].rt = RES_PROPERTY;
lpPropRes[0].res.resProperty.relop = RELOP_EQ;
lpPropRes[0].res.resProperty.ulPropTag = PR_EMAIL_ADDRESS;
lpPropRes[0].res.resProperty.lpProp = NULL;
m_pWABObject->AllocateMore(sizeof(SPropValue), lpPropRes, (LPVOID*) &(lpPropRes[0].res.resProperty.lpProp));
lpPropArray = lpPropRes[0].res.resProperty.lpProp;
if (!lpPropArray)
{
ATLTRACE("MAPIAllocateBuffer Failed");
hr = MAPI_E_NOT_ENOUGH_MEMORY;
goto exit;
}
lpPropArray->ulPropTag = PR_EMAIL_ADDRESS;
lpPropArray->Value.LPSZ = NULL;
m_pWABObject->AllocateMore(lstrlen(pszText) + 1, lpPropRes, (LPVOID *) &(lpPropArray->Value.LPSZ));
if (!lpPropArray->Value.LPSZ)
{
ATLTRACE("MAPIAllocateBuffer Failed");
hr = MAPI_E_NOT_ENOUGH_MEMORY;
goto exit;
}
StrCpyN(lpPropArray->Value.LPSZ, pszText, lstrlen(pszText) + 1);
#if 0
// Add the second OR clause
lpPropRes[1].rt = RES_PROPERTY;
lpPropRes[1].res.resProperty.relop = RELOP_EQ;
lpPropRes[1].res.resProperty.ulPropTag = PR_DISPLAY_NAME;
lpPropRes[1].res.resProperty.lpProp = NULL;
m_pWABObject->AllocateMore(sizeof(SPropValue), lpPropRes, (LPVOID*) &(lpPropRes[1].res.resProperty.lpProp));
lpPropArray = lpPropRes[1].res.resProperty.lpProp;
if (!lpPropArray)
{
ATLTRACE("MAPIAllocateBuffer Failed");
hr = MAPI_E_NOT_ENOUGH_MEMORY;
goto exit;
}
lpPropArray->ulPropTag = PR_DISPLAY_NAME;
lpPropArray->Value.LPSZ = NULL;
m_pWABObject->AllocateMore(lstrlen(pszText) + 1, lpPropRes, (LPVOID *) &(lpPropArray->Value.LPSZ));
if (!lpPropArray->Value.LPSZ)
{
ATLTRACE("MAPIAllocateBuffer Failed");
hr = MAPI_E_NOT_ENOUGH_MEMORY;
goto exit;
}
StrCpyN(lpPropArray->Value.LPSZ, pszText, lstrlen(pszText) + 1);
#endif
hr = S_OK;
exit:
return hr;
}
HRESULT CAddressBookData::_GetLDAPContentsList(ULONG cbContainerEID,
LPENTRYID pContainerEID,
SORT_INFO rSortInfo,
LPSRestriction pPropRes,
CContainedWindow& ctlList)
{
HRESULT hr = S_OK;
HRESULT hrTemp;
ULONG ulObjectType = 0;
LPMAPICONTAINER pContainer = NULL;
LPMAPITABLE pContentsTable = NULL;
LPSRowSet pSRowSet = NULL;
// Open the container object corresponding to pContainerEID
hr = m_pAdrBook->OpenEntry(cbContainerEID, pContainerEID, NULL, 0,
&ulObjectType, (LPUNKNOWN *) &pContainer);
if (FAILED(hr))
goto exit;
// Get the contents table from this container
hr = pContainer->GetContentsTable(0, &pContentsTable);
if (FAILED(hr))
goto exit;
// Order the columns in the ContentsTable to conform to the ones we want
// - which are mainly DisplayName, EntryID and ObjectType. The table is
// guaranteed to set the columns in the order requested.
Assert(PR_MSGR_DEF_ID);
ptaEid.aulPropTag[ieidPR_MSGR_DEF_ID] = PR_MSGR_DEF_ID;
hr = pContentsTable->SetColumns((LPSPropTagArray) &ptaEid, 0);
if(HR_FAILED(hr))
goto exit;
// Do the find
hr = pContentsTable->FindRow(pPropRes, BOOKMARK_BEGINNING, 0);
if (FAILED(hr))
goto exit;
// If this was a partial completion error, we want to continue but also
// return this information to the caller
if (MAPI_W_PARTIAL_COMPLETION == hr)
hrTemp = hr;
// If we got this far, we have a populated table. We can query the rows
// now.
hr = _QueryAllRows(pContentsTable, NULL, NULL, NULL, MAX_QUERY_SIZE, &pSRowSet);
if (FAILED(hr) || !pSRowSet)
goto exit;
// Fill in the ListView from the table
_FillListFromTable(ctlList, pSRowSet, TRUE);
exit:
if (pSRowSet)
_FreeProws(pSRowSet);
if (pContentsTable)
pContentsTable->Release();
if (pContainer)
pContainer->Release();
return (hr);
}
HRESULT CAddressBookData::_FillListFromTable(CContainedWindow& ctlList, LPSRowSet pSRowSet, BOOL bLDAP)
{
LPSBinary lpSB;
// Make sure the caller passed us a rowset
Assert(pSRowSet);
Assert(PR_MSGR_DEF_ID);
// Loop through the rows in the rowset
for (ULONG i = 0; i < pSRowSet->cRows; i++)
{
// Get the information out of the table that we need. Right now we're
// grabbing the entry ID, the display name, and the business phone number.
LPENTRYID lpEID = (LPENTRYID) pSRowSet->aRow[i].lpProps[ieidPR_ENTRYID].Value.bin.lpb;
ULONG cbEID = pSRowSet->aRow[i].lpProps[ieidPR_ENTRYID].Value.bin.cb;
DWORD nFlag = (pSRowSet->aRow[i].lpProps[ieidPR_OBJECT_TYPE].Value.l == MAPI_DISTLIST) ? MAB_GROUP : MAB_CONTACT;
LPTSTR lpszID = NULL;
LPTSTR lpszName = NULL;
if(nFlag == MAB_CONTACT)
{
if(pSRowSet->aRow[i].lpProps[ieidPR_USER_X509_CERTIFICATE].ulPropTag == PR_USER_X509_CERTIFICATE)
nFlag |= MAB_CERT;
}
if(PROP_TYPE(pSRowSet->aRow[i].lpProps[ieidPR_MSGR_DEF_ID/*ieidPR_EMAIL_ADDRESS*/].ulPropTag) == PT_TSTRING )
{
nFlag = nFlag | MAB_BUDDY;
lpszID = pSRowSet->aRow[i].lpProps[ieidPR_MSGR_DEF_ID/*ieidPR_EMAIL_ADDRESS*/].Value.lpszA;
}
else if(PROP_TYPE(pSRowSet->aRow[i].lpProps[ieidPR_EMAIL_ADDRESS].ulPropTag) == PT_TSTRING )
lpszID = pSRowSet->aRow[i].lpProps[ieidPR_EMAIL_ADDRESS].Value.lpszA;
else
lpszID = NULL;
if(PROP_TYPE(pSRowSet->aRow[i].lpProps[ieidPR_DISPLAY_NAME].ulPropTag) == PT_TSTRING )
lpszName = pSRowSet->aRow[i].lpProps[ieidPR_DISPLAY_NAME].Value.lpszA;
else
lpszName = lpszID;
// LPTSTR lpszPhone = pSRowSet->aRow[i].lpProps[ieidPR_BUSINESS_TELEPHONE_NUMBER].Value.lpszA;
// Allocate an ITEMINFO struct to store this information
lpSB = NULL;
m_pWABObject->AllocateBuffer(sizeof(SBinary), (LPVOID *) &lpSB);
if (lpSB)
{
// Save the information we'll need later
m_pWABObject->AllocateMore(cbEID, lpSB, (LPVOID *) &(lpSB->lpb));
if (!lpSB->lpb)
{
m_pWABObject->FreeBuffer(lpSB);
continue;
}
CopyMemory(lpSB->lpb, lpEID, cbEID);
lpSB->cb = cbEID;
// Create an item to add to the list
m_pAB->CheckAndAddAbEntry(lpSB, lpszID, lpszName, nFlag);
}
}
// Let's make sure the first item is selected
// ListView_SetItemState(ctlList, 0, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED);
return (S_OK);
}
HRESULT CAddressBookData::NewContact(HWND hwndParent)
{
HRESULT hr;
ULONG cbNewEntry;
LPENTRYID pNewEntry;
ULONG cbContainerID;
LPENTRYID pContainerID = 0;
if(!m_pAdrBook)
return E_FAIL;
hr = m_pAdrBook->GetPAB(&cbContainerID, &pContainerID);
if (FAILED(hr))
return(hr);
hr = m_pAdrBook->NewEntry((ULONG_PTR) hwndParent, /*CREATE_CHECK_DUP_STRICT*/ 0, cbContainerID, pContainerID, 0, NULL,
&cbNewEntry, &pNewEntry);
return (hr);
}
// Add new (Msgr) contact to address book
HRESULT CAddressBookData::AutoAddContact(TCHAR * pchName, TCHAR * pchID)
{
LPMAILUSER lpMailUser = NULL;
ULONG ulcPropCount = 1;
ULONG ulIndex = 0;
LPSPropValue lpPropArray = NULL;
SCODE sc;
LPWSTR pwszName = NULL,
pwszID = NULL;
HRESULT hr = S_OK;
if(!m_pAdrBook || !m_pWABObject)
return(S_FALSE);
// 1. Add entry to Address book
pwszName = PszToUnicode(CP_ACP, pchName);
if (!pwszName && (pchName && *pchName))
{
hr = E_OUTOFMEMORY;
goto out;
}
pwszID = PszToUnicode(CP_ACP, pchID);
if (!pwszID && (pchID && *pchID))
{
hr = E_OUTOFMEMORY;
goto out;
}
hr = HrWABCreateEntry(m_pAdrBook,
m_pWABObject,
pwszName,
pwszID,
CREATE_CHECK_DUP_STRICT,
&lpMailUser, KEEP_OPEN_READWRITE);
if(SUCCEEDED(hr))
{
// 2. Set custom property: default address for buddy
// Create a return prop array to pass back to the WAB
sc = m_pWABObject->AllocateBuffer(sizeof(SPropValue),
(LPVOID *)&lpPropArray);
if (sc!=S_OK)
goto out;
int nLen = lstrlen(pchID);
if(nLen)
{
lpPropArray[0].ulPropTag = MsgrPropTags[0];
sc = m_pWABObject->AllocateMore(nLen+1, lpPropArray,
(LPVOID *)&(lpPropArray[0].Value.LPSZ));
if (sc!=S_OK)
goto out;
StrCpyN(lpPropArray[0].Value.LPSZ, pchID, nLen+1);
}
// Set this new data on the object
//
if(lpMailUser)
{
hr = lpMailUser->SetProps(1, lpPropArray, NULL);
if(SUCCEEDED(hr))
hr = lpMailUser->SaveChanges(FORCE_SAVE);
}
}
out:
MemFree(pwszName);
MemFree(pwszID);
if(lpPropArray)
m_pWABObject->FreeBuffer(lpPropArray);
if(lpMailUser)
ReleaseObj(lpMailUser);
return(hr);
}
// Unicode string property version of template array
SizedSPropTagArray(6, ptaAddr_W) =
{
6,
{
PR_ADDRTYPE_W,
PR_DISPLAY_NAME_W,
PR_EMAIL_ADDRESS_W,
PR_ENTRYID,
PR_CONTACT_EMAIL_ADDRESSES_W, //4
PR_SEARCH_KEY
}
};
// ANSI string property version of template array
SizedSPropTagArray(6, ptaAddr_A) =
{
6,
{
PR_ADDRTYPE_A,
PR_DISPLAY_NAME_A,
PR_EMAIL_ADDRESS_A,
PR_ENTRYID,
PR_CONTACT_EMAIL_ADDRESSES_A,
PR_SEARCH_KEY
}
};
HRESULT CAddressBookData::AddRecipient(LPMIMEADDRESSTABLEW pAddrTable, LPSBinary pSB, BOOL fGroup)
{
HRESULT hr;
ULONG ulType = 0;
IMailUser *pMailUser = 0;
ULONG cValues;
SPropValue *pPropArray = 0;
ULONG ulObjType = 0;
LPMAPITABLE lpAB = NULL;
LPABCONT lpContainer = NULL;
ULONG lpcbEID;
LPENTRYID lpEID = NULL;
// Retrieve the item from the wab
hr = m_pAdrBook->OpenEntry(pSB->cb, (LPENTRYID) pSB->lpb, NULL,
MAPI_BEST_ACCESS, &ulType, (IUnknown **) &pMailUser);
if (FAILED(hr))
goto exit;
// Get the appropriate properties from the object
hr = pMailUser->GetProps((SPropTagArray *) &ptaAddr_W, 0, &cValues, &pPropArray);
if (FAILED(hr))
goto exit;
// Set those badboys on the address table
if(pPropArray[2].ulPropTag == PR_EMAIL_ADDRESS_W)
pAddrTable->AppendW(IAT_TO, IET_DECODED, pPropArray[2].Value.lpszW, NULL , NULL);
else if(pPropArray[4].ulPropTag == PR_CONTACT_EMAIL_ADDRESSES_W)
pAddrTable->AppendW(IAT_TO, IET_DECODED, pPropArray[4].Value.MVszW.lppszW[0], NULL , NULL);
else if((pPropArray[1].ulPropTag == PR_DISPLAY_NAME_W) && fGroup)
pAddrTable->AppendW(IAT_TO, IET_DECODED, pPropArray[1].Value.lpszW, NULL , NULL);
// Bug 34077 - they don't want to have a display name...
/* else if(pPropArray[1].ulPropTag == PR_DISPLAY_NAME)
pAddrTable->Append(IAT_TO, IET_DECODED, pPropArray[1].Value.lpszA, NULL , NULL);
else
Assert(FALSE); */
exit:
if (pPropArray)
m_pWABObject->FreeBuffer(pPropArray);
SafeRelease(pMailUser);
return (hr);
}
HRESULT CAddressBookData::SetDefaultMsgrID(LPSBinary pSB, LPTSTR pchID)
{
ULONG ulType = 0;
IMailUser *lpMailUser = 0;
LPSPropValue lpPropArray = NULL;
SCODE sc;
HRESULT hr = m_pAdrBook->OpenEntry(pSB->cb, (LPENTRYID) pSB->lpb, NULL,
MAPI_BEST_ACCESS, &ulType, (IUnknown **) &lpMailUser);
if (FAILED(hr))
goto exit;
if(SUCCEEDED(hr))
{
// 2. Set custom property: default address for buddy
// Create a return prop array to pass back to the WAB
sc = m_pWABObject->AllocateBuffer(sizeof(SPropValue),
(LPVOID *)&lpPropArray);
if (sc!=S_OK)
goto exit;
int nLen = lstrlen(pchID);
if(nLen)
{
lpPropArray[0].ulPropTag = MsgrPropTags[0];
sc = m_pWABObject->AllocateMore(nLen+1, lpPropArray,
(LPVOID *)&(lpPropArray[0].Value.LPSZ));
if (sc!=S_OK)
goto exit;
StrCpyN(lpPropArray[0].Value.LPSZ, pchID, nLen+1);
}
// Set this new data on the object
//
if(lpMailUser)
{
hr = lpMailUser->SetProps(1, lpPropArray, NULL);
if(SUCCEEDED(hr))
hr = lpMailUser->SaveChanges(FORCE_SAVE);
}
}
exit:
if(lpPropArray)
m_pWABObject->FreeBuffer(lpPropArray);
SafeRelease(lpMailUser);
return (hr);
}
HRESULT CAddressBookData::GetDisplayName(LPSBinary pSB, LPTSTR szDisplayName, int nMax)
{
ULONG ulType = 0;
IMailUser *pMailUser = 0;
ULONG cValues;
SPropValue *pPropArray = 0;
HRESULT hr = m_pAdrBook->OpenEntry(pSB->cb, (LPENTRYID) pSB->lpb, NULL,
MAPI_BEST_ACCESS, &ulType, (IUnknown **) &pMailUser);
if (FAILED(hr))
goto exit;
// Get the appropriate properties from the object
hr = pMailUser->GetProps((SPropTagArray *) &ptaAddr_A, 0, &cValues, &pPropArray);
if (FAILED(hr))
goto exit;
StrCpyN(szDisplayName, pPropArray[1].Value.lpszA, nMax);
szDisplayName[nMax - 1] = _T('\0');
exit:
if (pPropArray)
m_pWABObject->FreeBuffer(pPropArray);
SafeRelease(pMailUser);
return (hr);
}
BOOL CAddressBookData::CheckEmailAddr(LPSBinary pSB, LPTSTR szEmail)
{
ULONG ulType = 0;
IMailUser *pMailUser = 0;
ULONG cValues;
SPropValue *pPropArray = 0;
LPSPropValue lpPropMVEmail = NULL;
UINT i = 0;
BOOL fRet = FALSE;
HRESULT hr = m_pAdrBook->OpenEntry(pSB->cb, (LPENTRYID) pSB->lpb, NULL,
MAPI_BEST_ACCESS, &ulType, (IUnknown **) &pMailUser);
if (FAILED(hr))
goto exit;
// Get the appropriate properties from the object
hr = pMailUser->GetProps((SPropTagArray *) &ptaAddr_A, 0, &cValues, &pPropArray);
if (FAILED(hr))
goto exit;
// 4 element is PR_CONTACT_EMAIL_ADDRESSES in ptaAddr
lpPropMVEmail = &(pPropArray[4]);
if(lpPropMVEmail && (lpPropMVEmail->ulPropTag == PR_CONTACT_EMAIL_ADDRESSES))
{
// we have a multiple emails
//Assume, if this is present, so is MVAddrType, and defaultindex
for(i = 0; i < lpPropMVEmail->Value.MVszA.cValues; i++)
{
if(!lstrcmpi(lpPropMVEmail->Value.MVszA.lppszA[i], szEmail))
fRet = TRUE;
}
}
exit:
if (pPropArray)
m_pWABObject->FreeBuffer(pPropArray);
SafeRelease(pMailUser);
return (fRet);
}
HRESULT CAddressBookData::FreeListViewItem(LPSBinary pSB)
{
if (pSB)
m_pWABObject->FreeBuffer(pSB);
return (S_OK);
}
HRESULT CAddressBookData::ShowDetails(HWND hwndParent, LPSBinary pSB)
{
HRESULT hr;
ULONG_PTR ulUIParam = (ULONG_PTR) hwndParent;
hr = m_pAdrBook->Details(&ulUIParam, NULL, NULL, pSB->cb, (LPENTRYID) pSB->lpb,
NULL, NULL, NULL, 0);
return (hr);
}
HRESULT CAddressBookData::AddAddress(LPWSTR pwszDisplay, LPSTR pszAddress)
{
HRESULT hr;
LPABCONT pABContainer = NULL;
ULONG cbContainerID,
ul;
LPENTRYID pContainerID = 0;
LPMAPIPROP lpProps = 0;
SPropValue rgpv[3];
SPropTagArray ptaEID = { 1, { PR_ENTRYID } };
LPSPropValue ppvDefMailUser=0;
SizedSPropTagArray(1, ptaDefMailUser) =
{ 1, { PR_DEF_CREATE_MAILUSER } };
DWORD cUsedValues;
// Get the entry ID for the PAB
hr = m_pAdrBook->GetPAB(&cbContainerID, &pContainerID);
if (FAILED(hr))
goto error;
// Request the container
hr = m_pAdrBook->OpenEntry(cbContainerID, pContainerID, NULL,
0, &ul, (LPUNKNOWN *) &pABContainer);
Assert(ul == MAPI_ABCONT);
if (FAILED(hr))
goto error;
// Free the entry ID
m_pWABObject->FreeBuffer(pContainerID);
// Get the properties for the default mail template
hr = pABContainer->GetProps((LPSPropTagArray) &ptaDefMailUser, 0, &ul, &ppvDefMailUser);
if (FAILED(hr) || !ppvDefMailUser || ppvDefMailUser->ulPropTag != PR_DEF_CREATE_MAILUSER)
goto error;
// Create a new entry
hr=pABContainer->CreateEntry(ppvDefMailUser->Value.bin.cb,
(LPENTRYID) ppvDefMailUser->Value.bin.lpb,
CREATE_CHECK_DUP_STRICT, &lpProps);
if (FAILED(hr))
goto error;
// Fill in the properties for the display name and address
rgpv[0].ulPropTag = PR_DISPLAY_NAME_W;
rgpv[0].Value.lpszW = pwszDisplay;
rgpv[1].ulPropTag = PR_EMAIL_ADDRESS;
rgpv[1].Value.lpszA = pszAddress;
cUsedValues = 2;
// Set those props on the entry
hr = lpProps->SetProps(cUsedValues, rgpv, NULL);
if (FAILED(hr))
goto error;
// Save 'em
hr = lpProps->SaveChanges(KEEP_OPEN_READONLY);
if (FAILED(hr))
goto error;
error:
ReleaseObj(lpProps);
ReleaseObj(pABContainer);
if (ppvDefMailUser)
m_pWABObject->FreeBuffer(ppvDefMailUser);
return hr;
}
HRESULT CAddressBookData::DeleteItems(ENTRYLIST *pList)
{
ULONG ulObjType = 0;
LPABCONT lpContainer = NULL;
HRESULT hr = E_FAIL;
ULONG lpcbEID;
LPENTRYID lpEID = NULL;
// Get the entryid of the root PAB container
hr = m_pAdrBook->GetPAB(&lpcbEID, &lpEID);
// Open the root PAB container. This is where all the WAB contents reside.
ulObjType = 0;
hr = m_pAdrBook->OpenEntry(lpcbEID,
(LPENTRYID)lpEID,
NULL,
0,
&ulObjType,
(LPUNKNOWN *) &lpContainer);
m_pWABObject->FreeBuffer(lpEID);
lpEID = NULL;
// Delete those items
lpContainer->DeleteEntries(pList, 0);
lpContainer->Release();
return (S_OK);
}
HRESULT CAddressBookData::Find(HWND hwndParent)
{
m_pWABObject->Find(m_pAdrBook, hwndParent);
return (S_OK);
}
HRESULT CAddressBookData::NewGroup(HWND hwndParent)
{
HRESULT hr;
ULONG cbNewEntry = 0;
LPENTRYID pNewEntry = 0;
LPENTRYID pTplEid;
ULONG cbTplEid;
hr = _GetWABTemplateID(MAPI_DISTLIST, &cbTplEid, &pTplEid);
if (SUCCEEDED(hr))
{
hr = m_pAdrBook->NewEntry((ULONG_PTR) hwndParent, 0, 0, NULL, cbTplEid, pTplEid, &cbNewEntry, &pNewEntry);
Assert(pTplEid);
m_pWABObject->FreeBuffer(pTplEid);
}
return (hr);
}
HRESULT CAddressBookData::AddressBook(HWND hwndParent)
{
CWab *pWab = NULL;
if (SUCCEEDED(HrCreateWabObject(&pWab)))
{
pWab->HrBrowse(hwndParent);
pWab->Release();
}
else
{
AthMessageBoxW(hwndParent, MAKEINTRESOURCEW(idsAthena), MAKEINTRESOURCEW(idsGeneralWabError),
NULL, MB_OK | MB_ICONEXCLAMATION);
}
return (S_OK);
}
HRESULT CAddressBookData::_GetWABTemplateID(ULONG ulObjectType, ULONG *lpcbEID, LPENTRYID *lppEID)
{
LPABCONT lpContainer = NULL;
HRESULT hr = S_OK;
SCODE sc = ERROR_SUCCESS;
ULONG ulObjType = 0;
ULONG cbWABEID = 0;
LPENTRYID lpWABEID = NULL;
LPSPropValue lpCreateEIDs = NULL;
LPSPropValue lpNewProps = NULL;
ULONG cNewProps;
ULONG nIndex;
if ((!m_pAdrBook) || ((ulObjectType != MAPI_MAILUSER) && (ulObjectType != MAPI_DISTLIST)) )
{
hr = MAPI_E_INVALID_PARAMETER;
goto out;
}
*lpcbEID = 0;
*lppEID = NULL;
if (FAILED(hr = m_pAdrBook->GetPAB(&cbWABEID, &lpWABEID)))
{
goto out;
}
if (HR_FAILED(hr = m_pAdrBook->OpenEntry(cbWABEID, // size of EntryID to open
lpWABEID, // EntryID to open
NULL, // interface
0, // flags
&ulObjType,
(LPUNKNOWN *) &lpContainer)))
{
goto out;
}
// Get us the default creation entryids
if (FAILED(hr = lpContainer->GetProps((LPSPropTagArray) &ptaCreate,
0, &cNewProps, &lpCreateEIDs)))
{
goto out;
}
// Validate the properites
if (lpCreateEIDs[icrPR_DEF_CREATE_MAILUSER].ulPropTag != PR_DEF_CREATE_MAILUSER ||
lpCreateEIDs[icrPR_DEF_CREATE_DL].ulPropTag != PR_DEF_CREATE_DL)
{
goto out;
}
if (ulObjectType == MAPI_DISTLIST)
nIndex = icrPR_DEF_CREATE_DL;
else
nIndex = icrPR_DEF_CREATE_MAILUSER;
*lpcbEID = lpCreateEIDs[nIndex].Value.bin.cb;
m_pWABObject->AllocateBuffer(*lpcbEID, (LPVOID *) lppEID);
if (sc != S_OK)
{
hr = MAPI_E_NOT_ENOUGH_MEMORY;
goto out;
}
CopyMemory(*lppEID,lpCreateEIDs[nIndex].Value.bin.lpb,*lpcbEID);
out:
if (lpCreateEIDs)
m_pWABObject->FreeBuffer(lpCreateEIDs);
if (lpContainer)
lpContainer->Release();
if (lpWABEID)
m_pWABObject->FreeBuffer(lpWABEID);
return hr;
}
/*//$$****************************************************************
//
// InitNamedProps
//
// Gets the PropTags for the Named Props this app is interested in
//
//********************************************************************/
HRESULT CAddressBookData::InitNamedProps(/*LPWABEXTDISPLAY lpWED*/)
{
ULONG i;
HRESULT hr = E_FAIL;
LPSPropTagArray lptaMsgrProps = NULL;
LPMAPINAMEID * lppMsgrPropNames;
SCODE sc;
// LPMAILUSER lpMailUser = NULL;
WCHAR szBuf[msgrMax][MAX_PATH];
/* if(!lpWED)
goto err;
lpMailUser = (LPMAILUSER) lpWED->lpPropObj;
if(!lpMailUser)
goto err; */
sc = m_pWABObject->AllocateBuffer(sizeof(LPMAPINAMEID) * msgrMax,
(LPVOID *) &lppMsgrPropNames);
if(sc)
{
hr = ResultFromScode(sc);
goto err;
}
for(i=0;i<msgrMax;i++)
{
sc = m_pWABObject->AllocateMore(sizeof(MAPINAMEID),
lppMsgrPropNames,
(LPVOID *)&(lppMsgrPropNames[i]));
if(sc)
{
hr = ResultFromScode(sc);
goto err;
}
lppMsgrPropNames[i]->lpguid = (LPGUID) &WAB_ExtBAGuid;
lppMsgrPropNames[i]->ulKind = MNID_STRING;
*(szBuf[i]) = '\0';
// Convert prop name to wide-char
if ( !MultiByteToWideChar( GetACP(), 0, lpMsgrPropNames[i], -1, szBuf[i], ARRAYSIZE(szBuf[i]) ))
{
continue;
}
lppMsgrPropNames[i]->Kind.lpwstrName = (LPWSTR) szBuf[i];
}
hr = m_pAdrBook->GetIDsFromNames( msgrMax,
lppMsgrPropNames,
MAPI_CREATE,
&lptaMsgrProps);
if(HR_FAILED(hr))
goto err;
if(lptaMsgrProps)
{
// Set the property types on the returned props
MsgrPropTags[MsgrID] = PR_MSGR_DEF_ID = CHANGE_PROP_TYPE(lptaMsgrProps->aulPropTag[MsgrID], PT_TSTRING);
}
err:
if(lptaMsgrProps)
m_pWABObject->FreeBuffer( lptaMsgrProps);
if(lppMsgrPropNames)
m_pWABObject->FreeBuffer( lppMsgrPropNames);
return hr;
}