ADDRLKUP.C

// --addrlkup.c----------------------------------------------------------------- 
//
// Functions used in address mapping.
//
// Copyright (C) Microsoft Corp. 1986-1996. All Rights Reserved.
// -----------------------------------------------------------------------------

#include "edk.h"

#include "addrlkup.chk"

//$--HrFindExchangeGlobalAddressList-------------------------------------------------
// Returns the entry ID of the global address list container in the address
// book.
// -----------------------------------------------------------------------------
HRESULT HrFindExchangeGlobalAddressList( // RETURNS: return code
IN LPADRBOOK lpAdrBook, // address book pointer
OUT ULONG *lpcbeid, // pointer to count of bytes in entry ID
OUT LPENTRYID *lppeid) // pointer to entry ID pointer
{
HRESULT hr = NOERROR;
ULONG ulObjType = 0;
ULONG i = 0;
LPMAPIPROP lpRootContainer = NULL;
LPMAPIPROP lpContainer = NULL;
LPMAPITABLE lpContainerTable = NULL;
LPSRowSet lpRows = NULL;
ULONG cbContainerEntryId = 0;
LPENTRYID lpContainerEntryId = NULL;
LPSPropValue lpCurrProp = NULL;
SRestriction SRestrictAnd[2] = {0};
SRestriction SRestrictGAL = {0};
SPropValue SPropID = {0};
SPropValue SPropProvider = {0};
BYTE muid[] = MUIDEMSAB;

SizedSPropTagArray(1, rgPropTags) =
{
1,
{
PR_ENTRYID,
}
};

DEBUGPUBLIC("HrFindExchangeGlobalAddressList()");

hr = CHK_HrFindExchangeGlobalAddressList(
lpAdrBook,
lpcbeid,
lppeid);

if(FAILED(hr))
RETURN(hr);

*lpcbeid = 0;
*lppeid = NULL;

// Open the root container of the address book
hr = MAPICALL(lpAdrBook)->OpenEntry(
lpAdrBook,
0,
NULL,
NULL,
MAPI_DEFERRED_ERRORS,
&ulObjType,
(LPUNKNOWN FAR *)&lpRootContainer);

if(FAILED(hr))
{
goto cleanup;
}

if(ulObjType != MAPI_ABCONT)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

// Get the hierarchy table of the root container
hr = MAPICALL(((LPABCONT)lpRootContainer))->GetHierarchyTable(
(LPABCONT)lpRootContainer,
MAPI_DEFERRED_ERRORS|CONVENIENT_DEPTH,
&lpContainerTable);

if(FAILED(hr))
{
goto cleanup;
}

// Restrict the table to the global address list (GAL)
// ---------------------------------------------------

// Initialize provider restriction to only Exchange providers

SRestrictAnd[0].rt = RES_PROPERTY;
SRestrictAnd[0].res.resProperty.relop = RELOP_EQ;
SRestrictAnd[0].res.resProperty.ulPropTag = PR_AB_PROVIDER_ID;
SPropProvider.ulPropTag = PR_AB_PROVIDER_ID;

SPropProvider.Value.bin.cb = 16;
SPropProvider.Value.bin.lpb = (LPBYTE)muid;
SRestrictAnd[0].res.resProperty.lpProp = &SPropProvider;

// Initialize container ID restriction to only GAL container

SRestrictAnd[1].rt = RES_PROPERTY;
SRestrictAnd[1].res.resProperty.relop = RELOP_EQ;
SRestrictAnd[1].res.resProperty.ulPropTag = PR_EMS_AB_CONTAINERID;
SPropID.ulPropTag = PR_EMS_AB_CONTAINERID;
SPropID.Value.l = 0;
SRestrictAnd[1].res.resProperty.lpProp = &SPropID;

// Initialize AND restriction

SRestrictGAL.rt = RES_AND;
SRestrictGAL.res.resAnd.cRes = 2;
SRestrictGAL.res.resAnd.lpRes = &SRestrictAnd[0];

// Restrict the table to the GAL - only a single row should remain

// Get the row corresponding to the GAL

//
// Query all the rows
//

hr = HrQueryAllRows(
lpContainerTable,
(LPSPropTagArray)&rgPropTags,
&SRestrictGAL,
NULL,
0,
&lpRows);

if(FAILED(hr) || (lpRows == NULL) || (lpRows->cRows != 1))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

// Get the entry ID for the GAL

lpCurrProp = &(lpRows->aRow[0].lpProps[0]);

if(lpCurrProp->ulPropTag == PR_ENTRYID)
{
cbContainerEntryId = lpCurrProp->Value.bin.cb;
lpContainerEntryId = (LPENTRYID)lpCurrProp->Value.bin.lpb;
}
else
{
hr = HR_LOG(EDK_E_NOT_FOUND);
goto cleanup;
}

hr = MAPIAllocateBuffer(cbContainerEntryId, (LPVOID *)lppeid);

if(FAILED(hr))
{
*lpcbeid = 0;
*lppeid = NULL;
}
else
{
CopyMemory(
*lppeid,
lpContainerEntryId,
cbContainerEntryId);

*lpcbeid = cbContainerEntryId;
}

cleanup:

ULRELEASE(lpRootContainer);
ULRELEASE(lpContainerTable);
ULRELEASE(lpContainer);

FREEPROWS(lpRows);

if(FAILED(hr))
{
MAPIFREEBUFFER(*lppeid);

*lpcbeid = 0;
*lppeid = NULL;
}

RETURN(hr);
}

