1803 lines
61 KiB
C++
1803 lines
61 KiB
C++
|
//---------------------------------------------------------------------------
|
||
|
//
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 1992 - 1995
|
||
|
//
|
||
|
// File: cdssrch.cxx
|
||
|
//
|
||
|
// Contents: Microsoft ADs NDS Provider Generic Object
|
||
|
//
|
||
|
//
|
||
|
// History: 03-02-97 ShankSh Created.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
#include "nds.hxx"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
const int NO_NDS_RESULT_HANDLES = 32;
|
||
|
const int NO_UNCACHED_RESULTS_TO_KEEP = 3;
|
||
|
|
||
|
static
|
||
|
HRESULT
|
||
|
NdsValueToADsColumn(
|
||
|
LPWSTR pszColumnName,
|
||
|
DWORD dwSyntaxId,
|
||
|
DWORD dwValues,
|
||
|
LPBYTE lpValue,
|
||
|
ADS_SEARCH_COLUMN * pColumn
|
||
|
);
|
||
|
|
||
|
static
|
||
|
HRESULT
|
||
|
NdsValueToADsColumnAppend(
|
||
|
DWORD dwSyntaxId,
|
||
|
DWORD dwValues,
|
||
|
LPBYTE lpObject,
|
||
|
ADS_SEARCH_COLUMN * pColumn
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// Sets the appropriate search preferences.
|
||
|
//
|
||
|
HRESULT
|
||
|
CNDSGenObject::SetSearchPreference(
|
||
|
IN PADS_SEARCHPREF_INFO pSearchPrefs,
|
||
|
IN DWORD dwNumPrefs
|
||
|
)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
BOOL fWarning = FALSE;
|
||
|
DWORD i;
|
||
|
|
||
|
if (!pSearchPrefs && dwNumPrefs > 0) {
|
||
|
RRETURN (E_ADS_BAD_PARAMETER);
|
||
|
}
|
||
|
|
||
|
for (i=0; i<dwNumPrefs; i++) {
|
||
|
|
||
|
pSearchPrefs[i].dwStatus = ADS_STATUS_S_OK;
|
||
|
|
||
|
switch(pSearchPrefs[i].dwSearchPref) {
|
||
|
case ADS_SEARCHPREF_ASYNCHRONOUS:
|
||
|
case ADS_SEARCHPREF_SIZE_LIMIT:
|
||
|
case ADS_SEARCHPREF_TIME_LIMIT:
|
||
|
case ADS_SEARCHPREF_TIMEOUT:
|
||
|
case ADS_SEARCHPREF_PAGESIZE:
|
||
|
case ADS_SEARCHPREF_PAGED_TIME_LIMIT:
|
||
|
case ADS_SEARCHPREF_CHASE_REFERRALS:
|
||
|
//
|
||
|
// Can't be set
|
||
|
//
|
||
|
pSearchPrefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREF;
|
||
|
fWarning = TRUE;
|
||
|
continue;
|
||
|
|
||
|
case ADS_SEARCHPREF_DEREF_ALIASES:
|
||
|
if (pSearchPrefs[i].vValue.dwType != ADSTYPE_INTEGER) {
|
||
|
pSearchPrefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE;
|
||
|
fWarning = TRUE;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
switch (pSearchPrefs[i].vValue.Integer) {
|
||
|
case ADS_DEREF_NEVER:
|
||
|
_SearchPref._fDerefAliases = FALSE;
|
||
|
break;
|
||
|
|
||
|
case ADS_DEREF_ALWAYS:
|
||
|
_SearchPref._fDerefAliases = TRUE;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
pSearchPrefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE;
|
||
|
fWarning = TRUE;
|
||
|
continue;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case ADS_SEARCHPREF_ATTRIBTYPES_ONLY:
|
||
|
if (pSearchPrefs[i].vValue.dwType != ADSTYPE_BOOLEAN) {
|
||
|
pSearchPrefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE;
|
||
|
fWarning = TRUE;
|
||
|
continue;
|
||
|
}
|
||
|
_SearchPref._fAttrsOnly = pSearchPrefs[i].vValue.Boolean;
|
||
|
break;
|
||
|
|
||
|
case ADS_SEARCHPREF_CACHE_RESULTS:
|
||
|
if (pSearchPrefs[i].vValue.dwType != ADSTYPE_BOOLEAN) {
|
||
|
pSearchPrefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE;
|
||
|
fWarning = TRUE;
|
||
|
continue;
|
||
|
}
|
||
|
_SearchPref._fCacheResults = pSearchPrefs[i].vValue.Boolean;
|
||
|
break;
|
||
|
|
||
|
case ADS_SEARCHPREF_SEARCH_SCOPE:
|
||
|
if (pSearchPrefs[i].vValue.dwType != ADSTYPE_INTEGER) {
|
||
|
pSearchPrefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE;
|
||
|
fWarning = TRUE;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
switch (pSearchPrefs[i].vValue.Integer) {
|
||
|
case ADS_SCOPE_BASE:
|
||
|
_SearchPref._dwSearchScope = DS_SEARCH_ENTRY;
|
||
|
break;
|
||
|
|
||
|
case ADS_SCOPE_ONELEVEL:
|
||
|
_SearchPref._dwSearchScope = DS_SEARCH_SUBORDINATES;
|
||
|
break;
|
||
|
|
||
|
case ADS_SCOPE_SUBTREE:
|
||
|
_SearchPref._dwSearchScope = DS_SEARCH_SUBTREE;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
pSearchPrefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE;
|
||
|
fWarning = TRUE;
|
||
|
continue;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
pSearchPrefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREF;
|
||
|
fWarning = TRUE;
|
||
|
continue;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
RRETURN (fWarning ? S_ADS_ERRORSOCCURRED : S_OK);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT
|
||
|
CNDSGenObject::ExecuteSearch(
|
||
|
IN LPWSTR pszSearchFilter,
|
||
|
IN LPWSTR * pAttributeNames,
|
||
|
IN DWORD dwNumberAttributes,
|
||
|
OUT PADS_SEARCH_HANDLE phSearchHandle
|
||
|
)
|
||
|
{
|
||
|
PNDS_SEARCHINFO phSearchInfo = NULL;
|
||
|
LPWSTR szCurrAttr = NULL;
|
||
|
DWORD dwAttrNamesLen = 0;
|
||
|
HRESULT hr = S_OK;
|
||
|
ULONG i, j;
|
||
|
LPWSTR pszAttrNameBuffer = NULL, *ppszAttrs = NULL;
|
||
|
|
||
|
if (!phSearchHandle) {
|
||
|
RRETURN (E_ADS_BAD_PARAMETER);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Allocate search handle
|
||
|
//
|
||
|
phSearchInfo = (PNDS_SEARCHINFO) AllocADsMem(sizeof(NDS_SEARCHINFO));
|
||
|
if(!phSearchInfo)
|
||
|
BAIL_ON_FAILURE (hr = E_OUTOFMEMORY);
|
||
|
|
||
|
hr = AdsNdsGenerateFilterBuffer(
|
||
|
_hADsContext,
|
||
|
pszSearchFilter,
|
||
|
&phSearchInfo->_pFilterBuf
|
||
|
);
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
phSearchInfo->_fADsPathPresent = FALSE;
|
||
|
phSearchInfo->_fADsPathReturned = FALSE;
|
||
|
|
||
|
if (dwNumberAttributes == -1) {
|
||
|
//
|
||
|
// Specifies returning all attributes
|
||
|
//
|
||
|
|
||
|
phSearchInfo->_ppszAttrs = NULL;
|
||
|
phSearchInfo->_pszAttrNameBuffer = NULL;
|
||
|
phSearchInfo->_fADsPathPresent = TRUE;
|
||
|
phSearchInfo->_nAttrs = (DWORD) -1;
|
||
|
|
||
|
}
|
||
|
else {
|
||
|
ppszAttrs = (LPWSTR *) AllocADsMem(
|
||
|
sizeof(LPWSTR) *
|
||
|
(dwNumberAttributes)
|
||
|
);
|
||
|
if (!ppszAttrs)
|
||
|
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
|
||
|
|
||
|
for (i = 0; i < dwNumberAttributes; i++)
|
||
|
dwAttrNamesLen+= (wcslen(pAttributeNames[i]) + 1) * sizeof(WCHAR);
|
||
|
|
||
|
pszAttrNameBuffer = (LPWSTR) AllocADsMem(
|
||
|
dwAttrNamesLen
|
||
|
);
|
||
|
if (!pszAttrNameBuffer)
|
||
|
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
|
||
|
|
||
|
szCurrAttr = pszAttrNameBuffer;
|
||
|
for (i = 0, j = 0; i < dwNumberAttributes; i++) {
|
||
|
wcscpy(szCurrAttr, pAttributeNames[i]);
|
||
|
ppszAttrs[j] = szCurrAttr;
|
||
|
szCurrAttr += wcslen(ppszAttrs[j]) + 1;
|
||
|
|
||
|
if(_wcsicmp(ppszAttrs[j], L"ADsPath") == 0) {
|
||
|
//
|
||
|
// ADsPath need not be sent
|
||
|
//
|
||
|
|
||
|
phSearchInfo->_fADsPathPresent = TRUE;
|
||
|
}
|
||
|
else {
|
||
|
|
||
|
j++;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
phSearchInfo->_ppszAttrs = ppszAttrs;
|
||
|
phSearchInfo->_nAttrs = j;
|
||
|
phSearchInfo->_pszAttrNameBuffer = pszAttrNameBuffer;
|
||
|
}
|
||
|
|
||
|
phSearchInfo->_lIterationHandle = NO_MORE_ITERATIONS;
|
||
|
phSearchInfo->_pSearchResults = NULL;
|
||
|
phSearchInfo->_cSearchResults = 0;
|
||
|
phSearchInfo->_dwCurrResult = 0;
|
||
|
phSearchInfo->_cResultPrefetched = 0;
|
||
|
phSearchInfo->_fCheckForDuplicates = TRUE;
|
||
|
phSearchInfo->_dwCurrAttr = 0;
|
||
|
phSearchInfo->_SearchPref = _SearchPref;
|
||
|
|
||
|
*phSearchHandle = phSearchInfo;
|
||
|
|
||
|
RRETURN(S_OK);
|
||
|
|
||
|
error:
|
||
|
|
||
|
if(phSearchInfo) {
|
||
|
|
||
|
if(phSearchInfo->_ppszAttrs)
|
||
|
FreeADsMem(phSearchInfo->_ppszAttrs);
|
||
|
|
||
|
if(phSearchInfo->_pszAttrNameBuffer)
|
||
|
FreeADsMem(phSearchInfo->_pszAttrNameBuffer);
|
||
|
|
||
|
FreeADsMem(phSearchInfo);
|
||
|
}
|
||
|
|
||
|
RRETURN (hr);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT
|
||
|
CNDSGenObject::AbandonSearch(
|
||
|
IN ADS_SEARCH_HANDLE hSearchHandle
|
||
|
)
|
||
|
{
|
||
|
RRETURN(E_NOTIMPL);
|
||
|
}
|
||
|
|
||
|
HRESULT
|
||
|
CNDSGenObject::CloseSearchHandle (
|
||
|
IN ADS_SEARCH_HANDLE hSearchHandle
|
||
|
)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
PNDS_SEARCHINFO phSearchInfo = (PNDS_SEARCHINFO) hSearchHandle;
|
||
|
|
||
|
if (!phSearchInfo)
|
||
|
RRETURN (E_ADS_BAD_PARAMETER);
|
||
|
|
||
|
if (phSearchInfo->_pFilterBuf) {
|
||
|
ADsNdsFreeBuffer(phSearchInfo->_pFilterBuf);
|
||
|
}
|
||
|
|
||
|
if(phSearchInfo->_ppszAttrs)
|
||
|
FreeADsMem(phSearchInfo->_ppszAttrs);
|
||
|
|
||
|
if(phSearchInfo->_pszAttrNameBuffer)
|
||
|
FreeADsMem(phSearchInfo->_pszAttrNameBuffer);
|
||
|
|
||
|
if (phSearchInfo->_pSearchResults) {
|
||
|
|
||
|
for (DWORD i=0; i < phSearchInfo->_cSearchResults; i++) {
|
||
|
|
||
|
// If we're not caching all results, these may already have been freed
|
||
|
// and set to NULL, but this is okay --- ADsNdsFreeBuffer and
|
||
|
// ADsNdsFreeNdsObjInfoList will catch this.
|
||
|
|
||
|
ADsNdsFreeBuffer(phSearchInfo->_pSearchResults[i]._hSearchResult);
|
||
|
|
||
|
ADsNdsFreeNdsObjInfoList(phSearchInfo->_pSearchResults[i]._pObjects,
|
||
|
phSearchInfo->_pSearchResults[i]._dwObjects);
|
||
|
|
||
|
}
|
||
|
FreeADsMem(phSearchInfo->_pSearchResults);
|
||
|
}
|
||
|
|
||
|
FreeADsMem(phSearchInfo);
|
||
|
RRETURN (hr);
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT
|
||
|
CNDSGenObject::GetFirstRow(
|
||
|
IN ADS_SEARCH_HANDLE hSearchHandle
|
||
|
)
|
||
|
{
|
||
|
RRETURN(E_NOTIMPL);
|
||
|
}
|
||
|
|
||
|
HRESULT
|
||
|
CNDSGenObject::GetNextRow(
|
||
|
IN ADS_SEARCH_HANDLE hSearchHandle
|
||
|
)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
DWORD dwStatus = NO_ERROR;
|
||
|
PNDS_SEARCH_RESULT pResult, pNextResult, pEvictedResult;
|
||
|
PADSNDS_OBJECT_INFO pObject, pNextObject;
|
||
|
PNDS_SEARCHINFO phSearchInfo = (PNDS_SEARCHINFO) hSearchHandle;
|
||
|
DWORD dwType;
|
||
|
DWORD nObjectsSearched;
|
||
|
DWORD i;
|
||
|
|
||
|
if (!phSearchInfo) {
|
||
|
RRETURN(E_ADS_BAD_PARAMETER);
|
||
|
}
|
||
|
|
||
|
if (phSearchInfo->_fCheckForDuplicates) {
|
||
|
phSearchInfo->_dwCurrAttr = 0;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// dwCurrResult indexes the location of the array where we have already got
|
||
|
// information from. If it is < 0, it indicates that there is no information
|
||
|
// in this searchinfo at all
|
||
|
//
|
||
|
if (phSearchInfo->_dwCurrResult < 0)
|
||
|
RRETURN(S_ADS_NOMORE_ROWS);
|
||
|
|
||
|
if (phSearchInfo->_pSearchResults) {
|
||
|
pResult = &(phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]);
|
||
|
|
||
|
//
|
||
|
// If next object is available in current result
|
||
|
//
|
||
|
if (pResult->_pObjects &&
|
||
|
((pResult->_dwObjectCurrent+1) < pResult->_dwObjects)) {
|
||
|
pResult->_dwObjectCurrent++;
|
||
|
RRETURN(S_OK);
|
||
|
}
|
||
|
if (pResult->_dwObjectCurrent+1 == pResult->_dwObjects &&
|
||
|
(phSearchInfo->_cResultPrefetched > 0)) {
|
||
|
pNextResult = &(phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult+1]);
|
||
|
pNextResult->_dwObjectCurrent = 0;
|
||
|
phSearchInfo->_cResultPrefetched--;
|
||
|
|
||
|
//
|
||
|
// If next object points to NULL, it means we have no objects in
|
||
|
// the next row
|
||
|
//
|
||
|
if (!pNextResult->_pObjects)
|
||
|
RRETURN(S_ADS_NOMORE_ROWS);
|
||
|
|
||
|
if(phSearchInfo->_fCheckForDuplicates) {
|
||
|
pObject = pResult->_pObjects + pResult->_dwObjectCurrent;
|
||
|
pNextObject = pNextResult->_pObjects + pNextResult->_dwObjectCurrent;
|
||
|
if (!_wcsicmp(pObject->szObjectName, pNextObject->szObjectName)) {
|
||
|
//
|
||
|
// Duplicates; Skip one more result
|
||
|
//
|
||
|
//if (pNextResult->_dwObjectCurrent+1 < pNextResult->_dwObjects)
|
||
|
pNextResult->_dwObjectCurrent++;
|
||
|
//else
|
||
|
// RRETURN(S_ADS_NOMORE_ROWS);
|
||
|
}
|
||
|
}
|
||
|
if( pNextResult->_dwObjectCurrent >= pNextResult->_dwObjects &&
|
||
|
phSearchInfo->_lIterationHandle == NO_MORE_ITERATIONS) {
|
||
|
RRETURN(S_ADS_NOMORE_ROWS);
|
||
|
}
|
||
|
else {
|
||
|
//
|
||
|
// We have successfully moved onto the next value in the array
|
||
|
//
|
||
|
phSearchInfo->_dwCurrResult++;
|
||
|
|
||
|
if ( (phSearchInfo->_dwCurrResult >= NO_UNCACHED_RESULTS_TO_KEEP) &&
|
||
|
!phSearchInfo->_SearchPref._fCacheResults ) {
|
||
|
// Not caching --- evict the old result
|
||
|
pEvictedResult = &(phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult-NO_UNCACHED_RESULTS_TO_KEEP]);
|
||
|
|
||
|
ADsNdsFreeBuffer(pEvictedResult->_hSearchResult);
|
||
|
ADsNdsFreeNdsObjInfoList(pEvictedResult->_pObjects, pEvictedResult->_dwObjects);
|
||
|
|
||
|
pEvictedResult->_hSearchResult = NULL;
|
||
|
pEvictedResult->_pObjects = NULL;
|
||
|
pEvictedResult->_dwObjects = 0;
|
||
|
pEvictedResult->_fInUse = FALSE;
|
||
|
}
|
||
|
|
||
|
if ( pNextResult->_dwObjectCurrent >= pNextResult->_dwObjects) {
|
||
|
// phSearchInfo->_lIterationHandle != NO_MORE_ITERATIONS
|
||
|
|
||
|
// We have incremented pNextResult->_dwObjectCurrent past the number
|
||
|
// of objects in pNextResult, but there are more iterations left to go.
|
||
|
// This can occur if there was exactly one object in pNextResult, that
|
||
|
// object is a duplicate of the last object in pResult, and there are
|
||
|
// more objects left to retrieve. (This same case can also occur later
|
||
|
// in this function, after calling AdsNdsSearch to get a new result set,
|
||
|
// and code was added there as well to handle it.)
|
||
|
//
|
||
|
// We make it look like we've exhausted the results in pNextResult (which
|
||
|
// we have) and recursively get the next row to get the next
|
||
|
// result set (which may either be prefetched or retrieved from the server
|
||
|
// via AdsNdsSearch). Since _dwCurrResult has already been
|
||
|
// incremented, our pNextResult will be the recursive call's pResult,
|
||
|
// it will look like we've exhausted the objects in the result,
|
||
|
// and it will fetch the next result.
|
||
|
//
|
||
|
// We do this here, after the cache eviction code, so that we evict the
|
||
|
// _dwCurrentResult-NO_UNCACHED_RESULTS_TO_KEEP result before going on
|
||
|
// to _dwCurrentResult+1
|
||
|
|
||
|
pNextResult->_dwObjectCurrent = pNextResult->_dwObjects-1;
|
||
|
RRETURN(GetNextRow(hSearchHandle));
|
||
|
}
|
||
|
else {
|
||
|
// We haven't exhausted pNextResult, so we're done
|
||
|
RRETURN(S_OK);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if( pResult->_dwObjectCurrent+1 == pResult->_dwObjects &&
|
||
|
phSearchInfo->_lIterationHandle == NO_MORE_ITERATIONS)
|
||
|
RRETURN(S_ADS_NOMORE_ROWS);
|
||
|
}
|
||
|
|
||
|
if (!phSearchInfo->_pFilterBuf) {
|
||
|
//
|
||
|
// querynode not setup yet
|
||
|
//
|
||
|
RRETURN (E_FAIL);
|
||
|
}
|
||
|
|
||
|
if(!phSearchInfo->_pSearchResults) {
|
||
|
//
|
||
|
// Allocate an array of handles to Search Handles
|
||
|
//
|
||
|
phSearchInfo->_pSearchResults = (PNDS_SEARCH_RESULT) AllocADsMem(
|
||
|
sizeof(NDS_SEARCH_RESULT) *
|
||
|
NO_NDS_RESULT_HANDLES);
|
||
|
if(!phSearchInfo->_pSearchResults) {
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
goto error;
|
||
|
}
|
||
|
phSearchInfo->_dwCurrResult = 0;
|
||
|
phSearchInfo->_cSearchResults = NO_NDS_RESULT_HANDLES;
|
||
|
|
||
|
for (i=0; i < phSearchInfo->_cSearchResults; i++) {
|
||
|
phSearchInfo->_pSearchResults[i]._fInUse = 0;
|
||
|
phSearchInfo->_pSearchResults[i]._hSearchResult = NULL;
|
||
|
phSearchInfo->_pSearchResults[i]._pObjects = NULL;
|
||
|
phSearchInfo->_pSearchResults[i]._dwObjects = 0;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else {
|
||
|
phSearchInfo->_dwCurrResult++;
|
||
|
if (phSearchInfo->_dwCurrResult >= (LONG) phSearchInfo->_cSearchResults) {
|
||
|
//
|
||
|
// Need to allocate more memory for handles
|
||
|
//
|
||
|
|
||
|
phSearchInfo->_pSearchResults = (PNDS_SEARCH_RESULT) ReallocADsMem(
|
||
|
(void *) phSearchInfo->_pSearchResults,
|
||
|
sizeof(NDS_SEARCH_RESULT) *
|
||
|
phSearchInfo->_cSearchResults,
|
||
|
sizeof(NDS_SEARCH_RESULT) *
|
||
|
(phSearchInfo->_cSearchResults +
|
||
|
NO_NDS_RESULT_HANDLES)
|
||
|
);
|
||
|
if(!phSearchInfo->_pSearchResults) {
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
goto error;
|
||
|
}
|
||
|
|
||
|
for (i=phSearchInfo->_cSearchResults; i < phSearchInfo->_cSearchResults + NO_NDS_RESULT_HANDLES; i++) {
|
||
|
phSearchInfo->_pSearchResults[i]._fInUse = 0;
|
||
|
phSearchInfo->_pSearchResults[i]._hSearchResult = NULL;
|
||
|
phSearchInfo->_pSearchResults[i]._pObjects = NULL;
|
||
|
phSearchInfo->_pSearchResults[i]._dwObjects = 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
phSearchInfo->_cSearchResults += NO_NDS_RESULT_HANDLES;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pNextResult = &(phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]);
|
||
|
ADsNdsFreeNdsObjInfoList(pNextResult->_pObjects, pNextResult->_dwObjects);
|
||
|
pNextResult->_dwObjects = 0;
|
||
|
pNextResult->_pObjects = NULL;
|
||
|
pNextResult->_dwObjectCurrent = 0;
|
||
|
pNextResult->_hSearchResult = NULL;
|
||
|
pNextResult->_fInUse = TRUE;
|
||
|
|
||
|
hr = ADsNdsSearch(
|
||
|
_hADsContext,
|
||
|
_pszNDSDn,
|
||
|
_SearchPref._dwSearchScope,
|
||
|
_SearchPref._fDerefAliases,
|
||
|
phSearchInfo->_pFilterBuf,
|
||
|
0,
|
||
|
_SearchPref._fAttrsOnly ?
|
||
|
DS_ATTRIBUTE_NAMES : DS_ATTRIBUTE_VALUES,
|
||
|
phSearchInfo->_ppszAttrs,
|
||
|
phSearchInfo->_nAttrs,
|
||
|
0,
|
||
|
&nObjectsSearched,
|
||
|
&pNextResult->_hSearchResult,
|
||
|
&phSearchInfo->_lIterationHandle
|
||
|
);
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
hr = ADsNdsGetObjectListFromBuffer(
|
||
|
_hADsContext,
|
||
|
pNextResult->_hSearchResult,
|
||
|
(PDWORD)&pNextResult->_dwObjects,
|
||
|
&pNextResult->_pObjects
|
||
|
);
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
if (pNextResult->_dwObjects > 0) {
|
||
|
pNextResult->_dwObjectCurrent = 0;
|
||
|
if(phSearchInfo->_fCheckForDuplicates && phSearchInfo->_dwCurrResult > 0) {
|
||
|
pResult = &(phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult-1]);
|
||
|
pObject = pResult->_pObjects + pResult->_dwObjectCurrent;
|
||
|
pNextObject = pNextResult->_pObjects + pNextResult->_dwObjectCurrent;
|
||
|
if (!_wcsicmp(pObject->szObjectName, pNextObject->szObjectName)) {
|
||
|
//
|
||
|
// Duplicates; Skip one more result
|
||
|
//
|
||
|
pNextResult->_dwObjectCurrent++;
|
||
|
}
|
||
|
}
|
||
|
if( pNextResult->_dwObjectCurrent >= pNextResult->_dwObjects &&
|
||
|
phSearchInfo->_lIterationHandle == NO_MORE_ITERATIONS) {
|
||
|
phSearchInfo->_dwCurrResult--;
|
||
|
RRETURN(S_ADS_NOMORE_ROWS);
|
||
|
}
|
||
|
|
||
|
if ( !phSearchInfo->_SearchPref._fCacheResults &&
|
||
|
(phSearchInfo->_dwCurrResult >= NO_UNCACHED_RESULTS_TO_KEEP) ) {
|
||
|
// Not caching --- evict the old result
|
||
|
pEvictedResult = &(phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult-NO_UNCACHED_RESULTS_TO_KEEP]);
|
||
|
|
||
|
ADsNdsFreeBuffer(pEvictedResult->_hSearchResult);
|
||
|
ADsNdsFreeNdsObjInfoList(pEvictedResult->_pObjects, pEvictedResult->_dwObjects);
|
||
|
|
||
|
pEvictedResult->_hSearchResult = NULL;
|
||
|
pEvictedResult->_pObjects = NULL;
|
||
|
pEvictedResult->_dwObjects = 0;
|
||
|
pEvictedResult->_fInUse = FALSE;
|
||
|
}
|
||
|
|
||
|
// Above, we test if we have incremented _dwObjectCurrent past the last
|
||
|
// object in the result AND there are no more iterations. This would happen
|
||
|
// if there is exactly one object in this result, and that object is a duplicate
|
||
|
// of the last object in the previous result (i.e., the _wcsicmp above is executed
|
||
|
// and returns 0), and there are no more results (no more iterations to go).
|
||
|
//
|
||
|
// But, suppose the above conditions are true, EXCEPT that there are still more
|
||
|
// iterations to go. Then the above test wouldn't succeed, and we'd return with
|
||
|
// _dwObjectCurrent == _dwObjects, an invalid condition.
|
||
|
//
|
||
|
// In this case, we've exhausted the result and must fetch the next one.
|
||
|
// We do this by calling GetNextRow again. Since _dwCurrResult has already been
|
||
|
// incremented, our pNextResult will be the recursive call's pResult, it will look
|
||
|
// like we've exhausted the objects in the result, and it will fetch the next result.
|
||
|
//
|
||
|
// Note that we do this recursive call after the caching code so that we evict the
|
||
|
// _dwCurrResult-NO_UNCACHED_RESULTS_TO_KEEP entry before going on to _dwCurrResult+1.
|
||
|
if( pNextResult->_dwObjectCurrent >= pNextResult->_dwObjects) {
|
||
|
// phSearchInfo->_lIterationHandle != NO_MORE_ITERATIONS
|
||
|
pNextResult->_dwObjectCurrent = pNextResult->_dwObjects-1;
|
||
|
RRETURN(GetNextRow(hSearchHandle));
|
||
|
}
|
||
|
|
||
|
|
||
|
RRETURN(S_OK);
|
||
|
}
|
||
|
else {
|
||
|
phSearchInfo->_dwCurrResult--;
|
||
|
RRETURN(S_ADS_NOMORE_ROWS);
|
||
|
}
|
||
|
|
||
|
error:
|
||
|
RRETURN(hr);
|
||
|
}
|
||
|
|
||
|
HRESULT
|
||
|
CNDSGenObject::GetPreviousRow(
|
||
|
IN ADS_SEARCH_HANDLE hSearchHandle
|
||
|
)
|
||
|
{
|
||
|
PNDS_SEARCH_RESULT pResult, pPrevResult;
|
||
|
PNDS_SEARCHINFO phSearchInfo = (PNDS_SEARCHINFO) hSearchHandle;
|
||
|
|
||
|
if(!phSearchInfo || !phSearchInfo->_pSearchResults)
|
||
|
RRETURN(E_FAIL);
|
||
|
|
||
|
if (phSearchInfo->_fCheckForDuplicates) {
|
||
|
phSearchInfo->_dwCurrAttr = 0;
|
||
|
}
|
||
|
|
||
|
if (phSearchInfo->_dwCurrResult < 0)
|
||
|
RRETURN(S_ADS_NOMORE_ROWS);
|
||
|
|
||
|
pResult = &(phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]);
|
||
|
|
||
|
if (pResult->_dwObjectCurrent > 0)
|
||
|
pResult->_dwObjectCurrent--;
|
||
|
else if (phSearchInfo->_dwCurrResult > 0) {
|
||
|
pPrevResult = &(phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult-1]);
|
||
|
|
||
|
// Make sure the previous result hasn't been evicted from the cache
|
||
|
if (!pPrevResult->_fInUse)
|
||
|
RRETURN(S_ADS_NOMORE_ROWS);
|
||
|
|
||
|
pPrevResult->_dwObjectCurrent = pPrevResult->_dwObjects-1;
|
||
|
phSearchInfo->_cResultPrefetched++;
|
||
|
phSearchInfo->_dwCurrResult--;
|
||
|
|
||
|
|
||
|
// Check for duplicates
|
||
|
if (phSearchInfo->_fCheckForDuplicates) {
|
||
|
|
||
|
PADSNDS_OBJECT_INFO pObject, pPrevObject;
|
||
|
|
||
|
pPrevObject = pPrevResult->_pObjects + pPrevResult->_dwObjectCurrent;
|
||
|
pObject = pResult->_pObjects + pResult->_dwObjectCurrent;
|
||
|
|
||
|
if (!_wcsicmp(pPrevObject->szObjectName, pObject->szObjectName)) {
|
||
|
// dupe
|
||
|
RRETURN(GetPreviousRow(hSearchHandle));
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
}
|
||
|
else if(0 == pResult->_dwObjectCurrent)
|
||
|
// we are at the very beginning of the result set
|
||
|
pResult->_dwObjectCurrent--;
|
||
|
else
|
||
|
RRETURN(S_ADS_NOMORE_ROWS);
|
||
|
|
||
|
RRETURN(S_OK);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT
|
||
|
CNDSGenObject::GetColumn(
|
||
|
IN ADS_SEARCH_HANDLE hSearchHandle,
|
||
|
IN LPWSTR pszColumnName,
|
||
|
OUT PADS_SEARCH_COLUMN pColumn
|
||
|
)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
DWORD dwStatus;
|
||
|
DWORD dwSyntaxId = 0;
|
||
|
DWORD dwNumValues = 0;
|
||
|
LPNDS_ATTR_INFO pAttribute;
|
||
|
PNDS_SEARCH_RESULT pResult, pNextResult;
|
||
|
PADSNDS_OBJECT_INFO pObject, pNextObject;
|
||
|
DWORD cAttr;
|
||
|
BOOL fRowAdvanced = FALSE;
|
||
|
PNDS_SEARCHINFO phSearchInfo = (PNDS_SEARCHINFO) hSearchHandle;
|
||
|
|
||
|
LPWSTR pszNDSDn = NULL;
|
||
|
LPWSTR pszNDSTreeName = NULL;
|
||
|
LPWSTR szADsPath = NULL;
|
||
|
|
||
|
|
||
|
if( !pColumn ||
|
||
|
!phSearchInfo ||
|
||
|
!phSearchInfo->_pSearchResults )
|
||
|
RRETURN (E_ADS_BAD_PARAMETER);
|
||
|
|
||
|
pColumn->pszAttrName = NULL;
|
||
|
pColumn->dwADsType = ADSTYPE_INVALID;
|
||
|
pColumn->pADsValues = NULL;
|
||
|
pColumn->dwNumValues = 0;
|
||
|
pColumn->hReserved = NULL;
|
||
|
|
||
|
if (phSearchInfo->_dwCurrResult < 0)
|
||
|
RRETURN(S_ADS_NOMORE_ROWS);
|
||
|
|
||
|
pResult = &(phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]);
|
||
|
|
||
|
if( pResult->_dwObjectCurrent < 0 )
|
||
|
RRETURN (E_ADS_BAD_PARAMETER);
|
||
|
|
||
|
if ((pResult->_dwObjects == 0) || (!pResult->_pObjects))
|
||
|
RRETURN (S_ADS_NOMORE_COLUMNS);
|
||
|
|
||
|
pObject = pResult->_pObjects + pResult->_dwObjectCurrent;
|
||
|
|
||
|
pColumn->pszAttrName = AllocADsStr(pszColumnName);
|
||
|
if (!pColumn->pszAttrName)
|
||
|
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
|
||
|
|
||
|
if(!_wcsicmp (pszColumnName, L"ADsPath")) {
|
||
|
|
||
|
//
|
||
|
// Build the ADsPathName
|
||
|
//
|
||
|
|
||
|
hr = BuildNDSPathFromADsPath2(
|
||
|
_ADsPath,
|
||
|
&pszNDSTreeName,
|
||
|
&pszNDSDn
|
||
|
);
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
hr = BuildADsPathFromNDSPath(
|
||
|
pszNDSTreeName,
|
||
|
pObject->szObjectName,
|
||
|
&szADsPath
|
||
|
);
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
if(*szADsPath) {
|
||
|
pColumn->pADsValues = (PADSVALUE) AllocADsMem(sizeof(ADSVALUE));
|
||
|
if (!pColumn->pADsValues)
|
||
|
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
|
||
|
|
||
|
pColumn->dwADsType = ADSTYPE_CASE_IGNORE_STRING;
|
||
|
pColumn->dwNumValues = 1;
|
||
|
pColumn->pADsValues[0].dwType = ADSTYPE_CASE_IGNORE_STRING;
|
||
|
|
||
|
pColumn->pADsValues[0].CaseIgnoreString = AllocADsStr(szADsPath);
|
||
|
if (!pColumn->pADsValues[0].CaseIgnoreString)
|
||
|
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
|
||
|
|
||
|
pColumn->hReserved = pColumn->pADsValues[0].CaseIgnoreString;
|
||
|
}
|
||
|
|
||
|
if (szADsPath) {
|
||
|
FreeADsMem(szADsPath);
|
||
|
}
|
||
|
|
||
|
if (pszNDSDn) {
|
||
|
FreeADsMem(pszNDSDn);
|
||
|
}
|
||
|
|
||
|
if (pszNDSTreeName) {
|
||
|
FreeADsMem(pszNDSTreeName);
|
||
|
}
|
||
|
|
||
|
RRETURN(S_OK);
|
||
|
}
|
||
|
|
||
|
if (phSearchInfo->_SearchPref._fAttrsOnly) {
|
||
|
//
|
||
|
// Only Names got. So, don't return any values
|
||
|
//
|
||
|
RRETURN (S_OK);
|
||
|
}
|
||
|
|
||
|
pAttribute = (LPNDS_ATTR_INFO)pObject->lpAttribute;
|
||
|
|
||
|
for (cAttr=0;cAttr<pObject->dwNumAttributes;cAttr++,pAttribute++) {
|
||
|
if (_wcsicmp(
|
||
|
pAttribute->szAttributeName,
|
||
|
pszColumnName
|
||
|
) == 0)
|
||
|
break;
|
||
|
}
|
||
|
if (cAttr == pObject->dwNumAttributes) {
|
||
|
if(pResult->_dwObjectCurrent+1 != pResult->_dwObjects ||
|
||
|
(phSearchInfo->_lIterationHandle == NO_MORE_ITERATIONS &&
|
||
|
(phSearchInfo->_cResultPrefetched == 0))) {
|
||
|
//
|
||
|
// No need to look in the next result set;
|
||
|
//
|
||
|
BAIL_ON_FAILURE(hr = E_ADS_COLUMN_NOT_SET);
|
||
|
}
|
||
|
else {
|
||
|
//
|
||
|
// There is a chance that the column may come in the next
|
||
|
// result set. So, fetch the next set of results.
|
||
|
//
|
||
|
// Since this isn't actually the user causing the row to be advanced,
|
||
|
// we don't want to do any cache evictions
|
||
|
phSearchInfo->_fCheckForDuplicates = FALSE;
|
||
|
BOOL fCurrentCachingStatus = phSearchInfo->_SearchPref._fCacheResults;
|
||
|
phSearchInfo->_SearchPref._fCacheResults = TRUE;
|
||
|
hr = GetNextRow(
|
||
|
phSearchInfo
|
||
|
);
|
||
|
phSearchInfo->_fCheckForDuplicates = TRUE;
|
||
|
phSearchInfo->_SearchPref._fCacheResults = fCurrentCachingStatus;
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
if (hr == S_ADS_NOMORE_ROWS) {
|
||
|
BAIL_ON_FAILURE(hr = E_ADS_COLUMN_NOT_SET);
|
||
|
}
|
||
|
|
||
|
fRowAdvanced = TRUE;
|
||
|
|
||
|
pNextResult = &(phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]);
|
||
|
pNextObject = pNextResult->_pObjects + pNextResult->_dwObjectCurrent;
|
||
|
if (_wcsicmp(pObject->szObjectName, pNextObject->szObjectName)) {
|
||
|
//
|
||
|
// No need to look in the next object;
|
||
|
//
|
||
|
BAIL_ON_FAILURE(hr = E_ADS_COLUMN_NOT_SET);
|
||
|
}
|
||
|
else {
|
||
|
//
|
||
|
// Look in the next object
|
||
|
//
|
||
|
pAttribute = (LPNDS_ATTR_INFO)pNextObject->lpAttribute;
|
||
|
for (cAttr=0;cAttr<pNextObject->dwNumAttributes;cAttr++,pAttribute++) {
|
||
|
if (_wcsicmp(
|
||
|
pAttribute->szAttributeName,
|
||
|
pszColumnName
|
||
|
) == 0)
|
||
|
break;
|
||
|
}
|
||
|
if (cAttr == pNextObject->dwNumAttributes) {
|
||
|
//
|
||
|
// Didn't find in the next result set containing the row too
|
||
|
//
|
||
|
BAIL_ON_FAILURE(hr = E_ADS_COLUMN_NOT_SET);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
hr = NdsValueToADsColumn(
|
||
|
pszColumnName,
|
||
|
pAttribute->dwSyntaxId,
|
||
|
pAttribute->dwNumberOfValues,
|
||
|
(LPBYTE) pAttribute->lpValue,
|
||
|
pColumn
|
||
|
);
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
//
|
||
|
// Added in to support the case when one multivalue attribute is split into 2 packets. The
|
||
|
// following case checks
|
||
|
// 1) if we haven't advanced the row, if we have advanced already, the whole
|
||
|
// Attribute will already be completely residing in the second packet
|
||
|
// 2) the attribute was the last attribute from the last packet, thus
|
||
|
// the next attribute, (the first attribute of the next row) might be
|
||
|
// the same.
|
||
|
//
|
||
|
if ((!fRowAdvanced) &&
|
||
|
(cAttr == (pObject->dwNumAttributes - 1))) {
|
||
|
|
||
|
//
|
||
|
// If there is indeed a need to try out an extra packet
|
||
|
//
|
||
|
if(pResult->_dwObjectCurrent+1 != pResult->_dwObjects ||
|
||
|
(phSearchInfo->_lIterationHandle == NDS_NO_MORE_ITERATIONS &&
|
||
|
(phSearchInfo->_cResultPrefetched == 0))) {
|
||
|
//
|
||
|
// No need to look in the next result set;
|
||
|
//
|
||
|
hr = S_OK;
|
||
|
goto done;
|
||
|
}
|
||
|
else {
|
||
|
//
|
||
|
// There is a chance that the column may come in the next
|
||
|
// result set. So, fetch the next set of results.
|
||
|
//
|
||
|
// Since this isn't actually the user causing the row to be advanced,
|
||
|
// we don't want to do any cache evictions
|
||
|
phSearchInfo->_fCheckForDuplicates = FALSE;
|
||
|
BOOL fCurrentCachingStatus = phSearchInfo->_SearchPref._fCacheResults;
|
||
|
phSearchInfo->_SearchPref._fCacheResults = TRUE;
|
||
|
hr = GetNextRow(
|
||
|
phSearchInfo
|
||
|
);
|
||
|
phSearchInfo->_fCheckForDuplicates = TRUE;
|
||
|
phSearchInfo->_SearchPref._fCacheResults = fCurrentCachingStatus;
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
if (hr == S_ADS_NOMORE_ROWS) {
|
||
|
hr = S_OK;
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
fRowAdvanced = TRUE;
|
||
|
|
||
|
pNextResult = &(phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]);
|
||
|
pNextObject = pNextResult->_pObjects + pNextResult->_dwObjectCurrent;
|
||
|
if (_wcsicmp(pObject->szObjectName, pNextObject->szObjectName)) {
|
||
|
//
|
||
|
// No need to look in the next object, since objname is different
|
||
|
//
|
||
|
hr = S_OK;
|
||
|
goto done;
|
||
|
}
|
||
|
else {
|
||
|
//
|
||
|
// Look in the next object, look for the same attribute
|
||
|
//
|
||
|
pAttribute = (LPNDS_ATTR_INFO)pNextObject->lpAttribute;
|
||
|
for (cAttr=0;cAttr<pNextObject->dwNumAttributes;cAttr++,pAttribute++) {
|
||
|
if (_wcsicmp(
|
||
|
pAttribute->szAttributeName,
|
||
|
pszColumnName
|
||
|
) == 0)
|
||
|
break;
|
||
|
}
|
||
|
if (cAttr == pNextObject->dwNumAttributes) {
|
||
|
//
|
||
|
// Didn't find in the next result set containing the row too
|
||
|
//
|
||
|
hr = S_OK;
|
||
|
goto done;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If found, we'll append it to the last column
|
||
|
//
|
||
|
hr = NdsValueToADsColumnAppend(
|
||
|
pAttribute->dwSyntaxId,
|
||
|
pAttribute->dwNumberOfValues,
|
||
|
(LPBYTE) pAttribute->lpValue,
|
||
|
pColumn
|
||
|
);
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
}
|
||
|
done:
|
||
|
|
||
|
if (fRowAdvanced) {
|
||
|
phSearchInfo->_fCheckForDuplicates = FALSE;
|
||
|
GetPreviousRow(phSearchInfo);
|
||
|
phSearchInfo->_fCheckForDuplicates = TRUE;
|
||
|
}
|
||
|
|
||
|
if (szADsPath) {
|
||
|
FreeADsMem(szADsPath);
|
||
|
}
|
||
|
|
||
|
if (pszNDSDn) {
|
||
|
FreeADsMem(pszNDSDn);
|
||
|
}
|
||
|
|
||
|
if (pszNDSTreeName) {
|
||
|
FreeADsMem(pszNDSTreeName);
|
||
|
}
|
||
|
|
||
|
RRETURN(S_OK);
|
||
|
|
||
|
error:
|
||
|
|
||
|
if (fRowAdvanced) {
|
||
|
phSearchInfo->_fCheckForDuplicates = FALSE;
|
||
|
GetPreviousRow(phSearchInfo);
|
||
|
phSearchInfo->_fCheckForDuplicates = TRUE;
|
||
|
}
|
||
|
|
||
|
if (szADsPath) {
|
||
|
FreeADsMem(szADsPath);
|
||
|
}
|
||
|
|
||
|
if (pszNDSDn) {
|
||
|
FreeADsMem(pszNDSDn);
|
||
|
}
|
||
|
|
||
|
if (pszNDSTreeName) {
|
||
|
FreeADsMem(pszNDSTreeName);
|
||
|
}
|
||
|
|
||
|
FreeColumn(pColumn);
|
||
|
|
||
|
RRETURN (hr);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
HRESULT
|
||
|
CNDSGenObject::GetNextColumnName(
|
||
|
IN ADS_SEARCH_HANDLE hSearchHandle,
|
||
|
OUT LPWSTR * ppszColumnName
|
||
|
)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
LPNDS_ATTR_INFO pAttribute;
|
||
|
LPNDS_ATTR_INFO pAttributeOld = NULL;
|
||
|
LPNDS_NAME_ONLY pNameOnlyAttr;
|
||
|
PNDS_SEARCH_RESULT pResult, pNextResult;
|
||
|
PADSNDS_OBJECT_INFO pObject, pNextObject;
|
||
|
BOOL fRowAdvanced = FALSE;
|
||
|
PNDS_SEARCHINFO phSearchInfo = (PNDS_SEARCHINFO) hSearchHandle;
|
||
|
|
||
|
if( !phSearchInfo ||
|
||
|
!phSearchInfo->_pSearchResults ||
|
||
|
!ppszColumnName)
|
||
|
RRETURN (E_ADS_BAD_PARAMETER);
|
||
|
|
||
|
*ppszColumnName = NULL;
|
||
|
|
||
|
if (phSearchInfo->_dwCurrResult < 0)
|
||
|
RRETURN(S_ADS_NOMORE_ROWS);
|
||
|
|
||
|
pResult = &(phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]);
|
||
|
|
||
|
if( pResult->_dwObjectCurrent < 0 )
|
||
|
RRETURN (E_ADS_BAD_PARAMETER);
|
||
|
|
||
|
if ((pResult->_dwObjects == 0) || (!pResult->_pObjects))
|
||
|
RRETURN (S_ADS_NOMORE_COLUMNS);
|
||
|
|
||
|
pObject = pResult->_pObjects + pResult->_dwObjectCurrent;
|
||
|
|
||
|
pNameOnlyAttr = (LPNDS_NAME_ONLY)pObject->lpAttribute +
|
||
|
phSearchInfo->_dwCurrAttr;
|
||
|
pAttribute = (LPNDS_ATTR_INFO)pObject->lpAttribute +
|
||
|
phSearchInfo->_dwCurrAttr;
|
||
|
|
||
|
//
|
||
|
// Get the last attribute's name to test it to avoid getting duplicate
|
||
|
// column names. This will happen if a multi-value got divided into two
|
||
|
// packets. In that case, both attribute names would be the same.
|
||
|
// We are only getting the last attribute if this object has greater than
|
||
|
// 1 object, or else if this attribute is the first attribute, there would
|
||
|
// not be a one before
|
||
|
//
|
||
|
if (phSearchInfo->_dwCurrAttr > 0) {
|
||
|
pAttributeOld = pAttribute - 1;
|
||
|
}
|
||
|
|
||
|
if (phSearchInfo->_dwCurrAttr >= pObject->dwNumAttributes) {
|
||
|
if(pResult->_dwObjectCurrent+1 != pResult->_dwObjects ||
|
||
|
(phSearchInfo->_lIterationHandle == NO_MORE_ITERATIONS &&
|
||
|
(phSearchInfo->_cResultPrefetched == 0))) {
|
||
|
//
|
||
|
// No need to look in the next result set;
|
||
|
//
|
||
|
hr = S_ADS_NOMORE_COLUMNS;
|
||
|
goto error;
|
||
|
}
|
||
|
else {
|
||
|
//
|
||
|
// There is a chance that the column may come in the next
|
||
|
// result set. So, fetch the next set of results.
|
||
|
//
|
||
|
// Since this isn't actually the user causing the row to be advanced,
|
||
|
// we don't want to do any cache evictions
|
||
|
phSearchInfo->_fCheckForDuplicates = FALSE;
|
||
|
BOOL fCurrentCachingStatus = phSearchInfo->_SearchPref._fCacheResults;
|
||
|
phSearchInfo->_SearchPref._fCacheResults = TRUE;
|
||
|
hr = GetNextRow(
|
||
|
phSearchInfo
|
||
|
);
|
||
|
phSearchInfo->_fCheckForDuplicates = TRUE;
|
||
|
phSearchInfo->_SearchPref._fCacheResults = fCurrentCachingStatus;
|
||
|
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
if (hr == S_ADS_NOMORE_ROWS) {
|
||
|
hr = S_ADS_NOMORE_COLUMNS;
|
||
|
goto error;
|
||
|
}
|
||
|
|
||
|
fRowAdvanced = TRUE;
|
||
|
|
||
|
pNextResult = &(phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]);
|
||
|
pNextObject = pNextResult->_pObjects + pNextResult->_dwObjectCurrent;
|
||
|
if (_wcsicmp(pObject->szObjectName, pNextObject->szObjectName)) {
|
||
|
//
|
||
|
// No need to look in the next object;
|
||
|
//
|
||
|
hr = S_ADS_NOMORE_COLUMNS;
|
||
|
goto error;
|
||
|
}
|
||
|
else {
|
||
|
//
|
||
|
// Look in the next object
|
||
|
//
|
||
|
pNameOnlyAttr = (LPNDS_NAME_ONLY)pNextObject->lpAttribute +
|
||
|
phSearchInfo->_dwCurrAttr -
|
||
|
pObject->dwNumAttributes;
|
||
|
pAttribute = (LPNDS_ATTR_INFO)pNextObject->lpAttribute +
|
||
|
phSearchInfo->_dwCurrAttr -
|
||
|
pObject->dwNumAttributes;
|
||
|
//
|
||
|
// If the new attribute is after the first attribute in the new object,
|
||
|
// we'll reset AttributeOld to point to the attribute before this.
|
||
|
// Because the old attribute will be the one before the current one
|
||
|
// in this case.
|
||
|
//
|
||
|
if ((phSearchInfo->_dwCurrAttr - pObject->dwNumAttributes) > 0) {
|
||
|
pAttributeOld = pAttribute - 1;
|
||
|
}
|
||
|
|
||
|
if (phSearchInfo->_dwCurrAttr >= (pObject->dwNumAttributes +
|
||
|
pNextObject->dwNumAttributes)) {
|
||
|
//
|
||
|
// Didn't find in the next result set
|
||
|
// containing the row too
|
||
|
//
|
||
|
hr = S_ADS_NOMORE_COLUMNS;
|
||
|
goto error;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If it is a duplicate column, go on to the next one
|
||
|
//
|
||
|
if (pAttributeOld) {
|
||
|
if(wcscmp(pAttribute->szAttributeName,
|
||
|
pAttributeOld->szAttributeName) == 0) {
|
||
|
phSearchInfo->_dwCurrAttr++;
|
||
|
if (phSearchInfo->_dwCurrAttr >= (pObject->dwNumAttributes +
|
||
|
pNextObject->dwNumAttributes)) {
|
||
|
//
|
||
|
// Didn't find in the next result set
|
||
|
// containing the row too
|
||
|
//
|
||
|
hr = S_ADS_NOMORE_COLUMNS;
|
||
|
goto error;
|
||
|
}
|
||
|
pNameOnlyAttr = (LPNDS_NAME_ONLY)pNextObject->lpAttribute +
|
||
|
phSearchInfo->_dwCurrAttr -
|
||
|
pObject->dwNumAttributes;
|
||
|
pAttribute = (LPNDS_ATTR_INFO)pNextObject->lpAttribute +
|
||
|
phSearchInfo->_dwCurrAttr -
|
||
|
pObject->dwNumAttributes;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (phSearchInfo->_SearchPref._fAttrsOnly)
|
||
|
*ppszColumnName = AllocADsStr(
|
||
|
pNameOnlyAttr->szName
|
||
|
);
|
||
|
else
|
||
|
*ppszColumnName = AllocADsStr(
|
||
|
pAttribute->szAttributeName
|
||
|
);
|
||
|
|
||
|
phSearchInfo->_dwCurrAttr++;
|
||
|
|
||
|
if (fRowAdvanced) {
|
||
|
phSearchInfo->_fCheckForDuplicates = FALSE;
|
||
|
GetPreviousRow(phSearchInfo);
|
||
|
phSearchInfo->_fCheckForDuplicates = TRUE;
|
||
|
}
|
||
|
|
||
|
RRETURN(S_OK);
|
||
|
|
||
|
error:
|
||
|
|
||
|
if (fRowAdvanced) {
|
||
|
phSearchInfo->_fCheckForDuplicates = FALSE;
|
||
|
GetPreviousRow(phSearchInfo);
|
||
|
phSearchInfo->_fCheckForDuplicates = TRUE;
|
||
|
}
|
||
|
|
||
|
if (*ppszColumnName)
|
||
|
FreeADsStr(*ppszColumnName);
|
||
|
|
||
|
|
||
|
if (hr == S_ADS_NOMORE_COLUMNS && phSearchInfo->_fADsPathPresent) {
|
||
|
|
||
|
//
|
||
|
// If ADsPath was specified, return it as the last column in the row
|
||
|
//
|
||
|
|
||
|
if (!phSearchInfo->_fADsPathReturned) {
|
||
|
|
||
|
*ppszColumnName = AllocADsStr(L"ADsPath");
|
||
|
phSearchInfo->_fADsPathReturned = TRUE;
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
else {
|
||
|
|
||
|
//
|
||
|
// We need to reset it back so that we return it for the next
|
||
|
// row
|
||
|
//
|
||
|
|
||
|
phSearchInfo->_fADsPathReturned = FALSE;
|
||
|
hr = S_ADS_NOMORE_COLUMNS;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
RRETURN (hr);
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT
|
||
|
CNDSGenObject::FreeColumn(
|
||
|
IN PADS_SEARCH_COLUMN pColumn
|
||
|
)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
if(!pColumn)
|
||
|
RRETURN (E_ADS_BAD_PARAMETER);
|
||
|
|
||
|
if (pColumn->pszAttrName)
|
||
|
FreeADsStr(pColumn->pszAttrName);
|
||
|
|
||
|
if (pColumn->pADsValues) {
|
||
|
AdsFreeAdsValues(pColumn->pADsValues, pColumn->dwNumValues);
|
||
|
FreeADsMem(pColumn->pADsValues);
|
||
|
}
|
||
|
|
||
|
RRETURN(hr);
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT
|
||
|
NdsValueToADsColumn(
|
||
|
LPWSTR pszColumnName,
|
||
|
DWORD dwSyntaxId,
|
||
|
DWORD dwValues,
|
||
|
LPBYTE lpObject,
|
||
|
ADS_SEARCH_COLUMN * pColumn
|
||
|
)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
LPNDS_ASN1_TYPE_1 lpNDS_ASN1_1;
|
||
|
LPNDS_ASN1_TYPE_7 lpNDS_ASN1_7;
|
||
|
LPNDS_ASN1_TYPE_8 lpNDS_ASN1_8;
|
||
|
LPNDS_ASN1_TYPE_9 lpNDS_ASN1_9;
|
||
|
LPNDS_ASN1_TYPE_11 lpNDS_ASN1_11;
|
||
|
LPNDS_ASN1_TYPE_14 lpNDS_ASN1_14;
|
||
|
LPNDS_ASN1_TYPE_18 lpNDS_ASN1_18;
|
||
|
LPNDS_ASN1_TYPE_20 lpNDS_ASN1_20;
|
||
|
LPNDS_ASN1_TYPE_24 lpNDS_ASN1_24;
|
||
|
DWORD i, j, dwValuesAllocated = 0;
|
||
|
LPBYTE lpValue = NULL;
|
||
|
PNDSOBJECT lpNdsObject = NULL;
|
||
|
|
||
|
if(!pszColumnName || !pColumn || !lpObject)
|
||
|
RRETURN(E_ADS_BAD_PARAMETER);
|
||
|
|
||
|
lpNdsObject = (PNDSOBJECT) lpObject;
|
||
|
|
||
|
pColumn->hReserved = NULL;
|
||
|
pColumn->dwNumValues = dwValues;
|
||
|
pColumn->pADsValues = (PADSVALUE) AllocADsMem(
|
||
|
sizeof(ADSVALUE) * dwValues
|
||
|
);
|
||
|
if (!pColumn->pADsValues)
|
||
|
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
|
||
|
|
||
|
|
||
|
if (dwSyntaxId >= g_cMapNdsTypeToADsType)
|
||
|
pColumn->dwADsType = ADSTYPE_INVALID;
|
||
|
else
|
||
|
pColumn->dwADsType = g_MapNdsTypeToADsType[dwSyntaxId];
|
||
|
|
||
|
switch (dwSyntaxId) {
|
||
|
// WIDE STRING
|
||
|
case NDS_SYNTAX_ID_1:
|
||
|
case NDS_SYNTAX_ID_2:
|
||
|
case NDS_SYNTAX_ID_3:
|
||
|
case NDS_SYNTAX_ID_4:
|
||
|
case NDS_SYNTAX_ID_5:
|
||
|
case NDS_SYNTAX_ID_10:
|
||
|
for (i=0; i < dwValues; i++) {
|
||
|
lpNDS_ASN1_1 = (LPNDS_ASN1_TYPE_1) &((lpNdsObject + i)->NdsValue);
|
||
|
pColumn->pADsValues[i].dwType = pColumn->dwADsType;
|
||
|
pColumn->pADsValues[i].CaseIgnoreString = AllocADsStr(lpNDS_ASN1_1->DNString);
|
||
|
|
||
|
if (!(pColumn->pADsValues[i].CaseIgnoreString))
|
||
|
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
|
||
|
|
||
|
dwValuesAllocated++;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case NDS_SYNTAX_ID_20:
|
||
|
for (i=0; i < dwValues; i++) {
|
||
|
lpNDS_ASN1_20 = (LPNDS_ASN1_TYPE_20) &((lpNdsObject + i)->NdsValue);
|
||
|
pColumn->pADsValues[i].dwType = pColumn->dwADsType;
|
||
|
pColumn->pADsValues[i].ClassName = AllocADsStr(lpNDS_ASN1_20->ClassName);
|
||
|
|
||
|
if (!(pColumn->pADsValues[i].ClassName))
|
||
|
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
|
||
|
|
||
|
dwValuesAllocated++;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
// EMAIL
|
||
|
case NDS_SYNTAX_ID_14 :
|
||
|
for (i=0; i < dwValues; i++) {
|
||
|
lpNDS_ASN1_14 = (LPNDS_ASN1_TYPE_14) &((lpNdsObject + i)->NdsValue);
|
||
|
pColumn->pADsValues[i].dwType = pColumn->dwADsType;
|
||
|
pColumn->pADsValues[i].Email.Address = AllocADsStr(lpNDS_ASN1_14->Address);
|
||
|
pColumn->pADsValues[i].Email.Type = lpNDS_ASN1_14->Type;
|
||
|
|
||
|
if (!(pColumn->pADsValues[i].Email.Address))
|
||
|
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
|
||
|
|
||
|
dwValuesAllocated++;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
// BYTE STREAM
|
||
|
case NDS_SYNTAX_ID_9:
|
||
|
for (i=0; i < dwValues; i++) {
|
||
|
lpNDS_ASN1_9 = (LPNDS_ASN1_TYPE_9) &((lpNdsObject + i)->NdsValue);
|
||
|
pColumn->pADsValues[i].dwType = pColumn->dwADsType;
|
||
|
|
||
|
if (lpNDS_ASN1_9->Length)
|
||
|
{
|
||
|
LPBYTE lpByte = (LPBYTE)AllocADsMem(lpNDS_ASN1_9->Length);
|
||
|
if (!lpByte)
|
||
|
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
|
||
|
|
||
|
if (lpNDS_ASN1_9->OctetString)
|
||
|
memcpy(lpByte, lpNDS_ASN1_9->OctetString, lpNDS_ASN1_9->Length);
|
||
|
|
||
|
pColumn->pADsValues[i].OctetString.dwLength =lpNDS_ASN1_9->Length;
|
||
|
pColumn->pADsValues[i].OctetString.lpValue = lpByte;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pColumn->pADsValues[i].OctetString.dwLength = 0;
|
||
|
pColumn->pADsValues[i].OctetString.lpValue = NULL;
|
||
|
}
|
||
|
|
||
|
dwValuesAllocated++;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
// BOOLEAN
|
||
|
case NDS_SYNTAX_ID_7:
|
||
|
for (i=0; i < dwValues; i++) {
|
||
|
lpNDS_ASN1_7 = (LPNDS_ASN1_TYPE_7) &((lpNdsObject + i)->NdsValue);
|
||
|
pColumn->pADsValues[i].dwType = pColumn->dwADsType;
|
||
|
pColumn->pADsValues[i].Boolean = lpNDS_ASN1_7->Boolean;
|
||
|
}
|
||
|
|
||
|
dwValuesAllocated = dwValues; // no intermediate failures possible
|
||
|
break;
|
||
|
|
||
|
// INTEGER
|
||
|
case NDS_SYNTAX_ID_8:
|
||
|
case NDS_SYNTAX_ID_22:
|
||
|
case NDS_SYNTAX_ID_27:
|
||
|
for (i=0; i < dwValues; i++) {
|
||
|
lpNDS_ASN1_8 = (LPNDS_ASN1_TYPE_8) &((lpNdsObject + i)->NdsValue);
|
||
|
pColumn->pADsValues[i].dwType = pColumn->dwADsType;
|
||
|
pColumn->pADsValues[i].Integer = lpNDS_ASN1_8->Integer;
|
||
|
}
|
||
|
|
||
|
dwValuesAllocated = dwValues; // no intermediate failures possible
|
||
|
break;
|
||
|
|
||
|
// TIME
|
||
|
case NDS_SYNTAX_ID_24 :
|
||
|
for (i=0; i < dwValues; i++) {
|
||
|
lpNDS_ASN1_24 = (LPNDS_ASN1_TYPE_24) &((lpNdsObject + i)->NdsValue);
|
||
|
pColumn->pADsValues[i].dwType = pColumn->dwADsType;
|
||
|
hr = ConvertDWORDtoSYSTEMTIME(
|
||
|
lpNDS_ASN1_24->Time,
|
||
|
&(pColumn->pADsValues[i].UTCTime)
|
||
|
);
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
dwValuesAllocated++;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
// FAX NUMBER
|
||
|
case NDS_SYNTAX_ID_11 :
|
||
|
for (i=0; i < dwValues; i++) {
|
||
|
lpNDS_ASN1_11 = (LPNDS_ASN1_TYPE_11) &((lpNdsObject + i)->NdsValue);
|
||
|
|
||
|
pColumn->pADsValues[i].dwType = pColumn->dwADsType;
|
||
|
|
||
|
pColumn->pADsValues[i].pFaxNumber = (PADS_FAXNUMBER)AllocADsMem(sizeof(ADS_FAXNUMBER));
|
||
|
if (!pColumn->pADsValues[i].pFaxNumber) {
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
}
|
||
|
|
||
|
pColumn->pADsValues[i].pFaxNumber->TelephoneNumber =
|
||
|
AllocADsStr(lpNDS_ASN1_11->TelephoneNumber);
|
||
|
|
||
|
if (!pColumn->pADsValues[i].pFaxNumber->TelephoneNumber) {
|
||
|
FreeADsMem(pColumn->pADsValues[i].pFaxNumber);
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
}
|
||
|
|
||
|
hr = CopyOctetString(lpNDS_ASN1_11->NumberOfBits,
|
||
|
lpNDS_ASN1_11->Parameters,
|
||
|
&pColumn->pADsValues[i].pFaxNumber->NumberOfBits,
|
||
|
&pColumn->pADsValues[i].pFaxNumber->Parameters);
|
||
|
if (FAILED(hr)) {
|
||
|
FreeADsStr(pColumn->pADsValues[i].pFaxNumber->TelephoneNumber);
|
||
|
FreeADsMem(pColumn->pADsValues[i].pFaxNumber);
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
}
|
||
|
|
||
|
dwValuesAllocated++;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
// POSTAL ADDRESS
|
||
|
case NDS_SYNTAX_ID_18 :
|
||
|
for (i=0; i<dwValues; i++) {
|
||
|
lpNDS_ASN1_18 = (LPNDS_ASN1_TYPE_18) &((lpNdsObject + i)->NdsValue);
|
||
|
pColumn->pADsValues[i].dwType = pColumn->dwADsType;
|
||
|
|
||
|
pColumn->pADsValues[i].pPostalAddress = (PADS_POSTALADDRESS)AllocADsMem(sizeof(ADS_POSTALADDRESS));
|
||
|
if (!pColumn->pADsValues[i].pPostalAddress) {
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
}
|
||
|
|
||
|
for (j=0;j<6;j++) {
|
||
|
if (lpNDS_ASN1_18->PostalAddress[j]) {
|
||
|
pColumn->pADsValues[i].pPostalAddress->PostalAddress[j] =
|
||
|
AllocADsStr(
|
||
|
lpNDS_ASN1_18->PostalAddress[j]
|
||
|
);
|
||
|
}
|
||
|
else {
|
||
|
pColumn->pADsValues[i].pPostalAddress->PostalAddress[j] =
|
||
|
AllocADsStr(
|
||
|
L""
|
||
|
);
|
||
|
}
|
||
|
if (!pColumn->pADsValues[i].pPostalAddress->PostalAddress[j]) {
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
while (j>0) {
|
||
|
FreeADsStr(pColumn->pADsValues[i].pPostalAddress->PostalAddress[j-1]);
|
||
|
j--;
|
||
|
}
|
||
|
FreeADsMem(pColumn->pADsValues[i].pPostalAddress);
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
dwValuesAllocated++;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case NDS_SYNTAX_ID_6 :
|
||
|
case NDS_SYNTAX_ID_12 :
|
||
|
case NDS_SYNTAX_ID_13 :
|
||
|
case NDS_SYNTAX_ID_15 :
|
||
|
case NDS_SYNTAX_ID_16 :
|
||
|
case NDS_SYNTAX_ID_17 :
|
||
|
case NDS_SYNTAX_ID_19 :
|
||
|
case NDS_SYNTAX_ID_21 :
|
||
|
case NDS_SYNTAX_ID_23 :
|
||
|
case NDS_SYNTAX_ID_25 :
|
||
|
case NDS_SYNTAX_ID_26 :
|
||
|
default:
|
||
|
for (i=0; i < dwValues; i++) {
|
||
|
pColumn->pADsValues[i].dwType = pColumn->dwADsType;
|
||
|
pColumn->pADsValues[i].ProviderSpecific.dwLength =0;
|
||
|
pColumn->pADsValues[i].ProviderSpecific.lpValue = NULL;
|
||
|
}
|
||
|
|
||
|
dwValuesAllocated = dwValues; // no intermediate failures possible
|
||
|
break;
|
||
|
}
|
||
|
RRETURN(hr);
|
||
|
|
||
|
error:
|
||
|
|
||
|
if (pColumn->pADsValues) {
|
||
|
AdsFreeAdsValues(pColumn->pADsValues, dwValuesAllocated);
|
||
|
|
||
|
FreeADsMem(pColumn->pADsValues);
|
||
|
pColumn->pADsValues = NULL;
|
||
|
pColumn->dwNumValues = 0;
|
||
|
}
|
||
|
|
||
|
RRETURN(hr);
|
||
|
}
|
||
|
|
||
|
HRESULT
|
||
|
NdsValueToADsColumnAppend(
|
||
|
DWORD dwSyntaxId,
|
||
|
DWORD dwValues,
|
||
|
LPBYTE lpObject,
|
||
|
ADS_SEARCH_COLUMN * pColumn
|
||
|
)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
LPNDS_ASN1_TYPE_1 lpNDS_ASN1_1;
|
||
|
LPNDS_ASN1_TYPE_7 lpNDS_ASN1_7;
|
||
|
LPNDS_ASN1_TYPE_8 lpNDS_ASN1_8;
|
||
|
LPNDS_ASN1_TYPE_9 lpNDS_ASN1_9;
|
||
|
LPNDS_ASN1_TYPE_11 lpNDS_ASN1_11;
|
||
|
LPNDS_ASN1_TYPE_14 lpNDS_ASN1_14;
|
||
|
LPNDS_ASN1_TYPE_18 lpNDS_ASN1_18;
|
||
|
LPNDS_ASN1_TYPE_20 lpNDS_ASN1_20;
|
||
|
LPNDS_ASN1_TYPE_24 lpNDS_ASN1_24;
|
||
|
DWORD i, j, dwValuesAllocated;
|
||
|
PNDSOBJECT lpNdsObject = NULL;
|
||
|
PADSVALUE pADsValuesNew = NULL;
|
||
|
DWORD dwValuesBase;
|
||
|
|
||
|
if(!pColumn || !lpObject)
|
||
|
RRETURN(E_ADS_BAD_PARAMETER);
|
||
|
|
||
|
dwValuesBase = pColumn->dwNumValues;
|
||
|
dwValuesAllocated = pColumn->dwNumValues;
|
||
|
lpNdsObject = (PNDSOBJECT) lpObject;
|
||
|
|
||
|
//
|
||
|
// Allocate memory for new values + old values
|
||
|
//
|
||
|
pADsValuesNew = (PADSVALUE) AllocADsMem(
|
||
|
sizeof(ADSVALUE) * (pColumn->dwNumValues + dwValues)
|
||
|
);
|
||
|
if (!pADsValuesNew) {
|
||
|
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Copy old values into new array, and free the old one
|
||
|
//
|
||
|
memcpy(pADsValuesNew,
|
||
|
pColumn->pADsValues,
|
||
|
sizeof(ADSVALUE) * dwValuesBase);
|
||
|
FreeADsMem(pColumn->pADsValues);
|
||
|
pColumn->pADsValues = pADsValuesNew;
|
||
|
|
||
|
switch (dwSyntaxId) {
|
||
|
// WIDE STRING
|
||
|
case NDS_SYNTAX_ID_1:
|
||
|
case NDS_SYNTAX_ID_2:
|
||
|
case NDS_SYNTAX_ID_3:
|
||
|
case NDS_SYNTAX_ID_4:
|
||
|
case NDS_SYNTAX_ID_5:
|
||
|
case NDS_SYNTAX_ID_10:
|
||
|
for (i=0; i < dwValues; i++) {
|
||
|
lpNDS_ASN1_1 = (LPNDS_ASN1_TYPE_1) &((lpNdsObject + i)->NdsValue);
|
||
|
pColumn->pADsValues[dwValuesBase+i].dwType = pColumn->dwADsType;
|
||
|
pColumn->pADsValues[dwValuesBase+i].CaseIgnoreString = AllocADsStr(lpNDS_ASN1_1->DNString);
|
||
|
|
||
|
if (!(pColumn->pADsValues[dwValuesBase+i].CaseIgnoreString))
|
||
|
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
|
||
|
|
||
|
dwValuesAllocated++;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case NDS_SYNTAX_ID_20:
|
||
|
for (i=0; i < dwValues; i++) {
|
||
|
lpNDS_ASN1_20 = (LPNDS_ASN1_TYPE_20) &((lpNdsObject + i)->NdsValue);
|
||
|
pColumn->pADsValues[dwValuesBase+i].dwType = pColumn->dwADsType;
|
||
|
pColumn->pADsValues[dwValuesBase+i].ClassName = AllocADsStr(lpNDS_ASN1_20->ClassName);
|
||
|
|
||
|
if (!(pColumn->pADsValues[dwValuesBase+i].ClassName))
|
||
|
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
|
||
|
|
||
|
dwValuesAllocated++;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
// EMAIL
|
||
|
case NDS_SYNTAX_ID_14 :
|
||
|
for (i=0; i < dwValues; i++) {
|
||
|
lpNDS_ASN1_14 = (LPNDS_ASN1_TYPE_14) &((lpNdsObject + i)->NdsValue);
|
||
|
pColumn->pADsValues[dwValuesBase+i].dwType = pColumn->dwADsType;
|
||
|
pColumn->pADsValues[dwValuesBase+i].Email.Address = AllocADsStr(lpNDS_ASN1_14->Address);
|
||
|
pColumn->pADsValues[dwValuesBase+i].Email.Type = lpNDS_ASN1_14->Type;
|
||
|
|
||
|
if (!(pColumn->pADsValues[dwValuesBase+i].Email.Address))
|
||
|
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
|
||
|
|
||
|
dwValuesAllocated++;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
// BYTE STREAM
|
||
|
case NDS_SYNTAX_ID_9:
|
||
|
for (i=0; i < dwValues; i++) {
|
||
|
lpNDS_ASN1_9 = (LPNDS_ASN1_TYPE_9) &((lpNdsObject + i)->NdsValue);
|
||
|
pColumn->pADsValues[dwValuesBase+i].dwType = pColumn->dwADsType;
|
||
|
|
||
|
if (lpNDS_ASN1_9->Length)
|
||
|
{
|
||
|
LPBYTE lpByte = (LPBYTE)AllocADsMem(lpNDS_ASN1_9->Length);
|
||
|
if (!lpByte)
|
||
|
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
|
||
|
|
||
|
if (lpNDS_ASN1_9->OctetString)
|
||
|
memcpy(lpByte, lpNDS_ASN1_9->OctetString, lpNDS_ASN1_9->Length);
|
||
|
|
||
|
pColumn->pADsValues[dwValuesBase+i].OctetString.dwLength =lpNDS_ASN1_9->Length;
|
||
|
pColumn->pADsValues[dwValuesBase+i].OctetString.lpValue = lpByte;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pColumn->pADsValues[dwValuesBase+i].OctetString.dwLength = 0;
|
||
|
pColumn->pADsValues[dwValuesBase+i].OctetString.lpValue = NULL;
|
||
|
}
|
||
|
|
||
|
dwValuesAllocated++;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
// BOOLEAN
|
||
|
case NDS_SYNTAX_ID_7:
|
||
|
for (i=0; i < dwValues; i++) {
|
||
|
lpNDS_ASN1_7 = (LPNDS_ASN1_TYPE_7) &((lpNdsObject + i)->NdsValue);
|
||
|
pColumn->pADsValues[dwValuesBase+i].dwType = pColumn->dwADsType;
|
||
|
pColumn->pADsValues[dwValuesBase+i].Boolean = lpNDS_ASN1_7->Boolean;
|
||
|
}
|
||
|
|
||
|
dwValuesAllocated += dwValues; // no intermediate failures possible
|
||
|
break;
|
||
|
|
||
|
// INTEGER
|
||
|
case NDS_SYNTAX_ID_8:
|
||
|
case NDS_SYNTAX_ID_22:
|
||
|
case NDS_SYNTAX_ID_27:
|
||
|
for (i=0; i < dwValues; i++) {
|
||
|
lpNDS_ASN1_8 = (LPNDS_ASN1_TYPE_8) &((lpNdsObject + i)->NdsValue);
|
||
|
pColumn->pADsValues[dwValuesBase+i].dwType = pColumn->dwADsType;
|
||
|
pColumn->pADsValues[dwValuesBase+i].Integer = lpNDS_ASN1_8->Integer;
|
||
|
}
|
||
|
|
||
|
dwValuesAllocated += dwValues; // no intermediate failures possible
|
||
|
break;
|
||
|
|
||
|
// TIME
|
||
|
case NDS_SYNTAX_ID_24 :
|
||
|
for (i=0; i < dwValues; i++) {
|
||
|
lpNDS_ASN1_24 = (LPNDS_ASN1_TYPE_24) &((lpNdsObject + i)->NdsValue);
|
||
|
pColumn->pADsValues[i].dwType = pColumn->dwADsType;
|
||
|
hr = ConvertDWORDtoSYSTEMTIME(
|
||
|
lpNDS_ASN1_24->Time,
|
||
|
&(pColumn->pADsValues[dwValuesBase+i].UTCTime)
|
||
|
);
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
|
||
|
dwValuesAllocated++;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
// FAX NUMBER
|
||
|
case NDS_SYNTAX_ID_11 :
|
||
|
for (i=0; i < dwValues; i++) {
|
||
|
lpNDS_ASN1_11 = (LPNDS_ASN1_TYPE_11) &((lpNdsObject + i)->NdsValue);
|
||
|
|
||
|
pColumn->pADsValues[dwValuesBase+i].dwType = pColumn->dwADsType;
|
||
|
|
||
|
pColumn->pADsValues[dwValuesBase+i].pFaxNumber = (PADS_FAXNUMBER)AllocADsMem(sizeof(ADS_FAXNUMBER));
|
||
|
if (!pColumn->pADsValues[dwValuesBase+i].pFaxNumber) {
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
}
|
||
|
|
||
|
pColumn->pADsValues[dwValuesBase+i].pFaxNumber->TelephoneNumber =
|
||
|
AllocADsStr(lpNDS_ASN1_11->TelephoneNumber);
|
||
|
|
||
|
if (!pColumn->pADsValues[dwValuesBase+i].pFaxNumber->TelephoneNumber) {
|
||
|
FreeADsMem(pColumn->pADsValues[dwValuesBase+i].pFaxNumber);
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
}
|
||
|
|
||
|
hr = CopyOctetString(lpNDS_ASN1_11->NumberOfBits,
|
||
|
lpNDS_ASN1_11->Parameters,
|
||
|
&pColumn->pADsValues[dwValuesBase+i].pFaxNumber->NumberOfBits,
|
||
|
&pColumn->pADsValues[dwValuesBase+i].pFaxNumber->Parameters);
|
||
|
if (FAILED(hr)) {
|
||
|
FreeADsStr(pColumn->pADsValues[dwValuesBase+i].pFaxNumber->TelephoneNumber);
|
||
|
FreeADsMem(pColumn->pADsValues[dwValuesBase+i].pFaxNumber);
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
}
|
||
|
|
||
|
dwValuesAllocated++;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
// POSTAL ADDRESS
|
||
|
case NDS_SYNTAX_ID_18 :
|
||
|
for (i=0; i<dwValues; i++) {
|
||
|
lpNDS_ASN1_18 = (LPNDS_ASN1_TYPE_18) &((lpNdsObject + i)->NdsValue);
|
||
|
pColumn->pADsValues[dwValuesBase+i].dwType = pColumn->dwADsType;
|
||
|
|
||
|
pColumn->pADsValues[dwValuesBase+i].pPostalAddress = (PADS_POSTALADDRESS)AllocADsMem(sizeof(ADS_POSTALADDRESS));
|
||
|
if (!pColumn->pADsValues[dwValuesBase+i].pPostalAddress) {
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
}
|
||
|
|
||
|
for (j=0;j<6;j++) {
|
||
|
if (lpNDS_ASN1_18->PostalAddress[j]) {
|
||
|
pColumn->pADsValues[dwValuesBase+i].pPostalAddress->PostalAddress[j] =
|
||
|
AllocADsStr(
|
||
|
lpNDS_ASN1_18->PostalAddress[j]
|
||
|
);
|
||
|
}
|
||
|
else {
|
||
|
pColumn->pADsValues[dwValuesBase+i].pPostalAddress->PostalAddress[j] =
|
||
|
AllocADsStr(
|
||
|
L""
|
||
|
);
|
||
|
}
|
||
|
if (!pColumn->pADsValues[dwValuesBase+i].pPostalAddress->PostalAddress[j]) {
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
while (j>0) {
|
||
|
FreeADsStr(pColumn->pADsValues[dwValuesBase+i].pPostalAddress->PostalAddress[j-1]);
|
||
|
j--;
|
||
|
}
|
||
|
FreeADsMem(pColumn->pADsValues[dwValuesBase+i].pPostalAddress);
|
||
|
BAIL_ON_FAILURE(hr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
dwValuesAllocated++;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case NDS_SYNTAX_ID_6 :
|
||
|
case NDS_SYNTAX_ID_12 :
|
||
|
case NDS_SYNTAX_ID_13 :
|
||
|
case NDS_SYNTAX_ID_15 :
|
||
|
case NDS_SYNTAX_ID_16 :
|
||
|
case NDS_SYNTAX_ID_17 :
|
||
|
case NDS_SYNTAX_ID_19 :
|
||
|
case NDS_SYNTAX_ID_21 :
|
||
|
case NDS_SYNTAX_ID_23 :
|
||
|
case NDS_SYNTAX_ID_25 :
|
||
|
case NDS_SYNTAX_ID_26 :
|
||
|
default:
|
||
|
for (i=0; i < dwValues; i++) {
|
||
|
pColumn->pADsValues[dwValuesBase+i].dwType = pColumn->dwADsType;
|
||
|
pColumn->pADsValues[dwValuesBase+i].ProviderSpecific.dwLength =0;
|
||
|
pColumn->pADsValues[dwValuesBase+i].ProviderSpecific.lpValue = NULL;
|
||
|
}
|
||
|
|
||
|
dwValuesAllocated += dwValues;
|
||
|
break;
|
||
|
}
|
||
|
pColumn->dwNumValues = pColumn->dwNumValues + dwValues;
|
||
|
|
||
|
RRETURN(hr);
|
||
|
|
||
|
error:
|
||
|
|
||
|
if (pColumn->pADsValues) {
|
||
|
AdsFreeAdsValues(pColumn->pADsValues, dwValuesAllocated);
|
||
|
|
||
|
FreeADsMem(pColumn->pADsValues);
|
||
|
pColumn->pADsValues = NULL;
|
||
|
pColumn->dwNumValues = 0;
|
||
|
}
|
||
|
|
||
|
RRETURN(hr);
|
||
|
}
|
||
|
|
||
|
|