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