//$--HrGWResolveAddress@-------------------------------------------------------
// Returns the entry ID for the recipient identified by a given address.
// -----------------------------------------------------------------------------
HRESULT HrGWResolveAddressW(
IN LPABCONT lpGalABCont, // pointer to GAL container
IN LPCWSTR lpszAddress, // pointer to proxy address
OUT BOOL *lpfMapiRecip, // MAPI recipient
OUT ULONG *lpcbEntryID, // count of bytes in entry ID
OUT LPENTRYID *lppEntryID) // pointer to entry ID
{
HRESULT hr = NOERROR;
LPSTR lpszAddressA = NULL;

DEBUGPUBLIC( "HrGWResolveAddressW()");

hr = CHK_HrGWResolveAddressW(
lpGalABCont, lpszAddress, lpfMapiRecip,
lpcbEntryID, lppEntryID);
if( FAILED( hr))
RETURN( hr);

// MAPI doesn't officially support resolution of UNICODE
// addresses. Therefore, the address is converted to ANSI...

hr = HrStrWToStrA( lpszAddress, &lpszAddressA);
if( FAILED( hr))
goto cleanup;

hr = HrGWResolveAddressA(
lpGalABCont, lpszAddressA, lpfMapiRecip,
lpcbEntryID, lppEntryID);

cleanup:
MAPIFREEBUFFER( lpszAddressA);

RETURN(hr);
}

