windows-nt/Source/XPSP1/NT/ds/adsi/xml/cadsxml.cxx
2020-09-26 16:20:57 +08:00

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;
}