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.

806 lines
17 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1998 - 1999
  6. //
  7. // File: attribute.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "pch.h"
  11. #include "common.h"
  12. #include "attr.h"
  13. ///////////////////////////////////////////////////////////////////////////
  14. // CADSIAttribute
  15. CADSIAttribute::CADSIAttribute(ADS_ATTR_INFO* pInfo, BOOL bMulti, PCWSTR pszSyntax, BOOL bReadOnly)
  16. {
  17. m_pAttrInfo = pInfo;
  18. m_bDirty = FALSE;
  19. m_bMulti = bMulti;
  20. m_bReadOnly = bReadOnly;
  21. m_bSet = FALSE;
  22. m_bMandatory = FALSE;
  23. m_szSyntax = pszSyntax;
  24. PWSTR pwz = wcsrchr(pInfo->pszAttrName, L';');
  25. if (pwz)
  26. {
  27. pwz; // move past the hyphen to the range end value.
  28. ASSERT(*pwz);
  29. *pwz=L'\0';
  30. }
  31. }
  32. CADSIAttribute::CADSIAttribute(PADS_ATTR_INFO pInfo)
  33. {
  34. //
  35. // REVIEW_JEFFJON : these need to be updated with correct values
  36. //
  37. m_pAttrInfo = pInfo;
  38. m_bDirty = FALSE;
  39. m_bMulti = FALSE;
  40. m_bReadOnly = FALSE;
  41. m_bSet = FALSE;
  42. m_bMandatory = FALSE;
  43. PWSTR pwz = wcsrchr(pInfo->pszAttrName, L';');
  44. if (pwz)
  45. {
  46. pwz; // move past the hyphen to the range end value.
  47. ASSERT(*pwz);
  48. *pwz=L'\0';
  49. }
  50. }
  51. CADSIAttribute::CADSIAttribute(LPCWSTR lpszAttr)
  52. {
  53. m_pAttrInfo = new ADS_ATTR_INFO;
  54. memset(m_pAttrInfo, 0, sizeof(ADS_ATTR_INFO));
  55. PWSTR pwz = wcsrchr(lpszAttr, L';');
  56. if (pwz)
  57. {
  58. pwz; // move past the hyphen to the range end value.
  59. ASSERT(*pwz);
  60. *pwz=L'\0';
  61. }
  62. _AllocString(lpszAttr, &(m_pAttrInfo->pszAttrName));
  63. m_bMulti = FALSE;
  64. m_bDirty = FALSE;
  65. m_bReadOnly = FALSE;
  66. m_bSet = FALSE;
  67. m_bMandatory = FALSE;
  68. }
  69. CADSIAttribute::CADSIAttribute(CADSIAttribute* pOldAttr)
  70. {
  71. m_pAttrInfo = NULL;
  72. ADS_ATTR_INFO* pAttrInfo = pOldAttr->GetAttrInfo();
  73. // These copies are done separately because there are places
  74. // that I need to copy only the ADsAttrInfo and not the values
  75. //
  76. _CopyADsAttrInfo(pAttrInfo, &m_pAttrInfo);
  77. _CopyADsValues(pAttrInfo, m_pAttrInfo );
  78. m_bReadOnly = FALSE;
  79. m_bMulti = pOldAttr->m_bMulti;
  80. m_bDirty = pOldAttr->m_bDirty;
  81. m_szSyntax = pOldAttr->m_szSyntax;
  82. }
  83. CADSIAttribute::~CADSIAttribute()
  84. {
  85. if (!m_bReadOnly)
  86. {
  87. _FreeADsAttrInfo(&m_pAttrInfo, m_bReadOnly);
  88. }
  89. }
  90. ADSVALUE* CADSIAttribute::GetADSVALUE(int idx)
  91. {
  92. return &(m_pAttrInfo->pADsValues[idx]);
  93. }
  94. HRESULT CADSIAttribute::SetValues(PADSVALUE pADsValue, DWORD dwNumValues)
  95. {
  96. HRESULT hr = S_OK;
  97. ADS_ATTR_INFO* pNewAttrInfo = NULL;
  98. if (!_CopyADsAttrInfo(m_pAttrInfo, &pNewAttrInfo))
  99. {
  100. return E_FAIL;
  101. }
  102. pNewAttrInfo->dwNumValues = dwNumValues;
  103. pNewAttrInfo->pADsValues = pADsValue;
  104. if (pADsValue == NULL)
  105. {
  106. pNewAttrInfo->dwControlCode = ADS_ATTR_CLEAR;
  107. }
  108. else
  109. {
  110. pNewAttrInfo->dwADsType = pADsValue->dwType;
  111. }
  112. //
  113. // Free the old one and swap in the new one
  114. //
  115. if (!m_bReadOnly)
  116. {
  117. _FreeADsAttrInfo(&m_pAttrInfo, m_bReadOnly);
  118. }
  119. m_pAttrInfo = pNewAttrInfo;
  120. m_bReadOnly = FALSE;
  121. return hr;
  122. }
  123. HRESULT CADSIAttribute::SetValues(const CStringList& sValues)
  124. {
  125. HRESULT hr;
  126. ADS_ATTR_INFO* pNewAttrInfo = NULL;
  127. if (!_CopyADsAttrInfo(m_pAttrInfo, &pNewAttrInfo))
  128. {
  129. return E_FAIL;
  130. }
  131. int iCount = sValues.GetCount();
  132. pNewAttrInfo->dwNumValues = iCount;
  133. if (!_AllocValues(&pNewAttrInfo->pADsValues, iCount))
  134. {
  135. return E_FAIL;
  136. }
  137. int idx = 0;
  138. POSITION pos = sValues.GetHeadPosition();
  139. while (pos != NULL)
  140. {
  141. CString s = sValues.GetNext(pos);
  142. ADSVALUE* pADsValue = &(pNewAttrInfo->pADsValues[idx]);
  143. ASSERT(pADsValue != NULL);
  144. hr = _SetADsFromString(
  145. s,
  146. pNewAttrInfo->dwADsType,
  147. pADsValue
  148. );
  149. if (FAILED(hr))
  150. {
  151. _FreeADsAttrInfo(&pNewAttrInfo, FALSE);
  152. return hr;
  153. }
  154. idx++;
  155. }
  156. // Free the old one and swap in the new one
  157. //
  158. _FreeADsAttrInfo(&m_pAttrInfo, m_bReadOnly);
  159. m_pAttrInfo = pNewAttrInfo;
  160. m_bReadOnly = FALSE;
  161. return hr;
  162. }
  163. void CADSIAttribute::GetValues(CStringList& sValues, DWORD dwMaxCharCount)
  164. {
  165. GetStringFromADs(m_pAttrInfo, sValues, dwMaxCharCount);
  166. }
  167. ADS_ATTR_INFO* CADSIAttribute::GetAttrInfo()
  168. {
  169. return m_pAttrInfo;
  170. }
  171. ////////////////////////////////////////////////////////////////////////
  172. // Public Helper Functions
  173. ///////////////////////////////////////////////////////////////////////
  174. HRESULT CADSIAttribute::SetValuesInDS(CAttrList2* ptouchedAttr, IDirectoryObject* pDirObject)
  175. {
  176. DWORD dwReturn;
  177. DWORD dwAttrCount = 0;
  178. ADS_ATTR_INFO* pAttrInfo;
  179. pAttrInfo = new ADS_ATTR_INFO[ptouchedAttr->GetCount()];
  180. CADSIAttribute* pCurrentAttr;
  181. POSITION pos = ptouchedAttr->GetHeadPosition();
  182. while(pos != NULL)
  183. {
  184. ptouchedAttr->GetNextDirty(pos, &pCurrentAttr);
  185. if (pCurrentAttr != NULL)
  186. {
  187. ADS_ATTR_INFO* pCurrentAttrInfo = pCurrentAttr->GetAttrInfo();
  188. ADS_ATTR_INFO* pNewAttrInfo = &pAttrInfo[dwAttrCount];
  189. if (!_CopyADsAttrInfo(pCurrentAttrInfo, pNewAttrInfo))
  190. {
  191. for (DWORD itr = 0; itr < dwAttrCount; itr++)
  192. {
  193. _FreeADsAttrInfo(&pAttrInfo[itr]);
  194. }
  195. delete[] pAttrInfo;
  196. pAttrInfo = NULL;
  197. return E_FAIL;
  198. }
  199. if (!_CopyADsValues(pCurrentAttrInfo, pNewAttrInfo))
  200. {
  201. delete[] pAttrInfo;
  202. pAttrInfo = NULL;
  203. return E_FAIL;
  204. }
  205. if (pAttrInfo[dwAttrCount].dwNumValues == 0)
  206. {
  207. pAttrInfo[dwAttrCount].dwControlCode = ADS_ATTR_CLEAR;
  208. }
  209. else
  210. {
  211. pAttrInfo[dwAttrCount].dwControlCode = ADS_ATTR_UPDATE;
  212. }
  213. dwAttrCount++;
  214. }
  215. }
  216. // Commit the changes that have been made to the ADSI cache
  217. //
  218. HRESULT hr = pDirObject->SetObjectAttributes(pAttrInfo, dwAttrCount, &dwReturn);
  219. for (DWORD itr = 0; itr < dwAttrCount; itr++)
  220. {
  221. _FreeADsAttrInfo(&pAttrInfo[itr]);
  222. }
  223. delete[] pAttrInfo;
  224. pAttrInfo = NULL;
  225. return hr;
  226. }
  227. /////////////////////////////////////////////////////////////////////////
  228. // Private Helper Functions
  229. ////////////////////////////////////////////////////////////////////////
  230. HRESULT CADSIAttribute::_SetADsFromString(LPCWSTR lpszValue, ADSTYPE adsType, ADSVALUE* pADsValue)
  231. {
  232. HRESULT hr = E_FAIL;
  233. if ( adsType == ADSTYPE_INVALID )
  234. {
  235. return hr;
  236. }
  237. pADsValue->dwType = adsType;
  238. switch( adsType )
  239. {
  240. case ADSTYPE_DN_STRING :
  241. if (!_AllocString(lpszValue, &pADsValue->DNString))
  242. {
  243. return E_FAIL;
  244. }
  245. hr = S_OK;
  246. break;
  247. case ADSTYPE_CASE_EXACT_STRING :
  248. if (!_AllocString(lpszValue, &pADsValue->CaseExactString))
  249. {
  250. return E_FAIL;
  251. }
  252. hr = S_OK;
  253. break;
  254. case ADSTYPE_CASE_IGNORE_STRING :
  255. if (!_AllocString(lpszValue, &pADsValue->CaseIgnoreString))
  256. {
  257. return E_FAIL;
  258. }
  259. hr = S_OK;
  260. break;
  261. case ADSTYPE_PRINTABLE_STRING :
  262. if (!_AllocString(lpszValue, &pADsValue->PrintableString))
  263. {
  264. return E_FAIL;
  265. }
  266. hr = S_OK;
  267. break;
  268. case ADSTYPE_NUMERIC_STRING :
  269. if (!_AllocString(lpszValue, &pADsValue->NumericString))
  270. {
  271. return E_FAIL;
  272. }
  273. hr = S_OK;
  274. break;
  275. case ADSTYPE_OBJECT_CLASS :
  276. if (!_AllocString(lpszValue, &pADsValue->ClassName))
  277. {
  278. return E_FAIL;
  279. }
  280. hr = S_OK;
  281. break;
  282. case ADSTYPE_BOOLEAN :
  283. if (_wcsnicmp(lpszValue, L"TRUE", 4) == 0)
  284. {
  285. (DWORD)pADsValue->Boolean = TRUE;
  286. }
  287. else if (_wcsnicmp(lpszValue, L"FALSE", 5) == 0)
  288. {
  289. (DWORD)pADsValue->Boolean = FALSE;
  290. }
  291. else
  292. {
  293. return E_FAIL;
  294. }
  295. hr = S_OK;
  296. break;
  297. case ADSTYPE_INTEGER :
  298. int value;
  299. value = swscanf(lpszValue, L"%ld", &pADsValue->Integer);
  300. if (value > 0)
  301. {
  302. hr = S_OK;
  303. }
  304. else
  305. {
  306. hr = E_FAIL;
  307. }
  308. break;
  309. case ADSTYPE_OCTET_STRING :
  310. {
  311. pADsValue->OctetString.lpValue = new BYTE[256];
  312. int iCount = 0, index = 0, iResult = 0;
  313. do
  314. {
  315. while (lpszValue[index] == ' ' || lpszValue[index] == '/t')
  316. {
  317. index++;
  318. }
  319. iResult = swscanf(&lpszValue[index], L"0x%2x", &pADsValue->OctetString.lpValue[iCount++]);
  320. if (iResult == 0 && lpszValue[index] == '\0')
  321. {
  322. hr = S_OK;
  323. break;
  324. }
  325. index += 4; // REVIEW : OctetStrings must be in the form 0x00, ie 4 characters
  326. } while (iResult != 0);
  327. iCount--; // the last one had to fail
  328. pADsValue->OctetString.dwLength = iCount;
  329. }
  330. break;
  331. case ADSTYPE_LARGE_INTEGER :
  332. wtoli(lpszValue, pADsValue->LargeInteger);
  333. hr = S_OK;
  334. break;
  335. case ADSTYPE_UTC_TIME :
  336. int iNum;
  337. WORD n;
  338. iNum = swscanf(lpszValue, L"%02d/%02d/%04d %02d:%02d:%02d",
  339. &n,
  340. &pADsValue->UTCTime.wDay,
  341. &pADsValue->UTCTime.wYear,
  342. &pADsValue->UTCTime.wHour,
  343. &pADsValue->UTCTime.wMinute,
  344. &pADsValue->UTCTime.wSecond
  345. );
  346. pADsValue->UTCTime.wMonth = n;
  347. // This strange conversion is done so that the DayOfWeek will be set in
  348. // the UTCTime. By converting it to a filetime it ignores the dayofweek but
  349. // converting back fills it in.
  350. //
  351. FILETIME ft;
  352. SystemTimeToFileTime(&pADsValue->UTCTime, &ft);
  353. FileTimeToSystemTime(&ft, &pADsValue->UTCTime);
  354. if (iNum == 6)
  355. {
  356. hr = S_OK;
  357. }
  358. else
  359. {
  360. hr = E_FAIL;
  361. }
  362. break;
  363. default :
  364. break;
  365. }
  366. return hr;
  367. }
  368. BOOL CADSIAttribute::_AllocOctetString(ADS_OCTET_STRING& rOldOctetString,
  369. ADS_OCTET_STRING& rNew)
  370. {
  371. _FreeOctetString(rNew.lpValue);
  372. int iLength = rOldOctetString.dwLength;
  373. rNew.dwLength = iLength;
  374. rNew.lpValue = new BYTE[iLength];
  375. if (rNew.lpValue == NULL)
  376. {
  377. _FreeOctetString(rNew.lpValue);
  378. return FALSE;
  379. }
  380. memcpy(rNew.lpValue, rOldOctetString.lpValue, iLength);
  381. return TRUE;
  382. }
  383. void CADSIAttribute::_FreeOctetString(BYTE* lpValue)
  384. {
  385. if (lpValue != NULL)
  386. {
  387. delete lpValue;
  388. lpValue = NULL;
  389. }
  390. }
  391. BOOL CADSIAttribute::_AllocString(LPCWSTR lpsz, LPWSTR* lppszNew)
  392. {
  393. _FreeString(lppszNew);
  394. int iLength = wcslen(lpsz);
  395. *lppszNew = new WCHAR[iLength + 1]; // an extra for the NULL
  396. if (*lppszNew == NULL)
  397. {
  398. _FreeString(lppszNew);
  399. return FALSE;
  400. }
  401. wcscpy(*lppszNew, lpsz);
  402. return TRUE;
  403. }
  404. void CADSIAttribute::_FreeString(LPWSTR* lppsz)
  405. {
  406. if (*lppsz != NULL)
  407. {
  408. delete *lppsz;
  409. }
  410. *lppsz = NULL;
  411. }
  412. BOOL CADSIAttribute::_AllocValues(ADSVALUE** ppValues, DWORD dwLength)
  413. {
  414. _FreeADsValues(ppValues, dwLength);
  415. *ppValues = new ADSVALUE[dwLength];
  416. if (*ppValues == NULL)
  417. {
  418. _FreeADsValues(ppValues, dwLength);
  419. return FALSE;
  420. }
  421. memset(*ppValues, 0, sizeof(ADSVALUE) * dwLength);
  422. return TRUE;
  423. }
  424. BOOL CADSIAttribute::_CopyADsValues(ADS_ATTR_INFO* pOldAttrInfo, ADS_ATTR_INFO* pNewAttrInfo)
  425. {
  426. _FreeADsValues(&pNewAttrInfo->pADsValues, pNewAttrInfo->dwNumValues);
  427. pNewAttrInfo->dwNumValues = pOldAttrInfo->dwNumValues;
  428. if (!_AllocValues(&pNewAttrInfo->pADsValues, pOldAttrInfo->dwNumValues))
  429. {
  430. _FreeADsValues(&pNewAttrInfo->pADsValues, pNewAttrInfo->dwNumValues);
  431. return FALSE;
  432. }
  433. for (DWORD itr = 0; itr < pOldAttrInfo->dwNumValues; itr++)
  434. {
  435. pNewAttrInfo->pADsValues[itr].dwType = pOldAttrInfo->pADsValues[itr].dwType;
  436. switch( pNewAttrInfo->pADsValues[itr].dwType )
  437. {
  438. case ADSTYPE_DN_STRING :
  439. if (!_AllocString(pOldAttrInfo->pADsValues[itr].DNString,
  440. &pNewAttrInfo->pADsValues[itr].DNString))
  441. {
  442. _FreeADsValues(&pNewAttrInfo->pADsValues, pNewAttrInfo->dwNumValues);
  443. return FALSE;
  444. }
  445. break;
  446. case ADSTYPE_CASE_EXACT_STRING :
  447. if (!_AllocString(pOldAttrInfo->pADsValues[itr].CaseExactString,
  448. &pNewAttrInfo->pADsValues[itr].CaseExactString))
  449. {
  450. _FreeADsValues(&pNewAttrInfo->pADsValues, pNewAttrInfo->dwNumValues);
  451. return FALSE;
  452. }
  453. break;
  454. case ADSTYPE_CASE_IGNORE_STRING :
  455. if (!_AllocString(pOldAttrInfo->pADsValues[itr].CaseIgnoreString,
  456. &pNewAttrInfo->pADsValues[itr].CaseIgnoreString))
  457. {
  458. _FreeADsValues(&pNewAttrInfo->pADsValues, pNewAttrInfo->dwNumValues);
  459. return FALSE;
  460. }
  461. break;
  462. case ADSTYPE_PRINTABLE_STRING :
  463. if (!_AllocString(pOldAttrInfo->pADsValues[itr].PrintableString,
  464. &pNewAttrInfo->pADsValues[itr].PrintableString))
  465. {
  466. _FreeADsValues(&pNewAttrInfo->pADsValues, pNewAttrInfo->dwNumValues);
  467. return FALSE;
  468. }
  469. break;
  470. case ADSTYPE_NUMERIC_STRING :
  471. if (!_AllocString(pOldAttrInfo->pADsValues[itr].NumericString,
  472. &pNewAttrInfo->pADsValues[itr].NumericString))
  473. {
  474. _FreeADsValues(&pNewAttrInfo->pADsValues, pNewAttrInfo->dwNumValues);
  475. return FALSE;
  476. }
  477. break;
  478. case ADSTYPE_OBJECT_CLASS :
  479. if (!_AllocString(pOldAttrInfo->pADsValues[itr].ClassName,
  480. &pNewAttrInfo->pADsValues[itr].ClassName))
  481. {
  482. _FreeADsValues(&pNewAttrInfo->pADsValues, pNewAttrInfo->dwNumValues);
  483. return FALSE;
  484. }
  485. break;
  486. case ADSTYPE_BOOLEAN :
  487. pNewAttrInfo->pADsValues[itr].Boolean = pOldAttrInfo->pADsValues[itr].Boolean;
  488. break;
  489. case ADSTYPE_INTEGER :
  490. pNewAttrInfo->pADsValues[itr].Integer = pOldAttrInfo->pADsValues[itr].Integer;
  491. break;
  492. case ADSTYPE_OCTET_STRING :
  493. if (!_AllocOctetString(pOldAttrInfo->pADsValues[itr].OctetString,
  494. pNewAttrInfo->pADsValues[itr].OctetString))
  495. {
  496. _FreeADsValues(&pNewAttrInfo->pADsValues, pNewAttrInfo->dwNumValues);
  497. return FALSE;
  498. }
  499. break;
  500. case ADSTYPE_LARGE_INTEGER :
  501. pNewAttrInfo->pADsValues[itr].LargeInteger = pOldAttrInfo->pADsValues[itr].LargeInteger;
  502. break;
  503. case ADSTYPE_UTC_TIME :
  504. pNewAttrInfo->pADsValues[itr].UTCTime = pOldAttrInfo->pADsValues[itr].UTCTime;
  505. break;
  506. default :
  507. break;
  508. }
  509. }
  510. return TRUE;
  511. }
  512. void CADSIAttribute::_FreeADsValues(ADSVALUE** ppADsValues, DWORD dwLength)
  513. {
  514. ADSVALUE* pADsValue = *ppADsValues;
  515. for (DWORD idx = 0; idx < dwLength; idx++)
  516. {
  517. if (pADsValue != NULL)
  518. {
  519. switch( pADsValue->dwType )
  520. {
  521. case ADSTYPE_DN_STRING :
  522. _FreeString(&pADsValue->DNString);
  523. break;
  524. case ADSTYPE_CASE_EXACT_STRING :
  525. _FreeString(&pADsValue->CaseExactString);
  526. break;
  527. case ADSTYPE_CASE_IGNORE_STRING :
  528. _FreeString(&pADsValue->CaseIgnoreString);
  529. break;
  530. case ADSTYPE_PRINTABLE_STRING :
  531. _FreeString(&pADsValue->PrintableString);
  532. break;
  533. case ADSTYPE_NUMERIC_STRING :
  534. _FreeString(&pADsValue->NumericString);
  535. break;
  536. case ADSTYPE_OBJECT_CLASS :
  537. _FreeString(&pADsValue->ClassName);
  538. break;
  539. case ADSTYPE_OCTET_STRING :
  540. _FreeOctetString(pADsValue->OctetString.lpValue);
  541. break;
  542. default :
  543. break;
  544. }
  545. pADsValue++;
  546. }
  547. }
  548. // May be NULL if there are no values set
  549. // WARNING! : make sure that you memset the memory after
  550. // creating an ADS_ATTR_INFO so that it will be NULL if there
  551. // are no values
  552. //
  553. if (*ppADsValues != NULL)
  554. {
  555. delete *ppADsValues;
  556. *ppADsValues = NULL;
  557. }
  558. }
  559. // The values are not copied here. They must be copied after the ADS_ATTR_INFO
  560. // is copied by using _CopyADsValues()
  561. //
  562. BOOL CADSIAttribute::_CopyADsAttrInfo(ADS_ATTR_INFO* pAttrInfo, ADS_ATTR_INFO** ppNewAttrInfo)
  563. {
  564. _FreeADsAttrInfo(ppNewAttrInfo, FALSE);
  565. *ppNewAttrInfo = new ADS_ATTR_INFO;
  566. if (*ppNewAttrInfo == NULL)
  567. {
  568. return FALSE;
  569. }
  570. memset(*ppNewAttrInfo, 0, sizeof(ADS_ATTR_INFO));
  571. BOOL bReturn = _AllocString(pAttrInfo->pszAttrName, &((*ppNewAttrInfo)->pszAttrName));
  572. if (!bReturn)
  573. {
  574. _FreeADsAttrInfo(ppNewAttrInfo, FALSE);
  575. return FALSE;
  576. }
  577. (*ppNewAttrInfo)->dwADsType = pAttrInfo->dwADsType;
  578. (*ppNewAttrInfo)->dwControlCode = pAttrInfo->dwControlCode;
  579. (*ppNewAttrInfo)->dwNumValues = pAttrInfo->dwNumValues;
  580. return TRUE;
  581. }
  582. BOOL CADSIAttribute::_CopyADsAttrInfo(ADS_ATTR_INFO* pAttrInfo, ADS_ATTR_INFO* pNewAttrInfo)
  583. {
  584. memset(pNewAttrInfo, 0, sizeof(ADS_ATTR_INFO));
  585. BOOL bReturn = _AllocString(pAttrInfo->pszAttrName, &pNewAttrInfo->pszAttrName);
  586. if (!bReturn)
  587. {
  588. return FALSE;
  589. }
  590. pNewAttrInfo->dwADsType = pAttrInfo->dwADsType;
  591. pNewAttrInfo->dwControlCode = pAttrInfo->dwControlCode;
  592. pNewAttrInfo->dwNumValues = pAttrInfo->dwNumValues;
  593. return TRUE;
  594. }
  595. void CADSIAttribute::_FreeADsAttrInfo(ADS_ATTR_INFO** ppAttrInfo, BOOL bReadOnly)
  596. {
  597. if (*ppAttrInfo == NULL)
  598. {
  599. return;
  600. }
  601. if (!bReadOnly)
  602. {
  603. _FreeString(&(*ppAttrInfo)->pszAttrName);
  604. _FreeADsValues(&(*ppAttrInfo)->pADsValues, (*ppAttrInfo)->dwNumValues);
  605. delete *ppAttrInfo;
  606. }
  607. else
  608. {
  609. FreeADsMem(*ppAttrInfo);
  610. }
  611. *ppAttrInfo = NULL;
  612. }
  613. void CADSIAttribute::_FreeADsAttrInfo(ADS_ATTR_INFO* pAttrInfo)
  614. {
  615. if (pAttrInfo == NULL)
  616. {
  617. return;
  618. }
  619. _FreeString(&pAttrInfo->pszAttrName);
  620. _FreeADsValues(&pAttrInfo->pADsValues, pAttrInfo->dwNumValues);
  621. }
  622. ///////////////////////////////////////////////////////////////////////////
  623. // CAttrList2
  624. POSITION CAttrList2::FindProperty(LPCWSTR lpszAttr)
  625. {
  626. CADSIAttribute* pAttr;
  627. for (POSITION p = GetHeadPosition(); p != NULL; GetNext(p))
  628. {
  629. // I use GetAt here because I don't want to advance the POSITION
  630. // because it is returned if they are equal
  631. //
  632. pAttr = GetAt(p);
  633. CString sName;
  634. pAttr->GetProperty(sName);
  635. if (wcscmp(sName, lpszAttr) == 0)
  636. {
  637. break;
  638. }
  639. }
  640. return p;
  641. }
  642. BOOL CAttrList2::HasProperty(LPCWSTR lpszAttr)
  643. {
  644. POSITION pos = FindProperty(lpszAttr);
  645. return pos != NULL;
  646. }
  647. // Searches through the cache for the attribute
  648. // ppAttr will point to the CADSIAttribute if found, NULL if not
  649. //
  650. void CAttrList2::GetNextDirty(POSITION& pos, CADSIAttribute** ppAttr)
  651. {
  652. *ppAttr = GetNext(pos);
  653. if (pos == NULL && !(*ppAttr)->IsDirty())
  654. {
  655. *ppAttr = NULL;
  656. return;
  657. }
  658. while (!(*ppAttr)->IsDirty() && pos != NULL)
  659. {
  660. *ppAttr = GetNext(pos);
  661. if (!(*ppAttr)->IsDirty() && pos == NULL)
  662. {
  663. *ppAttr = NULL;
  664. break;
  665. }
  666. }
  667. }
  668. BOOL CAttrList2::HasDirty()
  669. {
  670. POSITION pos = GetHeadPosition();
  671. while (pos != NULL)
  672. {
  673. CADSIAttribute* pAttr = GetNext(pos);
  674. if (pAttr->IsDirty())
  675. {
  676. return TRUE;
  677. }
  678. }
  679. return FALSE;
  680. }