HRESULT HrGWResolveAddressA(
IN LPABCONT lpGalABCont, // pointer to GAL container
IN LPCSTR lpszAddress, // pointer to proxy address
OUT BOOL *lpfMapiRecip, // MAPI recipient
OUT ULONG *lpcbEntryID, // count of bytes in entry ID
OUT LPENTRYID *lppEntryID) // pointer to entry ID
{
HRESULT hr = NOERROR;
HRESULT hrT = 0;
SCODE sc = 0;
LPADRLIST lpAdrList = NULL;
LPFlagList lpFlagList = NULL;
SPropValue prop[2] = {0};
ULONG cbEntryID = 0;
LPENTRYID lpEntryID = NULL;

static const SizedSPropTagArray(2, rgPropTags) =
{ 2,
{
PR_ENTRYID,
PR_SEND_RICH_INFO
}
};

DEBUGPUBLIC("HrGWResolveAddressA()");

hr = CHK_HrGWResolveAddressA(
lpGalABCont,
lpszAddress,
lpfMapiRecip,
lpcbEntryID,
lppEntryID);

if(FAILED(hr))
RETURN(hr);

*lpfMapiRecip = FALSE;
*lpcbEntryID = 0;
*lppEntryID = NULL;

sc = MAPIAllocateBuffer( CbNewFlagList(1), (LPVOID*)&lpFlagList);

if(FAILED(sc))
{
hr = HR_LOG(E_OUTOFMEMORY);
goto cleanup;
}

lpFlagList->cFlags = 1;
lpFlagList->ulFlag[0] = MAPI_UNRESOLVED;

hr = HrMAPICreateSizedAddressList(1, &lpAdrList);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

prop[0].ulPropTag = PR_DISPLAY_NAME_A;
prop[0].Value.lpszA = (LPSTR)lpszAddress;
prop[1].ulPropTag = PR_RECIPIENT_TYPE;
prop[1].Value.ul = MAPI_TO;

hr = HrMAPISetAddressList(
0,
2,
prop,
lpAdrList);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

hrT = MAPICALL(lpGalABCont)->ResolveNames(
lpGalABCont,
(LPSPropTagArray)&rgPropTags,
EMS_AB_ADDRESS_LOOKUP,
lpAdrList,
lpFlagList);

if(lpFlagList->ulFlag[0] != MAPI_RESOLVED)
{
if(lpFlagList->ulFlag[0] == MAPI_AMBIGUOUS)
{
hrT = MAPI_E_AMBIGUOUS_RECIP;
}
else
{
hrT = MAPI_E_NOT_FOUND;
}
}

if(FAILED(hrT))
{
if(hrT == MAPI_E_NOT_FOUND)
{
hr = HR_LOG(EDK_E_NOT_FOUND);
}
else
{
hr = HR_LOG(E_FAIL);
};

goto cleanup;
}

cbEntryID = lpAdrList->aEntries[0].rgPropVals[0].Value.bin.cb;
lpEntryID = (LPENTRYID)lpAdrList->aEntries[0].rgPropVals[0].Value.bin.lpb;

sc = MAPIAllocateBuffer( cbEntryID, (LPVOID*)lppEntryID);

if(FAILED(sc))
{
hr = HR_LOG(E_OUTOFMEMORY);
goto cleanup;
}

CopyMemory(*lppEntryID, lpEntryID, cbEntryID);
*lpcbEntryID = cbEntryID;
*lpfMapiRecip = lpAdrList->aEntries[0].rgPropVals[1].Value.b;

cleanup:

MAPIFREEBUFFER(lpFlagList);

FREEPADRLIST(lpAdrList);

RETURN(hr);
}

//$--HrCheckForType@------------------------------------------------------------
// Check if the passed in string has the requested address type. If so, return
// the address value, otherwise fail.
// -----------------------------------------------------------------------------
static HRESULT HrCheckForTypeW( // RETURNS: return code
IN LPCWSTR lpszAddrType, // pointer to address type
IN LPCWSTR lpszProxy, // pointer to proxy address
OUT LPWSTR * lppszAddress) // pointer to address pointer
{
HRESULT hr = EDK_E_NOT_FOUND;
LPCWSTR lpszProxyAddr = NULL;
ULONG cbAddress = 0;
SCODE sc = 0;
ULONG cchProxy = 0;
ULONG cchProxyType = 0;

DEBUGPRIVATE("HrCheckForTypeW()");

hr = CHK_HrCheckForTypeW(
lpszAddrType,
lpszProxy,
lppszAddress);

if(FAILED(hr))
RETURN(hr);

// Initialize output parameter

*lppszAddress = NULL;

// find the ':' separator.

cchProxy = wcslen(lpszProxy);
cchProxyType = wcscspn(lpszProxy, L":");

if((cchProxyType == 0) || (cchProxyType >= cchProxy))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

hr = EDK_E_NOT_FOUND;

// does the address type match?
if((cchProxyType == wcslen(lpszAddrType)) &&
(_wcsnicmp(lpszProxy, lpszAddrType, cchProxyType) == 0))
{
// specified address type found
lpszProxyAddr = lpszProxy + cchProxyType + 1;

cbAddress = cbStrLenW(lpszProxyAddr);

// make a buffer to hold it.
sc = MAPIAllocateBuffer(cbAddress, (void **)lppszAddress);

if(FAILED(sc))
{
hr = HR_LOG(E_OUTOFMEMORY);
}
else
{
CopyMemory(*lppszAddress, lpszProxyAddr, cbAddress);

hr = NOERROR;
}
}

cleanup:

RETURN(hr);
}

