Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2157 lines
56 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 2000.
  5. //
  6. // File: cadsxml.cxx
  7. //
  8. // Contents: Contains the implementation of ADsXML. This class implements
  9. // XML persistence as an ADSI extension.
  10. //
  11. //----------------------------------------------------------------------------
  12. #include "cadsxml.hxx"
  13. long glnObjCnt = 0;
  14. // not used
  15. ULONG g_ulObjCount = 0;
  16. LPWSTR g_SchemaAttrs[] = { OID,
  17. LDAP_DISPLAY_NAME,
  18. TYPE,
  19. SUBCLASSOF,
  20. DESCRIPTION,
  21. MUST_CONTAIN,
  22. SYSTEM_MUST_CONTAIN,
  23. MAY_CONTAIN,
  24. SYSTEM_MAY_CONTAIN
  25. };
  26. DWORD g_dwNumSchemaAttrs = sizeof(g_SchemaAttrs)/sizeof(LPWSTR);
  27. SEARCHPREFINFO g_SearchPrefInfo[] =
  28. {
  29. {ADS_SEARCHPREF_ASYNCHRONOUS, VT_BOOL, L"Asynchronous"},
  30. {ADS_SEARCHPREF_DEREF_ALIASES, VT_I4, L"Deref Aliases"},
  31. {ADS_SEARCHPREF_SIZE_LIMIT, VT_I4,L"Size Limit"},
  32. {ADS_SEARCHPREF_TIME_LIMIT, VT_I4, L"Server Time Limit"},
  33. // {ADS_SEARCHPREF_ATTRIBTYPES_ONLY, VT_BOOL, L"Column Names only"},
  34. {ADS_SEARCHPREF_TIMEOUT, VT_I4, L"Timeout"},
  35. {ADS_SEARCHPREF_PAGESIZE, VT_I4, L"Page size"},
  36. {ADS_SEARCHPREF_PAGED_TIME_LIMIT, VT_I4, L"Time limit"},
  37. {ADS_SEARCHPREF_CHASE_REFERRALS, VT_I4, L"Chase referrals"},
  38. {ADS_SEARCHPREF_SORT_ON, VT_BSTR, L"Sort On"},
  39. {ADS_SEARCHPREF_CACHE_RESULTS, VT_BOOL, L"Cache Results"}
  40. };
  41. DWORD g_dwNumSearchPrefInfo = sizeof(g_SearchPrefInfo)/sizeof(SEARCHPREFINFO);
  42. DEFINE_IADsExtension_Implementation(CADsXML)
  43. DEFINE_DELEGATING_IDispatch_Implementation(CADsXML)
  44. //----------------------------------------------------------------------------
  45. // Function: CADsXML
  46. //
  47. // Synopsis: Constructor. Initializes member variables.
  48. //
  49. // Arguments: None
  50. //
  51. // Returns: Nothing
  52. //
  53. // Modifies: Nothing
  54. //
  55. //----------------------------------------------------------------------------
  56. CADsXML::CADsXML(void)
  57. {
  58. _pUnkOuter = NULL;
  59. _pADs = NULL;
  60. _pDispMgr = NULL;
  61. m_pCredentials = NULL;
  62. m_hFile = INVALID_HANDLE_VALUE;
  63. // make sure DLL isn't unloaded until all objects are destroyed
  64. InterlockedIncrement(&glnObjCnt);
  65. }
  66. //----------------------------------------------------------------------------
  67. // Function: ~CADsXML
  68. //
  69. // Synopsis: Destructor. Frees member variables.
  70. //
  71. // Arguments: None
  72. //
  73. // Returns: Nothing
  74. //
  75. // Modifies: Nothing
  76. //
  77. //----------------------------------------------------------------------------
  78. CADsXML::~CADsXML(void)
  79. {
  80. if(m_pCredentials != NULL)
  81. delete m_pCredentials;
  82. InterlockedDecrement(&glnObjCnt);
  83. if(_pDispMgr != NULL)
  84. delete _pDispMgr;
  85. //
  86. // no need to release _pUnkOuter since aggregatee cannot hold a reference
  87. // on aggregator.
  88. //
  89. }
  90. //----------------------------------------------------------------------------
  91. // Function: SaveXML
  92. //
  93. // Synopsis: Implements XML persistence.
  94. //
  95. // Arguments: See IADsXML reference
  96. //
  97. // Returns: S_OK on success, error otherwise.
  98. //
  99. // Modifies: Nothing
  100. //
  101. //----------------------------------------------------------------------------
  102. STDMETHODIMP CADsXML::SaveXML(
  103. VARIANT vDest,
  104. BSTR szFilter,
  105. BSTR szAttrs,
  106. long lScope,
  107. BSTR xslRef,
  108. long lFlag,
  109. BSTR szOptions,
  110. VARIANT *pDirSyncCookie
  111. )
  112. {
  113. HRESULT hr = S_OK;
  114. LPWSTR pszAttrs = NULL, pszOptions = NULL;
  115. // Validate inpute args
  116. hr = ValidateArgs(
  117. vDest,
  118. lScope,
  119. lFlag,
  120. pDirSyncCookie
  121. );
  122. BAIL_ON_FAILURE(hr);
  123. // Open output stream for writing
  124. hr = OpenOutputStream(vDest);
  125. BAIL_ON_FAILURE(hr);
  126. hr = WriteXMLHeader(xslRef);
  127. BAIL_ON_FAILURE(hr);
  128. // remove white spaces from attributes and search options, if required
  129. if(szAttrs != NULL) {
  130. pszAttrs = RemoveWhiteSpace(szAttrs);
  131. if(NULL == pszAttrs) {
  132. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  133. }
  134. }
  135. if(szOptions != NULL) {
  136. pszOptions = ReduceWhiteSpace(szOptions);
  137. if(NULL == pszOptions) {
  138. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  139. }
  140. }
  141. // persist schema first if required
  142. if(lFlag & ADS_XML_SCHEMA) {
  143. hr = OutputSchema();
  144. BAIL_ON_FAILURE(hr);
  145. }
  146. if(lFlag & ADS_XML_DSML) {
  147. hr = OutputData(
  148. szFilter,
  149. pszAttrs,
  150. lScope,
  151. pszOptions
  152. );
  153. BAIL_ON_FAILURE(hr);
  154. }
  155. hr = WriteXMLFooter();
  156. BAIL_ON_FAILURE(hr);
  157. CloseOutputStream();
  158. if(pszAttrs != NULL)
  159. FreeADsStr(pszAttrs);
  160. if(pszOptions != NULL)
  161. FreeADsMem(pszOptions);
  162. RRETURN(S_OK);
  163. error:
  164. if(pszAttrs != NULL)
  165. FreeADsStr(pszAttrs);
  166. if(pszOptions != NULL)
  167. FreeADsMem(pszOptions);
  168. RRETURN(hr);
  169. }
  170. //----------------------------------------------------------------------------
  171. // Function: ValidateArgs
  172. //
  173. // Synopsis: Validates the arguments passed into SaveXML
  174. //
  175. // Arguments: See IADsXML reference
  176. //
  177. // Returns: S_OK on success, error otherwise.
  178. //
  179. // Modifies: Nothing
  180. //
  181. //----------------------------------------------------------------------------
  182. HRESULT CADsXML::ValidateArgs(
  183. VARIANT vDest,
  184. long lScope,
  185. long lFlag,
  186. VARIANT *pDirSyncCookie
  187. )
  188. {
  189. ULONG ulDsmlVer = 0;
  190. if( (V_VT(&vDest) != VT_BSTR) || (NULL == V_BSTR(&vDest)) )
  191. RRETURN(E_INVALIDARG);
  192. if( (lScope != ADS_SCOPE_BASE) && (lScope != ADS_SCOPE_ONELEVEL) &&
  193. (lScope != ADS_SCOPE_SUBTREE) )
  194. RRETURN(E_INVALIDARG);
  195. //
  196. // 4 MSBs of lFlag specify DSML version. Check to see if this is a
  197. // supported value.
  198. //
  199. ulDsmlVer = ((ULONG) (lFlag & 0xf0000000)) >> 28;
  200. if(ulDsmlVer > 1)
  201. RRETURN(E_ADSXML_NOT_SUPPORTED);
  202. // check if lFlag is valid
  203. if( (lFlag & 0x0fffffff) & (~(ADS_XML_DSML | ADS_XML_SCHEMA)) )
  204. RRETURN(E_INVALIDARG);
  205. // not supported for now
  206. // if(pDirSyncCookie != NULL)
  207. // RRETURN(E_INVALIDARG);
  208. RRETURN(S_OK);
  209. }
  210. //----------------------------------------------------------------------------
  211. // Function: OpenOutputStream
  212. //
  213. // Synopsis: Opens the output stream for writing. Creates a file to store the
  214. // XML output.
  215. //
  216. // Arguments:
  217. //
  218. // vDest Specifies destination
  219. //
  220. // Returns: S_OK on success, error otherwise.
  221. //
  222. // Modifies: Nothing
  223. //
  224. //----------------------------------------------------------------------------
  225. HRESULT CADsXML::OpenOutputStream(
  226. VARIANT vDest
  227. )
  228. {
  229. LPWSTR pszFileName = NULL;
  230. HRESULT hr = S_OK;
  231. pszFileName = V_BSTR(&vDest);
  232. m_hFile = CreateFile(
  233. pszFileName,
  234. GENERIC_WRITE,
  235. 0,
  236. NULL,
  237. CREATE_ALWAYS,
  238. FILE_ATTRIBUTE_NORMAL,
  239. NULL
  240. );
  241. if(INVALID_HANDLE_VALUE == m_hFile) {
  242. hr = HRESULT_FROM_WIN32(GetLastError());
  243. BAIL_ON_FAILURE(hr);
  244. }
  245. RRETURN(S_OK);
  246. error:
  247. RRETURN(hr);
  248. }
  249. //----------------------------------------------------------------------------
  250. // Function: WriteXMLHeader
  251. //
  252. // Synopsis: Writes the standard XML header to the output. This includes
  253. // the XML version, XSL ref (if specified) and the DSML namespace.
  254. //
  255. // Arguments:
  256. //
  257. // xslRef XSL reference
  258. //
  259. // Returns: S_OK on success, error otherwise.
  260. //
  261. // Modifies: Nothing
  262. //
  263. //----------------------------------------------------------------------------
  264. HRESULT CADsXML::WriteXMLHeader(
  265. BSTR xslRef
  266. )
  267. {
  268. HRESULT hr = S_OK;
  269. WCHAR szUnicodeMark[] = {0xfeff, 0};
  270. BAIL_ON_FAILURE(hr = Write(szUnicodeMark));
  271. BAIL_ON_FAILURE(hr = WriteLine(XML_HEADING));
  272. if(xslRef != NULL) {
  273. BAIL_ON_FAILURE(hr = Write(XML_STYLESHEET_REF));
  274. BAIL_ON_FAILURE(hr = Write(xslRef, TRUE));
  275. BAIL_ON_FAILURE(hr = WriteLine(XML_STYLESHEET_REF_END));
  276. }
  277. BAIL_ON_FAILURE(hr = WriteLine(DSML_NAMESPACE));
  278. RRETURN(S_OK);
  279. error:
  280. RRETURN(hr);
  281. }
  282. //----------------------------------------------------------------------------
  283. // Function: WriteXMLFooter
  284. //
  285. // Synopsis: Closes the XML document with the appropriate tag.
  286. //
  287. // Arguments:
  288. //
  289. // Returns: S_OK on success, error otherwise.
  290. //
  291. // Modifies: Nothing
  292. //
  293. //----------------------------------------------------------------------------
  294. HRESULT CADsXML::WriteXMLFooter(void)
  295. {
  296. HRESULT hr = S_OK;
  297. hr = WriteLine(XML_FOOTER);
  298. BAIL_ON_FAILURE(hr);
  299. RRETURN(S_OK);
  300. error:
  301. RRETURN(hr);
  302. }
  303. //----------------------------------------------------------------------------
  304. // Function: OutputSchema
  305. //
  306. // Synopsis: Writes the schema to the output stream
  307. //
  308. // Arguments:
  309. //
  310. // Returns: S_OK on success, error otherwise.
  311. //
  312. // Modifies: Nothing
  313. //
  314. //----------------------------------------------------------------------------
  315. HRESULT CADsXML::OutputSchema(void)
  316. {
  317. HRESULT hr = S_OK;
  318. IADsObjectOptions *pObjOpt = NULL;
  319. VARIANT vServer, vSchemaPath;
  320. LPWSTR pszRootDSEPath = NULL, pszSchemaPath = NULL;
  321. IADs *pIADs = NULL;
  322. IDirectorySearch *pSearch = NULL;
  323. ADS_SEARCHPREF_INFO searchPrefs[2];
  324. ADS_SEARCH_HANDLE hSearch=NULL;
  325. LPWSTR pszUserName = NULL, pszPasswd = NULL;
  326. VariantInit(&vServer);
  327. VariantInit(&vSchemaPath);
  328. hr = _pUnkOuter->QueryInterface(
  329. IID_IADsObjectOptions,
  330. (void **) &pObjOpt
  331. );
  332. BAIL_ON_FAILURE(hr);
  333. hr = pObjOpt->GetOption(ADS_OPTION_SERVERNAME, &vServer);
  334. BAIL_ON_FAILURE(hr);
  335. pszRootDSEPath = (LPWSTR) AllocADsMem((wcslen(V_BSTR(&vServer))
  336. + wcslen(L"LDAP://")
  337. + wcslen(L"/RootDSE") + 1) * 2);
  338. wcscpy(pszRootDSEPath, L"LDAP://");
  339. wcscat(pszRootDSEPath, V_BSTR(&vServer));
  340. wcscat(pszRootDSEPath, L"/RootDSE");
  341. hr = ADsOpenObject(
  342. pszRootDSEPath,
  343. NULL,
  344. NULL,
  345. 0,
  346. IID_IADs,
  347. (void **) &pIADs
  348. );
  349. BAIL_ON_FAILURE(hr);
  350. hr = pIADs->Get(L"schemanamingcontext", &vSchemaPath);
  351. BAIL_ON_FAILURE(hr);
  352. pszSchemaPath = (LPWSTR) AllocADsMem((wcslen(V_BSTR(&vSchemaPath)) +
  353. wcslen(L"LDAP://") + wcslen(V_BSTR(&vServer)) +
  354. 2) * 2);
  355. wcscpy(pszSchemaPath, L"LDAP://");
  356. wcscat(pszSchemaPath, V_BSTR(&vServer));
  357. wcscat(pszSchemaPath, L"/");
  358. wcscat(pszSchemaPath, V_BSTR(&vSchemaPath));
  359. hr = m_pCredentials->GetUserName(&pszUserName);
  360. BAIL_ON_FAILURE(hr);
  361. hr = m_pCredentials->GetPassword(&pszPasswd);
  362. BAIL_ON_FAILURE(hr);
  363. hr = ADsOpenObject(
  364. pszSchemaPath,
  365. pszUserName,
  366. pszPasswd,
  367. m_dwAuthFlags,
  368. IID_IDirectorySearch,
  369. (void **) &pSearch
  370. );
  371. BAIL_ON_FAILURE(hr);
  372. // set the preferences for the search
  373. searchPrefs[0].dwSearchPref = ADS_SEARCHPREF_PAGESIZE;
  374. searchPrefs[0].vValue.dwType = ADSTYPE_INTEGER;
  375. searchPrefs[0].vValue.Integer = SCHEMA_PAGE_SIZE;
  376. searchPrefs[1].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
  377. searchPrefs[1].vValue.dwType = ADSTYPE_INTEGER;
  378. searchPrefs[1].vValue.Integer = ADS_SCOPE_ONELEVEL;
  379. hr = pSearch->SetSearchPreference(searchPrefs, 2);
  380. BAIL_ON_FAILURE(hr);
  381. hr = pSearch->ExecuteSearch(
  382. SCHEMA_FILTER,
  383. g_SchemaAttrs,
  384. g_dwNumSchemaAttrs,
  385. &hSearch
  386. );
  387. BAIL_ON_FAILURE(hr);
  388. //
  389. // if the search returned no results and the user requested schema to be
  390. // returned, return an error.
  391. //
  392. hr = pSearch->GetFirstRow(hSearch);
  393. BAIL_ON_FAILURE(hr);
  394. if(S_ADS_NOMORE_ROWS == hr) {
  395. BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED));
  396. }
  397. hr = OutputSchemaHeader();
  398. BAIL_ON_FAILURE(hr);
  399. while(hr != S_ADS_NOMORE_ROWS) {
  400. hr = OutputClassHeader(hSearch, pSearch);
  401. BAIL_ON_FAILURE(hr);
  402. hr = OutputClassAttrs(hSearch, pSearch);
  403. BAIL_ON_FAILURE(hr);
  404. hr = OutputClassFooter();
  405. BAIL_ON_FAILURE(hr);
  406. hr = pSearch->GetNextRow(hSearch);
  407. BAIL_ON_FAILURE(hr);
  408. }
  409. hr = OutputSchemaFooter();
  410. BAIL_ON_FAILURE(hr);
  411. error:
  412. if(pszUserName != NULL)
  413. FreeADsStr(pszUserName);
  414. if(pszPasswd != NULL)
  415. FreeADsStr(pszPasswd);
  416. if(pObjOpt != NULL)
  417. pObjOpt->Release();
  418. VariantClear(&vServer);
  419. VariantClear(&vSchemaPath);
  420. if(pszRootDSEPath != NULL)
  421. FreeADsMem(pszRootDSEPath);
  422. if(pszSchemaPath != NULL)
  423. FreeADsMem(pszSchemaPath);
  424. if(pIADs != NULL)
  425. pIADs->Release();
  426. if(hSearch != NULL)
  427. pSearch->CloseSearchHandle(hSearch);
  428. if(pSearch != NULL)
  429. pSearch->Release();
  430. RRETURN(hr);
  431. }
  432. //----------------------------------------------------------------------------
  433. // Function: OutputSchemaHeader
  434. //
  435. // Synopsis: Writes the schema tag to the output stream
  436. //
  437. // Arguments:
  438. //
  439. // Returns: S_OK on success, error otherwise.
  440. //
  441. // Modifies: Nothing
  442. //
  443. //----------------------------------------------------------------------------
  444. HRESULT CADsXML::OutputSchemaHeader(void)
  445. {
  446. HRESULT hr = S_OK;
  447. hr = WriteLine(DSML_SCHEMA_TAG);
  448. RRETURN(hr);
  449. }
  450. //----------------------------------------------------------------------------
  451. // Function: OutputClassHeader
  452. //
  453. // Synopsis: Writes class the and attributes to the output.
  454. //
  455. // Arguments:
  456. //
  457. // hSearch Handle returned by IDirectorySearch
  458. // pSearch IDirectorySearch interface
  459. //
  460. // Returns: S_OK on success, error otherwise.
  461. //
  462. // Modifies: Nothing
  463. //
  464. //----------------------------------------------------------------------------
  465. HRESULT CADsXML::OutputClassHeader(
  466. ADS_SEARCH_HANDLE hSearch,
  467. IDirectorySearch *pSearch
  468. )
  469. {
  470. ADS_SEARCH_COLUMN column;
  471. LPWSTR pszName = NULL;
  472. HRESULT hr = S_OK;
  473. hr = Write(DSML_CLASS_TAG);
  474. BAIL_ON_FAILURE(hr);
  475. hr = Write(L"id =\"");
  476. BAIL_ON_FAILURE(hr);
  477. hr = pSearch->GetColumn(hSearch, LDAP_DISPLAY_NAME, &column);
  478. BAIL_ON_FAILURE(hr);
  479. hr = Write(column.pADsValues->CaseIgnoreString, TRUE);
  480. pszName = AllocADsStr(column.pADsValues->CaseIgnoreString);
  481. if(NULL == pszName) {
  482. hr = E_OUTOFMEMORY;
  483. }
  484. pSearch->FreeColumn(&column);
  485. BAIL_ON_FAILURE(hr);
  486. hr = Write(L"\" ");
  487. BAIL_ON_FAILURE(hr);
  488. hr = Write(L"sup = \"");
  489. BAIL_ON_FAILURE(hr);
  490. hr = pSearch->GetColumn(hSearch, SUBCLASSOF, &column);
  491. BAIL_ON_FAILURE(hr);
  492. hr = Write(column.pADsValues->CaseIgnoreString, TRUE);
  493. pSearch->FreeColumn(&column);
  494. BAIL_ON_FAILURE(hr);
  495. hr = Write(L"\" ");
  496. BAIL_ON_FAILURE(hr);
  497. hr = Write(L"type = \"");
  498. BAIL_ON_FAILURE(hr);
  499. hr = pSearch->GetColumn(hSearch, TYPE, &column);
  500. BAIL_ON_FAILURE(hr);
  501. switch(column.pADsValues->Integer) {
  502. case 1:
  503. hr = Write(L"structural");
  504. break;
  505. case 2:
  506. hr = Write(L"abstract");
  507. break;
  508. case 3:
  509. hr = Write(L"auxiliary");
  510. break;
  511. }
  512. pSearch->FreeColumn(&column);
  513. BAIL_ON_FAILURE(hr);
  514. hr = WriteLine(L"\">");
  515. BAIL_ON_FAILURE(hr);
  516. hr = Write(NAME_TAG);
  517. BAIL_ON_FAILURE(hr);
  518. hr = Write(pszName, TRUE);
  519. BAIL_ON_FAILURE(hr);
  520. hr = WriteLine(NAME_TAG_CLOSE);
  521. BAIL_ON_FAILURE(hr);
  522. hr = Write(DESC_TAG);
  523. BAIL_ON_FAILURE(hr);
  524. hr = pSearch->GetColumn(hSearch, DESCRIPTION, & column);
  525. BAIL_ON_FAILURE(hr);
  526. hr = Write(column.pADsValues->CaseIgnoreString, TRUE);
  527. pSearch->FreeColumn(&column);
  528. BAIL_ON_FAILURE(hr);
  529. hr = WriteLine(DESC_TAG_CLOSE);
  530. BAIL_ON_FAILURE(hr);
  531. hr = Write(OID_TAG);
  532. BAIL_ON_FAILURE(hr);
  533. hr = pSearch->GetColumn(hSearch, OID, &column);
  534. BAIL_ON_FAILURE(hr);
  535. hr = Write(column.pADsValues->CaseIgnoreString, TRUE);
  536. pSearch->FreeColumn(&column);
  537. BAIL_ON_FAILURE(hr);
  538. hr = WriteLine(OID_TAG_CLOSE);
  539. BAIL_ON_FAILURE(hr);
  540. error:
  541. if(pszName)
  542. FreeADsStr(pszName);
  543. RRETURN(hr);
  544. }
  545. //----------------------------------------------------------------------------
  546. // Function: OutputClassAttrs
  547. //
  548. // Synopsis: Writes the names of the attributes of a class and whether
  549. // they are mandatory or not.
  550. //
  551. // Arguments:
  552. //
  553. // hSearch Handle returned by IDirectorySearch
  554. // pSearch IDirectorySearch interface
  555. //
  556. // Returns: S_OK on success, error otherwise.
  557. //
  558. // Modifies: Nothing
  559. //
  560. //----------------------------------------------------------------------------
  561. HRESULT CADsXML::OutputClassAttrs(
  562. ADS_SEARCH_HANDLE hSearch,
  563. IDirectorySearch *pSearch
  564. )
  565. {
  566. HRESULT hr = S_OK;
  567. hr = OutputAttrs(hSearch, pSearch, MUST_CONTAIN, TRUE);
  568. if(E_ADS_COLUMN_NOT_SET == hr)
  569. hr = S_OK;
  570. BAIL_ON_FAILURE(hr);
  571. hr = OutputAttrs(hSearch, pSearch, SYSTEM_MUST_CONTAIN, TRUE);
  572. if(E_ADS_COLUMN_NOT_SET == hr)
  573. hr = S_OK;
  574. BAIL_ON_FAILURE(hr);
  575. hr = OutputAttrs(hSearch, pSearch, MAY_CONTAIN, FALSE);
  576. if(E_ADS_COLUMN_NOT_SET == hr)
  577. hr = S_OK;
  578. BAIL_ON_FAILURE(hr);
  579. hr = OutputAttrs(hSearch, pSearch, SYSTEM_MAY_CONTAIN, FALSE);
  580. if(E_ADS_COLUMN_NOT_SET == hr)
  581. hr = S_OK;
  582. BAIL_ON_FAILURE(hr);
  583. error:
  584. RRETURN(hr);
  585. }
  586. //----------------------------------------------------------------------------
  587. // Function: OutputAttrs
  588. //
  589. // Synopsis: Writes the names of the attributes.
  590. //
  591. // Arguments:
  592. //
  593. // hSearch Handle returned by IDirectorySearch
  594. // pSearch IDirectorySearch interface
  595. // pszAttrName Name of the attribute in the class schema object
  596. // fMandatory Indicates if the attributes are mandatory or not
  597. //
  598. // Returns: S_OK on success, error otherwise.
  599. //
  600. // Modifies: Nothing
  601. //
  602. //----------------------------------------------------------------------------
  603. HRESULT CADsXML::OutputAttrs(
  604. ADS_SEARCH_HANDLE hSearch,
  605. IDirectorySearch *pSearch,
  606. LPWSTR pszAttrName,
  607. BOOL fMandatory
  608. )
  609. {
  610. HRESULT hr = S_OK;
  611. ADS_SEARCH_COLUMN column;
  612. DWORD i = 0;
  613. BOOL fFreeCols = FALSE;
  614. hr = pSearch->GetColumn(hSearch, pszAttrName, &column);
  615. BAIL_ON_FAILURE(hr);
  616. fFreeCols = TRUE;
  617. for(i = 0; i < column.dwNumValues; i++) {
  618. hr = Write(DSML_ATTR_TAG);
  619. BAIL_ON_FAILURE(hr);
  620. hr = Write(column.pADsValues[i].CaseIgnoreString, TRUE);
  621. BAIL_ON_FAILURE(hr);
  622. hr = Write(L"\" required=\"");
  623. BAIL_ON_FAILURE(hr);
  624. if(fMandatory)
  625. hr = Write(L"true");
  626. else
  627. hr = Write(L"false");
  628. BAIL_ON_FAILURE(hr);
  629. hr = WriteLine(L"\"/>");
  630. }
  631. error:
  632. if(fFreeCols)
  633. pSearch->FreeColumn(&column);
  634. RRETURN(hr);
  635. }
  636. //----------------------------------------------------------------------------
  637. // Function: OutputClassFooter
  638. //
  639. // Synopsis: Writes the end tag for the class
  640. //
  641. // Arguments:
  642. //
  643. // Returns: S_OK on success, error otherwise.
  644. //
  645. // Modifies: Nothing
  646. //
  647. //----------------------------------------------------------------------------
  648. HRESULT CADsXML::OutputClassFooter(void)
  649. {
  650. HRESULT hr = S_OK;
  651. hr = WriteLine(DSML_CLASS_TAG_CLOSE);
  652. RRETURN(hr);
  653. }
  654. //----------------------------------------------------------------------------
  655. // Function: OutputSchemaFooter
  656. //
  657. // Synopsis: Writes the schema end tag to the output stream
  658. //
  659. // Arguments:
  660. //
  661. // Returns: S_OK on success, error otherwise.
  662. //
  663. // Modifies: Nothing
  664. //
  665. //----------------------------------------------------------------------------
  666. HRESULT CADsXML::OutputSchemaFooter(void)
  667. {
  668. HRESULT hr = S_OK;
  669. hr = WriteLine(DSML_SCHEMA_TAG_CLOSE);
  670. RRETURN(hr);
  671. }
  672. //----------------------------------------------------------------------------
  673. // Function: CloseOutputStream
  674. //
  675. // Synopsis: Closes the output stream.
  676. //
  677. // Arguments:
  678. //
  679. // vDest Specifies destination
  680. //
  681. // Returns: S_OK on success, error otherwise.
  682. //
  683. // Modifies: Nothing
  684. //
  685. //----------------------------------------------------------------------------
  686. void CADsXML::CloseOutputStream(void)
  687. {
  688. if(m_hFile != INVALID_HANDLE_VALUE)
  689. CloseHandle(m_hFile);
  690. return;
  691. }
  692. //----------------------------------------------------------------------------
  693. // Function: Write
  694. //
  695. // Synopsis: Writes text to the output. Does not append newline.
  696. //
  697. //
  698. // szStr String to write to the output.
  699. // fEscape Indicates if string should be escaped ot not. FALSE by default.
  700. //
  701. // Returns: S_OK on success, error otherwise.
  702. //
  703. // Modifies: Nothing
  704. //
  705. //----------------------------------------------------------------------------
  706. HRESULT CADsXML::Write(LPWSTR szStr, BOOL fEscape)
  707. {
  708. BOOL bRetVal = 0;
  709. DWORD dwNumBytesWritten = 0;
  710. HRESULT hr = S_OK;
  711. LPWSTR pszEscapedStr = NULL;
  712. int i = 0, j = 0;
  713. WCHAR wc;
  714. ADsAssert(szStr != NULL);
  715. if(TRUE == fEscape) {
  716. pszEscapedStr = (LPWSTR) AllocADsMem(2*(wcslen(szStr)*6 + 1));
  717. if(NULL == pszEscapedStr) {
  718. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  719. }
  720. }
  721. else
  722. pszEscapedStr = szStr;
  723. for(i = 0; (TRUE == fEscape) && (szStr[i] != L'\0'); i++) {
  724. switch(szStr[i]) {
  725. case L'<':
  726. pszEscapedStr[j++] = L'&';
  727. pszEscapedStr[j++] = L'l';
  728. pszEscapedStr[j++] = L't';
  729. pszEscapedStr[j++] = L';';
  730. break;
  731. case L'>':
  732. pszEscapedStr[j++] = L'&';
  733. pszEscapedStr[j++] = L'g';
  734. pszEscapedStr[j++] = L't';
  735. pszEscapedStr[j++] = L';';
  736. break;
  737. case L'\'':
  738. pszEscapedStr[j++] = L'&';
  739. pszEscapedStr[j++] = L'a';
  740. pszEscapedStr[j++] = L'p';
  741. pszEscapedStr[j++] = L'o';
  742. pszEscapedStr[j++] = L's';
  743. pszEscapedStr[j++] = L';';
  744. break;
  745. case L'"':
  746. pszEscapedStr[j++] = L'&';
  747. pszEscapedStr[j++] = L'q';
  748. pszEscapedStr[j++] = L'u';
  749. pszEscapedStr[j++] = L'o';
  750. pszEscapedStr[j++] = L't';
  751. pszEscapedStr[j++] = L';';
  752. break;
  753. case L'&':
  754. pszEscapedStr[j++] = L'&';
  755. pszEscapedStr[j++] = L'a';
  756. pszEscapedStr[j++] = L'm';
  757. pszEscapedStr[j++] = L'p';
  758. pszEscapedStr[j++] = L';';
  759. break;
  760. default:
  761. pszEscapedStr[j++] = szStr[i];
  762. break;
  763. } // switch
  764. } // for
  765. // pszEscapedStr NULL terminated by AllocADsMem
  766. bRetVal = WriteFile(
  767. m_hFile,
  768. pszEscapedStr,
  769. wcslen(pszEscapedStr)*2,
  770. &dwNumBytesWritten,
  771. NULL
  772. );
  773. if(0 == bRetVal) {
  774. hr = HRESULT_FROM_WIN32(GetLastError());
  775. BAIL_ON_FAILURE(hr);
  776. }
  777. if(dwNumBytesWritten != (wcslen(pszEscapedStr)*2)) {
  778. hr = HRESULT_FROM_WIN32(ERROR_CANT_ACCESS_FILE);
  779. BAIL_ON_FAILURE(hr);
  780. }
  781. error:
  782. if(pszEscapedStr && (pszEscapedStr != szStr))
  783. FreeADsMem(pszEscapedStr);
  784. RRETURN(hr);
  785. }
  786. //----------------------------------------------------------------------------
  787. // Function: WriteLine
  788. //
  789. // Synopsis: Writes text to the output. Appends newline.
  790. //
  791. //
  792. // szStr String to write to the output.
  793. // fEscape Indicates if string should be escaped ot not. FALSE by default.
  794. //
  795. // Returns: S_OK on success, error otherwise.
  796. //
  797. // Modifies: Nothing
  798. //
  799. //----------------------------------------------------------------------------
  800. HRESULT CADsXML::WriteLine(LPWSTR szStr, BOOL fEscape)
  801. {
  802. HRESULT hr = S_OK;
  803. ADsAssert(szStr != NULL);
  804. hr = Write(szStr, fEscape);
  805. BAIL_ON_FAILURE(hr);
  806. hr = Write(L"\n");
  807. BAIL_ON_FAILURE(hr);
  808. error:
  809. RRETURN(hr);
  810. }
  811. //----------------------------------------------------------------------------
  812. // Function: QueryInterface
  813. //
  814. // Synopsis: Queries object for supported interfaces.
  815. //
  816. // Arguments:
  817. //
  818. // iid interface requested
  819. // ppInterface Returns pointer to interface requested. NULL if interface
  820. // is not supported.
  821. //
  822. // Returns: S_OK on success. Error code otherwise.
  823. //
  824. // Modifies: *ppInterface to return interface pointer
  825. //
  826. //----------------------------------------------------------------------------
  827. STDMETHODIMP CADsXML::QueryInterface(
  828. REFIID iid,
  829. LPVOID *ppInterface
  830. )
  831. {
  832. HRESULT hr = S_OK;
  833. hr = _pUnkOuter->QueryInterface(iid,ppInterface);
  834. RRETURN(hr);
  835. }
  836. //----------------------------------------------------------------------------
  837. // Function: NonDelegatingQueryInterface
  838. //
  839. // Synopsis: Queries object for supported interfaces.
  840. //
  841. // Arguments:
  842. //
  843. // iid interface requested
  844. // ppInterface Returns pointer to interface requested. NULL if interface
  845. // is not supported.
  846. //
  847. // Returns: S_OK on success. Error code otherwise.
  848. //
  849. // Modifies: *ppInterface to return interface pointer
  850. //
  851. //----------------------------------------------------------------------------
  852. STDMETHODIMP CADsXML::NonDelegatingQueryInterface(
  853. REFIID iid,
  854. LPVOID *ppInterface
  855. )
  856. {
  857. ADsAssert(ppInterface);
  858. if (IsEqualIID(iid, IID_IUnknown))
  859. *ppInterface = (INonDelegatingUnknown FAR *) this;
  860. else if (IsEqualIID(iid, IID_IADsExtension))
  861. *ppInterface = (IADsExtension FAR *) this;
  862. else if (IsEqualIID(iid, IID_IADsXML))
  863. *ppInterface = (IADsXML FAR *) this;
  864. else {
  865. *ppInterface = NULL;
  866. return E_NOINTERFACE;
  867. }
  868. ((IUnknown *) (*ppInterface)) -> AddRef();
  869. return S_OK;
  870. }
  871. //----------------------------------------------------------------------------
  872. // Function: Operate
  873. //
  874. // Synopsis: Implements IADsExtension::Operate.
  875. //
  876. // Arguments:
  877. //
  878. // dwCode Extension control code
  879. // varData1 Username
  880. // varData2 Password
  881. // varData3 User flags
  882. //
  883. // Returns: S_OK on success. Error code otherwise.
  884. //
  885. // Modifies: Nothing.
  886. //
  887. //----------------------------------------------------------------------------
  888. STDMETHODIMP CADsXML::Operate(
  889. THIS_ DWORD dwCode,
  890. VARIANT varData1,
  891. VARIANT varData2,
  892. VARIANT varData3
  893. )
  894. {
  895. HRESULT hr = S_OK;
  896. switch (dwCode) {
  897. case ADS_EXT_INITCREDENTIALS:
  898. ADsAssert(V_VT(&varData1) == VT_BSTR);
  899. ADsAssert(V_VT(&varData2) == VT_BSTR);
  900. ADsAssert(V_VT(&varData3) == VT_I4);
  901. m_pCredentials = new CCredentials(
  902. V_BSTR(&varData1),
  903. V_BSTR(&varData2),
  904. V_I4(&varData3)
  905. );
  906. if(NULL == m_pCredentials)
  907. RRETURN(E_OUTOFMEMORY);
  908. m_dwAuthFlags = V_I4(&varData3);
  909. break;
  910. default:
  911. RRETURN(E_FAIL);
  912. }
  913. RRETURN(S_OK);
  914. }
  915. //----------------------------------------------------------------------------
  916. // Function: OutputData
  917. //
  918. // Synopsis: Outputs data portion of DSML.
  919. //
  920. // Arguments:
  921. //
  922. // szFilter Search filter
  923. // szAttrs Attributes requested
  924. // lScope Search scope
  925. // szOptions Search preferences
  926. //
  927. // Returns: S_OK on success. Error code otherwise.
  928. //
  929. // Modifies: Nothing.
  930. //
  931. //----------------------------------------------------------------------------
  932. HRESULT CADsXML::OutputData(
  933. BSTR szFilter,
  934. BSTR szAttrs,
  935. long lScope,
  936. BSTR szOptions
  937. )
  938. {
  939. HRESULT hr = S_OK;
  940. IDirectorySearch *pSearch = NULL;
  941. LPWSTR *pAttrs = NULL;
  942. DWORD dwNumAttrs = 0, dwNumPrefs = 0;
  943. ADS_SEARCHPREF_INFO *psearchPrefs = NULL, searchPrefs;
  944. ADS_SEARCH_HANDLE hSearch=NULL;
  945. hr = _pUnkOuter->QueryInterface(
  946. IID_IDirectorySearch,
  947. (void **) &pSearch
  948. );
  949. BAIL_ON_FAILURE(hr);
  950. hr = ParseAttrList(
  951. szAttrs,
  952. &pAttrs,
  953. &dwNumAttrs
  954. );
  955. BAIL_ON_FAILURE(hr);
  956. if(szOptions != NULL) {
  957. hr = GetSearchPreferences(&psearchPrefs, &dwNumPrefs, lScope,
  958. szOptions);
  959. BAIL_ON_FAILURE(hr);
  960. }
  961. else {
  962. searchPrefs.dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
  963. searchPrefs.vValue.dwType = ADSTYPE_INTEGER;
  964. searchPrefs.vValue.Integer = lScope;
  965. psearchPrefs = &searchPrefs;
  966. dwNumPrefs = 1;
  967. }
  968. hr = pSearch->SetSearchPreference(psearchPrefs, dwNumPrefs);
  969. BAIL_ON_FAILURE(hr);
  970. hr = pSearch->ExecuteSearch(
  971. szFilter,
  972. pAttrs,
  973. dwNumAttrs,
  974. &hSearch
  975. );
  976. BAIL_ON_FAILURE(hr);
  977. hr = OutputDataHeader();
  978. BAIL_ON_FAILURE(hr);
  979. hr = pSearch->GetFirstRow(hSearch);
  980. BAIL_ON_FAILURE(hr);
  981. while(hr != S_ADS_NOMORE_ROWS) {
  982. hr = OutputEntryHeader(hSearch, pSearch);
  983. BAIL_ON_FAILURE(hr);
  984. hr = OutputEntryAttrs(hSearch, pSearch);
  985. BAIL_ON_FAILURE(hr);
  986. hr = OutputEntryFooter();
  987. BAIL_ON_FAILURE(hr);
  988. hr = pSearch->GetNextRow(hSearch);
  989. BAIL_ON_FAILURE(hr);
  990. }
  991. hr = OutputDataFooter();
  992. BAIL_ON_FAILURE(hr);
  993. error:
  994. if(hSearch != NULL)
  995. pSearch->CloseSearchHandle(hSearch);
  996. if(pSearch != NULL)
  997. pSearch->Release();
  998. if(psearchPrefs && (psearchPrefs != &searchPrefs)) {
  999. FreeSearchPrefInfo(psearchPrefs, dwNumPrefs);
  1000. }
  1001. if(pAttrs != NULL) {
  1002. int i = 0;
  1003. while(i < (int) dwNumAttrs) {
  1004. FreeADsStr(pAttrs[i]);
  1005. i++;
  1006. }
  1007. FreeADsMem(pAttrs);
  1008. }
  1009. RRETURN(hr);
  1010. }
  1011. //---------------------------------------------------------------------------
  1012. // Function: ParseAttrList
  1013. //
  1014. // Synopsis: Parses a single string containing the comm-separated attributes
  1015. // and returns the number of attributes and an array of strings
  1016. // containing teh attributes.
  1017. //
  1018. // Arguments:
  1019. //
  1020. // szAttrs Comma-separated attribute list
  1021. // ppAttrs Returns array of strings with attribute names
  1022. // pdwNumAttrs Returns number of attributes in list
  1023. //
  1024. // Returns: S_OK on success. Error code otherwise.
  1025. //
  1026. // Modifies: Nothing.
  1027. //
  1028. //----------------------------------------------------------------------------
  1029. HRESULT CADsXML::ParseAttrList(
  1030. BSTR szAttrs,
  1031. LPWSTR **ppAttrs,
  1032. DWORD *pdwNumAttrs
  1033. )
  1034. {
  1035. HRESULT hr = S_OK;
  1036. WCHAR *pwChar = NULL;
  1037. DWORD dwNumAttrs = 0;
  1038. DWORD i = 0;
  1039. BOOL fAddDn = TRUE, fAddObjClass = TRUE;
  1040. LPWSTR *pAttrs = NULL;
  1041. ADsAssert(ppAttrs && pdwNumAttrs);
  1042. if(NULL == szAttrs) {
  1043. *ppAttrs = NULL;
  1044. *pdwNumAttrs = -1;
  1045. RRETURN(S_OK);
  1046. }
  1047. pwChar = szAttrs;
  1048. while(pwChar = wcschr(pwChar, L',')) {
  1049. *pwChar = L'\0';
  1050. pwChar++;
  1051. dwNumAttrs++;
  1052. }
  1053. dwNumAttrs++;
  1054. pAttrs = (LPWSTR *) AllocADsMem(sizeof(LPWSTR) * (dwNumAttrs+2));
  1055. if(NULL == pAttrs) {
  1056. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1057. }
  1058. memset(pAttrs, 0, sizeof(LPWSTR) * dwNumAttrs);
  1059. pwChar = szAttrs;
  1060. for(i = 0; i < dwNumAttrs; i++) {
  1061. if(L'\0' == (*pwChar)) {
  1062. BAIL_ON_FAILURE(hr = E_INVALIDARG);
  1063. }
  1064. pAttrs[i] = AllocADsStr(pwChar);
  1065. if(NULL == pAttrs[i]) {
  1066. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1067. }
  1068. if(!_wcsicmp(pwChar, DISTINGUISHED_NAME))
  1069. fAddDn = FALSE;
  1070. else if(!_wcsicmp(pwChar, OBJECT_CLASS))
  1071. fAddObjClass = FALSE;
  1072. pwChar += (wcslen(pwChar) + 1);
  1073. }
  1074. if(fAddDn) {
  1075. pAttrs[dwNumAttrs] = AllocADsStr(DISTINGUISHED_NAME);
  1076. if(NULL == pAttrs[dwNumAttrs]) {
  1077. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1078. }
  1079. dwNumAttrs++;
  1080. }
  1081. if(fAddObjClass) {
  1082. pAttrs[dwNumAttrs] = AllocADsStr(OBJECT_CLASS);
  1083. if(NULL == pAttrs[dwNumAttrs]) {
  1084. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1085. }
  1086. dwNumAttrs++;
  1087. }
  1088. *pdwNumAttrs = dwNumAttrs;
  1089. *ppAttrs = pAttrs;
  1090. RRETURN(S_OK);
  1091. error:
  1092. if(pAttrs != NULL) {
  1093. i = 0;
  1094. while(pAttrs[i]) {
  1095. FreeADsStr(pAttrs[i]);
  1096. i++;
  1097. }
  1098. FreeADsMem(pAttrs);
  1099. }
  1100. RRETURN(hr);
  1101. }
  1102. //----------------------------------------------------------------------------
  1103. // Function: OutputDataHeader
  1104. //
  1105. // Synopsis: Outputs data header
  1106. //
  1107. // Arguments:
  1108. //
  1109. // None.
  1110. //
  1111. // Returns: S_OK on success. Error code otherwise.
  1112. //
  1113. // Modifies: Nothing.
  1114. //
  1115. //----------------------------------------------------------------------------
  1116. HRESULT CADsXML::OutputDataHeader(void)
  1117. {
  1118. HRESULT hr = S_OK;
  1119. hr = WriteLine(DSML_DATA_TAG);
  1120. RRETURN(hr);
  1121. }
  1122. //----------------------------------------------------------------------------
  1123. // Function: OutputEntryHeader
  1124. //
  1125. // Synopsis: Outputs the standar4d DSML header for each entry
  1126. //
  1127. // Arguments:
  1128. //
  1129. // hSearch Handle to search results
  1130. // pSearch IDirectorySearch interface pointer
  1131. //
  1132. // Returns: S_OK on success. Error code otherwise.
  1133. //
  1134. // Modifies: Nothing.
  1135. //
  1136. //----------------------------------------------------------------------------
  1137. HRESULT CADsXML::OutputEntryHeader(
  1138. ADS_SEARCH_HANDLE hSearch,
  1139. IDirectorySearch *pSearch
  1140. )
  1141. {
  1142. HRESULT hr = S_OK;
  1143. ADS_SEARCH_COLUMN column;
  1144. DWORD i = 0;
  1145. BOOL fFreeCols = FALSE;
  1146. hr = Write(DSML_ENTRY_TAG);
  1147. BAIL_ON_FAILURE(hr);
  1148. hr = Write(L"dn=\"");
  1149. BAIL_ON_FAILURE(hr);
  1150. hr = pSearch->GetColumn(hSearch, DISTINGUISHED_NAME, &column);
  1151. BAIL_ON_FAILURE(hr);
  1152. hr = Write(column.pADsValues->CaseIgnoreString, TRUE);
  1153. pSearch->FreeColumn(&column);
  1154. BAIL_ON_FAILURE(hr);
  1155. hr = WriteLine(L"\">");
  1156. BAIL_ON_FAILURE(hr);
  1157. hr = WriteLine(DSML_OBJECTCLASS_TAG);
  1158. BAIL_ON_FAILURE(hr);
  1159. hr = pSearch->GetColumn(hSearch, OBJECT_CLASS, &column);
  1160. BAIL_ON_FAILURE(hr);
  1161. fFreeCols = TRUE;
  1162. for(i = 0; i < column.dwNumValues; i++) {
  1163. hr = Write(DSML_OCVALUE_TAG);
  1164. BAIL_ON_FAILURE(hr);
  1165. hr = Write(column.pADsValues[i].CaseIgnoreString, TRUE);
  1166. BAIL_ON_FAILURE(hr);
  1167. hr = WriteLine(DSML_OCVALUE_TAG_CLOSE);
  1168. BAIL_ON_FAILURE(hr);
  1169. }
  1170. hr = WriteLine(DSML_OBJECTCLASS_TAG_CLOSE);
  1171. BAIL_ON_FAILURE(hr);
  1172. error:
  1173. if(fFreeCols)
  1174. pSearch->FreeColumn(&column);
  1175. RRETURN(hr);
  1176. }
  1177. //----------------------------------------------------------------------------
  1178. // Function: OutputEntryAttrs
  1179. //
  1180. // Synopsis: Outputs the attributes that were requested for each entry.
  1181. //
  1182. // Arguments:
  1183. //
  1184. // hSearch Handle to search results
  1185. // pSearch IDirectorySearch interface pointer
  1186. //
  1187. // Returns: S_OK on success. Error code otherwise.
  1188. //
  1189. // Modifies: Nothing.
  1190. //
  1191. //----------------------------------------------------------------------------
  1192. HRESULT CADsXML::OutputEntryAttrs(
  1193. ADS_SEARCH_HANDLE hSearch,
  1194. IDirectorySearch *pSearch
  1195. )
  1196. {
  1197. HRESULT hr = S_OK;
  1198. LPWSTR pszColumnName = NULL;
  1199. ADS_SEARCH_COLUMN column;
  1200. BOOL fFreeCols = FALSE;
  1201. hr = pSearch->GetNextColumnName(hSearch, &pszColumnName);
  1202. BAIL_ON_FAILURE(hr);
  1203. while(hr != S_ADS_NOMORE_COLUMNS) {
  1204. if(_wcsicmp(pszColumnName, DISTINGUISHED_NAME) &&
  1205. _wcsicmp(pszColumnName, OBJECT_CLASS)) {
  1206. hr = pSearch->GetColumn(
  1207. hSearch,
  1208. pszColumnName,
  1209. &column
  1210. );
  1211. BAIL_ON_FAILURE(hr);
  1212. fFreeCols = TRUE;
  1213. hr = Write(DSML_ENTRY_ATTR_TAG);
  1214. BAIL_ON_FAILURE(hr);
  1215. hr = Write(L" name=\"");
  1216. BAIL_ON_FAILURE(hr);
  1217. hr = Write(pszColumnName, TRUE);
  1218. BAIL_ON_FAILURE(hr);
  1219. if( (column.dwNumValues > 1) ||
  1220. (ADSTYPE_OCTET_STRING == column.dwADsType) ||
  1221. (ADSTYPE_NT_SECURITY_DESCRIPTOR == column.dwADsType) ||
  1222. (ADSTYPE_PROV_SPECIFIC == column.dwADsType) ) {
  1223. hr = WriteLine(L"\">");
  1224. }
  1225. else
  1226. hr = Write(L"\">");
  1227. BAIL_ON_FAILURE(hr);
  1228. hr = OutputValue(&column);
  1229. BAIL_ON_FAILURE(hr);
  1230. pSearch->FreeColumn(&column);
  1231. fFreeCols = FALSE;
  1232. hr = WriteLine(DSML_ENTRY_ATTR_TAG_CLOSE);
  1233. BAIL_ON_FAILURE(hr);
  1234. } // if
  1235. FreeADsMem(pszColumnName);
  1236. pszColumnName = NULL;
  1237. hr = pSearch->GetNextColumnName(hSearch, &pszColumnName);
  1238. BAIL_ON_FAILURE(hr);
  1239. }
  1240. error:
  1241. if(fFreeCols)
  1242. pSearch->FreeColumn(&column);
  1243. if(pszColumnName != NULL)
  1244. FreeADsMem(pszColumnName);
  1245. RRETURN(hr);
  1246. }
  1247. //----------------------------------------------------------------------------
  1248. // Function: OutputValue
  1249. //
  1250. // Synopsis: Outputs the value of an attribute
  1251. //
  1252. // Arguments:
  1253. //
  1254. // pColumn Attribute returned by IDirectorySearch
  1255. //
  1256. // Returns: S_OK on success. Error code otherwise.
  1257. //
  1258. // Modifies: Nothing.
  1259. //
  1260. //----------------------------------------------------------------------------
  1261. HRESULT CADsXML::OutputValue(ADS_SEARCH_COLUMN *pColumn)
  1262. {
  1263. HRESULT hr = S_OK;
  1264. DWORD i = 0;
  1265. WCHAR NumBuffer[256], pszTmp[256];;
  1266. DWORD dwLength = 0;
  1267. LPBYTE lpByte = NULL;
  1268. LPWSTR pszBase64Str = NULL;
  1269. int inBytes = 0, outBytes = 0, ret;
  1270. ADsAssert(pColumn);
  1271. for(i = 0; i < pColumn->dwNumValues; i++) {
  1272. switch(pColumn->dwADsType) {
  1273. case ADSTYPE_DN_STRING:
  1274. hr = Write(DSML_VALUE_TAG);
  1275. BAIL_ON_FAILURE(hr);
  1276. hr = Write(pColumn->pADsValues[i].DNString, TRUE);
  1277. break;
  1278. case ADSTYPE_CASE_EXACT_STRING:
  1279. hr = Write(DSML_VALUE_TAG);
  1280. BAIL_ON_FAILURE(hr);
  1281. hr = Write(pColumn->pADsValues[i].CaseExactString, TRUE);
  1282. break;
  1283. case ADSTYPE_CASE_IGNORE_STRING:
  1284. hr = Write(DSML_VALUE_TAG);
  1285. BAIL_ON_FAILURE(hr);
  1286. hr = Write(pColumn->pADsValues[i].CaseIgnoreString, TRUE);
  1287. break;
  1288. case ADSTYPE_PRINTABLE_STRING:
  1289. hr = Write(DSML_VALUE_TAG);
  1290. BAIL_ON_FAILURE(hr);
  1291. hr = Write(pColumn->pADsValues[i].PrintableString, TRUE);
  1292. break;
  1293. case ADSTYPE_NUMERIC_STRING:
  1294. hr = Write(DSML_VALUE_TAG);
  1295. BAIL_ON_FAILURE(hr);
  1296. hr = Write(pColumn->pADsValues[i].NumericString, TRUE);
  1297. break;
  1298. case ADSTYPE_BOOLEAN:
  1299. hr = Write(DSML_VALUE_TAG);
  1300. BAIL_ON_FAILURE(hr);
  1301. if(pColumn->pADsValues[i].Boolean)
  1302. hr = Write(L"true");
  1303. else
  1304. hr = Write(L"false");
  1305. break;
  1306. case ADSTYPE_INTEGER:
  1307. hr = Write(DSML_VALUE_TAG);
  1308. BAIL_ON_FAILURE(hr);
  1309. _itow(pColumn->pADsValues[i].Integer, NumBuffer, 10);
  1310. hr = Write(NumBuffer);
  1311. break;
  1312. case ADSTYPE_OCTET_STRING:
  1313. case ADSTYPE_PROV_SPECIFIC:
  1314. case ADSTYPE_NT_SECURITY_DESCRIPTOR:
  1315. hr = WriteLine(DSML_VALUE_ENCODING_TAG);
  1316. BAIL_ON_FAILURE(hr);
  1317. if(ADSTYPE_OCTET_STRING == pColumn->dwADsType) {
  1318. dwLength = pColumn->pADsValues[i].OctetString.dwLength;
  1319. lpByte = pColumn->pADsValues[i].OctetString.lpValue;
  1320. }
  1321. else if(ADSTYPE_PROV_SPECIFIC == pColumn->dwADsType) {
  1322. dwLength =
  1323. pColumn->pADsValues[i].ProviderSpecific.dwLength;
  1324. lpByte = pColumn->pADsValues[i].ProviderSpecific.lpValue;
  1325. }
  1326. else if(ADSTYPE_NT_SECURITY_DESCRIPTOR == pColumn->dwADsType) {
  1327. dwLength =
  1328. pColumn->pADsValues[i].SecurityDescriptor.dwLength;
  1329. lpByte = pColumn->pADsValues[i].SecurityDescriptor.lpValue;
  1330. }
  1331. //
  1332. // base64 encoding requires about 4/3 the size of the octet
  1333. // string. Approximate to twice the size. Since we are
  1334. // converting to WCHAR, need 4 times as much space.
  1335. //
  1336. pszBase64Str = (LPWSTR) AllocADsMem(2*(2*dwLength + 1));
  1337. if(NULL == pszBase64Str) {
  1338. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1339. }
  1340. inBytes = dwLength;
  1341. outBytes = 2*dwLength + 1;
  1342. ret = encodeBase64Buffer(
  1343. (char *) lpByte,
  1344. &inBytes,
  1345. pszBase64Str,
  1346. &outBytes,
  1347. LINE_LENGTH
  1348. );
  1349. if( (-1 == ret) || (inBytes != (int) dwLength) ) {
  1350. FreeADsMem(pszBase64Str);
  1351. BAIL_ON_FAILURE(hr = E_ADS_CANT_CONVERT_DATATYPE);
  1352. }
  1353. // base64 string need not be escaped
  1354. hr = WriteLine(pszBase64Str);
  1355. BAIL_ON_FAILURE(hr);
  1356. FreeADsMem(pszBase64Str);
  1357. break;
  1358. case ADSTYPE_UTC_TIME:
  1359. WCHAR pszTime[256];
  1360. SYSTEMTIME *pst;
  1361. hr = Write(DSML_VALUE_TAG);
  1362. BAIL_ON_FAILURE(hr);
  1363. pst = &(pColumn->pADsValues[i].UTCTime);
  1364. wsprintf(pszTime, L"%02d%02d%02d%02d%02d%02dZ",
  1365. pst->wYear % 100, pst->wMonth, pst->wDay,
  1366. pst->wHour, pst->wMinute, pst->wSecond);
  1367. hr = Write(pszTime);
  1368. BAIL_ON_FAILURE(hr);
  1369. break;
  1370. case ADSTYPE_LARGE_INTEGER:
  1371. LARGE_INTEGER *pLargeInt;
  1372. hr = Write(DSML_VALUE_TAG);
  1373. BAIL_ON_FAILURE(hr);
  1374. pLargeInt = &(pColumn->pADsValues[i].LargeInteger);
  1375. swprintf(NumBuffer, L"%I64d", *pLargeInt);
  1376. hr = Write(NumBuffer);
  1377. BAIL_ON_FAILURE(hr);
  1378. break;
  1379. case ADSTYPE_DN_WITH_BINARY:
  1380. ADS_DN_WITH_BINARY *pDnBin;
  1381. LPWSTR pszBinaryVal;
  1382. hr = Write(DSML_VALUE_TAG);
  1383. BAIL_ON_FAILURE(hr);
  1384. pDnBin = pColumn->pADsValues[i].pDNWithBinary;
  1385. swprintf(pszTmp, L"B:%d:", pDnBin->dwLength*2);
  1386. hr = Write(pszTmp);
  1387. BAIL_ON_FAILURE(hr);
  1388. pszBinaryVal = (LPWSTR)AllocADsMem(2*(pDnBin->dwLength*2 + 2));
  1389. if(NULL == pszBinaryVal) {
  1390. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1391. }
  1392. for(i = 0; i < pDnBin->dwLength; i++)
  1393. swprintf(pszBinaryVal+(i*2), L"%02x",
  1394. pDnBin->lpBinaryValue[i]);
  1395. wcscat(pszBinaryVal, L":");
  1396. hr = Write(pszBinaryVal);
  1397. FreeADsMem(pszBinaryVal);
  1398. BAIL_ON_FAILURE(hr);
  1399. hr = Write(pDnBin->pszDNString, TRUE);
  1400. BAIL_ON_FAILURE(hr);
  1401. break;
  1402. case ADSTYPE_DN_WITH_STRING:
  1403. ADS_DN_WITH_STRING *pDnStr;
  1404. hr = Write(DSML_VALUE_TAG);
  1405. BAIL_ON_FAILURE(hr);
  1406. pDnStr = pColumn->pADsValues[i].pDNWithString;
  1407. swprintf(pszTmp, L"S:%d:", wcslen(pDnStr->pszStringValue));
  1408. hr = Write(pszTmp);
  1409. BAIL_ON_FAILURE(hr);
  1410. hr = Write(pDnStr->pszStringValue, TRUE);
  1411. BAIL_ON_FAILURE(hr);
  1412. hr = Write(L":");
  1413. BAIL_ON_FAILURE(hr);
  1414. hr = Write(pDnStr->pszDNString, TRUE);
  1415. BAIL_ON_FAILURE(hr);
  1416. break;
  1417. default:
  1418. BAIL_ON_FAILURE(hr = E_ADS_CANT_CONVERT_DATATYPE);
  1419. break;
  1420. }
  1421. BAIL_ON_FAILURE(hr);
  1422. if( (pColumn->dwNumValues > 1) ||
  1423. (ADSTYPE_OCTET_STRING == pColumn->dwADsType) ||
  1424. (ADSTYPE_NT_SECURITY_DESCRIPTOR == pColumn->dwADsType) ||
  1425. (ADSTYPE_PROV_SPECIFIC == pColumn->dwADsType) ) {
  1426. hr = WriteLine(DSML_VALUE_TAG_CLOSE);
  1427. }
  1428. else
  1429. hr = Write(DSML_VALUE_TAG_CLOSE);
  1430. BAIL_ON_FAILURE(hr);
  1431. }
  1432. error:
  1433. RRETURN(hr);
  1434. }
  1435. //----------------------------------------------------------------------------
  1436. // Function: OutputEntryFooter
  1437. //
  1438. // Synopsis: Outputs the DSML footer for an entry
  1439. //
  1440. // Arguments:
  1441. //
  1442. // None
  1443. //
  1444. // Returns: S_OK on success. Error code otherwise.
  1445. //
  1446. // Modifies: Nothing.
  1447. //
  1448. //----------------------------------------------------------------------------
  1449. HRESULT CADsXML::OutputEntryFooter(void)
  1450. {
  1451. HRESULT hr = S_OK;
  1452. hr = WriteLine(DSML_ENTRY_TAG_CLOSE);
  1453. RRETURN(hr);
  1454. }
  1455. //----------------------------------------------------------------------------
  1456. // Function: OutputDataFooter
  1457. //
  1458. // Synopsis: Outputs the DSML footer for all data
  1459. //
  1460. // Arguments:
  1461. //
  1462. // None
  1463. //
  1464. // Returns: S_OK on success. Error code otherwise.
  1465. //
  1466. // Modifies: Nothing.
  1467. //
  1468. //----------------------------------------------------------------------------
  1469. HRESULT CADsXML::OutputDataFooter(void)
  1470. {
  1471. HRESULT hr = S_OK;
  1472. hr = WriteLine(DSML_DATA_TAG_CLOSE);
  1473. RRETURN(hr);
  1474. }
  1475. //----------------------------------------------------------------------------
  1476. // Function: RemoveWhiteSpace
  1477. //
  1478. // Synopsis: Remove all leading and trailing white space in every attribute
  1479. // of comma-separated attribute list
  1480. //
  1481. // Arguments:
  1482. //
  1483. // pszStr Comma-separated attribute list
  1484. //
  1485. // Returns: String with white spaces removed as mentioned above. NULL on
  1486. // error.
  1487. //
  1488. // Modifies: Nothing.
  1489. //
  1490. //----------------------------------------------------------------------------
  1491. LPWSTR CADsXML::RemoveWhiteSpace(BSTR pszStr)
  1492. {
  1493. LPWSTR pszNewStr = NULL;
  1494. int i,j, k;
  1495. WCHAR prevChar = L',';
  1496. ADsAssert(pszStr != NULL);
  1497. pszNewStr = AllocADsStr(pszStr);
  1498. if(NULL == pszNewStr)
  1499. return NULL;
  1500. for(i = 0, j = 0; i < (int) wcslen(pszStr); i++) {
  1501. if(iswspace(pszStr[i]) && (L',' == prevChar) )
  1502. continue;
  1503. prevChar = pszNewStr[j] = pszStr[i];
  1504. if(L',' == prevChar) {
  1505. k = j - 1;
  1506. while( (k >= 0) && (iswspace(pszNewStr[k])) )
  1507. k--;
  1508. j = k+1;
  1509. pszNewStr[j] = pszStr[i];
  1510. }
  1511. j++;
  1512. }
  1513. k = j - 1;
  1514. while( (k >= 0) && (iswspace(pszNewStr[k])) )
  1515. k--;
  1516. j = k+1;
  1517. pszNewStr[j] = L'\0';
  1518. return pszNewStr;
  1519. }
  1520. //----------------------------------------------------------------------------
  1521. // Function: ReduceWhiteSpace
  1522. //
  1523. // Synopsis: Removes white spaces from te string containing search prefs as
  1524. // follows. No white spaces are allowed before or immediately after
  1525. // an = sign. Each search preference is reduced to having at most
  1526. // one space in it i.e, "\t\tsort on = cn; timeout= 10" will
  1527. // be reduced to "sort on=cn;timeout=10"
  1528. //
  1529. // Arguments:
  1530. //
  1531. // pszStr String containing search prefs
  1532. //
  1533. // Returns: Reduced string. NULL on error.
  1534. //
  1535. // Modifies: Nothing.
  1536. //
  1537. //----------------------------------------------------------------------------
  1538. LPWSTR CADsXML::ReduceWhiteSpace(BSTR pszStr)
  1539. {
  1540. int i = 0, j = 0;
  1541. LPWSTR pszNewStr = NULL;
  1542. ADsAssert(pszStr != NULL);
  1543. pszNewStr = (LPWSTR) AllocADsMem(wcslen(pszStr)*2+2);
  1544. if(NULL == pszNewStr)
  1545. return NULL;
  1546. while(iswspace(pszStr[i]))
  1547. i++;
  1548. if(L'\0' == pszStr[i])
  1549. return pszNewStr;
  1550. while(1) {
  1551. pszNewStr[j] = pszStr[i];
  1552. if(L'\0' == pszStr[i]) {
  1553. if( (j != 0) && (pszNewStr[j-1] == L' ') )
  1554. pszNewStr[j-1] = pszStr[i];
  1555. return pszNewStr;
  1556. }
  1557. if(iswspace(pszStr[i])) {
  1558. if( (pszNewStr[j-1] == L';') ||
  1559. (pszNewStr[j-1] == L'=') ||
  1560. (pszNewStr[j-1] == L' ') ) {
  1561. i++;
  1562. continue;
  1563. }
  1564. else
  1565. pszNewStr[j] = L' ';
  1566. }
  1567. else if( (pszStr[i] == L'=') || (pszStr[i] == L';') ) {
  1568. if( (j != 0) && (pszNewStr[j-1] == L' ') ) {
  1569. pszNewStr[j-1] = pszStr[i];
  1570. i++;
  1571. continue;
  1572. }
  1573. }
  1574. i++;
  1575. j++;
  1576. }
  1577. }
  1578. //----------------------------------------------------------------------------
  1579. // Function: GetSearchPreferences
  1580. //
  1581. // Synopsis: Returns array of search preferences base n string containing
  1582. // options.
  1583. //
  1584. // Arguments:
  1585. //
  1586. // ppSearchPrefInfo Returns search preferences
  1587. // pdwNumPrefs Returns number of preferences
  1588. // lScope Search scope
  1589. // szOptions String containing options
  1590. //
  1591. // Returns: S_OK on success. Error code otherwise.
  1592. //
  1593. // Modifies: Nothing.
  1594. //
  1595. //----------------------------------------------------------------------------
  1596. HRESULT CADsXML::GetSearchPreferences(
  1597. ADS_SEARCHPREF_INFO** ppSearchPrefInfo,
  1598. DWORD *pdwNumPrefs,
  1599. LONG lScope,
  1600. LPWSTR szOptions
  1601. )
  1602. {
  1603. ADS_SEARCHPREF_INFO *pSearchPrefs = NULL;
  1604. DWORD dwNumPrefs = 0, dwLength = 0;
  1605. LPWSTR pszTmp = szOptions, pszTmp1 = NULL;
  1606. HRESULT hr = S_OK;
  1607. int i,j, cAttrs = 0;
  1608. LPWSTR pszCurrentAttr = NULL, pszFirstAttr = NULL, pszNextAttr = NULL;
  1609. LPWSTR pszOrder = NULL;
  1610. PADS_SORTKEY pSortKey = NULL;
  1611. ADsAssert(ppSearchPrefInfo && pdwNumPrefs);
  1612. *ppSearchPrefInfo = NULL;
  1613. *pdwNumPrefs = 0;
  1614. while(pszTmp = wcschr(pszTmp, L'=')) {
  1615. dwNumPrefs++;
  1616. *pszTmp = L'\0';
  1617. pszTmp++;
  1618. if(*pszTmp == L'\0') {
  1619. BAIL_ON_FAILURE(hr = E_INVALIDARG);
  1620. }
  1621. pszTmp1 = wcschr(pszTmp, L';');
  1622. if(pszTmp1 != NULL) {
  1623. *pszTmp1 = L'\0';
  1624. pszTmp = pszTmp1 + 1;
  1625. }
  1626. else
  1627. break;
  1628. }
  1629. if(0 == dwNumPrefs) {
  1630. BAIL_ON_FAILURE(hr = E_INVALIDARG);
  1631. }
  1632. dwNumPrefs++; //include search scope
  1633. pSearchPrefs = (ADS_SEARCHPREF_INFO *) AllocADsMem(dwNumPrefs *
  1634. sizeof(ADS_SEARCHPREF_INFO));
  1635. if(NULL == pSearchPrefs) {
  1636. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1637. }
  1638. pszTmp = szOptions;
  1639. for(i = 0; i < (int) (dwNumPrefs - 1); i++) {
  1640. for(j = 0; j < (int) g_dwNumSearchPrefInfo; j++) {
  1641. if(0 == _wcsicmp(pszTmp, g_SearchPrefInfo[j].pszName))
  1642. break;
  1643. }
  1644. if(j == (int) g_dwNumSearchPrefInfo) {
  1645. BAIL_ON_FAILURE(hr = E_INVALIDARG);
  1646. }
  1647. pSearchPrefs[i].dwSearchPref = g_SearchPrefInfo[j].Pref;
  1648. pszTmp = pszTmp + wcslen(pszTmp) + 1;
  1649. dwLength = wcslen(pszTmp);
  1650. if(0 == dwLength) {
  1651. BAIL_ON_FAILURE(hr = E_INVALIDARG);
  1652. }
  1653. switch(g_SearchPrefInfo[j].vtType) {
  1654. case VT_BOOL:
  1655. if(0 == _wcsicmp(pszTmp, L"true"))
  1656. pSearchPrefs[i].vValue.Boolean = VARIANT_TRUE;
  1657. else if (0 == _wcsicmp(pszTmp, L"false"))
  1658. pSearchPrefs[i].vValue.Boolean = VARIANT_FALSE;
  1659. else {
  1660. BAIL_ON_FAILURE(hr = E_INVALIDARG);
  1661. }
  1662. pSearchPrefs[i].vValue.dwType = ADSTYPE_BOOLEAN;
  1663. break;
  1664. case VT_I4:
  1665. for(j = 0; j < (int) wcslen(pszTmp); j++) {
  1666. if(0 == iswdigit(pszTmp[j])) {
  1667. BAIL_ON_FAILURE(hr = E_INVALIDARG);
  1668. }
  1669. }
  1670. pSearchPrefs[i].vValue.dwType = ADSTYPE_INTEGER;
  1671. pSearchPrefs[i].vValue.Integer = _wtoi(pszTmp);
  1672. break;
  1673. case VT_BSTR:
  1674. if(L'\0' == *pszTmp) {
  1675. BAIL_ON_FAILURE(hr = E_INVALIDARG);
  1676. }
  1677. // guard against a string ending in ',' since it won't be caught
  1678. // below
  1679. if(L',' == pszTmp[wcslen(pszTmp) -1]) {
  1680. BAIL_ON_FAILURE ( hr = E_INVALIDARG );
  1681. }
  1682. pszCurrentAttr = pszFirstAttr = wcstok(pszTmp, L",");
  1683. for(cAttrs=0; pszCurrentAttr != NULL; cAttrs++ ) {
  1684. pszCurrentAttr = wcstok(NULL, L",");
  1685. }
  1686. if(cAttrs == 0) { // shouldn't happen
  1687. BAIL_ON_FAILURE ( hr = E_INVALIDARG );
  1688. }
  1689. pSortKey = (PADS_SORTKEY) AllocADsMem(sizeof(ADS_SORTKEY) *
  1690. cAttrs);
  1691. if(NULL == pSortKey) {
  1692. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1693. }
  1694. pszCurrentAttr = pszFirstAttr;
  1695. for(j = 0; j < cAttrs; j++) {
  1696. pszNextAttr = pszCurrentAttr + wcslen(pszCurrentAttr) + 1;
  1697. if(L' ' == *pszCurrentAttr) {
  1698. // cannot happen for first attr in list since there will
  1699. // never be a space following =. However, subsequent attrs
  1700. // may have exactly one leading space.
  1701. pszCurrentAttr++;
  1702. if(L'\0' == *pszCurrentAttr) {
  1703. BAIL_ON_FAILURE(hr = E_INVALIDARG);
  1704. }
  1705. }
  1706. pszOrder = wcstok(pszCurrentAttr, L" ");
  1707. pszOrder = pszOrder ? wcstok(NULL, L" ") : NULL;
  1708. if (pszOrder && !_wcsicmp(pszOrder, L"DESC"))
  1709. pSortKey[j].fReverseorder = 1;
  1710. else
  1711. pSortKey[j].fReverseorder = 0; // This is the default
  1712. pSortKey[j].pszAttrType = AllocADsStr(pszCurrentAttr);
  1713. if(NULL == pSortKey[j].pszAttrType) {
  1714. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1715. }
  1716. pSortKey[j].pszReserved = NULL;
  1717. pszCurrentAttr = pszNextAttr;
  1718. }
  1719. pSearchPrefs[i].vValue.ProviderSpecific.dwLength =
  1720. sizeof(ADS_SORTKEY) * cAttrs;
  1721. pSearchPrefs[i].vValue.ProviderSpecific.lpValue =
  1722. (LPBYTE) pSortKey;
  1723. pSearchPrefs[i].vValue.dwType = ADSTYPE_PROV_SPECIFIC;
  1724. pSortKey = NULL;
  1725. break;
  1726. default:
  1727. BAIL_ON_FAILURE(hr = E_FAIL);
  1728. break;
  1729. } //switch
  1730. pszTmp = pszTmp + dwLength + 1;
  1731. } // for
  1732. // set the search scope
  1733. pSearchPrefs[i].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
  1734. pSearchPrefs[i].vValue.dwType = ADSTYPE_INTEGER;
  1735. pSearchPrefs[i].vValue.Integer = lScope;
  1736. *ppSearchPrefInfo = pSearchPrefs;
  1737. *pdwNumPrefs = dwNumPrefs;
  1738. error:
  1739. if(FAILED(hr)) {
  1740. if(pSortKey != NULL) {
  1741. for(j = 0; j < cAttrs; j++) {
  1742. if(pSortKey[j].pszAttrType)
  1743. FreeADsStr(pSortKey[j].pszAttrType);
  1744. }
  1745. FreeADsMem(pSortKey);
  1746. }
  1747. if(pSearchPrefs != NULL)
  1748. FreeSearchPrefInfo(pSearchPrefs, dwNumPrefs);
  1749. }
  1750. RRETURN(hr);
  1751. }
  1752. //----------------------------------------------------------------------------
  1753. // Function: FreeSearchPrefInfo
  1754. //
  1755. // Synopsis: Frees array of search prefs
  1756. //
  1757. // Arguments:
  1758. //
  1759. // pSearchPrefInfo Array of search prefs
  1760. // dwNumPrefs Number of preferences
  1761. //
  1762. // Returns: S_OK on success. Error code otherwise.
  1763. //
  1764. // Modifies: Nothing.
  1765. //
  1766. //----------------------------------------------------------------------------
  1767. void CADsXML::FreeSearchPrefInfo(
  1768. ADS_SEARCHPREF_INFO *pSearchPrefInfo,
  1769. DWORD dwNumPrefs
  1770. )
  1771. {
  1772. int i, j;
  1773. DWORD nSortKeys = 0;
  1774. PADS_SORTKEY pSortKey = NULL;
  1775. if( (NULL == pSearchPrefInfo) || (0 == dwNumPrefs) )
  1776. return;
  1777. for(i = 0; i < (int)dwNumPrefs; i++) {
  1778. if(ADSTYPE_PROV_SPECIFIC == pSearchPrefInfo[i].vValue.dwType) {
  1779. if (pSearchPrefInfo[i].dwSearchPref == ADS_SEARCHPREF_SORT_ON) {
  1780. nSortKeys = pSearchPrefInfo[i].vValue.ProviderSpecific.dwLength
  1781. / sizeof(ADS_SORTKEY);
  1782. pSortKey = (PADS_SORTKEY) pSearchPrefInfo[i].vValue.ProviderSpecific.lpValue;
  1783. for(j = 0; pSortKey && j < (int) nSortKeys; j++) {
  1784. FreeADsStr(pSortKey[j].pszAttrType);
  1785. }
  1786. if (pSortKey) {
  1787. FreeADsMem(pSortKey);
  1788. }
  1789. }
  1790. } // if
  1791. } // for
  1792. FreeADsMem(pSearchPrefInfo);
  1793. return;
  1794. }