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.

2745 lines
79 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1998 - 1999
  6. //
  7. // File: domain.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "preDNSsn.h"
  11. #include <SnapBase.h>
  12. #include "resource.h"
  13. #include "dnsutil.h"
  14. #include "DNSSnap.h"
  15. #include "snapdata.h"
  16. #include "server.h"
  17. #include "domain.h"
  18. #include "record.h"
  19. #include "zone.h"
  20. #include "delegwiz.h"
  21. #ifdef DEBUG_ALLOCATOR
  22. #ifdef _DEBUG
  23. #define new DEBUG_NEW
  24. #undef THIS_FILE
  25. static char THIS_FILE[] = __FILE__;
  26. #endif
  27. #endif
  28. BOOL _match(LPCWSTR lpszNSName,
  29. CDNS_A_RecordNode* pARecordNode)
  30. {
  31. TRACE(_T("NS %s A %s\n"), lpszNSName, pARecordNode->GetString(0));
  32. return DnsNameCompare_W((LPWSTR)lpszNSName, (LPWSTR)pARecordNode->GetString(0));
  33. }
  34. /////////////////////////////////////////////////////////////////////////
  35. // CNewDomainDialog
  36. class CNewDomainDialog : public CHelpDialog
  37. {
  38. // Construction
  39. public:
  40. CNewDomainDialog(CDNSDomainNode* pParentDomainNode,
  41. CComponentDataObject* pComponentData);
  42. enum { IDD = IDD_DOMAIN_ADDNEWDOMAIN };
  43. // Implementation
  44. protected:
  45. virtual BOOL OnInitDialog();
  46. virtual void OnOK();
  47. afx_msg void OnEditChange();
  48. afx_msg void OnIPv4CtrlChange();
  49. afx_msg BOOL OnHelpInfo(HELPINFO* pHelpInfo);
  50. DECLARE_MESSAGE_MAP()
  51. private:
  52. CDNSDomainNode* m_pParentDomainNode;
  53. CComponentDataObject* m_pComponentData;
  54. CEdit* GetDomainEdit() { return (CEdit*)GetDlgItem(IDC_EDIT_DOMAIN_NAME);}
  55. CDNSIPv4Control* GetDomainIPv4Ctrl()
  56. { return (CDNSIPv4Control*)GetDlgItem(IDC_IPEDIT_DOMAIN_NAME);}
  57. CString m_szDomainName;
  58. BOOL m_bAdvancedView;
  59. int m_nOctects;
  60. int m_nUTF8ParentLen;
  61. };
  62. BEGIN_MESSAGE_MAP(CNewDomainDialog, CHelpDialog)
  63. ON_EN_CHANGE(IDC_EDIT_DOMAIN_NAME,OnEditChange)
  64. ON_EN_CHANGE(IDC_IPEDIT_DOMAIN_NAME, OnIPv4CtrlChange)
  65. END_MESSAGE_MAP()
  66. CNewDomainDialog::CNewDomainDialog(CDNSDomainNode* pParentDomainNode,
  67. CComponentDataObject* pComponentData)
  68. : CHelpDialog(CNewDomainDialog::IDD, pComponentData)
  69. {
  70. ASSERT(pParentDomainNode != NULL);
  71. ASSERT(pComponentData != NULL);
  72. m_pParentDomainNode = pParentDomainNode;
  73. m_pComponentData = pComponentData;
  74. m_bAdvancedView = TRUE;
  75. m_nOctects = -1; // invalid if advanced view
  76. m_nUTF8ParentLen = UTF8StringLen(pParentDomainNode->GetFullName());
  77. }
  78. BOOL CNewDomainDialog::OnInitDialog()
  79. {
  80. CHelpDialog::OnInitDialog();
  81. // move the edit box in place of the IP control
  82. CDNSIPv4Control* pNameIPCtrl = GetDomainIPv4Ctrl();
  83. CEdit* pNameEdit = GetDomainEdit();
  84. pNameEdit->SetLimitText(MAX_DNS_NAME_LEN - m_nUTF8ParentLen - 1);
  85. CRect editRect;
  86. pNameEdit->GetWindowRect(editRect);
  87. ScreenToClient(editRect);
  88. CRect ipRect;
  89. pNameIPCtrl->GetWindowRect(ipRect);
  90. ScreenToClient(ipRect);
  91. ipRect.bottom = editRect.top + ipRect.Height();
  92. ipRect.right = editRect.left + ipRect.Width();
  93. ipRect.top = editRect.top;
  94. ipRect.left = editRect.left;
  95. pNameIPCtrl->MoveWindow(ipRect,TRUE);
  96. // determine if we need/can have advanced view
  97. CDNSRootData* pRootData = (CDNSRootData*)m_pComponentData->GetRootData();
  98. ASSERT(pRootData != NULL);
  99. m_bAdvancedView = pRootData->IsAdvancedView();
  100. // force advanced view if we are in a forward lookup zone
  101. if (!(m_pParentDomainNode->GetZoneNode()->IsReverse()))
  102. m_bAdvancedView = TRUE;
  103. // determine if we can have a normal view representation
  104. CString szDomainName = m_pParentDomainNode->GetFullName();
  105. if (!m_bAdvancedView)
  106. {
  107. // to have normal view we have to have a valid arpa suffix
  108. BOOL bArpa = RemoveInAddrArpaSuffix(szDomainName.GetBuffer(1));
  109. szDomainName.ReleaseBuffer(); // got "77.80.55.157"
  110. if (!bArpa)
  111. {
  112. m_bAdvancedView = TRUE; // no need to toggle
  113. }
  114. else
  115. {
  116. m_nOctects = ReverseIPString(szDomainName.GetBuffer(1));
  117. szDomainName.ReleaseBuffer(); // finally got "157.55.80.77"
  118. // to have a normal view representation we cannot
  119. // have more than 2 octects
  120. if (m_nOctects > 2)
  121. {
  122. m_bAdvancedView = TRUE; // force advanced for classless
  123. }
  124. else
  125. {
  126. ASSERT(m_nOctects > 0);
  127. switch(m_nOctects)
  128. {
  129. case 1: // e.g. "157", now "157._"
  130. szDomainName += _T(".0.0"); // got "157._.0.0"
  131. break;
  132. case 2: // e.g. "157.55"
  133. szDomainName += _T(".0"); // got "157.55._.0"
  134. break;
  135. };
  136. // set the IP control with IP mask value
  137. IP_ADDRESS ipAddr = IPStringToAddr(szDomainName);
  138. ASSERT(ipAddr != INADDR_NONE);
  139. pNameIPCtrl->SetIPv4Val(ipAddr);
  140. for (int k=0; k<4; k++)
  141. pNameIPCtrl->EnableField(k, k == m_nOctects);
  142. }
  143. }
  144. } // if (!m_bAdvancedView)
  145. // toggle text in static control
  146. CDNSToggleTextControlHelper staticTextToggle;
  147. UINT pnButtonStringIDs[2] = { IDS_NEW_DOMAIN_INST1, IDS_NEW_DOMAIN_INST2 };
  148. VERIFY(staticTextToggle.Init(this, IDC_STATIC_TEXT, pnButtonStringIDs));
  149. staticTextToggle.SetToggleState(m_bAdvancedView);
  150. //
  151. // enable/hide appropriate controls
  152. //
  153. if (m_bAdvancedView)
  154. {
  155. pNameIPCtrl->EnableWindow(FALSE);
  156. pNameIPCtrl->ShowWindow(FALSE);
  157. }
  158. else
  159. {
  160. pNameEdit->EnableWindow(FALSE);
  161. pNameEdit->ShowWindow(FALSE);
  162. }
  163. GetDlgItem(IDOK)->EnableWindow(!m_bAdvancedView);
  164. return TRUE; // return TRUE unless you set the focus to a control
  165. }
  166. void CNewDomainDialog::OnEditChange()
  167. {
  168. ASSERT(m_bAdvancedView);
  169. //
  170. // Get new name from control
  171. //
  172. GetDomainEdit()->GetWindowText(m_szDomainName);
  173. //
  174. // Trim white space
  175. //
  176. m_szDomainName.TrimLeft();
  177. m_szDomainName.TrimRight();
  178. //
  179. // Enable OK button if its a valid name
  180. //
  181. CString szFullDomainName;
  182. if (_wcsicmp(m_pParentDomainNode->GetFullName(), L".") == 0)
  183. {
  184. //
  185. // If the parent domain is the root zone just check the name followed by a '.'
  186. //
  187. szFullDomainName.Format(L"%s.", m_szDomainName);
  188. }
  189. else
  190. {
  191. //
  192. // Else append the parent domain name to the new name
  193. //
  194. szFullDomainName.Format(L"%s.%s", m_szDomainName, m_pParentDomainNode->GetFullName());
  195. }
  196. //
  197. // Get server flags
  198. //
  199. DWORD dwNameChecking = m_pParentDomainNode->GetServerNode()->GetNameCheckFlag();
  200. //
  201. // Is valid?
  202. //
  203. BOOL bIsValidName = (0 == ValidateDnsNameAgainstServerFlags(szFullDomainName,
  204. DnsNameDomain,
  205. dwNameChecking));
  206. GetDlgItem(IDOK)->EnableWindow(bIsValidName);
  207. }
  208. void CNewDomainDialog::OnIPv4CtrlChange()
  209. {
  210. ASSERT(!m_bAdvancedView);
  211. CDNSIPv4Control* pNameIPCtrl = GetDomainIPv4Ctrl();
  212. DWORD dwArr[4];
  213. pNameIPCtrl->GetArray(dwArr, 4);
  214. BOOL bEmpty = (dwArr[m_nOctects] == FIELD_EMPTY);
  215. if (!bEmpty)
  216. {
  217. ASSERT(dwArr[m_nOctects] <= 255);
  218. m_szDomainName.Format(_T("%d"), dwArr[m_nOctects]);
  219. }
  220. GetDlgItem(IDOK)->EnableWindow(!bEmpty);
  221. }
  222. void CNewDomainDialog::OnOK()
  223. {
  224. RECORD_SEARCH recordSearch = RECORD_NOT_FOUND;
  225. CDNSDomainNode* pNewParentDomain = NULL;
  226. CString szFullRecordName = m_szDomainName + L"." + m_pParentDomainNode->GetFullName();
  227. CString szNonExistentDomain;
  228. CDNSRecordNodeBase* pExistingRecordNode = 0;
  229. recordSearch = m_pParentDomainNode->GetZoneNode()->DoesContain(szFullRecordName,
  230. m_pComponentData,
  231. &pNewParentDomain,
  232. &pExistingRecordNode,
  233. szNonExistentDomain,
  234. TRUE);
  235. if (recordSearch == RECORD_NOT_FOUND &&
  236. pNewParentDomain != NULL)
  237. {
  238. DNS_STATUS err = pNewParentDomain->CreateSubdomain(m_szDomainName,m_pComponentData);
  239. if (err != 0)
  240. {
  241. // creation error, warn the user and prompt again
  242. DNSErrorDialog(err, IDS_MSG_DOMAIN_FAIL_CREATE);
  243. CEdit* pDomainNameEdit = GetDomainEdit();
  244. pDomainNameEdit->SetSel(0,-1);
  245. pDomainNameEdit->SetFocus();
  246. return;
  247. }
  248. }
  249. else if (recordSearch == NON_EXISTENT_SUBDOMAIN && pNewParentDomain != NULL)
  250. {
  251. CDNSRootData* pRootData = (CDNSRootData*)m_pComponentData->GetRootData();
  252. //
  253. // Create the node on the server
  254. //
  255. CDNSDomainNode* pNewDomainNode = pNewParentDomain->CreateSubdomainNode();
  256. if (pNewDomainNode == NULL)
  257. {
  258. ASSERT(pNewDomainNode != NULL);
  259. return;
  260. }
  261. pNewParentDomain->SetSubdomainName(pNewDomainNode, m_szDomainName, pRootData->IsAdvancedView());
  262. //
  263. // tell the newly created object to write to the server
  264. //
  265. DNS_STATUS err = pNewDomainNode->Create();
  266. if (err != 0)
  267. {
  268. DNSErrorDialog(err, IDS_MSG_DOMAIN_FAIL_CREATE);
  269. return;
  270. }
  271. if (!szNonExistentDomain.IsEmpty())
  272. {
  273. //
  274. // Create the first subdomain because the current domain is already enumerated
  275. // so we have to start the remaining enumeration at the new subdomain that is needed
  276. //
  277. CDNSDomainNode* pSubdomainNode = pNewParentDomain->CreateSubdomainNode();
  278. ASSERT(pSubdomainNode != NULL);
  279. pNewParentDomain->SetSubdomainName(pSubdomainNode, szNonExistentDomain, pRootData->IsAdvancedView());
  280. VERIFY(pNewParentDomain->AddChildToListAndUISorted(pSubdomainNode, m_pComponentData));
  281. m_pComponentData->SetDescriptionBarText(pNewParentDomain);
  282. //
  283. // I don't care what the results of this are, I am just using it
  284. // to do the expansion to the new record
  285. //
  286. recordSearch = pSubdomainNode->GetZoneNode()->DoesContain(szFullRecordName,
  287. m_pComponentData,
  288. &pNewParentDomain,
  289. &pExistingRecordNode,
  290. szNonExistentDomain,
  291. TRUE);
  292. }
  293. }
  294. else if (recordSearch == RECORD_NOT_FOUND_AT_THE_NODE)
  295. {
  296. //
  297. // Do nothing since this is a domain and it already exists
  298. //
  299. }
  300. else
  301. {
  302. DNS_STATUS err = m_pParentDomainNode->CreateSubdomain(m_szDomainName,m_pComponentData);
  303. if (err != 0)
  304. {
  305. // creation error, warn the user and prompt again
  306. DNSErrorDialog(err, IDS_MSG_DOMAIN_FAIL_CREATE);
  307. CEdit* pDomainNameEdit = GetDomainEdit();
  308. pDomainNameEdit->SetSel(0,-1);
  309. pDomainNameEdit->SetFocus();
  310. return;
  311. }
  312. }
  313. CHelpDialog::OnOK();
  314. }
  315. /////////////////////////////////////////////////////////////////////////
  316. // CDNSDomainQueryObj
  317. class CDNSDomainMsg : public CObjBase
  318. {
  319. };
  320. BOOL CDNSDomainQueryObj::Enumerate()
  321. {
  322. USES_CONVERSION;
  323. TRACE(_T("CDNSDomainQueryObj::Enumerate(): Server <%s> Zone/Domain %s Enumerating\n"), (LPCTSTR)m_szServerName, (LPCTSTR)m_szNodeName);
  324. DNS_STATUS err = 0;
  325. // if needed, get the zone info
  326. if (m_bIsZone && !m_bCache)
  327. {
  328. CDNSZoneInfoEx* pZoneInfo = new CDNSZoneInfoEx;
  329. if (pZoneInfo)
  330. {
  331. err = pZoneInfo->Query(m_szServerName, m_szFullNodeName, m_dwServerVersion);
  332. if (err != 0)
  333. {
  334. delete pZoneInfo;
  335. pZoneInfo = NULL;
  336. OnError(err);
  337. return FALSE; // no need to enumerate if we have no zone info
  338. }
  339. else
  340. {
  341. VERIFY(AddQueryResult(pZoneInfo));
  342. }
  343. }
  344. else
  345. {
  346. OnError(ERROR_OUTOFMEMORY);
  347. return FALSE;
  348. }
  349. }
  350. // if executing a query for a specific RR type, just do it right away
  351. if (m_wRecordType != DNS_TYPE_ALL)
  352. {
  353. // we assume that a type specific query does not have filtering enabled
  354. ASSERT(m_bGetAll);
  355. ASSERT(m_nFilterOption == DNS_QUERY_FILTER_DISABLED);
  356. err = EnumerateFiltered(m_wRecordType);
  357. if (err != 0)
  358. OnError(err);
  359. return FALSE; // we are done
  360. }
  361. // DO A MULTI PASS QUERY
  362. m_bFirstPass = TRUE;
  363. // there are items that cannot be filtered out for consistency
  364. // (zone info, SOA, Ns, etc.), so we disable any filtering while
  365. // getting them
  366. BOOL bGetAllOld = m_bGetAll;
  367. BOOL nFilterOptionOld = m_nFilterOption;
  368. m_bGetAll = TRUE;
  369. m_nFilterOption = DNS_QUERY_FILTER_DISABLED;
  370. // only zones or the cache have SOA RR's
  371. if (m_bIsZone || m_bCache)
  372. {
  373. err = EnumerateFiltered(DNS_TYPE_SOA);
  374. if (err != 0)
  375. {
  376. OnError(err);
  377. return FALSE;
  378. }
  379. }
  380. // only zones have WINS and NBSTAT RR's
  381. if (m_bIsZone)
  382. {
  383. if (m_bReverse)
  384. err = EnumerateFiltered(DNS_TYPE_NBSTAT);
  385. else
  386. err = EnumerateFiltered(DNS_TYPE_WINS);
  387. if (err != 0)
  388. {
  389. OnError(err);
  390. return FALSE;
  391. }
  392. }
  393. // need also to check for NS (zone or delegation)
  394. err = EnumerateFiltered(DNS_TYPE_NS);
  395. if (err != 0)
  396. {
  397. OnError(err);
  398. return FALSE;
  399. }
  400. // add a message in the queue to signal we are done with
  401. // the first phase
  402. CDNSDomainMsg* pDomainMsg = new CDNSDomainMsg;
  403. if (pDomainMsg)
  404. {
  405. AddQueryResult(pDomainMsg);
  406. }
  407. else
  408. {
  409. OnError(ERROR_OUTOFMEMORY);
  410. return FALSE;
  411. }
  412. // now query again, for all RR's, but need to filter the
  413. // known types out
  414. m_bFirstPass = FALSE;
  415. // restore the filtering parameters we had before
  416. m_bGetAll = bGetAllOld;
  417. m_nFilterOption = nFilterOptionOld;
  418. err = EnumerateFiltered(DNS_TYPE_ALL);
  419. if (err != 0)
  420. OnError(err);
  421. return FALSE;
  422. }
  423. DNS_STATUS CDNSDomainQueryObj::EnumerateFiltered(WORD wRecordType)
  424. {
  425. DWORD dwSelectFlags = m_dwSelectFlags;
  426. // for single type queries, we do not want subfolders
  427. if (wRecordType != DNS_TYPE_ALL)
  428. dwSelectFlags |= DNS_RPC_VIEW_NO_CHILDREN;
  429. return CDNSDomainNode::EnumerateNodes(m_szServerName,
  430. m_szZoneName.IsEmpty() ? NULL : (LPCWSTR)m_szZoneName,
  431. m_szNodeName,
  432. m_szFullNodeName,
  433. wRecordType,
  434. dwSelectFlags,
  435. m_bIsZone,
  436. m_bReverse,
  437. m_bAdvancedView,
  438. this);
  439. }
  440. BOOL CDNSDomainQueryObj::CanAddRecord(WORD wRecordType, LPCWSTR lpszRecordName)
  441. {
  442. if (m_nFilterOption == DNS_QUERY_FILTER_DISABLED)
  443. return TRUE; // we have no filtering at all
  444. // determine if this is a special record type for filtered queries
  445. BOOL bSpecialType = (wRecordType == DNS_TYPE_SOA) || (wRecordType == DNS_TYPE_NS) ||
  446. (wRecordType == DNS_TYPE_WINS) || (wRecordType == DNS_TYPE_NBSTAT);
  447. // in the first pass only special types allowed
  448. if (m_bFirstPass)
  449. return bSpecialType;
  450. // in the second pass do not allow special types
  451. if (!m_bFirstPass && bSpecialType)
  452. return FALSE;
  453. // we are left with normal types, apply the filtering, if required
  454. if (m_nFilterOption == DNS_QUERY_FILTER_NONE)
  455. return TRUE; // allow all
  456. // need to match the record name
  457. return MatchName(lpszRecordName);
  458. }
  459. /////////////////////////////////////////////////////////////////////////
  460. // CDNSDomainNode
  461. BEGIN_TOOLBAR_MAP(CDNSDomainNode)
  462. TOOLBAR_EVENT(toolbarNewRecord, OnNewRecord)
  463. END_TOOLBAR_MAP()
  464. // {720132BA-44B2-11d1-B92F-00A0C9A06D2D}
  465. const GUID CDNSDomainNode::NodeTypeGUID =
  466. { 0x720132ba, 0x44b2, 0x11d1, { 0xb9, 0x2f, 0x0, 0xa0, 0xc9, 0xa0, 0x6d, 0x2d } };
  467. CDNSDomainNode::CDNSDomainNode(BOOL bDelegation)
  468. {
  469. m_bDelegation = bDelegation;
  470. m_pZoneNode = NULL;
  471. m_pNSRecordNodeList = new CDNS_NS_RecordNodeList;
  472. ASSERT(m_pNSRecordNodeList != NULL);
  473. m_bHasDataForPropPages = FALSE;
  474. }
  475. CDNSDomainNode::~CDNSDomainNode()
  476. {
  477. TRACE(_T("~CDNSDomainNode(), name <%s>\n"),GetDisplayName());
  478. ASSERT(m_pNSRecordNodeList != NULL);
  479. delete m_pNSRecordNodeList;
  480. m_pNSRecordNodeList = NULL;
  481. }
  482. DWORD CDNSDomainNode::GetDefaultTTL()
  483. {
  484. if ( (m_pZoneNode != NULL) && (m_pZoneNode->GetZoneType() != DNS_ZONE_TYPE_CACHE) )
  485. return m_pZoneNode->GetSOARecordMinTTL();
  486. else
  487. return (DWORD)0; // no info available from SOA RR
  488. }
  489. void CDNSDomainNode::SetFullDNSName(BOOL bIsZone,
  490. BOOL,
  491. LPCTSTR lpszNodeName,
  492. LPCTSTR lpszParentFullName)
  493. {
  494. ASSERT(lpszNodeName != NULL);
  495. ASSERT(lpszParentFullName != NULL);
  496. if (bIsZone)
  497. {
  498. //
  499. // the two names have to be the same, zone parent of itself
  500. //
  501. ASSERT(_wcsicmp(lpszParentFullName, lpszNodeName) == 0);
  502. m_szFullName = lpszParentFullName;
  503. }
  504. else // it is a domain
  505. {
  506. ASSERT(_wcsicmp(lpszParentFullName, lpszNodeName) != 0);
  507. //
  508. // chain the node name to the parent full name to get the node's full name
  509. //
  510. if (lpszParentFullName[0] == L'.' )
  511. {
  512. //
  513. // if parent is "." and name is "bar", get "bar.": this is the case for the root
  514. // if parent is ".com" and name is "bar", get "bar.com":
  515. //
  516. m_szFullName.Format(_T("%s%s"), lpszNodeName,lpszParentFullName);
  517. }
  518. else
  519. {
  520. //
  521. // if parent is "foo.com" and name is "bar", get "bar.foo.com"
  522. //
  523. m_szFullName.Format(_T("%s.%s"), lpszNodeName,lpszParentFullName);
  524. }
  525. }
  526. TRACE(_T("CDNSDomainNode::SetFullDNSName() fullName = <%s>\n"), (LPCTSTR)m_szFullName);
  527. }
  528. void CDNSDomainNode::SetDisplayDNSName(BOOL bIsZone,
  529. BOOL bReverse,
  530. BOOL bAdvancedView,
  531. LPCTSTR lpszNodeName,
  532. LPCTSTR lpszParentFullName)
  533. {
  534. ASSERT(lpszNodeName != NULL);
  535. ASSERT(lpszParentFullName != NULL);
  536. if (_wcsicmp(lpszNodeName, L".") == 0)
  537. {
  538. CString szRootString;
  539. VERIFY(szRootString.LoadString(IDS_ROOT_ZONE_LABEL));
  540. m_szDisplayName = L"." + szRootString;
  541. }
  542. else
  543. {
  544. m_szDisplayName = lpszNodeName;
  545. }
  546. if (bIsZone && bReverse && !bAdvancedView)
  547. {
  548. CDNSZoneNode::SetZoneNormalViewHelper(m_szDisplayName);
  549. }
  550. }
  551. void CDNSDomainNode::SetNames(BOOL bIsZone, BOOL bReverse, BOOL bAdvancedView,
  552. LPCTSTR lpszNodeName, LPCTSTR lpszParentFullName)
  553. {
  554. ASSERT(lpszNodeName != NULL);
  555. ASSERT(lpszParentFullName != NULL);
  556. TRACE(_T("CDNSDomainNode::SetNames(bIsZone=%d, bReverse=%d, bAdvancedView=%d, lpszNodeName=<%s>, lpszParentFullName=<%s>)\n"),
  557. bIsZone, bReverse, bAdvancedView, lpszNodeName,lpszParentFullName);
  558. SetFullDNSName(bIsZone, bReverse, lpszNodeName, lpszParentFullName);
  559. SetDisplayDNSName(bIsZone, bReverse, bAdvancedView, lpszNodeName, lpszParentFullName);
  560. }
  561. void CDNSDomainNode::ChangePTRRecordsViewOption(BOOL bAdvanced,
  562. CComponentDataObject* pComponentDataObject)
  563. {
  564. POSITION pos;
  565. for( pos = m_containerChildList.GetHeadPosition(); pos != NULL; )
  566. {
  567. CTreeNode* pCurrentChild = m_containerChildList.GetNext(pos);
  568. // recurse down the tree
  569. CDNSDomainNode* pDomainNode = dynamic_cast<CDNSDomainNode*>(pCurrentChild);
  570. ASSERT(pDomainNode != NULL);
  571. pDomainNode->ChangePTRRecordsViewOption(bAdvanced, pComponentDataObject);
  572. }
  573. POSITION leafPos;
  574. for ( leafPos = m_leafChildList.GetHeadPosition(); leafPos != NULL; )
  575. {
  576. CTreeNode* pCurrentLeafNode = m_leafChildList.GetNext(leafPos);
  577. CDNSRecordNodeBase* pRecordNode = dynamic_cast<CDNSRecordNodeBase*>(pCurrentLeafNode);
  578. if (pRecordNode &&
  579. DNS_TYPE_PTR == pRecordNode->GetType())
  580. {
  581. CDNS_PTR_RecordNode* pPTRRecordNode = (CDNS_PTR_RecordNode*)pRecordNode;
  582. pPTRRecordNode->ChangeDisplayName(this, bAdvanced);
  583. }
  584. }
  585. }
  586. CQueryObj* CDNSDomainNode::OnCreateQuery()
  587. {
  588. // generic default setting
  589. WORD wRecordType = DNS_TYPE_ALL;
  590. DWORD dwSelectFlags = (m_pZoneNode->GetZoneType() == DNS_ZONE_TYPE_CACHE) ?
  591. DNS_RPC_VIEW_CACHE_DATA : DNS_RPC_VIEW_AUTHORITY_DATA;
  592. if (IsDelegation())
  593. {
  594. // special case the delegation: show only NS records and
  595. // will have no children shown (delegation cut)
  596. wRecordType = DNS_TYPE_NS;
  597. dwSelectFlags = DNS_RPC_VIEW_GLUE_DATA | DNS_RPC_VIEW_NO_CHILDREN;
  598. //dwSelectFlags = DNS_RPC_VIEW_GLUE_DATA |
  599. // DNS_RPC_VIEW_NO_CHILDREN | DNS_RPC_VIEW_ADDITIONAL_DATA;
  600. }
  601. BOOL bCache = GetZoneNode()->GetZoneType() == DNS_ZONE_TYPE_CACHE;
  602. LPCWSTR lpszZoneName = bCache ? NULL : m_pZoneNode->GetFullName();
  603. CDNSRootData* pRootData = (CDNSRootData*)GetRootContainer();
  604. ASSERT(pRootData != NULL);
  605. CDNSDomainQueryObj* pQuery = new
  606. CDNSDomainQueryObj(GetServerNode()->GetRPCName(),
  607. lpszZoneName,
  608. GetServerNode()->GetVersion(),
  609. GetDisplayName(),
  610. m_szFullName,
  611. wRecordType,
  612. dwSelectFlags,
  613. IsZone(),
  614. GetZoneNode()->IsReverse(),
  615. bCache,
  616. pRootData->IsAdvancedView());
  617. // delegations will not have any filtering option (data consistency)
  618. if (!IsDelegation())
  619. {
  620. pQuery->SetFilterOptions(pRootData->GetFilter());
  621. }
  622. return pQuery;
  623. }
  624. BOOL CDNSDomainNode::OnRefresh(CComponentDataObject* pComponentData,
  625. CNodeList* pNodeList)
  626. {
  627. if (pNodeList->GetCount() > 1) // multiple selection
  628. {
  629. BOOL bRet = TRUE;
  630. POSITION pos = pNodeList->GetHeadPosition();
  631. while (pos != NULL)
  632. {
  633. CTreeNode* pNode = pNodeList->GetNext(pos);
  634. ASSERT(pNode != NULL);
  635. CNodeList nodeList;
  636. nodeList.AddTail(pNode);
  637. if (!pNode->OnRefresh(pComponentData, &nodeList))
  638. {
  639. bRet = FALSE;
  640. }
  641. }
  642. return bRet;
  643. }
  644. //
  645. // single selection
  646. //
  647. if (CMTContainerNode::OnRefresh(pComponentData, pNodeList))
  648. {
  649. GetNSRecordNodeList()->RemoveAll();
  650. m_bHasDataForPropPages = FALSE;
  651. return TRUE;
  652. }
  653. return FALSE;
  654. }
  655. void CDNSDomainNode::OnThreadExitingNotification(CComponentDataObject* pComponentDataObject)
  656. {
  657. if (!m_bHasDataForPropPages)
  658. {
  659. // never got a CDNSDomainMsg notification object
  660. // but we are done anyway, so change it back
  661. m_bHasDataForPropPages = TRUE;
  662. }
  663. // call now the base class
  664. CDNSMTContainerNode::OnThreadExitingNotification(pComponentDataObject);
  665. }
  666. void CDNSDomainNode::OnHaveData(CObjBase* pObj, CComponentDataObject* pComponentDataObject)
  667. {
  668. if (IS_CLASS(*pObj, CDNSDomainMsg))
  669. {
  670. // special case for a "message" object sent through to update verbs
  671. TRACE(_T("Got CDNSDomainMsg\n"));
  672. delete pObj;
  673. ASSERT(!m_bHasDataForPropPages); // should get only once
  674. m_bHasDataForPropPages = TRUE;
  675. VERIFY(SUCCEEDED(pComponentDataObject->UpdateVerbState(this)));
  676. return;
  677. }
  678. if (IS_CLASS(*pObj, CDNSDomainNode))
  679. {
  680. // assume all the child containers are derived from this class
  681. CDNSDomainNode* pDomainNode = dynamic_cast<CDNSDomainNode*>(pObj);
  682. pDomainNode->SetServerNode(GetServerNode());
  683. pDomainNode->SetZone(m_pZoneNode);
  684. }
  685. else
  686. {
  687. OnHaveRecord(dynamic_cast<CDNSRecordNodeBase*>(pObj), pComponentDataObject);
  688. }
  689. AddChildToListAndUI(dynamic_cast<CTreeNode*>(pObj), pComponentDataObject);
  690. pComponentDataObject->SetDescriptionBarText(this);
  691. }
  692. void CDNSDomainNode::OnHaveRecord(CDNSRecordNodeBase* pRecordNode,
  693. CComponentDataObject* pComponentDataObject)
  694. {
  695. WORD wType = pRecordNode->GetType();
  696. if (wType == DNS_TYPE_PTR)
  697. {
  698. ASSERT(pComponentDataObject != NULL); // assume this for PTR
  699. CDNSRootData* pRootData = (CDNSRootData*)pComponentDataObject->GetRootData();
  700. ASSERT(pRootData != NULL);
  701. // if we are in normal view, have to change the
  702. // default advanced representation
  703. BOOL bAdvancedView = pRootData->IsAdvancedView();
  704. if (!bAdvancedView)
  705. ((CDNS_PTR_RecordNode*)pRecordNode)->ChangeDisplayName(this, bAdvancedView);
  706. }
  707. else if (wType == DNS_TYPE_NS)
  708. {
  709. ASSERT(pRecordNode->IsAtTheNode());
  710. GetNSRecordNodeList()->AddTail((CDNS_NS_RecordNode*)pRecordNode);
  711. }
  712. }
  713. BOOL CDNSDomainNode::OnAddMenuItem(LPCONTEXTMENUITEM2 pContextMenuItem2,
  714. long*)
  715. {
  716. if (pContextMenuItem2->lCommandID == IDM_SNAPIN_ADVANCED_VIEW)
  717. {
  718. pContextMenuItem2->fFlags = ((CDNSRootData*)GetRootContainer())->IsAdvancedView() ? MF_CHECKED : 0;
  719. return TRUE;
  720. }
  721. if (pContextMenuItem2->lCommandID == IDM_SNAPIN_FILTERING)
  722. {
  723. if (((CDNSRootData*)GetRootContainer())->IsFilteringEnabled())
  724. {
  725. pContextMenuItem2->fFlags = MF_CHECKED;
  726. }
  727. return TRUE;
  728. }
  729. DWORD dwType = m_pZoneNode->GetZoneType();
  730. BOOL bIsAutocreated = m_pZoneNode->IsAutocreated();
  731. BOOL bIsSecondaryOrCache = (dwType == DNS_ZONE_TYPE_SECONDARY) ||
  732. (dwType == DNS_ZONE_TYPE_CACHE) ||
  733. (dwType == DNS_ZONE_TYPE_STUB);
  734. BOOL bIsDelegatedDomain = !IsZone() && IsDelegation();
  735. if (bIsSecondaryOrCache || bIsAutocreated || bIsDelegatedDomain)
  736. {
  737. return FALSE;
  738. }
  739. // different add operations depending on the FWD/REV type
  740. if (!GetZoneNode()->IsReverse() &&
  741. (pContextMenuItem2->lCommandID == IDM_DOMAIN_NEW_PTR))
  742. {
  743. // do not add a PTR to a FWD lookup zone
  744. return FALSE;
  745. }
  746. if (GetZoneNode()->IsReverse() &&
  747. ((pContextMenuItem2->lCommandID == IDM_DOMAIN_NEW_HOST) ||
  748. (pContextMenuItem2->lCommandID == IDM_DOMAIN_NEW_MX)))
  749. {
  750. // do not add a HOST, MX, ALIAS to a REV lookup zone
  751. return FALSE;
  752. }
  753. // have the menu item added. but it might be grayed out...
  754. if (m_nState != loaded)
  755. {
  756. pContextMenuItem2->fFlags |= MF_GRAYED;
  757. }
  758. return TRUE;
  759. }
  760. HRESULT CDNSDomainNode::OnSetToolbarVerbState(IToolbar* pToolbar,
  761. CNodeList* pNodeList)
  762. {
  763. HRESULT hr = S_OK;
  764. //
  765. // Set the button state for each button on the toolbar
  766. //
  767. hr = pToolbar->SetButtonState(toolbarNewServer, ENABLED, FALSE);
  768. ASSERT(SUCCEEDED(hr));
  769. hr = pToolbar->SetButtonState(toolbarNewZone, ENABLED, FALSE);
  770. ASSERT(SUCCEEDED(hr));
  771. if (pNodeList->GetCount() > 1) // multiple selection
  772. {
  773. hr = pToolbar->SetButtonState(toolbarNewRecord, ENABLED, FALSE);
  774. }
  775. else if (pNodeList->GetCount() == 1) // single selection
  776. {
  777. DWORD dwType = m_pZoneNode->GetZoneType();
  778. BOOL bIsAutocreated = m_pZoneNode->IsAutocreated();
  779. BOOL bIsSecondaryOrCache = (dwType == DNS_ZONE_TYPE_SECONDARY) ||
  780. (dwType == DNS_ZONE_TYPE_CACHE) ||
  781. (dwType == DNS_ZONE_TYPE_STUB);
  782. BOOL bIsDelegatedDomain = !IsZone() && IsDelegation();
  783. BOOL bEnable = TRUE;
  784. if (bIsSecondaryOrCache || bIsAutocreated || bIsDelegatedDomain)
  785. {
  786. bEnable = FALSE;
  787. }
  788. hr = pToolbar->SetButtonState(toolbarNewRecord, ENABLED, bEnable);
  789. }
  790. return hr;
  791. }
  792. BOOL CDNSDomainNode::OnSetDeleteVerbState(DATA_OBJECT_TYPES type,
  793. BOOL* pbHide,
  794. CNodeList* pNodeList)
  795. {
  796. if (pNodeList->GetCount() > 1) // multiple selection
  797. {
  798. BOOL bRet = TRUE;
  799. BOOL bRetHide = FALSE;
  800. *pbHide = FALSE;
  801. POSITION pos = pNodeList->GetHeadPosition();
  802. while (pos != NULL)
  803. {
  804. CTreeNode* pNode = pNodeList->GetNext(pos);
  805. ASSERT(pNode != NULL);
  806. CNodeList nodeList;
  807. nodeList.AddTail(pNode);
  808. if (!pNode->OnSetDeleteVerbState(type, &bRetHide, &nodeList))
  809. {
  810. bRet = FALSE;
  811. break;
  812. }
  813. if (bRetHide)
  814. {
  815. *pbHide = TRUE;
  816. }
  817. }
  818. return bRet;
  819. }
  820. *pbHide = FALSE;
  821. DWORD dwType = m_pZoneNode->GetZoneType();
  822. BOOL bIsAutocreated = m_pZoneNode->IsAutocreated();
  823. if (IsThreadLocked())
  824. {
  825. return FALSE;
  826. }
  827. //
  828. // cannot delete from an autocreate zone/domain
  829. //
  830. if (bIsAutocreated)
  831. {
  832. return FALSE;
  833. }
  834. //
  835. // cannot delete from a secondary or stub zone, but can delete the zone itself
  836. // cannot delete the cache
  837. //
  838. if (
  839. (
  840. ( ((dwType == DNS_ZONE_TYPE_SECONDARY) || (dwType == DNS_ZONE_TYPE_STUB)) && !IsZone() ) || // subdomain of secondary
  841. ( (dwType == DNS_ZONE_TYPE_CACHE) && IsZone() ) // cache zone itself
  842. )
  843. )
  844. {
  845. return FALSE;
  846. }
  847. return TRUE;
  848. }
  849. BOOL CDNSDomainNode::OnSetRefreshVerbState(DATA_OBJECT_TYPES,
  850. BOOL* pbHide,
  851. CNodeList*)
  852. {
  853. *pbHide = FALSE;
  854. return !IsThreadLocked();
  855. }
  856. HRESULT CDNSDomainNode::OnCommand(long nCommandID,
  857. DATA_OBJECT_TYPES,
  858. CComponentDataObject* pComponentData,
  859. CNodeList* pNodeList)
  860. {
  861. if (pNodeList->GetCount() > 1) // multiple selection
  862. {
  863. return E_FAIL;
  864. }
  865. switch (nCommandID)
  866. {
  867. case IDM_DOMAIN_NEW_DOMAIN:
  868. OnNewDomain(pComponentData);
  869. break;
  870. case IDM_DOMAIN_NEW_DELEGATION:
  871. OnNewDelegation(pComponentData);
  872. break;
  873. case IDM_DOMAIN_NEW_RECORD:
  874. OnNewRecord(pComponentData, pNodeList);
  875. break;
  876. case IDM_DOMAIN_NEW_HOST:
  877. OnNewHost(pComponentData);
  878. break;
  879. case IDM_DOMAIN_NEW_ALIAS:
  880. OnNewAlias(pComponentData);
  881. break;
  882. case IDM_DOMAIN_NEW_MX:
  883. OnNewMailExchanger(pComponentData);
  884. break;
  885. case IDM_DOMAIN_NEW_PTR:
  886. OnNewPointer(pComponentData);
  887. break;
  888. case IDM_SNAPIN_ADVANCED_VIEW:
  889. ((CDNSRootData*)pComponentData->GetRootData())->OnViewOptions(pComponentData);
  890. break;
  891. case IDM_SNAPIN_FILTERING:
  892. {
  893. if(((CDNSRootData*)pComponentData->GetRootData())->OnFilteringOptions(pComponentData))
  894. {
  895. pComponentData->SetDescriptionBarText(this);
  896. }
  897. }
  898. break;
  899. default:
  900. ASSERT(FALSE); // Unknown command!
  901. return E_FAIL;
  902. }
  903. return S_OK;
  904. }
  905. LPWSTR CDNSDomainNode::GetDescriptionBarText()
  906. {
  907. static CString szFilterEnabled;
  908. static CString szRecordsFormat;
  909. INT_PTR nContainerCount = GetContainerChildList()->GetCount();
  910. INT_PTR nLeafCount = GetLeafChildList()->GetCount();
  911. //
  912. // If not already loaded, then load the format string L"%d record(s)"
  913. //
  914. if (szRecordsFormat.IsEmpty())
  915. {
  916. szRecordsFormat.LoadString(IDS_FORMAT_RECORDS);
  917. }
  918. //
  919. // Format the child count into the description bar text
  920. //
  921. m_szDescriptionBar.Format(szRecordsFormat, nContainerCount + nLeafCount);
  922. //
  923. // Add L"[Filter Activated]" if the filter is on
  924. //
  925. if(((CDNSRootData*)GetRootContainer())->IsFilteringEnabled())
  926. {
  927. //
  928. // If not already loaded, then load the L"[Filter Activated]" string
  929. //
  930. if (szFilterEnabled.IsEmpty())
  931. {
  932. szFilterEnabled.LoadString(IDS_FILTER_ENABLED);
  933. }
  934. m_szDescriptionBar += szFilterEnabled;
  935. }
  936. return (LPWSTR)(LPCWSTR)m_szDescriptionBar;
  937. }
  938. int CDNSDomainNode::GetImageIndex(BOOL)
  939. {
  940. int nIndex = 0;
  941. BOOL bDelegation = IsDelegation();
  942. switch (m_nState)
  943. {
  944. case notLoaded:
  945. nIndex = bDelegation ? DELEGATED_DOMAIN_IMAGE_NOT_LOADED : DOMAIN_IMAGE_NOT_LOADED;
  946. break;
  947. case loading:
  948. nIndex = bDelegation ? DELEGATED_DOMAIN_IMAGE_LOADING : DOMAIN_IMAGE_LOADING;
  949. break;
  950. case loaded:
  951. nIndex = bDelegation ? DELEGATED_DOMAIN_IMAGE_LOADED : DOMAIN_IMAGE_LOADED;
  952. break;
  953. case unableToLoad:
  954. nIndex = bDelegation ? DELEGATED_DOMAIN_IMAGE_UNABLE_TO_LOAD : DOMAIN_IMAGE_UNABLE_TO_LOAD;
  955. break;
  956. case accessDenied:
  957. nIndex = bDelegation ? DELEGATED_DOMAIN_IMAGE_ACCESS_DENIED : DOMAIN_IMAGE_ACCESS_DENIED;
  958. break;
  959. default:
  960. ASSERT(FALSE);
  961. }
  962. return nIndex;
  963. }
  964. void CDNSDomainNode::OnDelete(CComponentDataObject* pComponentData,
  965. CNodeList* pNodeList)
  966. {
  967. if (pNodeList->GetCount() > 1) // multiple selection
  968. {
  969. OnMultiselectDelete(pComponentData, pNodeList);
  970. return;
  971. }
  972. UINT nRet = DNSConfirmOperation(IDS_MSG_DOMAIN_DELETE, this);
  973. if (IDNO == nRet ||
  974. IDCANCEL == nRet)
  975. {
  976. return;
  977. }
  978. if (IsSheetLocked())
  979. {
  980. if (!CanCloseSheets())
  981. return;
  982. pComponentData->GetPropertyPageHolderTable()->DeleteSheetsOfNode(this);
  983. }
  984. ASSERT(!IsSheetLocked());
  985. DNS_STATUS err = Delete();
  986. if (err != 0)
  987. {
  988. DNSErrorDialog(err, IDS_MSG_DOMAIN_FAIL_DELETE);
  989. return;
  990. }
  991. // now remove from the UI and from the cache
  992. DeleteHelper(pComponentData);
  993. delete this; // gone
  994. }
  995. void CDNSDomainNode::OnMultiselectDelete(CComponentDataObject* pComponentData,
  996. CNodeList* pNodeList)
  997. {
  998. CThemeContextActivator activator;
  999. UINT nRet = DNSConfirmOperation(IDS_MSG_DOMAIN_MULTI_DELETE, this);
  1000. if (IDCANCEL == nRet ||
  1001. IDNO == nRet)
  1002. {
  1003. return;
  1004. }
  1005. DNS_STATUS* errArray = new DNS_STATUS[pNodeList->GetCount()];
  1006. if (errArray == NULL)
  1007. {
  1008. DNSErrorDialog(E_OUTOFMEMORY, IDS_MSG_DOMAIN_FAIL_DELETE);
  1009. return;
  1010. }
  1011. memset(errArray, 0, sizeof(DNS_STATUS) * pNodeList->GetCount());
  1012. BOOL bErrorOccurred = FALSE;
  1013. UINT idx = 0;
  1014. POSITION pos = pNodeList->GetHeadPosition();
  1015. while (pos != NULL)
  1016. {
  1017. CTreeNode* pTreeNode = pNodeList->GetNext(pos);
  1018. if (pTreeNode != NULL)
  1019. {
  1020. if (pTreeNode->IsSheetLocked())
  1021. {
  1022. if (!pTreeNode->CanCloseSheets())
  1023. {
  1024. idx++;
  1025. continue;
  1026. }
  1027. pComponentData->GetPropertyPageHolderTable()->DeleteSheetsOfNode(pTreeNode);
  1028. }
  1029. ASSERT(!pTreeNode->IsSheetLocked());
  1030. CDNSDomainNode* pDomainNode = dynamic_cast<CDNSDomainNode*>(pTreeNode);
  1031. if (pDomainNode != NULL)
  1032. {
  1033. errArray[idx] = pDomainNode->Delete();
  1034. if (errArray[idx] != 0)
  1035. {
  1036. bErrorOccurred = TRUE;
  1037. idx++;
  1038. continue;
  1039. }
  1040. //
  1041. // now remove from the UI and from the cache
  1042. //
  1043. pDomainNode->DeleteHelper(pComponentData);
  1044. delete pDomainNode; // gone
  1045. }
  1046. else
  1047. {
  1048. //
  1049. // If its not a domain node then it must be a record node
  1050. //
  1051. CDNSRecordNodeBase* pRecordNode = dynamic_cast<CDNSRecordNodeBase*>(pTreeNode);
  1052. if (pRecordNode != NULL)
  1053. {
  1054. errArray[idx] = pRecordNode->DeleteOnServerAndUI(pComponentData);
  1055. if (errArray[idx] != 0)
  1056. {
  1057. bErrorOccurred = TRUE;
  1058. idx++;
  1059. continue;
  1060. }
  1061. delete pRecordNode; // gone
  1062. }
  1063. else
  1064. {
  1065. //
  1066. // What type of node is this???
  1067. //
  1068. ASSERT(FALSE);
  1069. }
  1070. }
  1071. }
  1072. idx++;
  1073. }
  1074. //
  1075. // Now display the errors in some meaningful manner
  1076. //
  1077. if (bErrorOccurred)
  1078. {
  1079. CMultiselectErrorDialog dlg;
  1080. CString szTitle;
  1081. CString szCaption;
  1082. CString szColumnHeader;
  1083. VERIFY(szTitle.LoadString(IDS_MULTISELECT_ERROR_DIALOG_TITLE));
  1084. VERIFY(szCaption.LoadString(IDS_MULTISELECT_ERROR_DIALOG_CAPTION));
  1085. VERIFY(szColumnHeader.LoadString(IDS_MULTISELECT_ERROR_DIALOG_COLUMN_HEADER));
  1086. HRESULT hr = dlg.Initialize(pNodeList,
  1087. errArray,
  1088. static_cast<UINT>(pNodeList->GetCount()),
  1089. szTitle,
  1090. szCaption,
  1091. szColumnHeader);
  1092. if (SUCCEEDED(hr))
  1093. {
  1094. dlg.DoModal();
  1095. }
  1096. }
  1097. }
  1098. void CDNSDomainNode::OnNewDomain(CComponentDataObject* pComponentData)
  1099. {
  1100. CThemeContextActivator activator;
  1101. CNewDomainDialog dlg(this, pComponentData);
  1102. // the dialog will do the creation
  1103. dlg.DoModal();
  1104. }
  1105. void CDNSDomainNode::OnNewDelegation(CComponentDataObject* pComponentData)
  1106. {
  1107. CThemeContextActivator activator;
  1108. ASSERT(pComponentData != NULL);
  1109. CDNSMTContainerNode* pContainerNode = (CDNSMTContainerNode*)GetContainer();
  1110. ASSERT(pContainerNode != NULL);
  1111. CDNSDelegationWizardHolder* pHolder =
  1112. new CDNSDelegationWizardHolder(pContainerNode, this, pComponentData);
  1113. if (pHolder != NULL)
  1114. {
  1115. pHolder->DoModalWizard();
  1116. }
  1117. }
  1118. RECORD_SEARCH CDNSDomainNode::DoesContain(PCWSTR pszRecName,
  1119. CComponentDataObject* pComponentData,
  1120. CDNSDomainNode** ppDomainNode,
  1121. CDNSRecordNodeBase** ppExistingRecordNode,
  1122. CString& szNonExistentDomain,
  1123. BOOL bExpandNodes)
  1124. {
  1125. CDNSNameTokenizer recordTokenizer(pszRecName);
  1126. CDNSNameTokenizer domainTokenizer((IsZone()) ? GetFullName() : GetDisplayName());
  1127. if (!recordTokenizer.Tokenize(L".") || !domainTokenizer.Tokenize(L"."))
  1128. {
  1129. *ppDomainNode = NULL;
  1130. return RECORD_NOT_FOUND;
  1131. }
  1132. recordTokenizer.RemoveMatchingFromTail(domainTokenizer);
  1133. if (recordTokenizer.GetCount() == 0 && domainTokenizer.GetCount() == 0)
  1134. {
  1135. //
  1136. // Record is "At the node"
  1137. //
  1138. *ppDomainNode = this;
  1139. return RECORD_NOT_FOUND_AT_THE_NODE;
  1140. }
  1141. else if ((recordTokenizer.GetCount() == 0 && domainTokenizer.GetCount() != 0) ||
  1142. (recordTokenizer.GetCount() != 0 && domainTokenizer.GetCount() != 0))
  1143. {
  1144. //
  1145. // I don't understand how we got in this situation. It means we are searching in
  1146. // the wrong domain.
  1147. //
  1148. ASSERT(FALSE);
  1149. *ppDomainNode = NULL;
  1150. return RECORD_NOT_FOUND;
  1151. }
  1152. else // recordTokenizer.GetCount() != 0 && domainTokenizer.GetCount() == 0
  1153. {
  1154. //
  1155. // Need to search the children lists
  1156. //
  1157. //
  1158. // If the node hasn't been enumerated, do that now
  1159. //
  1160. if (!IsEnumerated())
  1161. {
  1162. if (!bExpandNodes)
  1163. {
  1164. *ppDomainNode = this;
  1165. return DOMAIN_NOT_ENUMERATED;
  1166. }
  1167. else
  1168. {
  1169. //
  1170. // Expand the node
  1171. //
  1172. HWND hWnd = NULL;
  1173. HRESULT hr = pComponentData->GetConsole()->GetMainWindow(&hWnd);
  1174. ASSERT(SUCCEEDED(hr));
  1175. CWnd* pParentWnd = CWnd::FromHandle(hWnd);
  1176. CThemeContextActivator activator;
  1177. CNodeEnumerationThread* pNodeEnumThread =
  1178. new CNodeEnumerationThread(pComponentData, this);
  1179. if (pNodeEnumThread)
  1180. {
  1181. CLongOperationDialog dlg(
  1182. pNodeEnumThread,
  1183. pParentWnd,
  1184. IDR_SEARCH_AVI);
  1185. dlg.DoModal();
  1186. }
  1187. }
  1188. }
  1189. CString szRemaining;
  1190. recordTokenizer.GetRemaining(szRemaining, L".");
  1191. //
  1192. // Search for domains that match the last token remaining in the record name
  1193. //
  1194. POSITION pos = m_containerChildList.GetHeadPosition();
  1195. while (pos != NULL)
  1196. {
  1197. CTreeNode* pCurrentChild = m_containerChildList.GetNext(pos);
  1198. CDNSDomainNode* pDomainNode = dynamic_cast<CDNSDomainNode*>(pCurrentChild);
  1199. if (pDomainNode == NULL)
  1200. {
  1201. ASSERT(FALSE);
  1202. continue;
  1203. }
  1204. if (_wcsicmp(pDomainNode->GetDisplayName(), recordTokenizer.GetTail()) == 0)
  1205. {
  1206. //
  1207. // Found a sub-domain in the path that we have in the UI
  1208. // recurse to see if it or any of its child match pszFullName
  1209. //
  1210. return pDomainNode->DoesContain(
  1211. szRemaining,
  1212. pComponentData,
  1213. ppDomainNode,
  1214. ppExistingRecordNode,
  1215. szNonExistentDomain,
  1216. bExpandNodes);
  1217. }
  1218. }
  1219. //
  1220. // If the remaining name doesn't match a domain and there
  1221. // is still a '.' in it then there is a non-existent domain
  1222. //
  1223. if (szRemaining.Find(L'.') != -1)
  1224. {
  1225. szNonExistentDomain = recordTokenizer.GetTail();
  1226. *ppDomainNode = this;
  1227. return NON_EXISTENT_SUBDOMAIN;
  1228. }
  1229. //
  1230. // Since no domains match, lets check the records
  1231. //
  1232. pos = m_leafChildList.GetHeadPosition();
  1233. while (pos != NULL)
  1234. {
  1235. CTreeNode* pCurrentChild = m_leafChildList.GetNext(pos);
  1236. if (pCurrentChild == NULL)
  1237. {
  1238. ASSERT(FALSE);
  1239. continue;
  1240. }
  1241. if (_wcsicmp(pCurrentChild->GetDisplayName(), szRemaining) == 0)
  1242. {
  1243. //
  1244. // We found the record and its in this domain
  1245. //
  1246. *ppDomainNode = this;
  1247. // the dynamic_cast will return NULL if the node is a zone or domain node
  1248. *ppExistingRecordNode = dynamic_cast<CDNSRecordNodeBase*>(pCurrentChild);
  1249. return RECORD_FOUND;
  1250. }
  1251. }
  1252. }
  1253. *ppDomainNode = this;
  1254. return RECORD_NOT_FOUND;
  1255. }
  1256. CDNSDomainNode* CDNSDomainNode::FindSubdomainNode(LPCTSTR lpszSubdomainNode)
  1257. {
  1258. //
  1259. // assume the string is the name of the subnode as FQDN
  1260. //
  1261. //
  1262. // Check the current node first since it could be zone that is a delegation of
  1263. // one of the protocol domains
  1264. //
  1265. if (_wcsicmp(GetFullName(), lpszSubdomainNode) == 0)
  1266. {
  1267. return this;
  1268. }
  1269. POSITION pos;
  1270. for( pos = m_containerChildList.GetHeadPosition(); pos != NULL; )
  1271. {
  1272. CTreeNode* pCurrentChild = m_containerChildList.GetNext(pos);
  1273. CDNSDomainNode* pSubDomainNode = dynamic_cast<CDNSDomainNode*>(pCurrentChild);
  1274. ASSERT(pSubDomainNode != NULL);
  1275. if (_wcsicmp(pSubDomainNode->GetFullName(), lpszSubdomainNode) == 0)
  1276. {
  1277. return pSubDomainNode;
  1278. }
  1279. }
  1280. return NULL; // not found
  1281. }
  1282. CDNSDomainNode* CDNSDomainNode::CreateSubdomainNode(BOOL bDelegation)
  1283. {
  1284. CDNSDomainNode* pNode = new CDNSDomainNode(bDelegation);
  1285. if (pNode)
  1286. {
  1287. pNode->SetServerNode(GetServerNode());
  1288. ASSERT(m_pZoneNode != NULL);
  1289. pNode->SetZone(m_pZoneNode);
  1290. }
  1291. return pNode;
  1292. }
  1293. void CDNSDomainNode::SetSubdomainName(CDNSDomainNode* pSubdomainNode,
  1294. LPCTSTR lpszSubdomainName, BOOL bAdvancedView)
  1295. {
  1296. ASSERT(m_pZoneNode != NULL);
  1297. ASSERT(pSubdomainNode != NULL);
  1298. BOOL bReverse = GetZoneNode()->IsReverse();
  1299. pSubdomainNode->SetNames(FALSE, bReverse, bAdvancedView, lpszSubdomainName, GetFullName());
  1300. }
  1301. DNS_STATUS CDNSDomainNode::CreateSubdomain(CDNSDomainNode* pSubdomainNode,
  1302. CComponentDataObject* pComponentData)
  1303. {
  1304. // tell the newly created object to write to the server
  1305. DNS_STATUS err = pSubdomainNode->Create();
  1306. if (err == 0)
  1307. {
  1308. // success, add to the UI
  1309. VERIFY(AddChildToListAndUI(pSubdomainNode, pComponentData));
  1310. pComponentData->SetDescriptionBarText(this);
  1311. }
  1312. return err;
  1313. }
  1314. DNS_STATUS CDNSDomainNode::CreateSubdomain(LPCTSTR lpszDomainName,
  1315. CComponentDataObject* pComponentData)
  1316. {
  1317. CDNSDomainNode* pSubdomainNode = CreateSubdomainNode();
  1318. ASSERT(pSubdomainNode != NULL);
  1319. CDNSRootData* pRootData = (CDNSRootData*)pComponentData->GetRootData();
  1320. SetSubdomainName(pSubdomainNode, lpszDomainName, pRootData->IsAdvancedView());
  1321. // tell the newly created object to write to the server
  1322. DNS_STATUS err = CreateSubdomain(pSubdomainNode, pComponentData);
  1323. if (err != 0)
  1324. {
  1325. // something went wrong, bail out
  1326. delete pSubdomainNode;
  1327. }
  1328. return err;
  1329. }
  1330. void CDNSDomainNode::OnNewRecordHelper(CComponentDataObject* pComponentData, WORD wType)
  1331. {
  1332. CThemeContextActivator activator;
  1333. ASSERT(pComponentData != NULL);
  1334. if (wType == 0)
  1335. {
  1336. CSelectDNSRecordTypeDialog dlg(this, pComponentData);
  1337. dlg.DoModal();
  1338. }
  1339. else
  1340. {
  1341. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  1342. CString szTitle;
  1343. szTitle.LoadString(IDS_NEW_RECORD_TITLE);
  1344. CDNSRecordPropertyPageHolder recordHolder(this, NULL, pComponentData, wType);
  1345. recordHolder.DoModalDialog(szTitle);
  1346. }
  1347. }
  1348. HRESULT CDNSDomainNode::OnNewRecord(CComponentDataObject* pComponentData,
  1349. CNodeList* pNodeList)
  1350. {
  1351. ASSERT(pNodeList->GetCount() == 1);
  1352. OnNewRecordHelper(pComponentData, 0);
  1353. return S_OK;
  1354. }
  1355. void CDNSDomainNode::OnNewHost(CComponentDataObject* pComponentData)
  1356. {
  1357. CThemeContextActivator activator;
  1358. //AFX_MANAGE_STATE(AfxGetStaticModuleState());
  1359. //OnNewRecordHelper(pComponentData, DNS_TYPE_A);
  1360. CNewHostDialog dlg(this, pComponentData);
  1361. dlg.DoModal();
  1362. }
  1363. void CDNSDomainNode::OnNewAlias(CComponentDataObject* pComponentData)
  1364. {
  1365. OnNewRecordHelper(pComponentData, DNS_TYPE_CNAME);
  1366. }
  1367. void CDNSDomainNode::OnNewMailExchanger(CComponentDataObject* pComponentData)
  1368. {
  1369. OnNewRecordHelper(pComponentData, DNS_TYPE_MX);
  1370. }
  1371. void CDNSDomainNode::OnNewPointer(CComponentDataObject* pComponentData)
  1372. {
  1373. OnNewRecordHelper(pComponentData, DNS_TYPE_PTR);
  1374. }
  1375. //////////////////////////////////////////////////////////////////////////////////
  1376. // display of property pages
  1377. BOOL CDNSDomainNode::HasPropertyPages(DATA_OBJECT_TYPES,
  1378. BOOL* pbHideVerb,
  1379. CNodeList* pNodeList)
  1380. {
  1381. if (pNodeList->GetCount() > 1) // multiple selection
  1382. {
  1383. *pbHideVerb = TRUE;
  1384. return FALSE;
  1385. }
  1386. *pbHideVerb = FALSE; // always show the verb
  1387. if (!m_bHasDataForPropPages)
  1388. return FALSE;
  1389. // cannot have property pages only in loaded state
  1390. //if (m_nState != loaded)
  1391. // return FALSE;
  1392. // have pages if it is a delegation
  1393. return IsDelegation();
  1394. }
  1395. HRESULT CDNSDomainNode::CreatePropertyPages(LPPROPERTYSHEETCALLBACK lpProvider,
  1396. LONG_PTR handle,
  1397. CNodeList* pNodeList)
  1398. {
  1399. ASSERT(pNodeList->GetCount() == 1); // multi-select not supported
  1400. ASSERT(m_bHasDataForPropPages);
  1401. ASSERT(IsDelegation() || GetZoneNode()->IsDSIntegrated());
  1402. if (GetSheetCount() > 0)
  1403. {
  1404. CComponentDataObject* pComponentDataObject =
  1405. ((CRootData*)(GetContainer()->GetRootContainer()))->GetComponentDataObject();
  1406. ASSERT(pComponentDataObject != NULL);
  1407. pComponentDataObject->GetPropertyPageHolderTable()->BroadcastSelectPage(this, DOMAIN_HOLDER_NS);
  1408. return S_OK;
  1409. }
  1410. return CreatePropertyPagesHelper(lpProvider, handle, DOMAIN_HOLDER_NS);
  1411. }
  1412. void CDNSDomainNode::Show(BOOL bShow, CComponentDataObject* pComponentData)
  1413. {
  1414. CDNSMTContainerNode::Show(bShow, pComponentData);
  1415. if (!bShow)
  1416. GetNSRecordNodeList()->RemoveAll();
  1417. }
  1418. HRESULT CDNSDomainNode::CreatePropertyPagesHelper(LPPROPERTYSHEETCALLBACK lpProvider,
  1419. LONG_PTR handle, long)
  1420. {
  1421. CComponentDataObject* pComponentDataObject =
  1422. ((CRootData*)(GetContainer()->GetRootContainer()))->GetComponentDataObject();
  1423. ASSERT(pComponentDataObject != NULL);
  1424. HRESULT hr = S_OK;
  1425. CDNSDomainPropertyPageHolder* pHolder =
  1426. new CDNSDomainPropertyPageHolder((CDNSDomainNode*)GetContainer(), this, pComponentDataObject);
  1427. if (pHolder)
  1428. {
  1429. pHolder->SetSheetTitle(IDS_PROP_SHEET_TITLE_FMT, this);
  1430. hr = pHolder->CreateModelessSheet(lpProvider, handle);
  1431. }
  1432. else
  1433. {
  1434. hr = E_OUTOFMEMORY;
  1435. }
  1436. return hr;
  1437. }
  1438. //////////////////////////////////////////////////////////////////////////////////
  1439. // Record Sorting in result pane
  1440. int FieldCompareHelper(CTreeNode* pNodeA, CTreeNode* pNodeB, int nCol)
  1441. {
  1442. int iRet = 0;
  1443. if (nCol == N_HEADER_NAME)
  1444. {
  1445. //
  1446. // If the name column is selected we have to sort PTR records by their
  1447. // address
  1448. //
  1449. CDNS_PTR_RecordNode* pRecNodeA = dynamic_cast<CDNS_PTR_RecordNode*>(pNodeA);
  1450. CDNS_PTR_RecordNode* pRecNodeB = dynamic_cast<CDNS_PTR_RecordNode*>(pNodeB);
  1451. if (pRecNodeA == NULL && pRecNodeB == NULL)
  1452. {
  1453. //
  1454. // Neither node is a PTR record, process normally
  1455. //
  1456. LPCTSTR lpszA = pNodeA->GetString(nCol);
  1457. LPCTSTR lpszB = pNodeB->GetString(nCol);
  1458. //
  1459. // cannot process NULL strings, have to use ""
  1460. //
  1461. if (lpszA == NULL || lpszB == NULL)
  1462. {
  1463. ASSERT(FALSE);
  1464. return -1;
  1465. }
  1466. iRet = _wcsicmp(lpszA, lpszB);
  1467. }
  1468. else if (pRecNodeA == NULL)
  1469. {
  1470. //
  1471. // Push non PTR records down in the list
  1472. //
  1473. iRet = 1;
  1474. }
  1475. else if (pRecNodeB == NULL)
  1476. {
  1477. //
  1478. // Push non PTR records down in the list
  1479. //
  1480. iRet = -1;
  1481. }
  1482. else
  1483. {
  1484. //
  1485. // Both nodes are PTR records, compare their Addresses
  1486. // Subtract one from the other
  1487. // This will result in < 0 returned if the first one is less than the second
  1488. // 0 if they are equal, and > 0 if the first is greater than the second
  1489. //
  1490. LPCWSTR lpszNameA, lpszNameB;
  1491. lpszNameA = pRecNodeA->GetTrueRecordName();
  1492. lpszNameB = pRecNodeB->GetTrueRecordName();
  1493. if (lpszNameA == NULL)
  1494. {
  1495. return -1;
  1496. }
  1497. if (lpszNameB == NULL)
  1498. {
  1499. return 1;
  1500. }
  1501. DWORD dwAddrA, dwAddrB;
  1502. int iConverts = swscanf(lpszNameA, L"%d", &dwAddrA);
  1503. if (iConverts != 1)
  1504. {
  1505. return -1;
  1506. }
  1507. iConverts = swscanf(lpszNameB, L"%d", &dwAddrB);
  1508. if (iConverts != 1)
  1509. {
  1510. return 1;
  1511. }
  1512. iRet = dwAddrA - dwAddrB;
  1513. }
  1514. }
  1515. else if (nCol == N_HEADER_DATA)
  1516. {
  1517. //
  1518. // If the data column is selected we have to check the record type so
  1519. // that we can sort by IP address
  1520. //
  1521. CDNS_A_RecordNode* pRecNodeA = dynamic_cast<CDNS_A_RecordNode*>(pNodeA);
  1522. CDNS_A_RecordNode* pRecNodeB = dynamic_cast<CDNS_A_RecordNode*>(pNodeB);
  1523. if (pRecNodeA == NULL && pRecNodeB == NULL)
  1524. {
  1525. //
  1526. // Neither node is an A record, process normally
  1527. //
  1528. LPCTSTR lpszA = pNodeA->GetString(nCol);
  1529. LPCTSTR lpszB = pNodeB->GetString(nCol);
  1530. //
  1531. // cannot process NULL strings, have to use ""
  1532. //
  1533. if (lpszA == NULL || lpszB == NULL)
  1534. {
  1535. ASSERT(FALSE);
  1536. return -1;
  1537. }
  1538. iRet = _wcsicmp(lpszA, lpszB);
  1539. }
  1540. else if (pRecNodeA == NULL)
  1541. {
  1542. //
  1543. // Push non A records down in the list
  1544. //
  1545. iRet = 1;
  1546. }
  1547. else if (pRecNodeB == NULL)
  1548. {
  1549. //
  1550. // Push non A records down in the list
  1551. //
  1552. iRet = -1;
  1553. }
  1554. else
  1555. {
  1556. //
  1557. // Both nodes are A records, compare their IP Addresses
  1558. // Subtract one from the other
  1559. // This will result in < 0 returned if the first one is less than the second
  1560. // 0 if they are equal, and > 0 if the first is greater than the second
  1561. //
  1562. DWORD dwIPA, dwIPB;
  1563. dwIPA = pRecNodeA->GetIPAddress();
  1564. dwIPB = pRecNodeB->GetIPAddress();
  1565. UINT nOctetCount = 0;
  1566. iRet = 0;
  1567. while (iRet == 0 && nOctetCount < 4)
  1568. {
  1569. iRet = (dwIPA & 0xff) - (dwIPB & 0xff);
  1570. dwIPA = dwIPA >> 8;
  1571. dwIPB = dwIPB >> 8;
  1572. ++nOctetCount;
  1573. }
  1574. }
  1575. }
  1576. else
  1577. {
  1578. LPCTSTR lpszA = pNodeA->GetString(nCol);
  1579. LPCTSTR lpszB = pNodeB->GetString(nCol);
  1580. //
  1581. // cannot process NULL strings, have to use ""
  1582. //
  1583. if (lpszA == NULL || lpszB == NULL)
  1584. {
  1585. ASSERT(FALSE);
  1586. return -1;
  1587. }
  1588. iRet = _wcsicmp(lpszA, lpszB);
  1589. }
  1590. return iRet;
  1591. }
  1592. int CDNSDomainNode::Compare(CTreeNode* pNodeA, CTreeNode* pNodeB, int nCol, long)
  1593. {
  1594. // sorting rules for secondary fields
  1595. int nColSec = N_HEADER_TYPE;
  1596. int nColThird = N_HEADER_DATA;
  1597. switch (nCol)
  1598. {
  1599. case N_HEADER_NAME:
  1600. nColSec = N_HEADER_TYPE;
  1601. nColThird = N_HEADER_DATA;
  1602. break;
  1603. case N_HEADER_TYPE:
  1604. nColSec = N_HEADER_NAME;
  1605. nColThird = N_HEADER_DATA;
  1606. break;
  1607. case N_HEADER_DATA:
  1608. nColSec = N_HEADER_NAME;
  1609. nColThird = N_HEADER_TYPE;
  1610. break;
  1611. default:
  1612. ASSERT(FALSE);
  1613. }
  1614. int nResult = FieldCompareHelper(pNodeA, pNodeB, nCol);
  1615. if (nResult != 0)
  1616. return nResult;
  1617. nResult = FieldCompareHelper(pNodeA, pNodeB, nColSec);
  1618. if (nResult != 0)
  1619. return nResult;
  1620. return FieldCompareHelper(pNodeA, pNodeB, nColThird);
  1621. }
  1622. //////////////////////////////////////////////////////////////////////////////////
  1623. // NS record bulk manipulation
  1624. // function to the user for confirmation on editing of A records
  1625. // associated with an NS record
  1626. BOOL _ConfirmEditAction(CDNSRecordNodeEditInfo* pInfo, BOOL bAsk)
  1627. {
  1628. if (!bAsk)
  1629. return TRUE; // silently do it
  1630. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  1631. ASSERT(pInfo->m_pRecord->GetType() == DNS_TYPE_A);
  1632. ASSERT(pInfo->m_pRecord != NULL);
  1633. CDNS_A_RecordNode* pARecordNode = (CDNS_A_RecordNode*)pInfo->m_pRecordNode;
  1634. // load format message
  1635. CString szFmt;
  1636. szFmt.LoadString(IDS_MSG_RECORD_DEL_A_FROM_NS);
  1637. // compose message
  1638. CString szMsg;
  1639. szMsg.Format((LPCWSTR)szFmt, pARecordNode->GetString(0), pARecordNode->GetString(2));
  1640. return (IDYES == DNSMessageBox(szMsg, MB_YESNO | MB_ICONWARNING ) );
  1641. }
  1642. void CDNSDomainNode::GetNSRecordNodesInfo(CDNSRecordNodeEditInfoList* pNSInfoList)
  1643. {
  1644. ASSERT(pNSInfoList != NULL);
  1645. if (!pNSInfoList->IsEmpty())
  1646. {
  1647. ASSERT(FALSE); // should never happen
  1648. pNSInfoList->RemoveAllNodes();
  1649. }
  1650. CDNS_NS_RecordNodeList* pNodeList = GetNSRecordNodeList();
  1651. // for each NS record in the list, create an entry in the info list
  1652. POSITION pos;
  1653. for( pos = pNodeList->GetHeadPosition(); pos != NULL; )
  1654. {
  1655. CDNS_NS_RecordNode* pCurrNode = pNodeList->GetNext(pos);
  1656. ASSERT(pCurrNode != NULL);
  1657. CDNSRecordNodeEditInfo* pNSNodeInfo = new CDNSRecordNodeEditInfo();
  1658. if (pNSNodeInfo)
  1659. {
  1660. // set the data for the NS record, already in the list, so we do now own the memory
  1661. pNSNodeInfo->CreateFromExistingRecord(pCurrNode, FALSE /*bOwnMemory*/, TRUE /*bUpdateUI*/);
  1662. // for the current NS record, find the associated A records
  1663. FindARecordsFromNSInfo(pCurrNode->GetString(2),pNSNodeInfo->m_pEditInfoList);
  1664. pNSInfoList->AddTail(pNSNodeInfo);
  1665. }
  1666. }
  1667. }
  1668. BOOL CDNSDomainNode::HasNSRecords()
  1669. {
  1670. return GetNSRecordNodeList()->GetCount() > 0;
  1671. }
  1672. BOOL CDNSDomainNode::UpdateNSRecordNodesInfo(CDNSRecordNodeEditInfoList* pNewInfoList,
  1673. CComponentDataObject* pComponentData)
  1674. {
  1675. ASSERT(pNewInfoList != NULL);
  1676. // return false if at least one operation failed
  1677. BOOL bRes = TRUE;
  1678. CDNS_NS_RecordNodeList* pNSRecordNodeList = GetNSRecordNodeList();
  1679. // clear the current state in this domain object
  1680. pNSRecordNodeList->RemoveAll();
  1681. // rebuild the current list from the new one, while applying the changes
  1682. POSITION pos;
  1683. for ( pos = pNewInfoList->GetHeadPosition(); pos != NULL; )
  1684. {
  1685. CDNSRecordNodeEditInfo* pCurrentInfo = pNewInfoList->GetNext(pos);
  1686. ASSERT(pCurrentInfo->m_pRecordNode != NULL);
  1687. ASSERT(pCurrentInfo->m_pRecord != NULL);
  1688. switch (pCurrentInfo->m_action)
  1689. {
  1690. case CDNSRecordNodeEditInfo::add:
  1691. case CDNSRecordNodeEditInfo::edit:
  1692. {
  1693. if (pCurrentInfo->Update(this, pComponentData) == 0)
  1694. {
  1695. ASSERT(pCurrentInfo->m_pRecordNode->GetType() == DNS_TYPE_NS);
  1696. pNSRecordNodeList->AddTail((CDNS_NS_RecordNode*)pCurrentInfo->m_pRecordNode);
  1697. pCurrentInfo->m_bOwnMemory = FALSE; // relinquish ownership
  1698. }
  1699. else
  1700. {
  1701. bRes = FALSE;
  1702. }
  1703. }
  1704. break;
  1705. case CDNSRecordNodeEditInfo::remove:
  1706. {
  1707. if (pCurrentInfo->m_bExisting)
  1708. {
  1709. if (pCurrentInfo->Remove(this, pComponentData) != 0)
  1710. bRes = FALSE;
  1711. }
  1712. }
  1713. break;
  1714. case CDNSRecordNodeEditInfo::none:
  1715. //
  1716. // Do nothing if the the node has been added and then removed without having been applied
  1717. //
  1718. break;
  1719. default:
  1720. {
  1721. ASSERT(pCurrentInfo->m_bOwnMemory == FALSE);
  1722. ASSERT(pCurrentInfo->m_action == CDNSRecordNodeEditInfo::unchanged);
  1723. //
  1724. // We still have to update the NS record because the server needs to
  1725. // update the record in memory (bug 23905)
  1726. //
  1727. if (pCurrentInfo->Update(this, pComponentData) == 0)
  1728. {
  1729. pNSRecordNodeList->AddTail((CDNS_NS_RecordNode*)pCurrentInfo->m_pRecordNode);
  1730. }
  1731. }
  1732. }; // switch
  1733. // now we have to apply the changes in the list of A records
  1734. if (pCurrentInfo->m_dwErr == 0 && pCurrentInfo->m_action != CDNSRecordNodeEditInfo::none)
  1735. UpdateARecordsOfNSInfo(pCurrentInfo, pComponentData);
  1736. } // for
  1737. return bRes;
  1738. }
  1739. // static function
  1740. void CDNSDomainNode::UpdateARecordsOfNSInfoHelper(CDNSDomainNode* pDomainNode,
  1741. CDNSRecordNodeEditInfo* pNSInfo,
  1742. CComponentDataObject* pComponentData,
  1743. BOOL bAskConfirmation)
  1744. {
  1745. ASSERT(pNSInfo->m_dwErr == 0);
  1746. ASSERT(pNSInfo->m_pRecordNode != NULL);
  1747. ASSERT(pNSInfo->m_pRecordNode->GetType() == DNS_TYPE_NS);
  1748. POSITION pos;
  1749. // get the list of related A records
  1750. CDNSRecordNodeEditInfoList* pNSInfoList = pNSInfo->m_pEditInfoList;
  1751. for( pos = pNSInfoList->GetHeadPosition(); pos != NULL; )
  1752. {
  1753. CDNSRecordNodeEditInfo* pCurrentInfo = pNSInfoList->GetNext(pos);
  1754. ASSERT(pCurrentInfo->m_pRecordNode != NULL);
  1755. ASSERT(pCurrentInfo->m_pRecord != NULL);
  1756. CDNS_A_RecordNode* pARecordNode = (CDNS_A_RecordNode*)pCurrentInfo->m_pRecordNode;
  1757. ASSERT(pNSInfo->m_pRecord != NULL);
  1758. CDNS_NS_Record* pNSRecord = (CDNS_NS_Record*)pNSInfo->m_pRecord;
  1759. BOOL bHostNameChanged = !_match(pNSRecord->m_szNameNode, pARecordNode);
  1760. if (bHostNameChanged)
  1761. {
  1762. // the NS record points to a different host, so need
  1763. // to delete the old A RR and create a new one
  1764. BOOL bRemoveOld = _ConfirmEditAction(pCurrentInfo, bAskConfirmation);
  1765. CDNSRecordNodeEditInfo::actionType oldAction = pCurrentInfo->m_action;
  1766. if (pCurrentInfo->m_bExisting && bRemoveOld)
  1767. {
  1768. // if the A record was an existing one, need to remove first
  1769. pCurrentInfo->m_action = CDNSRecordNodeEditInfo::remove;
  1770. pCurrentInfo->Remove(pDomainNode, pComponentData);
  1771. }
  1772. // now decide if have to add
  1773. if (oldAction == CDNSRecordNodeEditInfo::remove && bRemoveOld)
  1774. {
  1775. // it was meant to be removed anyway
  1776. pCurrentInfo->m_bOwnMemory = TRUE; // edit info will clean up memory
  1777. }
  1778. else
  1779. {
  1780. // it was meant to be edited or added, restore old action code
  1781. pCurrentInfo->m_action = oldAction;
  1782. // change the name of the record
  1783. pCurrentInfo->m_pRecordNode->SetRecordName(pNSRecord->m_szNameNode, FALSE /*bAtTheNode*/);
  1784. // add new A record with different FQDN
  1785. pCurrentInfo->m_action = CDNSRecordNodeEditInfo::add;
  1786. pCurrentInfo->Update(pDomainNode, pComponentData);
  1787. pCurrentInfo->m_bOwnMemory = FALSE; // written im master structures
  1788. }
  1789. }
  1790. else // the name is still the same
  1791. {
  1792. switch(pNSInfo->m_action)
  1793. {
  1794. case CDNSRecordNodeEditInfo::remove:
  1795. {
  1796. // NS record marked for deletion means removing the associated A records
  1797. if (pCurrentInfo->m_bExisting && _ConfirmEditAction(pCurrentInfo, bAskConfirmation))
  1798. {
  1799. pCurrentInfo->Remove(pDomainNode, pComponentData);
  1800. pCurrentInfo->m_bOwnMemory = TRUE; // it will cleanup itself
  1801. }
  1802. }
  1803. break;
  1804. case CDNSRecordNodeEditInfo::add:
  1805. {
  1806. if (!pCurrentInfo->m_bExisting)
  1807. {
  1808. pCurrentInfo->Update(pDomainNode, pComponentData);
  1809. pCurrentInfo->m_bOwnMemory = FALSE; // written im master structures
  1810. }
  1811. }
  1812. break;
  1813. case CDNSRecordNodeEditInfo::edit:
  1814. {
  1815. // NS host name not changed, just update list of A records
  1816. switch(pCurrentInfo->m_action)
  1817. {
  1818. case CDNSRecordNodeEditInfo::remove:
  1819. {
  1820. if (pCurrentInfo->m_bExisting && _ConfirmEditAction(pCurrentInfo, bAskConfirmation))
  1821. {
  1822. pCurrentInfo->Remove(pDomainNode, pComponentData);
  1823. pCurrentInfo->m_bOwnMemory = TRUE; // it will cleanup itself
  1824. }
  1825. }
  1826. break;
  1827. case CDNSRecordNodeEditInfo::edit:
  1828. {
  1829. // we just changed the TTL
  1830. ASSERT(pCurrentInfo->m_bExisting);
  1831. pCurrentInfo->Update(pDomainNode, pComponentData);
  1832. pCurrentInfo->m_bOwnMemory = FALSE; // written im master structures
  1833. }
  1834. break;
  1835. case CDNSRecordNodeEditInfo::add:
  1836. {
  1837. if (!pCurrentInfo->m_bExisting)
  1838. {
  1839. pCurrentInfo->Update(pDomainNode, pComponentData);
  1840. pCurrentInfo->m_bOwnMemory = FALSE; // written im master structures
  1841. }
  1842. }
  1843. break;
  1844. }; // switch
  1845. }
  1846. break;
  1847. }; // switch
  1848. } // if,else
  1849. } // for
  1850. }
  1851. void CDNSDomainNode::UpdateARecordsOfNSInfo(CDNSRecordNodeEditInfo* pNSInfo,
  1852. CComponentDataObject* pComponentData)
  1853. {
  1854. // create a fake domain object to run a query looking for
  1855. // A records that match the given list of NS records
  1856. CDNSDummyDomainNode fakeDomain;
  1857. fakeDomain.SetServerNode(GetServerNode());
  1858. fakeDomain.SetZone(GetZoneNode());
  1859. BOOL bAskConfirmation = TRUE; // we migth delete A RR's that we need
  1860. UpdateARecordsOfNSInfoHelper(&fakeDomain, pNSInfo, pComponentData, bAskConfirmation);
  1861. }
  1862. void CDNSDomainNode::FindARecordsFromNSInfo(LPCTSTR lpszNSName,
  1863. CDNSRecordNodeEditInfoList* pNSInfoList)
  1864. {
  1865. // just call the static version
  1866. CDNSRootData* pRootData = (CDNSRootData*)GetRootContainer();
  1867. ASSERT(pRootData != NULL);
  1868. DWORD cAddrCount;
  1869. PIP_ADDRESS pipAddrs;
  1870. GetServerNode()->GetListenAddressesInfo(&cAddrCount, &pipAddrs);
  1871. if (cAddrCount == 0)
  1872. {
  1873. // listening on all addresses
  1874. GetServerNode()->GetServerAddressesInfo(&cAddrCount, &pipAddrs);
  1875. }
  1876. FindARecordsFromNSInfo(GetServerNode()->GetRPCName(),
  1877. GetServerNode()->GetVersion(),
  1878. cAddrCount, pipAddrs,
  1879. GetZoneNode()->GetFullName(),
  1880. lpszNSName,
  1881. pNSInfoList,
  1882. pRootData->IsAdvancedView());
  1883. }
  1884. void CDNSDomainNode::FindARecordsFromNSInfo(LPCWSTR lpszServerName, DWORD dwServerVersion,
  1885. DWORD cServerAddrCount, PIP_ADDRESS pipServerAddrs,
  1886. LPCWSTR lpszZoneName,
  1887. LPCWSTR lpszNSName,
  1888. CDNSRecordNodeEditInfoList* pNSInfoList,
  1889. BOOL bAdvancedView)
  1890. {
  1891. ASSERT(pNSInfoList != NULL);
  1892. ASSERT(pNSInfoList->IsEmpty());
  1893. // specifically look for A records matching a given NS name
  1894. // set query flags to get all the possible data
  1895. DWORD dwSelectFlags = DNS_RPC_VIEW_AUTHORITY_DATA | DNS_RPC_VIEW_GLUE_DATA |
  1896. DNS_RPC_VIEW_ADDITIONAL_DATA;
  1897. CDNSDomainQueryObj query(lpszServerName,
  1898. lpszZoneName,
  1899. dwServerVersion,
  1900. NULL, // lpszNodeName, no need here
  1901. lpszNSName,
  1902. DNS_TYPE_A,
  1903. dwSelectFlags,
  1904. FALSE, // zone
  1905. FALSE, // reverse
  1906. FALSE, // cache
  1907. bAdvancedView);
  1908. query.Enumerate();
  1909. // get record from the queue into the info
  1910. CObjBaseList* pChildList = query.GetQueue();
  1911. //int n = pChildList->GetCount();
  1912. while (!pChildList->IsEmpty())
  1913. {
  1914. CTreeNode* pNode = dynamic_cast<CTreeNode*>(pChildList->RemoveHead());
  1915. if (pNode &&
  1916. !pNode->IsContainer())
  1917. {
  1918. CDNSRecordNodeBase* pRec = (CDNSRecordNodeBase*)pNode;
  1919. if (pRec->GetType() == DNS_TYPE_A)
  1920. {
  1921. TRACE(_T("Record <%s>\n"), pRec->GetString(2));
  1922. pRec->SetRecordName(lpszNSName, FALSE /*bAtTheNode*/);
  1923. CDNSRecordNodeEditInfo* pANodeInfo = new CDNSRecordNodeEditInfo;
  1924. if (pANodeInfo)
  1925. {
  1926. // NOTICE: we assume that all the nodes are glue, so we own the memory
  1927. pANodeInfo->CreateFromExistingRecord(pRec, TRUE /*bOwnMemory*/, FALSE /*bUpdateUI*/);
  1928. pNSInfoList->AddTail(pANodeInfo);
  1929. }
  1930. }
  1931. }
  1932. else
  1933. delete pNode; // discard
  1934. }
  1935. if (pNSInfoList->GetCount() > 0)
  1936. return; // got the info we needed just using RPC
  1937. // Could not find the A records, we need to try DnsQuery to get info outside the server
  1938. // search using DnsQuery and convert
  1939. PDNS_RECORD pDnsQueryARecordList = NULL;
  1940. // if available, use the provided addresses to do a DnsQuery()
  1941. PIP_ARRAY pipArr = NULL;
  1942. if ( (cServerAddrCount > 0) && (pipServerAddrs != NULL) )
  1943. {
  1944. pipArr = (PIP_ARRAY)malloc(sizeof(DWORD)+sizeof(IP_ADDRESS)*cServerAddrCount);
  1945. if (!pipArr)
  1946. {
  1947. return;
  1948. }
  1949. pipArr->AddrCount = cServerAddrCount;
  1950. memcpy(pipArr->AddrArray, pipServerAddrs, sizeof(IP_ADDRESS)*cServerAddrCount);
  1951. }
  1952. DWORD dwErr = ::DnsQuery((LPWSTR)lpszNSName, DNS_TYPE_A,
  1953. DNS_QUERY_NO_RECURSION, pipArr, &pDnsQueryARecordList, NULL);
  1954. if (pipArr)
  1955. {
  1956. free(pipArr);
  1957. pipArr = 0;
  1958. }
  1959. // no luck, try a simple query, with no IP addresses specified
  1960. if (pDnsQueryARecordList == NULL)
  1961. {
  1962. dwErr = ::DnsQuery((LPWSTR)lpszNSName, DNS_TYPE_A,
  1963. DNS_QUERY_NO_RECURSION, NULL, &pDnsQueryARecordList, NULL);
  1964. }
  1965. if (pDnsQueryARecordList == NULL)
  1966. return; // failed, no way to resolve IP address
  1967. PDNS_RECORD pCurrDnsQueryRecord = pDnsQueryARecordList;
  1968. while (pCurrDnsQueryRecord)
  1969. {
  1970. if (pCurrDnsQueryRecord->Flags.S.Section == DNSREC_ANSWER)
  1971. {
  1972. if (pCurrDnsQueryRecord->wType == DNS_TYPE_A)
  1973. {
  1974. // create a record node
  1975. CDNSRecordNodeBase* pRecordNode =
  1976. CDNSRecordInfo::CreateRecordNode(pCurrDnsQueryRecord->wType);
  1977. pRecordNode->CreateFromDnsQueryRecord(pCurrDnsQueryRecord, 0x0);
  1978. pRecordNode->SetRecordName(lpszNSName, FALSE /*bAtTheNode*/);
  1979. CDNSRecordNodeEditInfo* pANodeInfo = new CDNSRecordNodeEditInfo;
  1980. if (pANodeInfo)
  1981. {
  1982. pANodeInfo->m_bFromDnsQuery = TRUE;
  1983. //
  1984. // NOTICE: we assume that all the nodes are glue, so we own the memory
  1985. //
  1986. pANodeInfo->CreateFromExistingRecord(pRecordNode, TRUE /*bOwnMemory*/, FALSE /*bUpdateUI*/);
  1987. pNSInfoList->AddTail(pANodeInfo);
  1988. }
  1989. }
  1990. }
  1991. // goto next record
  1992. pCurrDnsQueryRecord = pCurrDnsQueryRecord->pNext;
  1993. }
  1994. DnsRecordListFree(pDnsQueryARecordList, DnsFreeRecordListDeep);
  1995. }
  1996. //////////////////////////////////////////////////////////////////////////////////
  1997. DNS_STATUS CDNSDomainNode::EnumerateNodes(LPCTSTR lpszServerName,
  1998. LPCTSTR lpszZoneName,
  1999. LPCTSTR lpszNodeName,
  2000. LPCTSTR lpszFullNodeName,
  2001. WORD wRecordType,
  2002. DWORD dwSelectFlag,
  2003. BOOL, BOOL bReverse, BOOL bAdvancedView,
  2004. CDNSDomainQueryObj* pQuery)
  2005. {
  2006. ASSERT(pQuery != NULL);
  2007. USES_CONVERSION;
  2008. DNS_STATUS err = 0;
  2009. CHAR szStartChildAnsi[3*MAX_DNS_NAME_LEN + 1]; // can have multibyte chars, count NULL
  2010. szStartChildAnsi[0] = NULL;
  2011. WCHAR szStartChild[MAX_DNS_NAME_LEN + 1]; // count NULL
  2012. szStartChild[0] = NULL;
  2013. CTreeNode* pNodeToInsert = NULL; // delayed insert
  2014. CDNSRecordNodeBase* pMoreDataNode = NULL;
  2015. // convert to UTF8 names
  2016. LPCSTR lpszFullNodeNameAnsi = W_TO_UTF8(lpszFullNodeName);
  2017. LPCSTR lpszZoneNameAnsi = W_TO_UTF8(lpszZoneName);
  2018. BOOL bTooMuchData = FALSE;
  2019. do // while more data
  2020. {
  2021. // get a chunk of data from RPC call
  2022. BYTE* pbRpcBuffer = NULL;
  2023. DWORD cbRpcBufferUsed = 0;
  2024. err = ::DnssrvEnumRecords(lpszServerName,
  2025. lpszZoneNameAnsi,
  2026. lpszFullNodeNameAnsi, // e.g. "foo.bar.com."
  2027. szStartChildAnsi, // Start Child
  2028. wRecordType,
  2029. dwSelectFlag,
  2030. NULL, // pszFilterStart
  2031. NULL, // pszFilterStop
  2032. &cbRpcBufferUsed,
  2033. &pbRpcBuffer);
  2034. if ((err != ERROR_MORE_DATA) && (err != 0))
  2035. return err; // bail out if there is an error
  2036. // walk the memory and build objects
  2037. DNS_RPC_NODE * pDnsNode = (DNS_RPC_NODE *)pbRpcBuffer;
  2038. DNS_RPC_RECORD * pDnsRecord;
  2039. void* pvEndOfRpcBuffer = pbRpcBuffer + cbRpcBufferUsed;
  2040. while ( (!bTooMuchData) && (pDnsNode < pvEndOfRpcBuffer) )
  2041. {
  2042. // get an ANSI null terminated copy
  2043. memcpy(szStartChildAnsi, pDnsNode->dnsNodeName.achName, pDnsNode->dnsNodeName.cchNameLength);
  2044. szStartChildAnsi[pDnsNode->dnsNodeName.cchNameLength] = NULL;
  2045. //
  2046. // get a UNICODE null terminated copy
  2047. //
  2048. if (szStartChildAnsi[0] == NULL)
  2049. {
  2050. szStartChild[0] = NULL;
  2051. }
  2052. else
  2053. {
  2054. DnsUtf8ToWHelper(szStartChild, szStartChildAnsi, pDnsNode->dnsNodeName.cchNameLength+1);
  2055. }
  2056. if (pDnsNode->dwChildCount || (pDnsNode->dwFlags & DNS_RPC_NODE_FLAG_STICKY))
  2057. {
  2058. BOOL bDelegation = ( ((dwSelectFlag & DNS_RPC_VIEW_CACHE_DATA) == 0) &&
  2059. ((pDnsNode->dwFlags & DNS_RPC_FLAG_ZONE_ROOT) != 0) );
  2060. CDNSDomainNode* p = NULL;
  2061. if (pQuery->CanAddDomain(szStartChild))
  2062. {
  2063. bTooMuchData = pQuery->TooMuchData();
  2064. if (!bTooMuchData)
  2065. {
  2066. p = new CDNSDomainNode(bDelegation);
  2067. if (p)
  2068. {
  2069. p->SetNames(FALSE, bReverse, bAdvancedView, szStartChild, lpszFullNodeName);
  2070. }
  2071. }
  2072. }
  2073. if (pNodeToInsert != NULL)
  2074. {
  2075. VERIFY(pQuery->AddQueryResult(pNodeToInsert));
  2076. }
  2077. pNodeToInsert = p;
  2078. }
  2079. pDnsRecord = (DNS_RPC_RECORD *)((BYTE *)pDnsNode + NEXT_DWORD(pDnsNode->wLength));
  2080. ASSERT(IS_DWORD_ALIGNED(pDnsRecord));
  2081. //
  2082. // Add the records under that node
  2083. //
  2084. UINT cRecordCount = pDnsNode->wRecordCount;
  2085. while ( (!bTooMuchData) && (cRecordCount--) )
  2086. {
  2087. CDNSRecordNodeBase* p = NULL;
  2088. BOOL bAtTheNode = szStartChild[0] == NULL;
  2089. LPCWSTR lpszRecordName = (bAtTheNode) ? lpszNodeName : szStartChild;
  2090. if (pQuery->CanAddRecord(pDnsRecord->wType, lpszRecordName))
  2091. {
  2092. TRACE(_T("\tCan add record %ws\n"), lpszRecordName);
  2093. bTooMuchData = pQuery->TooMuchData();
  2094. if (!bTooMuchData)
  2095. {
  2096. if (bAtTheNode)
  2097. {
  2098. p = CDNSRecordInfo::CreateRecordNodeFromRPCData(
  2099. lpszRecordName, pDnsRecord,bAtTheNode);
  2100. }
  2101. else
  2102. {
  2103. // filter out the NS records that are not at the node
  2104. if (pDnsRecord->wType != DNS_TYPE_NS)
  2105. {
  2106. p = CDNSRecordInfo::CreateRecordNodeFromRPCData(
  2107. lpszRecordName, pDnsRecord,bAtTheNode);
  2108. }
  2109. }
  2110. } // if not too much data
  2111. } // if can add
  2112. if (p != NULL)
  2113. {
  2114. p->SetFlagsDown(TN_FLAG_DNS_RECORD_FULL_NAME, !bAdvancedView);
  2115. if (pNodeToInsert != NULL)
  2116. {
  2117. VERIFY(pQuery->AddQueryResult(pNodeToInsert));
  2118. }
  2119. if (pMoreDataNode != NULL)
  2120. {
  2121. //
  2122. // If there was more data check to see if the new node is the same as the
  2123. // last node from the previous batch. Insert it if they are different, delete
  2124. // it if they are not
  2125. //
  2126. CString szMoreDataName = pMoreDataNode->GetDisplayName();
  2127. CString szPName = p->GetDisplayName();
  2128. if (szMoreDataName == szPName &&
  2129. pMoreDataNode->GetType() == p->GetType() &&
  2130. _wcsicmp(pMoreDataNode->GetString(3), p->GetString(3)) == 0)
  2131. {
  2132. delete pMoreDataNode;
  2133. }
  2134. else
  2135. {
  2136. VERIFY(pQuery->AddQueryResult(pMoreDataNode));
  2137. }
  2138. pMoreDataNode = NULL;
  2139. }
  2140. pNodeToInsert = p;
  2141. }
  2142. else
  2143. {
  2144. if (pMoreDataNode)
  2145. {
  2146. // We might still have to add the "more data" node
  2147. // even if the current node didn't match the filter
  2148. VERIFY(pQuery->AddQueryResult(pMoreDataNode));
  2149. pMoreDataNode = NULL;
  2150. }
  2151. }
  2152. pDnsRecord = DNS_NEXT_RECORD(pDnsRecord);
  2153. } // while cRecordCount
  2154. // The new node is found at the end of the last record
  2155. pDnsNode = (DNS_RPC_NODE *)pDnsRecord;
  2156. } // while end of buffer
  2157. // we still have a node to insert, but we discard it if there is more data
  2158. // because we are going to get it again and we want to avoid duplication
  2159. if (pNodeToInsert != NULL)
  2160. {
  2161. if (bTooMuchData)
  2162. {
  2163. delete pNodeToInsert;
  2164. }
  2165. else if (err == ERROR_MORE_DATA)
  2166. {
  2167. //
  2168. // Doesn't matter if this turns out NULL because we only want
  2169. // pMoreDataNode to be a record node. If its a domain node we
  2170. // can just ignore it
  2171. //
  2172. pMoreDataNode = dynamic_cast<CDNSRecordNodeBase*>(pNodeToInsert);
  2173. }
  2174. else
  2175. {
  2176. VERIFY(pQuery->AddQueryResult(pNodeToInsert));
  2177. }
  2178. pNodeToInsert = NULL;
  2179. }
  2180. ::DnssrvFreeRecordsBuffer(pbRpcBuffer);
  2181. } while ( !bTooMuchData && (err == ERROR_MORE_DATA) ) ;
  2182. // we are bailing out because of too much data,
  2183. // need to let the main tread know
  2184. if (bTooMuchData && (err != ERROR_MORE_DATA))
  2185. {
  2186. err = ERROR_MORE_DATA;
  2187. }
  2188. return err;
  2189. }
  2190. DNS_STATUS CDNSDomainNode::Create()
  2191. {
  2192. USES_CONVERSION;
  2193. LPCWSTR lpszFullZoneName = NULL;
  2194. CDNSZoneNode* pZoneNode = GetZoneNode();
  2195. if (pZoneNode != NULL)
  2196. lpszFullZoneName = pZoneNode->GetFullName();
  2197. DNS_STATUS err = ::DnssrvUpdateRecord(GetServerNode()->GetRPCName(),
  2198. W_TO_UTF8(lpszFullZoneName),
  2199. W_TO_UTF8(GetFullName()),
  2200. NULL, NULL);
  2201. return err;
  2202. }
  2203. DNS_STATUS CDNSDomainNode::Delete()
  2204. {
  2205. USES_CONVERSION;
  2206. LPCWSTR lpszFullZoneName = NULL;
  2207. CDNSZoneNode* pZoneNode = GetZoneNode();
  2208. if (pZoneNode != NULL)
  2209. lpszFullZoneName = pZoneNode->GetFullName();
  2210. return ::DnssrvDeleteNode(GetServerNode()->GetRPCName(),
  2211. W_TO_UTF8(lpszFullZoneName),
  2212. W_TO_UTF8(GetFullName()),
  2213. TRUE // fDeleteSubtree
  2214. );
  2215. }
  2216. /////////////////////////////////////////////////////////////////////////
  2217. // CDNSRootHintsNode
  2218. DNS_STATUS CDNSRootHintsNode::QueryForRootHints(LPCTSTR lpszServerName, DWORD dwServerVersion)
  2219. {
  2220. USES_CONVERSION;
  2221. DWORD dwSelectFlags = DNS_RPC_VIEW_ROOT_HINT_DATA | DNS_RPC_VIEW_ADDITIONAL_DATA | DNS_RPC_VIEW_NO_CHILDREN;
  2222. CDNSDomainQueryObj query(lpszServerName,
  2223. UTF8_TO_W(DNS_ZONE_ROOT_HINTS), //lpszZoneName, needs to be "..RootHints" as defined in dnsrpc.h
  2224. dwServerVersion,
  2225. GetDisplayName(),
  2226. m_szFullName,
  2227. DNS_TYPE_NS,
  2228. dwSelectFlags,
  2229. FALSE, // zone
  2230. FALSE, // reverse
  2231. FALSE, // cache
  2232. FALSE);
  2233. query.Enumerate();
  2234. DWORD dwErr = query.GetError();
  2235. if (dwErr != 0)
  2236. return dwErr;
  2237. // get record from the queue into the folder
  2238. CObjBaseList* pChildList = query.GetQueue();
  2239. //int n = pChildList->GetCount();
  2240. while (!pChildList->IsEmpty())
  2241. {
  2242. CTreeNode* pNode = dynamic_cast<CTreeNode*>(pChildList->RemoveHead());
  2243. // NOTICE: for NT 4.0 servers, we get bogus container nodes
  2244. // that we have to suppress
  2245. if(pNode->IsContainer())
  2246. {
  2247. delete pNode;
  2248. }
  2249. else
  2250. {
  2251. OnHaveRecord((CDNSRecordNodeBase*)pNode, NULL); // add to the list of NS records
  2252. AddChildToList(pNode);
  2253. }
  2254. }
  2255. return (DNS_STATUS)dwErr;
  2256. }
  2257. void CDNSRootHintsNode::FindARecordsFromNSInfo(LPCTSTR lpszNSName,
  2258. CDNSRecordNodeEditInfoList* pNSInfoList)
  2259. {
  2260. ASSERT(pNSInfoList != NULL);
  2261. //
  2262. // for root hints, we have all the records in this folder and we
  2263. // can edit them
  2264. //
  2265. POSITION pos;
  2266. for( pos = m_leafChildList.GetHeadPosition(); pos != NULL; )
  2267. {
  2268. CTreeNode* pCurrentChild = m_leafChildList.GetNext(pos);
  2269. ASSERT(!pCurrentChild->IsContainer());
  2270. CDNSRecordNodeBase* pRecordNode = dynamic_cast<CDNSRecordNodeBase*>(pCurrentChild);
  2271. if (pRecordNode &&
  2272. DNS_TYPE_A == pRecordNode->GetType())
  2273. {
  2274. CDNS_A_RecordNode* pARecordNode = (CDNS_A_RecordNode*)pRecordNode;
  2275. if (_match(lpszNSName, pARecordNode))
  2276. {
  2277. CDNSRecordNodeEditInfo* pANodeInfo = new CDNSRecordNodeEditInfo;
  2278. //
  2279. // NOTICE: the root hints folder owns the memory
  2280. //
  2281. if (pANodeInfo != NULL)
  2282. {
  2283. pANodeInfo->CreateFromExistingRecord(pARecordNode, FALSE /*bOwnMemory*/, TRUE /*bUpdateUI*/);
  2284. pNSInfoList->AddTail(pANodeInfo);
  2285. }
  2286. else
  2287. {
  2288. TRACE(_T("Failed to allocate memory in CDNSRootHintsNode::FindARecordsFromNSInfo"));
  2289. ASSERT(FALSE);
  2290. }
  2291. }
  2292. }
  2293. }
  2294. }
  2295. void CDNSRootHintsNode::UpdateARecordsOfNSInfo(CDNSRecordNodeEditInfo* pNSInfo,
  2296. CComponentDataObject* pComponentData)
  2297. {
  2298. BOOL bAskConfirmation = FALSE; // need to edit ALL A records
  2299. UpdateARecordsOfNSInfoHelper(this, pNSInfo, pComponentData, bAskConfirmation);
  2300. }
  2301. DNS_STATUS CDNSRootHintsNode::Clear()
  2302. {
  2303. //
  2304. // clear the list of cached NS record pointers
  2305. //
  2306. GetNSRecordNodeList()->RemoveAll();
  2307. //
  2308. // remove all the records from the server
  2309. //
  2310. DNS_STATUS err = 0;
  2311. POSITION pos;
  2312. for( pos = m_leafChildList.GetHeadPosition(); pos != NULL; )
  2313. {
  2314. CTreeNode* pCurrentChild = m_leafChildList.GetNext(pos);
  2315. ASSERT(!pCurrentChild->IsContainer());
  2316. CDNSRecordNodeBase* pRecordNode = (CDNSRecordNodeBase*)pCurrentChild;
  2317. DNS_STATUS currErr = pRecordNode->DeleteOnServer();
  2318. if (currErr != 0)
  2319. {
  2320. //
  2321. // just ge the last error, if any
  2322. //
  2323. err = currErr;
  2324. }
  2325. }
  2326. //
  2327. // clear the list of children in the folder (we are hidden, so no UI deletions)
  2328. //
  2329. RemoveAllChildrenFromList();
  2330. return err;
  2331. }
  2332. DNS_STATUS CDNSRootHintsNode::InitializeFromDnsQueryData(PDNS_RECORD pRootHintsRecordList)
  2333. {
  2334. // need to remove all the previous root hints from the server
  2335. // let's be sure we get recent data
  2336. // clear the list of children in the folder (we are hidden, so no UI deletions)
  2337. RemoveAllChildrenFromList();
  2338. // acqure the list of current root hints
  2339. CDNSServerNode* pServerNode = GetServerNode();
  2340. DNS_STATUS dwErr = QueryForRootHints(pServerNode->GetRPCName(), pServerNode->GetVersion());
  2341. if (dwErr != 0)
  2342. {
  2343. TRACE(_T("Failed to remove old Root Hints, dwErr = %x hex\n"), dwErr);
  2344. return dwErr;
  2345. }
  2346. // remove all the old root hints from server and client side
  2347. dwErr = Clear();
  2348. if (dwErr != 0)
  2349. {
  2350. TRACE(_T("Failed to clear Root Hints, dwErr = %x hex\n"), dwErr);
  2351. return dwErr;
  2352. }
  2353. // walk through the list of root hints,
  2354. // convert to C++ format,
  2355. // write to server and add to the folder list (no UI, folder hidden)
  2356. PDNS_RECORD pCurrDnsQueryRecord = pRootHintsRecordList;
  2357. while (pCurrDnsQueryRecord != NULL)
  2358. {
  2359. ASSERT( (pCurrDnsQueryRecord->wType == DNS_TYPE_A) ||
  2360. (pCurrDnsQueryRecord->wType == DNS_TYPE_NS) );
  2361. // create a record node and read data from DnsQuery format
  2362. CDNSRecordNodeBase* pRecordNode =
  2363. CDNSRecordInfo::CreateRecordNode(pCurrDnsQueryRecord->wType);
  2364. pRecordNode->CreateFromDnsQueryRecord(pCurrDnsQueryRecord, DNS_RPC_RECORD_FLAG_ZONE_ROOT);
  2365. // set the record node container
  2366. pRecordNode->SetContainer(this);
  2367. // set the record node name
  2368. BOOL bAtTheNode = (pCurrDnsQueryRecord->wType == DNS_TYPE_NS);
  2369. pRecordNode->SetRecordName(pCurrDnsQueryRecord->pName, bAtTheNode);
  2370. // write on server
  2371. // the default TTL does not apply here
  2372. DNS_STATUS err = pRecordNode->Update(NULL, FALSE); // NULL = create new, FALSE = use def TTL
  2373. if (err == 0)
  2374. VERIFY(AddChildToList(pRecordNode));
  2375. else
  2376. {
  2377. dwErr = err; // mark las error
  2378. delete pRecordNode; // something went wrong
  2379. }
  2380. pCurrDnsQueryRecord = pCurrDnsQueryRecord->pNext;
  2381. }
  2382. // force a write on the server, to make sure the cache file is written right away
  2383. return CDNSZoneNode::WriteToDatabase(pServerNode->GetRPCName(), DNS_ZONE_ROOT_HINTS);
  2384. }
  2385. void CDNSRootHintsNode::ShowPageForNode(CComponentDataObject* pComponentDataObject)
  2386. {
  2387. ASSERT(pComponentDataObject != NULL);
  2388. if (pComponentDataObject)
  2389. {
  2390. pComponentDataObject->GetPropertyPageHolderTable()->BroadcastSelectPage(GetServerNode(), 3);
  2391. }
  2392. }