static HRESULT HrCheckForTypeA( // RETURNS: return code
IN LPCSTR lpszAddrType, // pointer to address type
IN LPCSTR lpszProxy, // pointer to proxy address
OUT LPSTR * lppszAddress) // pointer to address pointer
{
HRESULT hr = EDK_E_NOT_FOUND;
LPCSTR lpszProxyAddr = NULL;
ULONG cbAddress = 0;
SCODE sc = 0;
ULONG cchProxy = 0;
ULONG cchProxyType = 0;

DEBUGPRIVATE("HrCheckForTypeA()");

hr = CHK_HrCheckForTypeA(
lpszAddrType,
lpszProxy,
lppszAddress);

if(FAILED(hr))
RETURN(hr);

// Initialize output parameter

*lppszAddress = NULL;

// find the ':' separator.

cchProxy = lstrlenA(lpszProxy);
cchProxyType = strcspn(lpszProxy, ":");

if((cchProxyType == 0) || (cchProxyType >= cchProxy))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

hr = EDK_E_NOT_FOUND;

// does the address type match?
if((cchProxyType == (ULONG)lstrlenA(lpszAddrType)) &&
(_strnicmp(lpszProxy, lpszAddrType, cchProxyType) == 0))
{
// specified address type found
lpszProxyAddr = lpszProxy + cchProxyType + 1;

cbAddress = cbStrLenA(lpszProxyAddr);

// make a buffer to hold it.
sc = MAPIAllocateBuffer(cbAddress, (void **)lppszAddress);

if(FAILED(sc))
{
hr = HR_LOG(E_OUTOFMEMORY);
}
else
{
CopyMemory(*lppszAddress, lpszProxyAddr, cbAddress);

hr = NOERROR;
}
}

cleanup:

RETURN(hr);
}

//$--HrGWResolveProxy@---------------------------------------------------------
// Returns the address of a specified type for the recipient identified by
// a given entry ID.
// -----------------------------------------------------------------------------
#define IADDRTYPE 0
#define IEMAILADDR 1
#define IMAPIRECIP 2
#define IPROXYADDR 3

