2158 lines
56 KiB
C++
2158 lines
56 KiB
C++
//----------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 2000.
|
|
//
|
|
// File: cadsxml.cxx
|
|
//
|
|
// Contents: Contains the implementation of ADsXML. This class implements
|
|
// XML persistence as an ADSI extension.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include "cadsxml.hxx"
|
|
|
|
long glnObjCnt = 0;
|
|
|
|
// not used
|
|
ULONG g_ulObjCount = 0;
|
|
|
|
LPWSTR g_SchemaAttrs[] = { OID,
|
|
LDAP_DISPLAY_NAME,
|
|
TYPE,
|
|
SUBCLASSOF,
|
|
DESCRIPTION,
|
|
MUST_CONTAIN,
|
|
SYSTEM_MUST_CONTAIN,
|
|
MAY_CONTAIN,
|
|
SYSTEM_MAY_CONTAIN
|
|
};
|
|
DWORD g_dwNumSchemaAttrs = sizeof(g_SchemaAttrs)/sizeof(LPWSTR);
|
|
|
|
SEARCHPREFINFO g_SearchPrefInfo[] =
|
|
{
|
|
{ADS_SEARCHPREF_ASYNCHRONOUS, VT_BOOL, L"Asynchronous"},
|
|
{ADS_SEARCHPREF_DEREF_ALIASES, VT_I4, L"Deref Aliases"},
|
|
{ADS_SEARCHPREF_SIZE_LIMIT, VT_I4,L"Size Limit"},
|
|
{ADS_SEARCHPREF_TIME_LIMIT, VT_I4, L"Server Time Limit"},
|
|
// {ADS_SEARCHPREF_ATTRIBTYPES_ONLY, VT_BOOL, L"Column Names only"},
|
|
{ADS_SEARCHPREF_TIMEOUT, VT_I4, L"Timeout"},
|
|
{ADS_SEARCHPREF_PAGESIZE, VT_I4, L"Page size"},
|
|
{ADS_SEARCHPREF_PAGED_TIME_LIMIT, VT_I4, L"Time limit"},
|
|
{ADS_SEARCHPREF_CHASE_REFERRALS, VT_I4, L"Chase referrals"},
|
|
{ADS_SEARCHPREF_SORT_ON, VT_BSTR, L"Sort On"},
|
|
{ADS_SEARCHPREF_CACHE_RESULTS, VT_BOOL, L"Cache Results"}
|
|
};
|
|
|
|
DWORD g_dwNumSearchPrefInfo = sizeof(g_SearchPrefInfo)/sizeof(SEARCHPREFINFO);
|
|
|
|
|
|
DEFINE_IADsExtension_Implementation(CADsXML)
|
|
DEFINE_DELEGATING_IDispatch_Implementation(CADsXML)
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: CADsXML
|
|
//
|
|
// Synopsis: Constructor. Initializes member variables.
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
// Modifies: Nothing
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
CADsXML::CADsXML(void)
|
|
{
|
|
_pUnkOuter = NULL;
|
|
_pADs = NULL;
|
|
_pDispMgr = NULL;
|
|
m_pCredentials = NULL;
|
|
m_hFile = INVALID_HANDLE_VALUE;
|
|
|
|
// make sure DLL isn't unloaded until all objects are destroyed
|
|
InterlockedIncrement(&glnObjCnt);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: ~CADsXML
|
|
//
|
|
// Synopsis: Destructor. Frees member variables.
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
// Modifies: Nothing
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
CADsXML::~CADsXML(void)
|
|
{
|
|
if(m_pCredentials != NULL)
|
|
delete m_pCredentials;
|
|
|
|
InterlockedDecrement(&glnObjCnt);
|
|
|
|
if(_pDispMgr != NULL)
|
|
delete _pDispMgr;
|
|
|
|
//
|
|
// no need to release _pUnkOuter since aggregatee cannot hold a reference
|
|
// on aggregator.
|
|
//
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: SaveXML
|
|
//
|
|
// Synopsis: Implements XML persistence.
|
|
//
|
|
// Arguments: See IADsXML reference
|
|
//
|
|
// Returns: S_OK on success, error otherwise.
|
|
//
|
|
// Modifies: Nothing
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
STDMETHODIMP CADsXML::SaveXML(
|
|
VARIANT vDest,
|
|
BSTR szFilter,
|
|
BSTR szAttrs,
|
|
long lScope,
|
|
BSTR xslRef,
|
|
long lFlag,
|
|
BSTR szOptions,
|
|
VARIANT *pDirSyncCookie
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPWSTR pszAttrs = NULL, pszOptions = NULL;
|
|
|
|
// Validate inpute args
|
|
hr = ValidateArgs(
|
|
vDest,
|
|
lScope,
|
|
lFlag,
|
|
pDirSyncCookie
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
// Open output stream for writing
|
|
hr = OpenOutputStream(vDest);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = WriteXMLHeader(xslRef);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
// remove white spaces from attributes and search options, if required
|
|
if(szAttrs != NULL) {
|
|
pszAttrs = RemoveWhiteSpace(szAttrs);
|
|
if(NULL == pszAttrs) {
|
|
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
|
|
}
|
|
}
|
|
if(szOptions != NULL) {
|
|
pszOptions = ReduceWhiteSpace(szOptions);
|
|
if(NULL == pszOptions) {
|
|
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
|
|
}
|
|
}
|
|
|
|
// persist schema first if required
|
|
if(lFlag & ADS_XML_SCHEMA) {
|
|
hr = OutputSchema();
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
if(lFlag & ADS_XML_DSML) {
|
|
hr = OutputData(
|
|
szFilter,
|
|
pszAttrs,
|
|
lScope,
|
|
pszOptions
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
hr = WriteXMLFooter();
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
CloseOutputStream();
|
|
|
|
if(pszAttrs != NULL)
|
|
FreeADsStr(pszAttrs);
|
|
|
|
if(pszOptions != NULL)
|
|
FreeADsMem(pszOptions);
|
|
|
|
RRETURN(S_OK);
|
|
|
|
error:
|
|
|
|
if(pszAttrs != NULL)
|
|
FreeADsStr(pszAttrs);
|
|
|
|
if(pszOptions != NULL)
|
|
FreeADsMem(pszOptions);
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: ValidateArgs
|
|
//
|
|
// Synopsis: Validates the arguments passed into SaveXML
|
|
//
|
|
// Arguments: See IADsXML reference
|
|
//
|
|
// Returns: S_OK on success, error otherwise.
|
|
//
|
|
// Modifies: Nothing
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CADsXML::ValidateArgs(
|
|
VARIANT vDest,
|
|
long lScope,
|
|
long lFlag,
|
|
VARIANT *pDirSyncCookie
|
|
)
|
|
{
|
|
ULONG ulDsmlVer = 0;
|
|
|
|
if( (V_VT(&vDest) != VT_BSTR) || (NULL == V_BSTR(&vDest)) )
|
|
RRETURN(E_INVALIDARG);
|
|
|
|
if( (lScope != ADS_SCOPE_BASE) && (lScope != ADS_SCOPE_ONELEVEL) &&
|
|
(lScope != ADS_SCOPE_SUBTREE) )
|
|
RRETURN(E_INVALIDARG);
|
|
|
|
//
|
|
// 4 MSBs of lFlag specify DSML version. Check to see if this is a
|
|
// supported value.
|
|
//
|
|
ulDsmlVer = ((ULONG) (lFlag & 0xf0000000)) >> 28;
|
|
if(ulDsmlVer > 1)
|
|
RRETURN(E_ADSXML_NOT_SUPPORTED);
|
|
|
|
// check if lFlag is valid
|
|
if( (lFlag & 0x0fffffff) & (~(ADS_XML_DSML | ADS_XML_SCHEMA)) )
|
|
RRETURN(E_INVALIDARG);
|
|
|
|
// not supported for now
|
|
// if(pDirSyncCookie != NULL)
|
|
// RRETURN(E_INVALIDARG);
|
|
|
|
RRETURN(S_OK);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: OpenOutputStream
|
|
//
|
|
// Synopsis: Opens the output stream for writing. Creates a file to store the
|
|
// XML output.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// vDest Specifies destination
|
|
//
|
|
// Returns: S_OK on success, error otherwise.
|
|
//
|
|
// Modifies: Nothing
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CADsXML::OpenOutputStream(
|
|
VARIANT vDest
|
|
)
|
|
{
|
|
LPWSTR pszFileName = NULL;
|
|
HRESULT hr = S_OK;
|
|
|
|
pszFileName = V_BSTR(&vDest);
|
|
|
|
m_hFile = CreateFile(
|
|
pszFileName,
|
|
GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL
|
|
);
|
|
|
|
if(INVALID_HANDLE_VALUE == m_hFile) {
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
RRETURN(S_OK);
|
|
|
|
error:
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: WriteXMLHeader
|
|
//
|
|
// Synopsis: Writes the standard XML header to the output. This includes
|
|
// the XML version, XSL ref (if specified) and the DSML namespace.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// xslRef XSL reference
|
|
//
|
|
// Returns: S_OK on success, error otherwise.
|
|
//
|
|
// Modifies: Nothing
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CADsXML::WriteXMLHeader(
|
|
BSTR xslRef
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
WCHAR szUnicodeMark[] = {0xfeff, 0};
|
|
|
|
BAIL_ON_FAILURE(hr = Write(szUnicodeMark));
|
|
|
|
BAIL_ON_FAILURE(hr = WriteLine(XML_HEADING));
|
|
|
|
if(xslRef != NULL) {
|
|
BAIL_ON_FAILURE(hr = Write(XML_STYLESHEET_REF));
|
|
BAIL_ON_FAILURE(hr = Write(xslRef, TRUE));
|
|
BAIL_ON_FAILURE(hr = WriteLine(XML_STYLESHEET_REF_END));
|
|
}
|
|
|
|
BAIL_ON_FAILURE(hr = WriteLine(DSML_NAMESPACE));
|
|
|
|
RRETURN(S_OK);
|
|
|
|
error:
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: WriteXMLFooter
|
|
//
|
|
// Synopsis: Closes the XML document with the appropriate tag.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns: S_OK on success, error otherwise.
|
|
//
|
|
// Modifies: Nothing
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CADsXML::WriteXMLFooter(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = WriteLine(XML_FOOTER);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
RRETURN(S_OK);
|
|
|
|
error:
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: OutputSchema
|
|
//
|
|
// Synopsis: Writes the schema to the output stream
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns: S_OK on success, error otherwise.
|
|
//
|
|
// Modifies: Nothing
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CADsXML::OutputSchema(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IADsObjectOptions *pObjOpt = NULL;
|
|
VARIANT vServer, vSchemaPath;
|
|
LPWSTR pszRootDSEPath = NULL, pszSchemaPath = NULL;
|
|
IADs *pIADs = NULL;
|
|
IDirectorySearch *pSearch = NULL;
|
|
ADS_SEARCHPREF_INFO searchPrefs[2];
|
|
ADS_SEARCH_HANDLE hSearch=NULL;
|
|
LPWSTR pszUserName = NULL, pszPasswd = NULL;
|
|
|
|
VariantInit(&vServer);
|
|
VariantInit(&vSchemaPath);
|
|
|
|
hr = _pUnkOuter->QueryInterface(
|
|
IID_IADsObjectOptions,
|
|
(void **) &pObjOpt
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = pObjOpt->GetOption(ADS_OPTION_SERVERNAME, &vServer);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
pszRootDSEPath = (LPWSTR) AllocADsMem((wcslen(V_BSTR(&vServer))
|
|
+ wcslen(L"LDAP://")
|
|
+ wcslen(L"/RootDSE") + 1) * 2);
|
|
wcscpy(pszRootDSEPath, L"LDAP://");
|
|
wcscat(pszRootDSEPath, V_BSTR(&vServer));
|
|
wcscat(pszRootDSEPath, L"/RootDSE");
|
|
|
|
hr = ADsOpenObject(
|
|
pszRootDSEPath,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
IID_IADs,
|
|
(void **) &pIADs
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = pIADs->Get(L"schemanamingcontext", &vSchemaPath);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
pszSchemaPath = (LPWSTR) AllocADsMem((wcslen(V_BSTR(&vSchemaPath)) +
|
|
wcslen(L"LDAP://") + wcslen(V_BSTR(&vServer)) +
|
|
2) * 2);
|
|
wcscpy(pszSchemaPath, L"LDAP://");
|
|
wcscat(pszSchemaPath, V_BSTR(&vServer));
|
|
wcscat(pszSchemaPath, L"/");
|
|
wcscat(pszSchemaPath, V_BSTR(&vSchemaPath));
|
|
|
|
hr = m_pCredentials->GetUserName(&pszUserName);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = m_pCredentials->GetPassword(&pszPasswd);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = ADsOpenObject(
|
|
pszSchemaPath,
|
|
pszUserName,
|
|
pszPasswd,
|
|
m_dwAuthFlags,
|
|
IID_IDirectorySearch,
|
|
(void **) &pSearch
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
// set the preferences for the search
|
|
searchPrefs[0].dwSearchPref = ADS_SEARCHPREF_PAGESIZE;
|
|
searchPrefs[0].vValue.dwType = ADSTYPE_INTEGER;
|
|
searchPrefs[0].vValue.Integer = SCHEMA_PAGE_SIZE;
|
|
|
|
searchPrefs[1].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
|
|
searchPrefs[1].vValue.dwType = ADSTYPE_INTEGER;
|
|
searchPrefs[1].vValue.Integer = ADS_SCOPE_ONELEVEL;
|
|
|
|
hr = pSearch->SetSearchPreference(searchPrefs, 2);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = pSearch->ExecuteSearch(
|
|
SCHEMA_FILTER,
|
|
g_SchemaAttrs,
|
|
g_dwNumSchemaAttrs,
|
|
&hSearch
|
|
);
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// if the search returned no results and the user requested schema to be
|
|
// returned, return an error.
|
|
//
|
|
hr = pSearch->GetFirstRow(hSearch);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
if(S_ADS_NOMORE_ROWS == hr) {
|
|
BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED));
|
|
}
|
|
|
|
hr = OutputSchemaHeader();
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
while(hr != S_ADS_NOMORE_ROWS) {
|
|
hr = OutputClassHeader(hSearch, pSearch);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = OutputClassAttrs(hSearch, pSearch);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = OutputClassFooter();
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = pSearch->GetNextRow(hSearch);
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
hr = OutputSchemaFooter();
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
error:
|
|
|
|
if(pszUserName != NULL)
|
|
FreeADsStr(pszUserName);
|
|
|
|
if(pszPasswd != NULL)
|
|
FreeADsStr(pszPasswd);
|
|
|
|
if(pObjOpt != NULL)
|
|
pObjOpt->Release();
|
|
|
|
VariantClear(&vServer);
|
|
VariantClear(&vSchemaPath);
|
|
|
|
if(pszRootDSEPath != NULL)
|
|
FreeADsMem(pszRootDSEPath);
|
|
|
|
if(pszSchemaPath != NULL)
|
|
FreeADsMem(pszSchemaPath);
|
|
|
|
if(pIADs != NULL)
|
|
pIADs->Release();
|
|
|
|
if(hSearch != NULL)
|
|
pSearch->CloseSearchHandle(hSearch);
|
|
|
|
if(pSearch != NULL)
|
|
pSearch->Release();
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: OutputSchemaHeader
|
|
//
|
|
// Synopsis: Writes the schema tag to the output stream
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns: S_OK on success, error otherwise.
|
|
//
|
|
// Modifies: Nothing
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CADsXML::OutputSchemaHeader(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = WriteLine(DSML_SCHEMA_TAG);
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: OutputClassHeader
|
|
//
|
|
// Synopsis: Writes class the and attributes to the output.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// hSearch Handle returned by IDirectorySearch
|
|
// pSearch IDirectorySearch interface
|
|
//
|
|
// Returns: S_OK on success, error otherwise.
|
|
//
|
|
// Modifies: Nothing
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CADsXML::OutputClassHeader(
|
|
ADS_SEARCH_HANDLE hSearch,
|
|
IDirectorySearch *pSearch
|
|
)
|
|
{
|
|
ADS_SEARCH_COLUMN column;
|
|
LPWSTR pszName = NULL;
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = Write(DSML_CLASS_TAG);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = Write(L"id =\"");
|
|
BAIL_ON_FAILURE(hr);
|
|
hr = pSearch->GetColumn(hSearch, LDAP_DISPLAY_NAME, &column);
|
|
BAIL_ON_FAILURE(hr);
|
|
hr = Write(column.pADsValues->CaseIgnoreString, TRUE);
|
|
pszName = AllocADsStr(column.pADsValues->CaseIgnoreString);
|
|
if(NULL == pszName) {
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
pSearch->FreeColumn(&column);
|
|
BAIL_ON_FAILURE(hr);
|
|
hr = Write(L"\" ");
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = Write(L"sup = \"");
|
|
BAIL_ON_FAILURE(hr);
|
|
hr = pSearch->GetColumn(hSearch, SUBCLASSOF, &column);
|
|
BAIL_ON_FAILURE(hr);
|
|
hr = Write(column.pADsValues->CaseIgnoreString, TRUE);
|
|
pSearch->FreeColumn(&column);
|
|
BAIL_ON_FAILURE(hr);
|
|
hr = Write(L"\" ");
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = Write(L"type = \"");
|
|
BAIL_ON_FAILURE(hr);
|
|
hr = pSearch->GetColumn(hSearch, TYPE, &column);
|
|
BAIL_ON_FAILURE(hr);
|
|
switch(column.pADsValues->Integer) {
|
|
case 1:
|
|
hr = Write(L"structural");
|
|
break;
|
|
case 2:
|
|
hr = Write(L"abstract");
|
|
break;
|
|
case 3:
|
|
hr = Write(L"auxiliary");
|
|
break;
|
|
}
|
|
pSearch->FreeColumn(&column);
|
|
BAIL_ON_FAILURE(hr);
|
|
hr = WriteLine(L"\">");
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = Write(NAME_TAG);
|
|
BAIL_ON_FAILURE(hr);
|
|
hr = Write(pszName, TRUE);
|
|
BAIL_ON_FAILURE(hr);
|
|
hr = WriteLine(NAME_TAG_CLOSE);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = Write(DESC_TAG);
|
|
BAIL_ON_FAILURE(hr);
|
|
hr = pSearch->GetColumn(hSearch, DESCRIPTION, & column);
|
|
BAIL_ON_FAILURE(hr);
|
|
hr = Write(column.pADsValues->CaseIgnoreString, TRUE);
|
|
pSearch->FreeColumn(&column);
|
|
BAIL_ON_FAILURE(hr);
|
|
hr = WriteLine(DESC_TAG_CLOSE);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = Write(OID_TAG);
|
|
BAIL_ON_FAILURE(hr);
|
|
hr = pSearch->GetColumn(hSearch, OID, &column);
|
|
BAIL_ON_FAILURE(hr);
|
|
hr = Write(column.pADsValues->CaseIgnoreString, TRUE);
|
|
pSearch->FreeColumn(&column);
|
|
BAIL_ON_FAILURE(hr);
|
|
hr = WriteLine(OID_TAG_CLOSE);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
error:
|
|
if(pszName)
|
|
FreeADsStr(pszName);
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: OutputClassAttrs
|
|
//
|
|
// Synopsis: Writes the names of the attributes of a class and whether
|
|
// they are mandatory or not.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// hSearch Handle returned by IDirectorySearch
|
|
// pSearch IDirectorySearch interface
|
|
//
|
|
// Returns: S_OK on success, error otherwise.
|
|
//
|
|
// Modifies: Nothing
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CADsXML::OutputClassAttrs(
|
|
ADS_SEARCH_HANDLE hSearch,
|
|
IDirectorySearch *pSearch
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = OutputAttrs(hSearch, pSearch, MUST_CONTAIN, TRUE);
|
|
if(E_ADS_COLUMN_NOT_SET == hr)
|
|
hr = S_OK;
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = OutputAttrs(hSearch, pSearch, SYSTEM_MUST_CONTAIN, TRUE);
|
|
if(E_ADS_COLUMN_NOT_SET == hr)
|
|
hr = S_OK;
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = OutputAttrs(hSearch, pSearch, MAY_CONTAIN, FALSE);
|
|
if(E_ADS_COLUMN_NOT_SET == hr)
|
|
hr = S_OK;
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = OutputAttrs(hSearch, pSearch, SYSTEM_MAY_CONTAIN, FALSE);
|
|
if(E_ADS_COLUMN_NOT_SET == hr)
|
|
hr = S_OK;
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
error:
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: OutputAttrs
|
|
//
|
|
// Synopsis: Writes the names of the attributes.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// hSearch Handle returned by IDirectorySearch
|
|
// pSearch IDirectorySearch interface
|
|
// pszAttrName Name of the attribute in the class schema object
|
|
// fMandatory Indicates if the attributes are mandatory or not
|
|
//
|
|
// Returns: S_OK on success, error otherwise.
|
|
//
|
|
// Modifies: Nothing
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CADsXML::OutputAttrs(
|
|
ADS_SEARCH_HANDLE hSearch,
|
|
IDirectorySearch *pSearch,
|
|
LPWSTR pszAttrName,
|
|
BOOL fMandatory
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ADS_SEARCH_COLUMN column;
|
|
DWORD i = 0;
|
|
BOOL fFreeCols = FALSE;
|
|
|
|
hr = pSearch->GetColumn(hSearch, pszAttrName, &column);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
fFreeCols = TRUE;
|
|
|
|
for(i = 0; i < column.dwNumValues; i++) {
|
|
hr = Write(DSML_ATTR_TAG);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = Write(column.pADsValues[i].CaseIgnoreString, TRUE);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = Write(L"\" required=\"");
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
if(fMandatory)
|
|
hr = Write(L"true");
|
|
else
|
|
hr = Write(L"false");
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = WriteLine(L"\"/>");
|
|
}
|
|
|
|
error:
|
|
|
|
if(fFreeCols)
|
|
pSearch->FreeColumn(&column);
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: OutputClassFooter
|
|
//
|
|
// Synopsis: Writes the end tag for the class
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns: S_OK on success, error otherwise.
|
|
//
|
|
// Modifies: Nothing
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CADsXML::OutputClassFooter(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = WriteLine(DSML_CLASS_TAG_CLOSE);
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: OutputSchemaFooter
|
|
//
|
|
// Synopsis: Writes the schema end tag to the output stream
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns: S_OK on success, error otherwise.
|
|
//
|
|
// Modifies: Nothing
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CADsXML::OutputSchemaFooter(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = WriteLine(DSML_SCHEMA_TAG_CLOSE);
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: CloseOutputStream
|
|
//
|
|
// Synopsis: Closes the output stream.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// vDest Specifies destination
|
|
//
|
|
// Returns: S_OK on success, error otherwise.
|
|
//
|
|
// Modifies: Nothing
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
void CADsXML::CloseOutputStream(void)
|
|
{
|
|
if(m_hFile != INVALID_HANDLE_VALUE)
|
|
CloseHandle(m_hFile);
|
|
|
|
return;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: Write
|
|
//
|
|
// Synopsis: Writes text to the output. Does not append newline.
|
|
//
|
|
//
|
|
// szStr String to write to the output.
|
|
// fEscape Indicates if string should be escaped ot not. FALSE by default.
|
|
//
|
|
// Returns: S_OK on success, error otherwise.
|
|
//
|
|
// Modifies: Nothing
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CADsXML::Write(LPWSTR szStr, BOOL fEscape)
|
|
{
|
|
BOOL bRetVal = 0;
|
|
DWORD dwNumBytesWritten = 0;
|
|
HRESULT hr = S_OK;
|
|
LPWSTR pszEscapedStr = NULL;
|
|
int i = 0, j = 0;
|
|
WCHAR wc;
|
|
|
|
ADsAssert(szStr != NULL);
|
|
|
|
if(TRUE == fEscape) {
|
|
pszEscapedStr = (LPWSTR) AllocADsMem(2*(wcslen(szStr)*6 + 1));
|
|
if(NULL == pszEscapedStr) {
|
|
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
|
|
}
|
|
}
|
|
else
|
|
pszEscapedStr = szStr;
|
|
|
|
for(i = 0; (TRUE == fEscape) && (szStr[i] != L'\0'); i++) {
|
|
switch(szStr[i]) {
|
|
case L'<':
|
|
pszEscapedStr[j++] = L'&';
|
|
pszEscapedStr[j++] = L'l';
|
|
pszEscapedStr[j++] = L't';
|
|
pszEscapedStr[j++] = L';';
|
|
break;
|
|
case L'>':
|
|
pszEscapedStr[j++] = L'&';
|
|
pszEscapedStr[j++] = L'g';
|
|
pszEscapedStr[j++] = L't';
|
|
pszEscapedStr[j++] = L';';
|
|
break;
|
|
case L'\'':
|
|
pszEscapedStr[j++] = L'&';
|
|
pszEscapedStr[j++] = L'a';
|
|
pszEscapedStr[j++] = L'p';
|
|
pszEscapedStr[j++] = L'o';
|
|
pszEscapedStr[j++] = L's';
|
|
pszEscapedStr[j++] = L';';
|
|
break;
|
|
case L'"':
|
|
pszEscapedStr[j++] = L'&';
|
|
pszEscapedStr[j++] = L'q';
|
|
pszEscapedStr[j++] = L'u';
|
|
pszEscapedStr[j++] = L'o';
|
|
pszEscapedStr[j++] = L't';
|
|
pszEscapedStr[j++] = L';';
|
|
break;
|
|
case L'&':
|
|
pszEscapedStr[j++] = L'&';
|
|
pszEscapedStr[j++] = L'a';
|
|
pszEscapedStr[j++] = L'm';
|
|
pszEscapedStr[j++] = L'p';
|
|
pszEscapedStr[j++] = L';';
|
|
break;
|
|
default:
|
|
pszEscapedStr[j++] = szStr[i];
|
|
break;
|
|
} // switch
|
|
} // for
|
|
|
|
// pszEscapedStr NULL terminated by AllocADsMem
|
|
|
|
|
|
bRetVal = WriteFile(
|
|
m_hFile,
|
|
pszEscapedStr,
|
|
wcslen(pszEscapedStr)*2,
|
|
&dwNumBytesWritten,
|
|
NULL
|
|
);
|
|
|
|
if(0 == bRetVal) {
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
if(dwNumBytesWritten != (wcslen(pszEscapedStr)*2)) {
|
|
hr = HRESULT_FROM_WIN32(ERROR_CANT_ACCESS_FILE);
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
error:
|
|
|
|
if(pszEscapedStr && (pszEscapedStr != szStr))
|
|
FreeADsMem(pszEscapedStr);
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: WriteLine
|
|
//
|
|
// Synopsis: Writes text to the output. Appends newline.
|
|
//
|
|
//
|
|
// szStr String to write to the output.
|
|
// fEscape Indicates if string should be escaped ot not. FALSE by default.
|
|
//
|
|
// Returns: S_OK on success, error otherwise.
|
|
//
|
|
// Modifies: Nothing
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CADsXML::WriteLine(LPWSTR szStr, BOOL fEscape)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
ADsAssert(szStr != NULL);
|
|
|
|
hr = Write(szStr, fEscape);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = Write(L"\n");
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
error:
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: QueryInterface
|
|
//
|
|
// Synopsis: Queries object for supported interfaces.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// iid interface requested
|
|
// ppInterface Returns pointer to interface requested. NULL if interface
|
|
// is not supported.
|
|
//
|
|
// Returns: S_OK on success. Error code otherwise.
|
|
//
|
|
// Modifies: *ppInterface to return interface pointer
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
STDMETHODIMP CADsXML::QueryInterface(
|
|
REFIID iid,
|
|
LPVOID *ppInterface
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = _pUnkOuter->QueryInterface(iid,ppInterface);
|
|
|
|
RRETURN(hr);
|
|
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: NonDelegatingQueryInterface
|
|
//
|
|
// Synopsis: Queries object for supported interfaces.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// iid interface requested
|
|
// ppInterface Returns pointer to interface requested. NULL if interface
|
|
// is not supported.
|
|
//
|
|
// Returns: S_OK on success. Error code otherwise.
|
|
//
|
|
// Modifies: *ppInterface to return interface pointer
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
STDMETHODIMP CADsXML::NonDelegatingQueryInterface(
|
|
REFIID iid,
|
|
LPVOID *ppInterface
|
|
)
|
|
{
|
|
ADsAssert(ppInterface);
|
|
|
|
if (IsEqualIID(iid, IID_IUnknown))
|
|
*ppInterface = (INonDelegatingUnknown FAR *) this;
|
|
else if (IsEqualIID(iid, IID_IADsExtension))
|
|
*ppInterface = (IADsExtension FAR *) this;
|
|
else if (IsEqualIID(iid, IID_IADsXML))
|
|
*ppInterface = (IADsXML FAR *) this;
|
|
else {
|
|
*ppInterface = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
((IUnknown *) (*ppInterface)) -> AddRef();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: Operate
|
|
//
|
|
// Synopsis: Implements IADsExtension::Operate.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// dwCode Extension control code
|
|
// varData1 Username
|
|
// varData2 Password
|
|
// varData3 User flags
|
|
//
|
|
// Returns: S_OK on success. Error code otherwise.
|
|
//
|
|
// Modifies: Nothing.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
STDMETHODIMP CADsXML::Operate(
|
|
THIS_ DWORD dwCode,
|
|
VARIANT varData1,
|
|
VARIANT varData2,
|
|
VARIANT varData3
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
switch (dwCode) {
|
|
|
|
case ADS_EXT_INITCREDENTIALS:
|
|
ADsAssert(V_VT(&varData1) == VT_BSTR);
|
|
ADsAssert(V_VT(&varData2) == VT_BSTR);
|
|
ADsAssert(V_VT(&varData3) == VT_I4);
|
|
|
|
m_pCredentials = new CCredentials(
|
|
V_BSTR(&varData1),
|
|
V_BSTR(&varData2),
|
|
V_I4(&varData3)
|
|
);
|
|
if(NULL == m_pCredentials)
|
|
RRETURN(E_OUTOFMEMORY);
|
|
|
|
m_dwAuthFlags = V_I4(&varData3);
|
|
|
|
break;
|
|
|
|
default:
|
|
RRETURN(E_FAIL);
|
|
}
|
|
|
|
RRETURN(S_OK);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: OutputData
|
|
//
|
|
// Synopsis: Outputs data portion of DSML.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// szFilter Search filter
|
|
// szAttrs Attributes requested
|
|
// lScope Search scope
|
|
// szOptions Search preferences
|
|
//
|
|
// Returns: S_OK on success. Error code otherwise.
|
|
//
|
|
// Modifies: Nothing.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT CADsXML::OutputData(
|
|
BSTR szFilter,
|
|
BSTR szAttrs,
|
|
long lScope,
|
|
BSTR szOptions
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IDirectorySearch *pSearch = NULL;
|
|
LPWSTR *pAttrs = NULL;
|
|
DWORD dwNumAttrs = 0, dwNumPrefs = 0;
|
|
ADS_SEARCHPREF_INFO *psearchPrefs = NULL, searchPrefs;
|
|
ADS_SEARCH_HANDLE hSearch=NULL;
|
|
|
|
hr = _pUnkOuter->QueryInterface(
|
|
IID_IDirectorySearch,
|
|
(void **) &pSearch
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = ParseAttrList(
|
|
szAttrs,
|
|
&pAttrs,
|
|
&dwNumAttrs
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
if(szOptions != NULL) {
|
|
hr = GetSearchPreferences(&psearchPrefs, &dwNumPrefs, lScope,
|
|
szOptions);
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
else {
|
|
searchPrefs.dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
|
|
searchPrefs.vValue.dwType = ADSTYPE_INTEGER;
|
|
searchPrefs.vValue.Integer = lScope;
|
|
|
|
psearchPrefs = &searchPrefs;
|
|
dwNumPrefs = 1;
|
|
}
|
|
|
|
hr = pSearch->SetSearchPreference(psearchPrefs, dwNumPrefs);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = pSearch->ExecuteSearch(
|
|
szFilter,
|
|
pAttrs,
|
|
dwNumAttrs,
|
|
&hSearch
|
|
);
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = OutputDataHeader();
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = pSearch->GetFirstRow(hSearch);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
while(hr != S_ADS_NOMORE_ROWS) {
|
|
hr = OutputEntryHeader(hSearch, pSearch);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = OutputEntryAttrs(hSearch, pSearch);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = OutputEntryFooter();
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = pSearch->GetNextRow(hSearch);
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
hr = OutputDataFooter();
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
error:
|
|
|
|
if(hSearch != NULL)
|
|
pSearch->CloseSearchHandle(hSearch);
|
|
|
|
if(pSearch != NULL)
|
|
pSearch->Release();
|
|
|
|
if(psearchPrefs && (psearchPrefs != &searchPrefs)) {
|
|
FreeSearchPrefInfo(psearchPrefs, dwNumPrefs);
|
|
}
|
|
|
|
if(pAttrs != NULL) {
|
|
int i = 0;
|
|
|
|
while(i < (int) dwNumAttrs) {
|
|
FreeADsStr(pAttrs[i]);
|
|
i++;
|
|
}
|
|
FreeADsMem(pAttrs);
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Function: ParseAttrList
|
|
//
|
|
// Synopsis: Parses a single string containing the comm-separated attributes
|
|
// and returns the number of attributes and an array of strings
|
|
// containing teh attributes.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// szAttrs Comma-separated attribute list
|
|
// ppAttrs Returns array of strings with attribute names
|
|
// pdwNumAttrs Returns number of attributes in list
|
|
//
|
|
// Returns: S_OK on success. Error code otherwise.
|
|
//
|
|
// Modifies: Nothing.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT CADsXML::ParseAttrList(
|
|
BSTR szAttrs,
|
|
LPWSTR **ppAttrs,
|
|
DWORD *pdwNumAttrs
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
WCHAR *pwChar = NULL;
|
|
DWORD dwNumAttrs = 0;
|
|
DWORD i = 0;
|
|
BOOL fAddDn = TRUE, fAddObjClass = TRUE;
|
|
LPWSTR *pAttrs = NULL;
|
|
|
|
ADsAssert(ppAttrs && pdwNumAttrs);
|
|
|
|
if(NULL == szAttrs) {
|
|
*ppAttrs = NULL;
|
|
*pdwNumAttrs = -1;
|
|
|
|
RRETURN(S_OK);
|
|
}
|
|
|
|
pwChar = szAttrs;
|
|
while(pwChar = wcschr(pwChar, L',')) {
|
|
*pwChar = L'\0';
|
|
pwChar++;
|
|
dwNumAttrs++;
|
|
}
|
|
dwNumAttrs++;
|
|
|
|
pAttrs = (LPWSTR *) AllocADsMem(sizeof(LPWSTR) * (dwNumAttrs+2));
|
|
if(NULL == pAttrs) {
|
|
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
|
|
}
|
|
memset(pAttrs, 0, sizeof(LPWSTR) * dwNumAttrs);
|
|
|
|
pwChar = szAttrs;
|
|
|
|
for(i = 0; i < dwNumAttrs; i++) {
|
|
if(L'\0' == (*pwChar)) {
|
|
BAIL_ON_FAILURE(hr = E_INVALIDARG);
|
|
}
|
|
|
|
pAttrs[i] = AllocADsStr(pwChar);
|
|
if(NULL == pAttrs[i]) {
|
|
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
|
|
}
|
|
|
|
if(!_wcsicmp(pwChar, DISTINGUISHED_NAME))
|
|
fAddDn = FALSE;
|
|
else if(!_wcsicmp(pwChar, OBJECT_CLASS))
|
|
fAddObjClass = FALSE;
|
|
|
|
pwChar += (wcslen(pwChar) + 1);
|
|
}
|
|
|
|
if(fAddDn) {
|
|
pAttrs[dwNumAttrs] = AllocADsStr(DISTINGUISHED_NAME);
|
|
if(NULL == pAttrs[dwNumAttrs]) {
|
|
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
|
|
}
|
|
dwNumAttrs++;
|
|
}
|
|
|
|
if(fAddObjClass) {
|
|
pAttrs[dwNumAttrs] = AllocADsStr(OBJECT_CLASS);
|
|
if(NULL == pAttrs[dwNumAttrs]) {
|
|
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
|
|
}
|
|
dwNumAttrs++;
|
|
}
|
|
|
|
*pdwNumAttrs = dwNumAttrs;
|
|
*ppAttrs = pAttrs;
|
|
|
|
RRETURN(S_OK);
|
|
|
|
error:
|
|
|
|
if(pAttrs != NULL) {
|
|
i = 0;
|
|
|
|
while(pAttrs[i]) {
|
|
FreeADsStr(pAttrs[i]);
|
|
i++;
|
|
}
|
|
|
|
FreeADsMem(pAttrs);
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: OutputDataHeader
|
|
//
|
|
// Synopsis: Outputs data header
|
|
//
|
|
// Arguments:
|
|
//
|
|
// None.
|
|
//
|
|
// Returns: S_OK on success. Error code otherwise.
|
|
//
|
|
// Modifies: Nothing.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT CADsXML::OutputDataHeader(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = WriteLine(DSML_DATA_TAG);
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: OutputEntryHeader
|
|
//
|
|
// Synopsis: Outputs the standar4d DSML header for each entry
|
|
//
|
|
// Arguments:
|
|
//
|
|
// hSearch Handle to search results
|
|
// pSearch IDirectorySearch interface pointer
|
|
//
|
|
// Returns: S_OK on success. Error code otherwise.
|
|
//
|
|
// Modifies: Nothing.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT CADsXML::OutputEntryHeader(
|
|
ADS_SEARCH_HANDLE hSearch,
|
|
IDirectorySearch *pSearch
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ADS_SEARCH_COLUMN column;
|
|
DWORD i = 0;
|
|
BOOL fFreeCols = FALSE;
|
|
|
|
hr = Write(DSML_ENTRY_TAG);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = Write(L"dn=\"");
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = pSearch->GetColumn(hSearch, DISTINGUISHED_NAME, &column);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = Write(column.pADsValues->CaseIgnoreString, TRUE);
|
|
pSearch->FreeColumn(&column);
|
|
BAIL_ON_FAILURE(hr);
|
|
hr = WriteLine(L"\">");
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = WriteLine(DSML_OBJECTCLASS_TAG);
|
|
BAIL_ON_FAILURE(hr);
|
|
hr = pSearch->GetColumn(hSearch, OBJECT_CLASS, &column);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
fFreeCols = TRUE;
|
|
|
|
for(i = 0; i < column.dwNumValues; i++) {
|
|
hr = Write(DSML_OCVALUE_TAG);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = Write(column.pADsValues[i].CaseIgnoreString, TRUE);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = WriteLine(DSML_OCVALUE_TAG_CLOSE);
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
hr = WriteLine(DSML_OBJECTCLASS_TAG_CLOSE);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
error:
|
|
|
|
if(fFreeCols)
|
|
pSearch->FreeColumn(&column);
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: OutputEntryAttrs
|
|
//
|
|
// Synopsis: Outputs the attributes that were requested for each entry.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// hSearch Handle to search results
|
|
// pSearch IDirectorySearch interface pointer
|
|
//
|
|
// Returns: S_OK on success. Error code otherwise.
|
|
//
|
|
// Modifies: Nothing.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CADsXML::OutputEntryAttrs(
|
|
ADS_SEARCH_HANDLE hSearch,
|
|
IDirectorySearch *pSearch
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPWSTR pszColumnName = NULL;
|
|
ADS_SEARCH_COLUMN column;
|
|
BOOL fFreeCols = FALSE;
|
|
|
|
hr = pSearch->GetNextColumnName(hSearch, &pszColumnName);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
while(hr != S_ADS_NOMORE_COLUMNS) {
|
|
if(_wcsicmp(pszColumnName, DISTINGUISHED_NAME) &&
|
|
_wcsicmp(pszColumnName, OBJECT_CLASS)) {
|
|
|
|
hr = pSearch->GetColumn(
|
|
hSearch,
|
|
pszColumnName,
|
|
&column
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
fFreeCols = TRUE;
|
|
|
|
hr = Write(DSML_ENTRY_ATTR_TAG);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = Write(L" name=\"");
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = Write(pszColumnName, TRUE);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
if( (column.dwNumValues > 1) ||
|
|
(ADSTYPE_OCTET_STRING == column.dwADsType) ||
|
|
(ADSTYPE_NT_SECURITY_DESCRIPTOR == column.dwADsType) ||
|
|
(ADSTYPE_PROV_SPECIFIC == column.dwADsType) ) {
|
|
hr = WriteLine(L"\">");
|
|
}
|
|
else
|
|
hr = Write(L"\">");
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = OutputValue(&column);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
pSearch->FreeColumn(&column);
|
|
fFreeCols = FALSE;
|
|
|
|
hr = WriteLine(DSML_ENTRY_ATTR_TAG_CLOSE);
|
|
BAIL_ON_FAILURE(hr);
|
|
} // if
|
|
|
|
FreeADsMem(pszColumnName);
|
|
pszColumnName = NULL;
|
|
hr = pSearch->GetNextColumnName(hSearch, &pszColumnName);
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
error:
|
|
|
|
if(fFreeCols)
|
|
pSearch->FreeColumn(&column);
|
|
|
|
if(pszColumnName != NULL)
|
|
FreeADsMem(pszColumnName);
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: OutputValue
|
|
//
|
|
// Synopsis: Outputs the value of an attribute
|
|
//
|
|
// Arguments:
|
|
//
|
|
// pColumn Attribute returned by IDirectorySearch
|
|
//
|
|
// Returns: S_OK on success. Error code otherwise.
|
|
//
|
|
// Modifies: Nothing.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT CADsXML::OutputValue(ADS_SEARCH_COLUMN *pColumn)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD i = 0;
|
|
WCHAR NumBuffer[256], pszTmp[256];;
|
|
DWORD dwLength = 0;
|
|
LPBYTE lpByte = NULL;
|
|
LPWSTR pszBase64Str = NULL;
|
|
int inBytes = 0, outBytes = 0, ret;
|
|
|
|
ADsAssert(pColumn);
|
|
|
|
for(i = 0; i < pColumn->dwNumValues; i++) {
|
|
|
|
switch(pColumn->dwADsType) {
|
|
case ADSTYPE_DN_STRING:
|
|
hr = Write(DSML_VALUE_TAG);
|
|
BAIL_ON_FAILURE(hr);
|
|
hr = Write(pColumn->pADsValues[i].DNString, TRUE);
|
|
break;
|
|
case ADSTYPE_CASE_EXACT_STRING:
|
|
hr = Write(DSML_VALUE_TAG);
|
|
BAIL_ON_FAILURE(hr);
|
|
hr = Write(pColumn->pADsValues[i].CaseExactString, TRUE);
|
|
break;
|
|
case ADSTYPE_CASE_IGNORE_STRING:
|
|
hr = Write(DSML_VALUE_TAG);
|
|
BAIL_ON_FAILURE(hr);
|
|
hr = Write(pColumn->pADsValues[i].CaseIgnoreString, TRUE);
|
|
break;
|
|
case ADSTYPE_PRINTABLE_STRING:
|
|
hr = Write(DSML_VALUE_TAG);
|
|
BAIL_ON_FAILURE(hr);
|
|
hr = Write(pColumn->pADsValues[i].PrintableString, TRUE);
|
|
break;
|
|
case ADSTYPE_NUMERIC_STRING:
|
|
hr = Write(DSML_VALUE_TAG);
|
|
BAIL_ON_FAILURE(hr);
|
|
hr = Write(pColumn->pADsValues[i].NumericString, TRUE);
|
|
break;
|
|
case ADSTYPE_BOOLEAN:
|
|
hr = Write(DSML_VALUE_TAG);
|
|
BAIL_ON_FAILURE(hr);
|
|
if(pColumn->pADsValues[i].Boolean)
|
|
hr = Write(L"true");
|
|
else
|
|
hr = Write(L"false");
|
|
break;
|
|
case ADSTYPE_INTEGER:
|
|
hr = Write(DSML_VALUE_TAG);
|
|
BAIL_ON_FAILURE(hr);
|
|
_itow(pColumn->pADsValues[i].Integer, NumBuffer, 10);
|
|
hr = Write(NumBuffer);
|
|
break;
|
|
case ADSTYPE_OCTET_STRING:
|
|
case ADSTYPE_PROV_SPECIFIC:
|
|
case ADSTYPE_NT_SECURITY_DESCRIPTOR:
|
|
hr = WriteLine(DSML_VALUE_ENCODING_TAG);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
if(ADSTYPE_OCTET_STRING == pColumn->dwADsType) {
|
|
dwLength = pColumn->pADsValues[i].OctetString.dwLength;
|
|
lpByte = pColumn->pADsValues[i].OctetString.lpValue;
|
|
}
|
|
else if(ADSTYPE_PROV_SPECIFIC == pColumn->dwADsType) {
|
|
dwLength =
|
|
pColumn->pADsValues[i].ProviderSpecific.dwLength;
|
|
lpByte = pColumn->pADsValues[i].ProviderSpecific.lpValue;
|
|
}
|
|
else if(ADSTYPE_NT_SECURITY_DESCRIPTOR == pColumn->dwADsType) {
|
|
dwLength =
|
|
pColumn->pADsValues[i].SecurityDescriptor.dwLength;
|
|
lpByte = pColumn->pADsValues[i].SecurityDescriptor.lpValue;
|
|
}
|
|
|
|
//
|
|
// base64 encoding requires about 4/3 the size of the octet
|
|
// string. Approximate to twice the size. Since we are
|
|
// converting to WCHAR, need 4 times as much space.
|
|
//
|
|
pszBase64Str = (LPWSTR) AllocADsMem(2*(2*dwLength + 1));
|
|
if(NULL == pszBase64Str) {
|
|
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
|
|
}
|
|
inBytes = dwLength;
|
|
outBytes = 2*dwLength + 1;
|
|
ret = encodeBase64Buffer(
|
|
(char *) lpByte,
|
|
&inBytes,
|
|
pszBase64Str,
|
|
&outBytes,
|
|
LINE_LENGTH
|
|
);
|
|
if( (-1 == ret) || (inBytes != (int) dwLength) ) {
|
|
FreeADsMem(pszBase64Str);
|
|
BAIL_ON_FAILURE(hr = E_ADS_CANT_CONVERT_DATATYPE);
|
|
}
|
|
|
|
// base64 string need not be escaped
|
|
hr = WriteLine(pszBase64Str);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
FreeADsMem(pszBase64Str);
|
|
|
|
break;
|
|
case ADSTYPE_UTC_TIME:
|
|
WCHAR pszTime[256];
|
|
SYSTEMTIME *pst;
|
|
|
|
hr = Write(DSML_VALUE_TAG);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
pst = &(pColumn->pADsValues[i].UTCTime);
|
|
wsprintf(pszTime, L"%02d%02d%02d%02d%02d%02dZ",
|
|
pst->wYear % 100, pst->wMonth, pst->wDay,
|
|
pst->wHour, pst->wMinute, pst->wSecond);
|
|
hr = Write(pszTime);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
break;
|
|
case ADSTYPE_LARGE_INTEGER:
|
|
LARGE_INTEGER *pLargeInt;
|
|
|
|
hr = Write(DSML_VALUE_TAG);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
pLargeInt = &(pColumn->pADsValues[i].LargeInteger);
|
|
swprintf(NumBuffer, L"%I64d", *pLargeInt);
|
|
|
|
hr = Write(NumBuffer);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
break;
|
|
|
|
case ADSTYPE_DN_WITH_BINARY:
|
|
ADS_DN_WITH_BINARY *pDnBin;
|
|
LPWSTR pszBinaryVal;
|
|
|
|
hr = Write(DSML_VALUE_TAG);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
pDnBin = pColumn->pADsValues[i].pDNWithBinary;
|
|
swprintf(pszTmp, L"B:%d:", pDnBin->dwLength*2);
|
|
|
|
hr = Write(pszTmp);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
pszBinaryVal = (LPWSTR)AllocADsMem(2*(pDnBin->dwLength*2 + 2));
|
|
if(NULL == pszBinaryVal) {
|
|
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
|
|
}
|
|
|
|
for(i = 0; i < pDnBin->dwLength; i++)
|
|
swprintf(pszBinaryVal+(i*2), L"%02x",
|
|
pDnBin->lpBinaryValue[i]);
|
|
|
|
wcscat(pszBinaryVal, L":");
|
|
|
|
hr = Write(pszBinaryVal);
|
|
FreeADsMem(pszBinaryVal);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = Write(pDnBin->pszDNString, TRUE);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
break;
|
|
|
|
case ADSTYPE_DN_WITH_STRING:
|
|
ADS_DN_WITH_STRING *pDnStr;
|
|
|
|
hr = Write(DSML_VALUE_TAG);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
pDnStr = pColumn->pADsValues[i].pDNWithString;
|
|
swprintf(pszTmp, L"S:%d:", wcslen(pDnStr->pszStringValue));
|
|
|
|
hr = Write(pszTmp);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = Write(pDnStr->pszStringValue, TRUE);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = Write(L":");
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = Write(pDnStr->pszDNString, TRUE);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
break;
|
|
|
|
default:
|
|
BAIL_ON_FAILURE(hr = E_ADS_CANT_CONVERT_DATATYPE);
|
|
break;
|
|
}
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
if( (pColumn->dwNumValues > 1) ||
|
|
(ADSTYPE_OCTET_STRING == pColumn->dwADsType) ||
|
|
(ADSTYPE_NT_SECURITY_DESCRIPTOR == pColumn->dwADsType) ||
|
|
(ADSTYPE_PROV_SPECIFIC == pColumn->dwADsType) ) {
|
|
hr = WriteLine(DSML_VALUE_TAG_CLOSE);
|
|
}
|
|
else
|
|
hr = Write(DSML_VALUE_TAG_CLOSE);
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
error:
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: OutputEntryFooter
|
|
//
|
|
// Synopsis: Outputs the DSML footer for an entry
|
|
//
|
|
// Arguments:
|
|
//
|
|
// None
|
|
//
|
|
// Returns: S_OK on success. Error code otherwise.
|
|
//
|
|
// Modifies: Nothing.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CADsXML::OutputEntryFooter(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = WriteLine(DSML_ENTRY_TAG_CLOSE);
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: OutputDataFooter
|
|
//
|
|
// Synopsis: Outputs the DSML footer for all data
|
|
//
|
|
// Arguments:
|
|
//
|
|
// None
|
|
//
|
|
// Returns: S_OK on success. Error code otherwise.
|
|
//
|
|
// Modifies: Nothing.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CADsXML::OutputDataFooter(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = WriteLine(DSML_DATA_TAG_CLOSE);
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: RemoveWhiteSpace
|
|
//
|
|
// Synopsis: Remove all leading and trailing white space in every attribute
|
|
// of comma-separated attribute list
|
|
//
|
|
// Arguments:
|
|
//
|
|
// pszStr Comma-separated attribute list
|
|
//
|
|
// Returns: String with white spaces removed as mentioned above. NULL on
|
|
// error.
|
|
//
|
|
// Modifies: Nothing.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
LPWSTR CADsXML::RemoveWhiteSpace(BSTR pszStr)
|
|
{
|
|
LPWSTR pszNewStr = NULL;
|
|
int i,j, k;
|
|
WCHAR prevChar = L',';
|
|
|
|
ADsAssert(pszStr != NULL);
|
|
|
|
pszNewStr = AllocADsStr(pszStr);
|
|
if(NULL == pszNewStr)
|
|
return NULL;
|
|
|
|
for(i = 0, j = 0; i < (int) wcslen(pszStr); i++) {
|
|
if(iswspace(pszStr[i]) && (L',' == prevChar) )
|
|
continue;
|
|
|
|
prevChar = pszNewStr[j] = pszStr[i];
|
|
if(L',' == prevChar) {
|
|
k = j - 1;
|
|
while( (k >= 0) && (iswspace(pszNewStr[k])) )
|
|
k--;
|
|
j = k+1;
|
|
pszNewStr[j] = pszStr[i];
|
|
}
|
|
j++;
|
|
}
|
|
|
|
k = j - 1;
|
|
while( (k >= 0) && (iswspace(pszNewStr[k])) )
|
|
k--;
|
|
j = k+1;
|
|
|
|
pszNewStr[j] = L'\0';
|
|
|
|
return pszNewStr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: ReduceWhiteSpace
|
|
//
|
|
// Synopsis: Removes white spaces from te string containing search prefs as
|
|
// follows. No white spaces are allowed before or immediately after
|
|
// an = sign. Each search preference is reduced to having at most
|
|
// one space in it i.e, "\t\tsort on = cn; timeout= 10" will
|
|
// be reduced to "sort on=cn;timeout=10"
|
|
//
|
|
// Arguments:
|
|
//
|
|
// pszStr String containing search prefs
|
|
//
|
|
// Returns: Reduced string. NULL on error.
|
|
//
|
|
// Modifies: Nothing.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
LPWSTR CADsXML::ReduceWhiteSpace(BSTR pszStr)
|
|
{
|
|
int i = 0, j = 0;
|
|
LPWSTR pszNewStr = NULL;
|
|
|
|
ADsAssert(pszStr != NULL);
|
|
|
|
pszNewStr = (LPWSTR) AllocADsMem(wcslen(pszStr)*2+2);
|
|
if(NULL == pszNewStr)
|
|
return NULL;
|
|
|
|
while(iswspace(pszStr[i]))
|
|
i++;
|
|
|
|
if(L'\0' == pszStr[i])
|
|
return pszNewStr;
|
|
|
|
while(1) {
|
|
pszNewStr[j] = pszStr[i];
|
|
|
|
if(L'\0' == pszStr[i]) {
|
|
if( (j != 0) && (pszNewStr[j-1] == L' ') )
|
|
pszNewStr[j-1] = pszStr[i];
|
|
return pszNewStr;
|
|
}
|
|
|
|
if(iswspace(pszStr[i])) {
|
|
if( (pszNewStr[j-1] == L';') ||
|
|
(pszNewStr[j-1] == L'=') ||
|
|
(pszNewStr[j-1] == L' ') ) {
|
|
i++;
|
|
continue;
|
|
}
|
|
else
|
|
pszNewStr[j] = L' ';
|
|
}
|
|
else if( (pszStr[i] == L'=') || (pszStr[i] == L';') ) {
|
|
if( (j != 0) && (pszNewStr[j-1] == L' ') ) {
|
|
pszNewStr[j-1] = pszStr[i];
|
|
i++;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
i++;
|
|
j++;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: GetSearchPreferences
|
|
//
|
|
// Synopsis: Returns array of search preferences base n string containing
|
|
// options.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// ppSearchPrefInfo Returns search preferences
|
|
// pdwNumPrefs Returns number of preferences
|
|
// lScope Search scope
|
|
// szOptions String containing options
|
|
//
|
|
// Returns: S_OK on success. Error code otherwise.
|
|
//
|
|
// Modifies: Nothing.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CADsXML::GetSearchPreferences(
|
|
ADS_SEARCHPREF_INFO** ppSearchPrefInfo,
|
|
DWORD *pdwNumPrefs,
|
|
LONG lScope,
|
|
LPWSTR szOptions
|
|
)
|
|
{
|
|
ADS_SEARCHPREF_INFO *pSearchPrefs = NULL;
|
|
DWORD dwNumPrefs = 0, dwLength = 0;
|
|
LPWSTR pszTmp = szOptions, pszTmp1 = NULL;
|
|
HRESULT hr = S_OK;
|
|
int i,j, cAttrs = 0;
|
|
LPWSTR pszCurrentAttr = NULL, pszFirstAttr = NULL, pszNextAttr = NULL;
|
|
LPWSTR pszOrder = NULL;
|
|
PADS_SORTKEY pSortKey = NULL;
|
|
|
|
ADsAssert(ppSearchPrefInfo && pdwNumPrefs);
|
|
|
|
*ppSearchPrefInfo = NULL;
|
|
*pdwNumPrefs = 0;
|
|
|
|
while(pszTmp = wcschr(pszTmp, L'=')) {
|
|
dwNumPrefs++;
|
|
*pszTmp = L'\0';
|
|
pszTmp++;
|
|
|
|
if(*pszTmp == L'\0') {
|
|
BAIL_ON_FAILURE(hr = E_INVALIDARG);
|
|
}
|
|
|
|
pszTmp1 = wcschr(pszTmp, L';');
|
|
if(pszTmp1 != NULL) {
|
|
*pszTmp1 = L'\0';
|
|
pszTmp = pszTmp1 + 1;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
if(0 == dwNumPrefs) {
|
|
BAIL_ON_FAILURE(hr = E_INVALIDARG);
|
|
}
|
|
|
|
dwNumPrefs++; //include search scope
|
|
|
|
pSearchPrefs = (ADS_SEARCHPREF_INFO *) AllocADsMem(dwNumPrefs *
|
|
sizeof(ADS_SEARCHPREF_INFO));
|
|
if(NULL == pSearchPrefs) {
|
|
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
|
|
}
|
|
|
|
pszTmp = szOptions;
|
|
|
|
for(i = 0; i < (int) (dwNumPrefs - 1); i++) {
|
|
for(j = 0; j < (int) g_dwNumSearchPrefInfo; j++) {
|
|
if(0 == _wcsicmp(pszTmp, g_SearchPrefInfo[j].pszName))
|
|
break;
|
|
}
|
|
|
|
if(j == (int) g_dwNumSearchPrefInfo) {
|
|
BAIL_ON_FAILURE(hr = E_INVALIDARG);
|
|
}
|
|
|
|
pSearchPrefs[i].dwSearchPref = g_SearchPrefInfo[j].Pref;
|
|
|
|
pszTmp = pszTmp + wcslen(pszTmp) + 1;
|
|
dwLength = wcslen(pszTmp);
|
|
if(0 == dwLength) {
|
|
BAIL_ON_FAILURE(hr = E_INVALIDARG);
|
|
}
|
|
|
|
switch(g_SearchPrefInfo[j].vtType) {
|
|
case VT_BOOL:
|
|
if(0 == _wcsicmp(pszTmp, L"true"))
|
|
pSearchPrefs[i].vValue.Boolean = VARIANT_TRUE;
|
|
else if (0 == _wcsicmp(pszTmp, L"false"))
|
|
pSearchPrefs[i].vValue.Boolean = VARIANT_FALSE;
|
|
else {
|
|
BAIL_ON_FAILURE(hr = E_INVALIDARG);
|
|
}
|
|
pSearchPrefs[i].vValue.dwType = ADSTYPE_BOOLEAN;
|
|
|
|
break;
|
|
|
|
case VT_I4:
|
|
for(j = 0; j < (int) wcslen(pszTmp); j++) {
|
|
if(0 == iswdigit(pszTmp[j])) {
|
|
BAIL_ON_FAILURE(hr = E_INVALIDARG);
|
|
}
|
|
}
|
|
|
|
pSearchPrefs[i].vValue.dwType = ADSTYPE_INTEGER;
|
|
pSearchPrefs[i].vValue.Integer = _wtoi(pszTmp);
|
|
|
|
break;
|
|
|
|
case VT_BSTR:
|
|
if(L'\0' == *pszTmp) {
|
|
BAIL_ON_FAILURE(hr = E_INVALIDARG);
|
|
}
|
|
|
|
// guard against a string ending in ',' since it won't be caught
|
|
// below
|
|
if(L',' == pszTmp[wcslen(pszTmp) -1]) {
|
|
BAIL_ON_FAILURE ( hr = E_INVALIDARG );
|
|
}
|
|
|
|
pszCurrentAttr = pszFirstAttr = wcstok(pszTmp, L",");
|
|
|
|
for(cAttrs=0; pszCurrentAttr != NULL; cAttrs++ ) {
|
|
pszCurrentAttr = wcstok(NULL, L",");
|
|
}
|
|
|
|
if(cAttrs == 0) { // shouldn't happen
|
|
BAIL_ON_FAILURE ( hr = E_INVALIDARG );
|
|
}
|
|
|
|
pSortKey = (PADS_SORTKEY) AllocADsMem(sizeof(ADS_SORTKEY) *
|
|
cAttrs);
|
|
if(NULL == pSortKey) {
|
|
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
|
|
}
|
|
|
|
pszCurrentAttr = pszFirstAttr;
|
|
|
|
for(j = 0; j < cAttrs; j++) {
|
|
pszNextAttr = pszCurrentAttr + wcslen(pszCurrentAttr) + 1;
|
|
|
|
if(L' ' == *pszCurrentAttr) {
|
|
// cannot happen for first attr in list since there will
|
|
// never be a space following =. However, subsequent attrs
|
|
// may have exactly one leading space.
|
|
pszCurrentAttr++;
|
|
if(L'\0' == *pszCurrentAttr) {
|
|
BAIL_ON_FAILURE(hr = E_INVALIDARG);
|
|
}
|
|
}
|
|
|
|
pszOrder = wcstok(pszCurrentAttr, L" ");
|
|
pszOrder = pszOrder ? wcstok(NULL, L" ") : NULL;
|
|
|
|
if (pszOrder && !_wcsicmp(pszOrder, L"DESC"))
|
|
pSortKey[j].fReverseorder = 1;
|
|
else
|
|
pSortKey[j].fReverseorder = 0; // This is the default
|
|
|
|
pSortKey[j].pszAttrType = AllocADsStr(pszCurrentAttr);
|
|
if(NULL == pSortKey[j].pszAttrType) {
|
|
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
|
|
}
|
|
|
|
pSortKey[j].pszReserved = NULL;
|
|
|
|
pszCurrentAttr = pszNextAttr;
|
|
}
|
|
|
|
pSearchPrefs[i].vValue.ProviderSpecific.dwLength =
|
|
sizeof(ADS_SORTKEY) * cAttrs;
|
|
pSearchPrefs[i].vValue.ProviderSpecific.lpValue =
|
|
(LPBYTE) pSortKey;
|
|
|
|
pSearchPrefs[i].vValue.dwType = ADSTYPE_PROV_SPECIFIC;
|
|
|
|
pSortKey = NULL;
|
|
|
|
break;
|
|
|
|
default:
|
|
BAIL_ON_FAILURE(hr = E_FAIL);
|
|
break;
|
|
} //switch
|
|
|
|
pszTmp = pszTmp + dwLength + 1;
|
|
|
|
} // for
|
|
|
|
// set the search scope
|
|
pSearchPrefs[i].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
|
|
pSearchPrefs[i].vValue.dwType = ADSTYPE_INTEGER;
|
|
pSearchPrefs[i].vValue.Integer = lScope;
|
|
|
|
*ppSearchPrefInfo = pSearchPrefs;
|
|
*pdwNumPrefs = dwNumPrefs;
|
|
|
|
error:
|
|
|
|
if(FAILED(hr)) {
|
|
if(pSortKey != NULL) {
|
|
for(j = 0; j < cAttrs; j++) {
|
|
if(pSortKey[j].pszAttrType)
|
|
FreeADsStr(pSortKey[j].pszAttrType);
|
|
}
|
|
|
|
FreeADsMem(pSortKey);
|
|
}
|
|
|
|
if(pSearchPrefs != NULL)
|
|
FreeSearchPrefInfo(pSearchPrefs, dwNumPrefs);
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: FreeSearchPrefInfo
|
|
//
|
|
// Synopsis: Frees array of search prefs
|
|
//
|
|
// Arguments:
|
|
//
|
|
// pSearchPrefInfo Array of search prefs
|
|
// dwNumPrefs Number of preferences
|
|
//
|
|
// Returns: S_OK on success. Error code otherwise.
|
|
//
|
|
// Modifies: Nothing.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CADsXML::FreeSearchPrefInfo(
|
|
ADS_SEARCHPREF_INFO *pSearchPrefInfo,
|
|
DWORD dwNumPrefs
|
|
)
|
|
{
|
|
int i, j;
|
|
DWORD nSortKeys = 0;
|
|
PADS_SORTKEY pSortKey = NULL;
|
|
|
|
if( (NULL == pSearchPrefInfo) || (0 == dwNumPrefs) )
|
|
return;
|
|
|
|
for(i = 0; i < (int)dwNumPrefs; i++) {
|
|
if(ADSTYPE_PROV_SPECIFIC == pSearchPrefInfo[i].vValue.dwType) {
|
|
if (pSearchPrefInfo[i].dwSearchPref == ADS_SEARCHPREF_SORT_ON) {
|
|
nSortKeys = pSearchPrefInfo[i].vValue.ProviderSpecific.dwLength
|
|
/ sizeof(ADS_SORTKEY);
|
|
pSortKey = (PADS_SORTKEY) pSearchPrefInfo[i].vValue.ProviderSpecific.lpValue;
|
|
for(j = 0; pSortKey && j < (int) nSortKeys; j++) {
|
|
FreeADsStr(pSortKey[j].pszAttrType);
|
|
}
|
|
|
|
if (pSortKey) {
|
|
FreeADsMem(pSortKey);
|
|
}
|
|
}
|
|
} // if
|
|
} // for
|
|
|
|
FreeADsMem(pSearchPrefInfo);
|
|
|
|
return;
|
|
}
|
|
|