Leaked source code of windows server 2003
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.

1252 lines
39 KiB

  1. // DSColumn.cpp : Implementation of ds column routines and classes
  2. //+-------------------------------------------------------------------------
  3. //
  4. // Microsoft Windows
  5. // Copyright (C) Microsoft Corporation, 1992 - 1999
  6. //
  7. // File: DSColumn.cpp
  8. //
  9. // Contents: DS Column routines, classes, and static data
  10. //
  11. // History: 12-Mar-99 JeffJon Created
  12. //
  13. //
  14. //--------------------------------------------------------------------------
  15. #include "stdafx.h"
  16. #include "resource.h"
  17. #include "util.h"
  18. #include "DSColumn.h"
  19. #include "dscookie.h"
  20. #include "dsutil.h"
  21. BOOL ColumnExtractStringValue(
  22. OUT CString& strref,
  23. IN CDSCookie*,
  24. IN PADS_SEARCH_COLUMN pColumn,
  25. IN DWORD iValue)
  26. {
  27. if (pColumn == NULL || pColumn->dwNumValues <= iValue)
  28. {
  29. return FALSE;
  30. }
  31. switch (pColumn->dwADsType)
  32. {
  33. case ADSTYPE_CASE_IGNORE_STRING:
  34. strref = (LPCWSTR)pColumn->pADsValues[iValue].CaseIgnoreString;
  35. break;
  36. case ADSTYPE_DN_STRING:
  37. strref = (LPCWSTR)pColumn->pADsValues[iValue].DNString;
  38. break;
  39. default:
  40. return FALSE;
  41. }
  42. return TRUE;
  43. }
  44. BOOL ColumnExtractString(
  45. OUT CString& strref,
  46. IN CDSCookie* pCookie,
  47. IN PADS_SEARCH_COLUMN pColumn)
  48. {
  49. return ColumnExtractStringValue( strref, pCookie, pColumn, 0 );
  50. }
  51. BOOL ColumnExtractElementFromDN(
  52. OUT CString& strref,
  53. IN CDSCookie* pCookie,
  54. IN PADS_SEARCH_COLUMN pColumn,
  55. long lElement,
  56. IN DWORD iValue = 0);
  57. BOOL ColumnExtractElementFromDN(
  58. OUT CString& strref,
  59. IN CDSCookie* pCookie,
  60. IN PADS_SEARCH_COLUMN pColumn,
  61. long lElement,
  62. IN DWORD iValue)
  63. {
  64. if (pColumn == NULL)
  65. {
  66. return FALSE;
  67. }
  68. BOOL fRetval = FALSE;
  69. CString str;
  70. CComBSTR bstr;
  71. HRESULT hr = S_OK;
  72. do { // false loop
  73. if ( !ColumnExtractStringValue( str, pCookie, pColumn, iValue ) || str.IsEmpty() )
  74. {
  75. strref.Empty();
  76. fRetval = TRUE;
  77. break;
  78. }
  79. CPathCracker pathCracker;
  80. hr = pathCracker.Set(const_cast<BSTR>((LPCTSTR)str), ADS_SETTYPE_DN);
  81. if ( FAILED(hr) )
  82. break;
  83. // no need to reset this
  84. hr = pathCracker.SetDisplayType(ADS_DISPLAY_VALUE_ONLY);
  85. if ( FAILED(hr) )
  86. break;
  87. hr = pathCracker.put_EscapedMode(ADS_ESCAPEDMODE_OFF);
  88. if ( FAILED(hr) )
  89. break;
  90. hr = pathCracker.GetElement(lElement, &bstr);
  91. strref = bstr;
  92. fRetval = TRUE;
  93. } while (FALSE); // false loop
  94. return fRetval;
  95. }
  96. BOOL ColumnExtractLeafFromDN(
  97. OUT CString& strref,
  98. IN CDSCookie* pCookie,
  99. IN PADS_SEARCH_COLUMN pColumn)
  100. {
  101. return ColumnExtractElementFromDN( strref, pCookie, pColumn, 0 );
  102. }
  103. BOOL ColumnExtractParentFromDN(
  104. OUT CString& strref,
  105. IN CDSCookie* pCookie,
  106. IN PADS_SEARCH_COLUMN pColumn)
  107. {
  108. return ColumnExtractElementFromDN( strref, pCookie, pColumn, 1 );
  109. }
  110. BOOL ColumnExtractGreatGrandparentFromDN(
  111. OUT CString& strref,
  112. IN CDSCookie* pCookie,
  113. IN PADS_SEARCH_COLUMN pColumn)
  114. {
  115. return ColumnExtractElementFromDN( strref, pCookie, pColumn, 3 );
  116. }
  117. BOOL ColumnExtractConnectionDisplayName(
  118. OUT CString& strref,
  119. IN CDSCookie* pCookie,
  120. IN PADS_SEARCH_COLUMN pColumn)
  121. {
  122. if (pColumn == NULL)
  123. {
  124. return FALSE;
  125. }
  126. ADS_INTEGER adsint = 0;
  127. switch (pColumn->dwADsType)
  128. {
  129. case ADSTYPE_INTEGER:
  130. adsint = pColumn->pADsValues->Integer;
  131. break;
  132. default:
  133. // no value, let it stay 0
  134. break;
  135. }
  136. if (NTDSCONN_OPT_IS_GENERATED & adsint) {
  137. strref.LoadString (IDS_CONNECTION_KCC_GENERATED);
  138. } else {
  139. strref = pCookie->GetName();
  140. }
  141. return TRUE;
  142. }
  143. BOOL ColumnExtractAttribute(
  144. OUT CString& strref,
  145. IN CDSCookie*,
  146. IN PADS_SEARCH_COLUMN pColumn)
  147. {
  148. if (pColumn == NULL)
  149. {
  150. return FALSE;
  151. }
  152. switch (pColumn->dwADsType)
  153. {
  154. case ADSTYPE_DN_STRING :
  155. strref = pColumn->pADsValues->DNString;
  156. break;
  157. case ADSTYPE_CASE_EXACT_STRING :
  158. strref = pColumn->pADsValues->CaseExactString;
  159. break;
  160. case ADSTYPE_CASE_IGNORE_STRING:
  161. strref = pColumn->pADsValues->CaseIgnoreString;
  162. break;
  163. case ADSTYPE_PRINTABLE_STRING :
  164. strref = pColumn->pADsValues->PrintableString;
  165. break;
  166. case ADSTYPE_NUMERIC_STRING :
  167. strref = pColumn->pADsValues->NumericString;
  168. break;
  169. case ADSTYPE_OBJECT_CLASS :
  170. strref = pColumn->pADsValues->ClassName;
  171. break;
  172. case ADSTYPE_BOOLEAN :
  173. strref = ((DWORD)pColumn->pADsValues->Boolean) ? L"TRUE" : L"FALSE";
  174. break;
  175. case ADSTYPE_INTEGER :
  176. strref.Format(L"%d", (DWORD) pColumn->pADsValues->Integer);
  177. break;
  178. case ADSTYPE_OCTET_STRING :
  179. {
  180. CString sOctet = L"";
  181. BYTE b;
  182. for ( DWORD idx=0; idx<pColumn->pADsValues->OctetString.dwLength; idx++)
  183. {
  184. b = ((BYTE *)pColumn->pADsValues->OctetString.lpValue)[idx];
  185. sOctet.Format(L"0x%02x ", b);
  186. strref += sOctet;
  187. }
  188. }
  189. break;
  190. case ADSTYPE_UTC_TIME:
  191. {
  192. PTSTR ptszDate = NULL;
  193. int cchDate = 0;
  194. SYSTEMTIME st = {0};
  195. if (!SystemTimeToTzSpecificLocalTime(NULL, &pColumn->pADsValues->UTCTime, &st))
  196. {
  197. strref = L"";
  198. return TRUE;
  199. }
  200. cchDate = GetDateFormat(LOCALE_USER_DEFAULT, 0 ,
  201. &st, NULL,
  202. ptszDate, 0);
  203. ptszDate = (PTSTR)malloc(sizeof(TCHAR) * cchDate);
  204. if (GetDateFormat(LOCALE_USER_DEFAULT, 0,
  205. &st, NULL,
  206. ptszDate, cchDate))
  207. {
  208. strref = ptszDate;
  209. }
  210. else
  211. {
  212. strref = L"";
  213. }
  214. free(ptszDate);
  215. PTSTR ptszTime = NULL;
  216. cchDate = GetTimeFormat(LOCALE_USER_DEFAULT, 0 ,
  217. &st, NULL,
  218. ptszTime, 0);
  219. ptszTime = (PTSTR)malloc(sizeof(TCHAR) * cchDate);
  220. if (ptszTime != NULL)
  221. {
  222. if (GetTimeFormat(LOCALE_USER_DEFAULT, 0,
  223. &st, NULL,
  224. ptszTime, cchDate))
  225. {
  226. strref += _T(" ") + CString(ptszTime);
  227. }
  228. else
  229. {
  230. strref += _T("");
  231. }
  232. free(ptszTime);
  233. }
  234. else
  235. {
  236. strref = _T("");
  237. }
  238. }
  239. break;
  240. default :
  241. ASSERT(FALSE);
  242. break;
  243. }
  244. return TRUE;
  245. }
  246. BOOL _ColumnCrackDN(
  247. OUT CString& strref,
  248. IN LPCTSTR lpcszDN,
  249. IN CRACK_NAME_OPR RequestedOpr)
  250. {
  251. PWSTR pwzName = NULL;
  252. HRESULT hr = CrackName(const_cast<PTSTR>(lpcszDN),
  253. &pwzName,
  254. RequestedOpr,
  255. NULL);
  256. if (SUCCEEDED(hr))
  257. {
  258. if (GET_OBJ_CAN_NAME_EX == RequestedOpr)
  259. {
  260. LPTSTR ptzCanName = wcschr( pwzName, _T('\n') );
  261. if (NULL != ptzCanName)
  262. strref = ptzCanName+1;
  263. else
  264. strref.Empty();
  265. }
  266. else
  267. {
  268. strref = pwzName;
  269. }
  270. LocalFreeStringW(&pwzName);
  271. }
  272. else
  273. {
  274. strref.Empty();
  275. }
  276. return TRUE;
  277. }
  278. BOOL ColumnExtractNameFromSID(
  279. OUT CString& strref,
  280. IN CDSCookie* pCookie,
  281. IN PADS_SEARCH_COLUMN)
  282. {
  283. return _ColumnCrackDN( strref, pCookie->GetPath(), GET_OBJ_CAN_NAME );
  284. }
  285. BOOL ColumnExtractCanonicalNameFromDN(
  286. OUT CString& strref,
  287. IN CDSCookie* pCookie,
  288. IN PADS_SEARCH_COLUMN pColumn)
  289. {
  290. if (pColumn == NULL)
  291. {
  292. return FALSE;
  293. }
  294. CString str;
  295. if ( !ColumnExtractString( str, pCookie, pColumn ) || str.IsEmpty() )
  296. {
  297. strref.Empty();
  298. return TRUE;
  299. }
  300. return _ColumnCrackDN( strref, str, GET_OBJ_CAN_NAME_EX );
  301. }
  302. BOOL ColumnExtractDomainFromDN(
  303. OUT CString& strref,
  304. IN CDSCookie* pCookie,
  305. IN PADS_SEARCH_COLUMN pColumn)
  306. {
  307. if (pColumn == NULL)
  308. {
  309. return FALSE;
  310. }
  311. CString str;
  312. if ( !ColumnExtractString( str, pCookie, pColumn ) || str.IsEmpty() )
  313. {
  314. strref.Empty();
  315. return TRUE;
  316. }
  317. return _ColumnCrackDN( strref, str, GET_DNS_DOMAIN_NAME );
  318. }
  319. int _cdecl _qsort_CompareColumns(const void * elem1, const void * elem2)
  320. {
  321. PADSVALUE p1 = (PADSVALUE)elem1;
  322. PADSVALUE p2 = (PADSVALUE)elem2;
  323. if (!p1 || !p2 || !p1->DNString || !p2->DNString)
  324. return 0;
  325. return wcscmp( p1->DNString, p2->DNString );
  326. }
  327. BOOL ColumnExtractLeafList(
  328. OUT CString& strref,
  329. IN CDSCookie* pCookie,
  330. IN PADS_SEARCH_COLUMN pColumn)
  331. {
  332. if (pColumn == NULL)
  333. {
  334. return FALSE;
  335. }
  336. // alphabetical order
  337. qsort( pColumn->pADsValues,
  338. pColumn->dwNumValues,
  339. sizeof(ADSVALUE),
  340. _qsort_CompareColumns );
  341. CString strSeparator;
  342. strSeparator.LoadString(IDS_SEPARATOR);
  343. for (DWORD iValue = 0; iValue < pColumn->dwNumValues; iValue++)
  344. {
  345. CString strTransport;
  346. if ( !ColumnExtractElementFromDN(
  347. strTransport, pCookie, pColumn, 0, iValue) )
  348. return FALSE;
  349. if (0 < iValue)
  350. strref += strSeparator;
  351. strref += strTransport;
  352. }
  353. return TRUE;
  354. }
  355. BOOL _ColumnCrackFRS(
  356. OUT CString& strref,
  357. IN CDSCookie* pCookie,
  358. IN CRACK_NAME_OPR RequestedOpr)
  359. {
  360. CDSCookieInfoConnection* pExtraInfo = NULL;
  361. if ( NULL == pCookie
  362. || _wcsicmp( pCookie->GetClass(), L"nTDSConnection" )
  363. || NULL == (pExtraInfo = (CDSCookieInfoConnection*)pCookie->GetExtraInfo())
  364. || pExtraInfo->GetClass() != CDSCookieInfoBase::connection
  365. || pExtraInfo->m_strFRSComputerReference.IsEmpty()
  366. )
  367. {
  368. strref.Empty();
  369. return TRUE;
  370. }
  371. return _ColumnCrackDN( strref, pExtraInfo->m_strFRSComputerReference, RequestedOpr );
  372. }
  373. BOOL ColumnExtractFRSComputer(
  374. OUT CString& strref,
  375. IN CDSCookie* pCookie,
  376. IN PADS_SEARCH_COLUMN)
  377. {
  378. return _ColumnCrackFRS( strref, pCookie, GET_OBJ_CAN_NAME_EX );
  379. }
  380. BOOL ColumnExtractFRSDomain(
  381. OUT CString& strref,
  382. IN CDSCookie* pCookie,
  383. IN PADS_SEARCH_COLUMN)
  384. {
  385. return _ColumnCrackFRS( strref, pCookie, GET_DNS_DOMAIN_NAME );
  386. }
  387. // JonN 10/22/01 483649
  388. BOOL ColumnExtractReplInterval(
  389. OUT CString& strref,
  390. IN CDSCookie*,
  391. IN PADS_SEARCH_COLUMN pColumn)
  392. {
  393. if (pColumn == NULL || pColumn->dwADsType != ADSTYPE_INTEGER)
  394. {
  395. return FALSE;
  396. }
  397. DWORD dwCost = pColumn->pADsValues->Integer;
  398. if (dwCost < 15)
  399. dwCost = 15;
  400. strref.Format(L"%d", dwCost);
  401. return TRUE;
  402. }
  403. ATTRIBUTE_COLUMN colName = { ATTR_COLTYPE_NAME,
  404. IDS_COLUMN_NAME, //column header
  405. 100, //col. width
  406. NULL, //ldap attr. name
  407. NULL }; //extract fn()
  408. ATTRIBUTE_COLUMN colClass= { ATTR_COLTYPE_CLASS,
  409. IDS_COLUMN_TYPE, //column header
  410. 100, //col. width
  411. NULL, //ldap attr. name
  412. NULL }; //extract fn()
  413. ATTRIBUTE_COLUMN colDesc = { ATTR_COLTYPE_DESC,
  414. IDS_COLUMN_DESCRIPTION, //column header
  415. 150, //col. width
  416. NULL, //ldap attr. name
  417. NULL }; //extract fn()
  418. ATTRIBUTE_COLUMN colSite = { ATTR_COLTYPE_SPECIAL,
  419. IDS_COLUMN_SITE, //column header
  420. 100, //col. width
  421. L"siteObject", //ldap attr. name
  422. ColumnExtractLeafFromDN }; //extract fn()
  423. ATTRIBUTE_COLUMN colLocation = { ATTR_COLTYPE_SPECIAL,
  424. IDS_COLUMN_LOCATION, //column header
  425. 150, //col. width
  426. L"location", //ldap attr. name
  427. NULL }; //extract fn()
  428. ATTRIBUTE_COLUMN colDomain = { ATTR_COLTYPE_SPECIAL,
  429. IDS_COLUMN_DOMAIN, //column header
  430. 150, //col. width
  431. L"serverReference", //ldap attr. name
  432. ColumnExtractDomainFromDN }; //extract fn()
  433. ATTRIBUTE_COLUMN colBridgehead = { ATTR_COLTYPE_SPECIAL,
  434. IDS_COLUMN_BRIDGEHEAD, //column header
  435. 150, //col. width
  436. L"bridgeheadTransportList", //ldap attr. name
  437. ColumnExtractLeafList }; //extract fn()
  438. ATTRIBUTE_COLUMN colReplicaComputer = { ATTR_COLTYPE_SPECIAL,
  439. IDS_COLUMN_COMPUTER, //column header
  440. 100, //col. width
  441. L"fRSComputerReference", //ldap attr. name
  442. ColumnExtractCanonicalNameFromDN }; //extract fn()
  443. ATTRIBUTE_COLUMN colReplicaDomain = { ATTR_COLTYPE_SPECIAL,
  444. IDS_COLUMN_DOMAIN, //column header
  445. 150, //col. width
  446. L"fRSComputerReference", //ldap attr. name
  447. ColumnExtractDomainFromDN }; //extract fn()
  448. ATTRIBUTE_COLUMN colFromFRSComputer = { ATTR_COLTYPE_SPECIAL,
  449. IDS_COLUMN_FROM_COMPUTER, //column header
  450. 100, //col. width
  451. L"fromServer", //ldap attr. name
  452. ColumnExtractFRSComputer }; //extract fn()
  453. ATTRIBUTE_COLUMN colFromFRSDomain = { ATTR_COLTYPE_SPECIAL,
  454. IDS_COLUMN_FROM_DOMAIN, //column header
  455. 150, //col. width
  456. L"fromServer", //ldap attr. name
  457. ColumnExtractFRSDomain }; //extract fn()
  458. ATTRIBUTE_COLUMN colConnectionName={ ATTR_COLTYPE_SPECIAL,
  459. IDS_COLUMN_NAME, //column header
  460. 150, //col. width
  461. L"options", //ldap attr. name
  462. ColumnExtractConnectionDisplayName}; //extract fn()
  463. ATTRIBUTE_COLUMN colFromServer={ ATTR_COLTYPE_SPECIAL,
  464. IDS_COLUMN_FROM_SERVER, //column header
  465. 100, //col. width
  466. L"fromServer", //ldap attr. name
  467. ColumnExtractParentFromDN }; //extract fn()
  468. ATTRIBUTE_COLUMN colFromSite={ ATTR_COLTYPE_SPECIAL,
  469. IDS_COLUMN_FROM_SITE, //column header
  470. 100, //col. width
  471. L"fromServer", //ldap attr. name
  472. ColumnExtractGreatGrandparentFromDN }; //extract fn()
  473. ATTRIBUTE_COLUMN colCost = { ATTR_COLTYPE_SPECIAL,
  474. IDS_COLUMN_COST, //column header
  475. 75, //col. width
  476. L"cost", //ldap attr. name
  477. ColumnExtractAttribute}; //extract fn()
  478. ATTRIBUTE_COLUMN colReplInterval = { ATTR_COLTYPE_SPECIAL,
  479. IDS_COLUMN_REPLINTERVAL, //column header
  480. 150, //col. width
  481. L"replInterval", //ldap attr. name
  482. ColumnExtractReplInterval}; // JonN 10/22/01 483649
  483. ATTRIBUTE_COLUMN colNameFromSID={ ATTR_COLTYPE_SPECIAL,
  484. IDS_COLUMN_READABLE_NAME, // column header
  485. 100, // column width
  486. L"container",
  487. ColumnExtractNameFromSID }; // extract fn()
  488. ATTRIBUTE_COLUMN colGenericSpecial={ ATTR_COLTYPE_SPECIAL,
  489. 0, // resource id 0 means load it from the special column array
  490. 50,
  491. NULL,
  492. ColumnExtractAttribute };
  493. ATTRIBUTE_COLUMN colModifiedTime={ ATTR_COLTYPE_MODIFIED_TIME,
  494. 0,
  495. 50,
  496. NULL,
  497. ColumnExtractAttribute };
  498. SPECIAL_COLUMN g_specialCols[] =
  499. {
  500. { IDS_COLUMN_BUSINESS_PHONE, L"telephoneNumber", 100 },
  501. { IDS_COLUMN_CITY, L"l", 150 },
  502. { IDS_COLUMN_COMPANY, L"company", 150 },
  503. { IDS_COLUMN_COUNTRY, L"c", AUTO_WIDTH }, // Default to the width of the header string
  504. { IDS_COLUMN_DEPARTMENT, L"department", 150 },
  505. { IDS_COLUMN_DISPLAY_NAME, L"displayName", 100 },
  506. { IDS_COLUMN_SAM_ACCOUNT_NAME, L"sAMAccountName", 120 },
  507. { IDS_COLUMN_MAIL, L"mail", 100 },
  508. { IDS_COLUMN_ALIAS_NAME, L"mailNickname", 175 },
  509. { IDS_COLUMN_HOME_MDB, L"homeMDB", 100 },
  510. { IDS_COLUMN_FIRST_NAME, L"givenName", 100 },
  511. { IDS_COLUMN_IMHOMEURL, L"msExchIMPhysicalURL", 170 },
  512. { IDS_COLUMN_IMURL, L"msExchIMMetaPhysicalURL", 140 },
  513. { IDS_COLUMN_LAST_NAME, L"sn", 100 },
  514. { IDS_COLUMN_MODIFIED, L"whenChanged", 130 },
  515. { IDS_COLUMN_OFFICE, L"physicalDeliveryOfficeName", 100 },
  516. { IDS_COLUMN_STATE, L"st", 100 },
  517. { IDS_COLUMN_TARGET_ADDRESS , L"targetAddress", 100 },
  518. { IDS_COLUMN_TITLE, L"title", 100 },
  519. { IDS_COLUMN_UPN, L"userPrincipalName", 200 },
  520. { IDS_COLUMN_TEXTENCODEORADDRESS, L"textEncodedORAddress", 130 },
  521. { IDS_COLUMN_ZIP_CODE, L"postalCode", 100 }
  522. };
  523. PATTRIBUTE_COLUMN colsSubnetContainer[6] = { &colName, &colSite, &colLocation, &colClass, &colDesc, NULL };
  524. PATTRIBUTE_COLUMN colsSitesContainer[5] = { &colName, &colLocation, &colClass, &colDesc, NULL };
  525. PATTRIBUTE_COLUMN colsServersContainer[6] = { &colName, &colDomain, &colBridgehead, &colClass, &colDesc, NULL };
  526. PATTRIBUTE_COLUMN colsNTDSDSA[6] = { &colConnectionName, &colFromServer, &colFromSite, &colClass, &colDesc, NULL };
  527. PATTRIBUTE_COLUMN colsInterSiteTransport[6] = { &colName, &colClass, &colDesc, &colCost, &colReplInterval, NULL };
  528. PATTRIBUTE_COLUMN colsFRSReplicaSet[6] = { &colName, &colReplicaComputer, &colReplicaDomain, &colClass, &colDesc, NULL };
  529. PATTRIBUTE_COLUMN colsFRSMember[6] = { &colConnectionName, &colFromFRSComputer, &colFromFRSDomain, &colClass, &colDesc, NULL };
  530. PATTRIBUTE_COLUMN colsFSP[5] = { &colName, &colClass, &colDesc, &colNameFromSID, NULL };
  531. PATTRIBUTE_COLUMN colsSpecial[26] = { &colName, &colClass, &colDesc, &colGenericSpecial, &colGenericSpecial,
  532. &colGenericSpecial, &colGenericSpecial, &colGenericSpecial, &colGenericSpecial, &colGenericSpecial,
  533. &colGenericSpecial, &colGenericSpecial, &colGenericSpecial, &colGenericSpecial, &colGenericSpecial,
  534. &colGenericSpecial, &colGenericSpecial, &colModifiedTime, &colGenericSpecial, &colGenericSpecial,
  535. &colGenericSpecial, &colGenericSpecial, &colGenericSpecial, &colGenericSpecial, &colGenericSpecial,
  536. NULL };
  537. PATTRIBUTE_COLUMN colsDefault[4] = { &colName, &colClass, &colDesc, NULL };
  538. // currently, any additional columns must be of string type
  539. COLUMNS_FOR_CLASS g_colarray[] = {
  540. { _T("subnetContainer"), _T("subnetContainer"), 5, colsSubnetContainer },
  541. { _T("sitesContainer"), _T("sitesContainer"), 4, colsSitesContainer},
  542. { _T("serversContainer"), _T("serversContainer"), 5, colsServersContainer},
  543. { _T("nTDSDSA"), _T("nTDSDSA"), 5, colsNTDSDSA },
  544. { _T("interSiteTransport"), _T("interSiteTransport"), 5, colsInterSiteTransport},
  545. { _T("nTFRSReplicaSet"), _T("nTFRSReplicaSet"), 5, colsFRSReplicaSet },
  546. { _T("nTFRSMember"), _T("nTFRSMember"), 5, colsFRSMember },
  547. { _T("ForeignSecurityPrincipals"), _T("ForeignSecurityPrincipals"), 4, colsFSP },
  548. { SPECIAL_COLUMN_SET, SPECIAL_COLUMN_SET, 25, colsSpecial },
  549. { NULL, DEFAULT_COLUMN_SET, 3, colsDefault } // empty one at the end; must be here
  550. };
  551. /*
  552. COLUMNS_FOR_CLASS* GetColumnsForClass( LPCTSTR i_pcszLdapClassName )
  553. {
  554. if (NULL == i_pcszLdapClassName)
  555. i_pcszLdapClassName = L"";
  556. COLUMNS_FOR_CLASS* pColsForClass;
  557. for (pColsForClass = g_colarray; NULL != pColsForClass->pcszLdapClassName; pColsForClass++) {
  558. if ( 0 == _wcsicmp(i_pcszLdapClassName, pColsForClass->pcszLdapClassName) ) {
  559. break;
  560. }
  561. }
  562. ASSERT( NULL != pColsForClass );
  563. return pColsForClass;
  564. }
  565. */
  566. ////////////////////////////////////////////////////////////////////////////////////
  567. // CDSColumnSet
  568. CDSColumnSet* CDSColumnSet::CreateColumnSet(PCOLUMNS_FOR_CLASS pColsForClass, SnapinType snapinType)
  569. {
  570. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  571. // Using the class name as both the column id and the class name for the column set
  572. CDSColumnSet* pNewColumnSet = new CDSColumnSet(pColsForClass->pcszColumnID, pColsForClass->pcszLdapClassName);
  573. if (!pNewColumnSet)
  574. {
  575. TRACE(L"Unable to allocate memory for new column set\n");
  576. ASSERT(FALSE);
  577. return 0;
  578. }
  579. UINT nUserColCount = 0;
  580. for (int idx = 0; idx < pColsForClass->nColumns; idx ++)
  581. {
  582. CString cstrHeader;
  583. CDSColumn* pNewColumn;
  584. if (pColsForClass->apColumns[idx]->resid == 0)
  585. {
  586. // Don't add the exchange special columns in DSSite
  587. if (snapinType == SNAPINTYPE_SITE)
  588. continue;
  589. cstrHeader.LoadString(g_specialCols[nUserColCount].resid);
  590. pNewColumn = new CDSColumn((LPCWSTR)cstrHeader,
  591. LVCFMT_LEFT,
  592. g_specialCols[nUserColCount].iColumnWidth,
  593. idx,
  594. FALSE,
  595. g_specialCols[nUserColCount].ptszAttribute,
  596. pColsForClass->apColumns[idx]->coltype,
  597. pColsForClass->apColumns[idx]->pfnExtract);
  598. nUserColCount++;
  599. }
  600. else
  601. {
  602. cstrHeader.LoadString(pColsForClass->apColumns[idx]->resid);
  603. pNewColumn = new CDSColumn((LPCWSTR)cstrHeader,
  604. LVCFMT_LEFT,
  605. pColsForClass->apColumns[idx]->iColumnWidth,
  606. idx,
  607. TRUE,
  608. pColsForClass->apColumns[idx]->pcszAttribute,
  609. pColsForClass->apColumns[idx]->coltype,
  610. pColsForClass->apColumns[idx]->pfnExtract);
  611. }
  612. ASSERT(pNewColumn);
  613. if (pNewColumn)
  614. {
  615. pNewColumnSet->AddColumn(pNewColumn);
  616. }
  617. }
  618. return pNewColumnSet;
  619. }
  620. CDSColumnSet* CDSColumnSet::CreateColumnSetFromString(LPCWSTR lpszClassName, SnapinType snapinType)
  621. {
  622. COLUMNS_FOR_CLASS* pColsForClass;
  623. for (pColsForClass = g_colarray; pColsForClass->pcszLdapClassName != NULL; pColsForClass++)
  624. {
  625. if (lpszClassName != NULL && pColsForClass->pcszLdapClassName != NULL)
  626. {
  627. if (wcscmp(pColsForClass->pcszLdapClassName, lpszClassName) == 0)
  628. {
  629. break;
  630. }
  631. }
  632. }
  633. return CDSColumnSet::CreateColumnSet(pColsForClass, snapinType);
  634. }
  635. CDSColumnSet* CDSColumnSet::CreateDescriptionColumnSet()
  636. {
  637. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  638. CString szNameHeader;
  639. VERIFY(szNameHeader.LoadString(IDS_COLUMN_NAME));
  640. CColumn* pNameColumn = new CColumn(szNameHeader,
  641. LVCFMT_LEFT,
  642. 100,
  643. 0,
  644. TRUE);
  645. if (pNameColumn == NULL)
  646. {
  647. return NULL;
  648. }
  649. CString szDescriptionHeader;
  650. VERIFY(szDescriptionHeader.LoadString(IDS_COLUMN_DESCRIPTION));
  651. CColumn* pDescColumn = new CColumn(szDescriptionHeader,
  652. LVCFMT_LEFT,
  653. 150,
  654. 1,
  655. TRUE);
  656. if (pDescColumn == NULL)
  657. {
  658. if (pNameColumn)
  659. {
  660. delete pNameColumn;
  661. }
  662. return NULL;
  663. }
  664. CDSColumnSet* pDSColumnSet = new CDSColumnSet(L"***---Description Set---***", NULL);
  665. if (pDSColumnSet == NULL)
  666. {
  667. if (pNameColumn)
  668. {
  669. delete pNameColumn;
  670. }
  671. if (pDescColumn)
  672. {
  673. delete pDescColumn;
  674. }
  675. return NULL;
  676. }
  677. pDSColumnSet->AddColumn(pNameColumn);
  678. pDSColumnSet->AddColumn(pDescColumn);
  679. return pDSColumnSet;
  680. }
  681. CDSColumnSet* CDSColumnSet::CreateColumnSetFromDisplaySpecifiers(PCWSTR pszClassName, SnapinType snapinType, MyBasePathsInfo* pBasePathsInfo)
  682. {
  683. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  684. HRESULT hr = S_OK;
  685. CDSColumnSet* pNewColumnSet = NULL;
  686. BOOL bDefaultHardcodedSet = FALSE;
  687. //
  688. // Using the class name as both the column id and the class name for the column set
  689. //
  690. pNewColumnSet = new CDSColumnSet(pszClassName, pszClassName);
  691. if (pNewColumnSet != NULL)
  692. {
  693. //
  694. // Start with the hardcoded columns
  695. //
  696. COLUMNS_FOR_CLASS* pColsForClass;
  697. for (pColsForClass = g_colarray; pColsForClass->pcszLdapClassName != NULL; pColsForClass++)
  698. {
  699. if (pszClassName != NULL && pColsForClass->pcszLdapClassName != NULL)
  700. {
  701. if (wcscmp(pColsForClass->pcszLdapClassName, pszClassName) == 0)
  702. {
  703. break;
  704. }
  705. }
  706. }
  707. if (pColsForClass != NULL)
  708. {
  709. if (wcscmp(pColsForClass->pcszColumnID, DEFAULT_COLUMN_SET) == 0)
  710. {
  711. bDefaultHardcodedSet = TRUE;
  712. }
  713. UINT nUserColCount = 0;
  714. for (int idx = 0; idx < pColsForClass->nColumns; idx ++)
  715. {
  716. CString cstrHeader;
  717. CDSColumn* pNewColumn;
  718. if (pColsForClass->apColumns[idx]->resid == 0)
  719. {
  720. // Don't add the exchange special columns in DSSite
  721. if (snapinType == SNAPINTYPE_SITE)
  722. continue;
  723. cstrHeader.LoadString(g_specialCols[nUserColCount].resid);
  724. pNewColumn = new CDSColumn((LPCWSTR)cstrHeader,
  725. LVCFMT_LEFT,
  726. g_specialCols[nUserColCount].iColumnWidth,
  727. idx,
  728. FALSE,
  729. g_specialCols[nUserColCount].ptszAttribute,
  730. pColsForClass->apColumns[idx]->coltype,
  731. pColsForClass->apColumns[idx]->pfnExtract);
  732. nUserColCount++;
  733. }
  734. else
  735. {
  736. cstrHeader.LoadString(pColsForClass->apColumns[idx]->resid);
  737. pNewColumn = new CDSColumn((LPCWSTR)cstrHeader,
  738. LVCFMT_LEFT,
  739. pColsForClass->apColumns[idx]->iColumnWidth,
  740. idx,
  741. TRUE,
  742. pColsForClass->apColumns[idx]->pcszAttribute,
  743. pColsForClass->apColumns[idx]->coltype,
  744. pColsForClass->apColumns[idx]->pfnExtract);
  745. }
  746. pNewColumnSet->AddColumn(pNewColumn);
  747. }
  748. }
  749. //
  750. // Now add the DS extraColumns
  751. //
  752. CStringList strListColumns;
  753. hr = GetDisplaySpecifierProperty(pszClassName, L"extraColumns", pBasePathsInfo, strListColumns);
  754. if (FAILED(hr))
  755. {
  756. hr = GetDisplaySpecifierProperty(pszClassName, L"extraColumns", pBasePathsInfo, strListColumns, true);
  757. }
  758. if (SUCCEEDED(hr))
  759. {
  760. UINT nColCount = static_cast<UINT>(pNewColumnSet->GetCount());
  761. POSITION pos = strListColumns.GetHeadPosition();
  762. while (pos != NULL)
  763. {
  764. CDSColumn* pNewColumn = NULL;
  765. CString szExtraColumn = strListColumns.GetNext(pos);
  766. if (!szExtraColumn.IsEmpty())
  767. {
  768. //
  769. // Parse the 5-tuple to get the elements to make the column
  770. //
  771. CString szAttributeName;
  772. CString szColHeader;
  773. BOOL bVisible = TRUE;
  774. int iColumnWidth = 0;
  775. GUID guidCallbackInterface; // unused. Reserved for future callback interface
  776. PWSTR pszTemp = new WCHAR[szExtraColumn.GetLength() + 1];
  777. if (pszTemp != NULL)
  778. {
  779. wcscpy(pszTemp, (LPCWSTR)szExtraColumn);
  780. PWSTR pszVisible = NULL;
  781. PWSTR pszColumnWidth = NULL;
  782. PWSTR pszGuidCallback = NULL;
  783. PWSTR pszNextTuple = pszTemp;
  784. pszNextTuple = wcstok(pszTemp, L",");
  785. if (pszNextTuple != NULL)
  786. {
  787. szAttributeName = pszNextTuple;
  788. }
  789. pszNextTuple = wcstok(NULL, L",");
  790. if (pszNextTuple != NULL)
  791. {
  792. szColHeader = pszNextTuple;
  793. }
  794. pszNextTuple = wcstok(NULL, L",");
  795. if (pszNextTuple != NULL)
  796. {
  797. pszVisible = pszNextTuple;
  798. int i = _wtoi(pszVisible);
  799. if (i == 0)
  800. {
  801. bVisible = FALSE;
  802. }
  803. else
  804. {
  805. bVisible = TRUE;
  806. }
  807. }
  808. pszNextTuple = wcstok(NULL, L",");
  809. if (pszNextTuple != NULL)
  810. {
  811. pszColumnWidth = pszNextTuple;
  812. iColumnWidth = _wtoi(pszColumnWidth);
  813. }
  814. pszNextTuple = wcstok(NULL, L",");
  815. if (pszNextTuple != NULL)
  816. {
  817. pszGuidCallback = pszNextTuple;
  818. HRESULT hr2 = ::CLSIDFromString(pszGuidCallback, &guidCallbackInterface);
  819. if (FAILED(hr2))
  820. {
  821. memset(&guidCallbackInterface, 0, sizeof(GUID));
  822. }
  823. }
  824. // NTRAID#NTBUG9-702278-2002/09/11-artm
  825. // Need to intelligently get the type of the column's data.
  826. // If the type of the attribute is UTC time, we need to
  827. // pass the time column type to make sure the correct sorting
  828. // method is used.
  829. ATTRIBUTE_COLUMN_TYPE columnType = ATTR_COLTYPE_SPECIAL;
  830. ADSTYPE attributeType = ADSTYPE_INVALID;
  831. hr = pBasePathsInfo->GetAttributeADsType(szAttributeName, attributeType);
  832. if (SUCCEEDED(hr) && attributeType == ADSTYPE_UTC_TIME)
  833. {
  834. columnType = ATTR_COLTYPE_MODIFIED_TIME;
  835. }
  836. //
  837. // Create the column with the retrieved data
  838. //
  839. pNewColumn = new CDSColumn((PCWSTR)szColHeader,
  840. LVCFMT_LEFT,
  841. iColumnWidth,
  842. nColCount++,
  843. bVisible,
  844. (PCWSTR)szAttributeName,
  845. columnType,
  846. ColumnExtractAttribute); // this will be changed to the interface when that is implemented
  847. }
  848. delete[] pszTemp;
  849. }
  850. if (pNewColumn != NULL)
  851. {
  852. pNewColumnSet->AddColumn(pNewColumn);
  853. }
  854. }
  855. }
  856. }
  857. //
  858. // If we failed to retrieve columns from the display specifier
  859. // and we hit the default hardcoded set but we were not asking
  860. // for the default hardcoded set and the snapin isn't the sites snapin
  861. // Then we delete the column set and we will pickup the actual default
  862. // column set since we are returning NULL
  863. //
  864. if (FAILED(hr) &&
  865. bDefaultHardcodedSet &&
  866. _wcsicmp(pszClassName, DEFAULT_COLUMN_SET) != 0 &&
  867. snapinType != SNAPINTYPE_SITE)
  868. {
  869. delete pNewColumnSet;
  870. pNewColumnSet = NULL;
  871. }
  872. return pNewColumnSet;
  873. }
  874. HRESULT CColumnSet::Save(IStream* pStm)
  875. {
  876. // save the column set ID
  877. HRESULT hr = SaveStringHelper(GetColumnID(), pStm);
  878. if (FAILED(hr))
  879. return hr;
  880. // save the # of visible columns and
  881. // the indexes of the visible columns
  882. // NOTICE: we use MMC's MMC_VISIBLE_COLUMNS format to be consitent
  883. // and to be able to read back easily
  884. INT nTotalCols = GetNumCols();
  885. // allocate a bit more than needed (i.e. total # of columns)
  886. MMC_VISIBLE_COLUMNS* pVisibleColumns =
  887. (MMC_VISIBLE_COLUMNS*)new BYTE[sizeof(MMC_VISIBLE_COLUMNS) + (sizeof(INT)*(nTotalCols-1))];
  888. if (!pVisibleColumns)
  889. {
  890. return E_OUTOFMEMORY;
  891. }
  892. pVisibleColumns->nVisibleColumns = 0;
  893. int iIndex = 0;
  894. for (POSITION pos = GetHeadPosition(); (pos != NULL); )
  895. {
  896. CColumn* pCol = GetNext(pos);
  897. if (pCol->IsVisible())
  898. {
  899. pVisibleColumns->rgVisibleCols[pVisibleColumns->nVisibleColumns] = iIndex;
  900. (pVisibleColumns->nVisibleColumns)++;
  901. }
  902. iIndex++;
  903. }
  904. // save the right length of the struct
  905. ULONG nByteCount = sizeof(MMC_VISIBLE_COLUMNS) + (sizeof(INT)*(pVisibleColumns->nVisibleColumns-1));
  906. ULONG nBytesWritten;
  907. hr = pStm->Write((void*)pVisibleColumns, nByteCount, &nBytesWritten);
  908. if (SUCCEEDED(hr))
  909. {
  910. if (nBytesWritten < nByteCount)
  911. {
  912. hr = STG_E_CANTSAVE;
  913. }
  914. }
  915. delete[] pVisibleColumns;
  916. pVisibleColumns = 0;
  917. return hr;
  918. }
  919. HRESULT CColumnSet::Load(IStream* pStm)
  920. {
  921. // NOTICE: we already loaded the column set ID and
  922. // got a columns set that matches this
  923. // read the # of visible columns
  924. DWORD dwColCount = 0;
  925. INT nCountMax = GetNumCols();
  926. HRESULT hr = LoadDWordHelper(pStm, &dwColCount);
  927. if (FAILED(hr) || ((INT)dwColCount > nCountMax))
  928. return E_FAIL;
  929. // allocate some space for the array past the struct
  930. MMC_VISIBLE_COLUMNS* pVisibleColumns =
  931. (MMC_VISIBLE_COLUMNS*)new BYTE[sizeof(MMC_VISIBLE_COLUMNS) + (sizeof(INT)*(dwColCount-1))];
  932. if (!pVisibleColumns)
  933. {
  934. return E_OUTOFMEMORY;
  935. }
  936. pVisibleColumns->nVisibleColumns = (INT)dwColCount;
  937. // load the array of indexes of visible columns
  938. ULONG nBytesRead;
  939. ULONG nByteCount = sizeof(DWORD)*dwColCount;
  940. INT* pArr = pVisibleColumns->rgVisibleCols;
  941. hr = pStm->Read(pArr, nByteCount, &nBytesRead);
  942. if (SUCCEEDED(hr))
  943. {
  944. if (nBytesRead < nByteCount)
  945. {
  946. hr = E_FAIL;
  947. }
  948. else
  949. {
  950. // update columns
  951. AddVisibleColumns(pVisibleColumns);
  952. }
  953. }
  954. delete[] pVisibleColumns;
  955. pVisibleColumns = 0;
  956. return S_OK;
  957. }
  958. /////////////////////////////////////////////////////////////////////////////////////////
  959. // CColumnSetList
  960. void CColumnSetList::Initialize(SnapinType snapinType,
  961. MyBasePathsInfo* pBasePathsInfo)
  962. {
  963. m_pBasePathsInfo = pBasePathsInfo;
  964. m_snapinType = snapinType;
  965. }
  966. //
  967. // Find the column set given a column set ID
  968. //
  969. CColumnSet* CColumnSetList::FindColumnSet(LPCWSTR lpszColumnID)
  970. {
  971. POSITION pos = GetHeadPosition();
  972. while (pos != NULL)
  973. {
  974. CColumnSet* pTempSet = GetNext(pos);
  975. ASSERT(pTempSet != NULL);
  976. LPCWSTR lpszTempNodeID = pTempSet->GetColumnID();
  977. if (wcscmp(lpszTempNodeID, lpszColumnID) == 0)
  978. {
  979. return pTempSet;
  980. }
  981. }
  982. CColumnSet* pNewColSet = CDSColumnSet::CreateColumnSetFromDisplaySpecifiers(lpszColumnID,
  983. m_snapinType,
  984. m_pBasePathsInfo);
  985. if (pNewColSet != NULL)
  986. {
  987. AddTail(pNewColSet);
  988. return pNewColSet;
  989. }
  990. return GetSpecialColumnSet();
  991. }
  992. CColumnSet* CColumnSetList::GetDefaultColumnSet()
  993. {
  994. if (m_pDefaultColumnSet == NULL)
  995. {
  996. m_pDefaultColumnSet = CDSColumnSet::CreateColumnSetFromDisplaySpecifiers(DEFAULT_COLUMN_SET,
  997. m_snapinType,
  998. m_pBasePathsInfo);
  999. }
  1000. return m_pDefaultColumnSet;
  1001. }
  1002. CColumnSet* CColumnSetList::GetSpecialColumnSet()
  1003. {
  1004. if (m_pSpecialColumnSet == NULL)
  1005. {
  1006. m_pSpecialColumnSet =
  1007. CDSColumnSet::CreateColumnSetFromString(SPECIAL_COLUMN_SET, m_snapinType);
  1008. }
  1009. ASSERT(m_pSpecialColumnSet);
  1010. return m_pSpecialColumnSet;
  1011. }
  1012. HRESULT CColumnSetList::Save(IStream* pStm)
  1013. {
  1014. // save # of items in the list
  1015. DWORD dwCount = (DWORD)GetCount();
  1016. // list count plus default column set
  1017. if (m_pDefaultColumnSet)
  1018. {
  1019. ++dwCount;
  1020. }
  1021. // And special column set
  1022. if (m_pSpecialColumnSet)
  1023. {
  1024. ++dwCount;
  1025. }
  1026. HRESULT hr = SaveDWordHelper(pStm, dwCount);
  1027. if (FAILED(hr))
  1028. return hr;
  1029. // save columnset list
  1030. for (POSITION pos = GetHeadPosition(); pos != NULL; )
  1031. {
  1032. CColumnSet* pTempSet = GetNext(pos);
  1033. if (pTempSet == NULL)
  1034. {
  1035. ASSERT(pTempSet != NULL);
  1036. continue;
  1037. }
  1038. hr = pTempSet->Save(pStm);
  1039. if (FAILED(hr))
  1040. return hr;
  1041. }
  1042. // save default column set
  1043. if (m_pDefaultColumnSet != NULL)
  1044. {
  1045. hr = m_pDefaultColumnSet->Save(pStm);
  1046. }
  1047. // save the special column set
  1048. if (m_pSpecialColumnSet)
  1049. {
  1050. hr = m_pSpecialColumnSet->Save(pStm);
  1051. }
  1052. return hr;
  1053. }
  1054. HRESULT CColumnSetList::Load(IStream* pStm)
  1055. {
  1056. // load # of items in the list
  1057. DWORD dwLoadCount;
  1058. HRESULT hr = LoadDWordHelper(pStm, &dwLoadCount);
  1059. if (FAILED(hr))
  1060. return hr;
  1061. // load column list
  1062. CString szColumnID;
  1063. for (DWORD iColSet = 0; iColSet< dwLoadCount; iColSet++)
  1064. {
  1065. // load the string with the name of the column set
  1066. hr = LoadStringHelper(szColumnID, pStm);
  1067. if (FAILED(hr))
  1068. return hr;
  1069. ASSERT(!szColumnID.IsEmpty());
  1070. CColumnSet* pColumnSet = 0;
  1071. if (szColumnID.CompareNoCase(DEFAULT_COLUMN_SET) == 0)
  1072. {
  1073. pColumnSet = GetDefaultColumnSet();
  1074. }
  1075. else if (szColumnID.CompareNoCase(SPECIAL_COLUMN_SET) == 0)
  1076. {
  1077. pColumnSet = GetSpecialColumnSet();
  1078. }
  1079. else
  1080. {
  1081. pColumnSet = FindColumnSet(szColumnID);
  1082. }
  1083. if (pColumnSet != NULL)
  1084. {
  1085. hr = pColumnSet->Load(pStm);
  1086. if (FAILED(hr))
  1087. {
  1088. return hr;
  1089. }
  1090. }
  1091. }
  1092. return S_OK;
  1093. }