HRESULT HrGWResolveProxyW( // RETURNS: return code
IN LPADRBOOK lpAdrBook, // pointer to address book
IN ULONG cbeid, // count of bytes in the entry ID
IN LPENTRYID lpeid, // pointer to the entry ID
IN LPCWSTR lpszAddrType, // pointer to the address type
OUT BOOL *lpfMapiRecip, // MAPI recipient
OUT LPWSTR * lppszAddress) // pointer to the address pointer
{
HRESULT hr = EDK_E_NOT_FOUND;
HRESULT hrT = 0;
SCODE sc = 0;
ULONG i = 0;
ULONG cbAddress = 0;
ULONG cProxy = 0;
LPSPropValue lpProps = NULL;
LPADRLIST lpAdrList = NULL;
SPropValue prop[2] = {0};

SizedSPropTagArray(4, rgPropTags) =
{
4,
{
PR_ADDRTYPE_W,
PR_EMAIL_ADDRESS_W,
PR_SEND_RICH_INFO,
PR_EMS_AB_PROXY_ADDRESSES_W
}
};

DEBUGPUBLIC("HrGWResolveProxyW()");

hr = CHK_HrGWResolveProxyW(
lpAdrBook,
cbeid,
lpeid,
lpszAddrType,
lpfMapiRecip,
lppszAddress);

if(FAILED(hr))
RETURN(hr);

// Initialize output parameters

*lpfMapiRecip = FALSE;
*lppszAddress = NULL;

hr = HrMAPICreateSizedAddressList(1, &lpAdrList);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

prop[0].ulPropTag = PR_ENTRYID;
prop[0].Value.bin.cb = cbeid;
prop[0].Value.bin.lpb = (LPBYTE)lpeid;
prop[1].ulPropTag = PR_RECIPIENT_TYPE;
prop[1].Value.ul = MAPI_TO;

hr = HrMAPISetAddressList(
0,
2,
prop,
lpAdrList);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

hrT = MAPICALL(lpAdrBook)->PrepareRecips( lpAdrBook,
0,
(LPSPropTagArray)&rgPropTags,
lpAdrList);

if(FAILED(hrT))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

lpProps = lpAdrList->aEntries[0].rgPropVals;

//
// Hack: detect the case where prepare recips doesn't work correctly.
// This happens when trying to look up a recipient that is in
// a replicated directory but not in the local directory.
//
if (lpAdrList->aEntries[0].cValues == 3)
{
MODULE_ERROR("PrepareRecips() failed but did not declare.");

hr = HR_LOG(E_FAIL);
goto cleanup;
}

// If the given address type matches the PR_ADDRTYPE value,
// return the PR_EMAIL_ADDRESS value

if((PROP_TYPE(lpProps[IADDRTYPE].ulPropTag) != PT_ERROR) &&
(PROP_TYPE(lpProps[IEMAILADDR].ulPropTag) != PT_ERROR) &&
(_wcsicmp(lpProps[IADDRTYPE].Value.lpszW, lpszAddrType) == 0))
{
cbAddress = cbStrLenW(lpProps[IEMAILADDR].Value.lpszW);

sc = MAPIAllocateBuffer(cbAddress, (void **)lppszAddress);

if(FAILED(sc))
{
hr = HR_LOG(E_OUTOFMEMORY);
}
else
{
CopyMemory(*lppszAddress, lpProps[IEMAILADDR].Value.lpszW, cbAddress);
hr = NOERROR;
}

goto cleanup;
}

// Search for a PR_EMS_AB_PROXY_ADDRESSES of the given type if present.

else if(PROP_TYPE(lpProps[IPROXYADDR].ulPropTag) != PT_ERROR)
{
// count of proxy addresses
cProxy = lpAdrList->aEntries[0].rgPropVals[IPROXYADDR].Value.MVszW.cValues;

for(i = 0; i < cProxy; i++)
{
hr = HrCheckForTypeW(
lpszAddrType,
lpProps[IPROXYADDR].Value.MVszW.lppszW[i],
lppszAddress);

if(hr == EDK_E_NOT_FOUND)
{
continue;
}
else if(FAILED(hr))
{
goto cleanup;
}
else
{
//
// Found a matching proxy address.
//

goto cleanup;
}
}
}
else
{
hr = HR_LOG(EDK_E_NOT_FOUND);
goto cleanup;
}

cleanup:

if(SUCCEEDED(hr))
{
*lpfMapiRecip = lpAdrList->aEntries[0].rgPropVals[IMAPIRECIP].Value.b;
}

FREEPADRLIST(lpAdrList);

RETURN(hr);
}

HRESULT HrGWResolveProxyA( // RETURNS: return code
IN LPADRBOOK lpAdrBook, // pointer to address book
IN ULONG cbeid, // count of bytes in the entry ID
IN LPENTRYID lpeid, // pointer to the entry ID
IN LPCSTR lpszAddrType, // pointer to the address type
OUT BOOL *lpfMapiRecip, // MAPI recipient
OUT LPSTR * lppszAddress) // pointer to the address pointer
{
HRESULT hr = EDK_E_NOT_FOUND;
HRESULT hrT = 0;
SCODE sc = 0;
ULONG i = 0;
ULONG cbAddress = 0;
ULONG cProxy = 0;
LPSPropValue lpProps = NULL;
LPADRLIST lpAdrList = NULL;
SPropValue prop[2] = {0};

SizedSPropTagArray(4, rgPropTags) =
{
4,
{
PR_ADDRTYPE_A,
PR_EMAIL_ADDRESS_A,
PR_SEND_RICH_INFO,
PR_EMS_AB_PROXY_ADDRESSES_A
}
};

DEBUGPUBLIC("HrGWResolveProxyA()");

hr = CHK_HrGWResolveProxyA(
lpAdrBook,
cbeid,
lpeid,
lpszAddrType,
lpfMapiRecip,
lppszAddress);

if(FAILED(hr))
RETURN(hr);

// Initialize output parameters

*lpfMapiRecip = FALSE;
*lppszAddress = NULL;

hr = HrMAPICreateSizedAddressList(1, &lpAdrList);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

prop[0].ulPropTag = PR_ENTRYID;
prop[0].Value.bin.cb = cbeid;
prop[0].Value.bin.lpb = (LPBYTE)lpeid;
prop[1].ulPropTag = PR_RECIPIENT_TYPE;
prop[1].Value.ul = MAPI_TO;

hr = HrMAPISetAddressList(
0,
2,
prop,
lpAdrList);

if(FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

hrT = MAPICALL(lpAdrBook)->PrepareRecips( lpAdrBook,
0,
(LPSPropTagArray)&rgPropTags,
lpAdrList);

if(FAILED(hrT))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

lpProps = lpAdrList->aEntries[0].rgPropVals;

//
// Hack: detect the case where prepare recips doesn't work correctly.
// This happens when trying to look up a recipient that is in
// a replicated directory but not in the local directory.
//
if (lpAdrList->aEntries[0].cValues == 3)
{
MODULE_ERROR("PrepareRecips() failed but did not declare.");

hr = HR_LOG(E_FAIL);
goto cleanup;
}

// If the given address type matches the PR_ADDRTYPE value,
// return the PR_EMAIL_ADDRESS value

if((PROP_TYPE(lpProps[IADDRTYPE].ulPropTag) != PT_ERROR) &&
(PROP_TYPE(lpProps[IEMAILADDR].ulPropTag) != PT_ERROR) &&
(_strcmpi(lpProps[IADDRTYPE].Value.lpszA, lpszAddrType) == 0))
{
cbAddress = cbStrLenA(lpProps[IEMAILADDR].Value.lpszA);

sc = MAPIAllocateBuffer(cbAddress, (void **)lppszAddress);

if(FAILED(sc))
{
hr = HR_LOG(E_OUTOFMEMORY);
}
else
{
CopyMemory(*lppszAddress, lpProps[IEMAILADDR].Value.lpszW, cbAddress);
hr = NOERROR;
}

goto cleanup;
}

// Search for a PR_EMS_AB_PROXY_ADDRESSES of the given type if present.

else if(PROP_TYPE(lpProps[IPROXYADDR].ulPropTag) != PT_ERROR)
{
// count of proxy addresses
cProxy = lpAdrList->aEntries[0].rgPropVals[IPROXYADDR].Value.MVszA.cValues;

for(i = 0; i < cProxy; i++)
{
hr = HrCheckForTypeA(
lpszAddrType,
lpProps[IPROXYADDR].Value.MVszA.lppszA[i],
lppszAddress);

if(hr == EDK_E_NOT_FOUND)
{
continue;
}
else if(FAILED(hr))
{
goto cleanup;
}
else
{
//
// Found a matching proxy address.
//

goto cleanup;
}
}
}
else
{
hr = HR_LOG(EDK_E_NOT_FOUND);
goto cleanup;
}

cleanup:

if(SUCCEEDED(hr))
{
*lpfMapiRecip = lpAdrList->aEntries[0].rgPropVals[IMAPIRECIP].Value.b;
}

FREEPADRLIST(lpAdrList);

RETURN(hr);
}