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

1778 lines
46 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1998 - 1999
  6. //
  7. // File: nspage.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 "nspage.h"
  21. #include "uiutil.h"
  22. #include "ipeditor.h"
  23. #include "browser.h"
  24. ///////////////////////////////////////////////////////////////////////////////
  25. // CDNS_NS_RecordDialog
  26. class CDNS_NS_RecordDialog : public CPropertyPage
  27. {
  28. public:
  29. CDNS_NS_RecordDialog(CDNSNameServersPropertyPage* pNSPage, BOOL bNew);
  30. CDNS_NS_RecordDialog(CDNSNameServersWizardPage* pNSWiz, BOOL bNew);
  31. ~CDNS_NS_RecordDialog();
  32. INT_PTR DoModalSheet();
  33. // data
  34. BOOL m_bDirty;
  35. CDNSRecordNodeEditInfo* m_pNSInfo;
  36. protected:
  37. virtual int OnCreate(LPCREATESTRUCT lpCreateStruct);
  38. virtual BOOL OnInitDialog();
  39. virtual void OnOK();
  40. afx_msg void OnServerNameChange();
  41. afx_msg void OnBrowse();
  42. afx_msg void OnQuery();
  43. BOOL OnHelpInfo(HELPINFO* pHelpInfo);
  44. DECLARE_MESSAGE_MAP()
  45. private:
  46. class CARecordAddressesIPEditor : public CIPEditor
  47. {
  48. public:
  49. CARecordAddressesIPEditor(CDNS_NS_RecordDialog* pNSRecordDialog)
  50. { m_pNSRecordDialog = pNSRecordDialog;}
  51. void SetIpAddresses(CDNSRecordNodeEditInfo* pNSInfo);
  52. BOOL GetIpAddresses(CDNSRecordNodeEditInfo* pNSInfo);
  53. protected:
  54. virtual void OnChangeData();
  55. private:
  56. CDNS_NS_RecordDialog* m_pNSRecordDialog;
  57. };
  58. CARecordAddressesIPEditor m_RecordAddressesEditor;
  59. BOOL m_bNew;
  60. CDNSNameServersPropertyPage* m_pNSPage;
  61. CDNSNameServersWizardPage* m_pNSWiz;
  62. CPropertyPageBase* GetPage()
  63. {
  64. if (m_pNSPage != NULL)
  65. {
  66. return m_pNSPage;
  67. }
  68. return m_pNSWiz;
  69. }
  70. HWND m_hWndOKButton;
  71. HWND m_hWndQueryButton;
  72. CDNSTTLControl* GetTTLCtrl() { return (CDNSTTLControl*)GetDlgItem(IDC_TTLEDIT);}
  73. CEdit* GetServerEdit() { return (CEdit*)GetDlgItem(IDC_SERVER_NAME_EDIT); }
  74. CDNS_NS_Record* GetNSRecord()
  75. {
  76. ASSERT( m_pNSInfo != NULL);
  77. ASSERT( m_pNSInfo->m_pRecord->m_wType == DNS_TYPE_NS);
  78. return (CDNS_NS_Record*)m_pNSInfo->m_pRecord;
  79. }
  80. void GetNSServerName(CString& szNameNode);
  81. void SyncUIButtons();
  82. void EnableTTLCtrl(BOOL bShow);
  83. friend class CARecordAddressesIPEditor;
  84. };
  85. INT_PTR CDNS_NS_RecordDialog::DoModalSheet()
  86. {
  87. /* NOTE : The first call to this may cause a first-chance exception. Excerpt from MSDN January 2000.
  88. Note The first time a property page is created from its corresponding dialog resource,
  89. it may cause a first-chance exception. This is a result of the property page changing
  90. the style of the dialog resource to the required style prior to creating the page. Because
  91. resources are generally read-only, this causes an exception. The exception is handled by
  92. the system, and a copy of the modified resource is made automatically by the system. The
  93. first-chance exception can thus be ignored.
  94. Since this exception must be handled by the operating system, do not wrap calls to
  95. CPropertySheet::DoModal with a C++ try/catch block in which the catch handles all exceptions,
  96. for example, catch (...). This will handle the exception intended for the operating system,
  97. causing unpredictable behavior. Using C++ exception handling with specific exception types
  98. or using structured exception handling where the Access Violation exception is passed through
  99. to the operating system is safe, however.
  100. */
  101. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  102. CString szTitle;
  103. szTitle.LoadString(m_bNew ? IDS_NEW_RECORD_TITLE : IDS_EDIT_RECORD_TITLE);
  104. CPropertySheet hostSheet;
  105. hostSheet.m_psh.dwFlags |= PSH_NOAPPLYNOW;
  106. hostSheet.m_psh.pszCaption = (LPCTSTR)szTitle;
  107. hostSheet.AddPage(this);
  108. INT_PTR iRes = hostSheet.DoModal();
  109. GetPage()->GetHolder()->PopDialogHWnd();
  110. return iRes;
  111. }
  112. void CDNS_NS_RecordDialog::CARecordAddressesIPEditor::OnChangeData()
  113. {
  114. m_pNSRecordDialog->SyncUIButtons();
  115. }
  116. void CDNS_NS_RecordDialog::CARecordAddressesIPEditor::
  117. SetIpAddresses(CDNSRecordNodeEditInfo* pNSInfo)
  118. {
  119. Clear();
  120. ASSERT(pNSInfo != NULL);
  121. INT_PTR nArraySize = pNSInfo->m_pEditInfoList->GetCount();
  122. if (nArraySize == 0)
  123. return;
  124. DWORD* pArr = (DWORD*)malloc(nArraySize*sizeof(DWORD));
  125. if (!pArr)
  126. {
  127. return;
  128. }
  129. int k=0;
  130. POSITION pos;
  131. for( pos = pNSInfo->m_pEditInfoList->GetHeadPosition(); pos != NULL; )
  132. {
  133. CDNSRecordNodeEditInfo* pARecordInfo = pNSInfo->m_pEditInfoList->GetNext(pos);
  134. ASSERT(pARecordInfo != NULL);
  135. if (pARecordInfo->m_action != CDNSRecordNodeEditInfo::remove)
  136. {
  137. ASSERT(pARecordInfo->m_pRecord != NULL);
  138. ASSERT(pARecordInfo->m_pRecord->m_wType == DNS_TYPE_A);
  139. CDNS_A_Record* pARecord = (CDNS_A_Record*)pARecordInfo->m_pRecord;
  140. pArr[k++] = pARecord->m_ipAddress;
  141. }
  142. }
  143. AddAddresses(pArr, k);
  144. if (pArr)
  145. {
  146. free(pArr);
  147. }
  148. }
  149. BOOL CDNS_NS_RecordDialog::CARecordAddressesIPEditor::
  150. GetIpAddresses(CDNSRecordNodeEditInfo* pNSInfo)
  151. {
  152. BOOL bDirty = FALSE;
  153. int nArraySize = GetCount();
  154. // if the count of IP addresses is zero,
  155. // we mark the NS record as slated for removal
  156. if (nArraySize == 0)
  157. pNSInfo->m_action = CDNSRecordNodeEditInfo::remove;
  158. // read the IP addresses from IP editor, if any
  159. DWORD* pArr = (nArraySize >0) ? (DWORD*)malloc(nArraySize*sizeof(DWORD)) : NULL;
  160. if (!pArr)
  161. {
  162. return FALSE;
  163. }
  164. int nFilled = 0;
  165. if (nArraySize > 0)
  166. GetAddresses(pArr, nArraySize, &nFilled);
  167. ASSERT(nFilled == nArraySize);
  168. ASSERT(pNSInfo->m_pRecord != NULL);
  169. ASSERT(pNSInfo->m_pRecord->GetType() == DNS_TYPE_NS);
  170. CDNS_NS_Record* pNSRecord = (CDNS_NS_Record*)pNSInfo->m_pRecord;
  171. CDNSRecordNodeEditInfoList* pNSInfoList = pNSInfo->m_pEditInfoList;
  172. CDNSRecordNodeEditInfoList NSInfoRemoveList;
  173. POSITION pos;
  174. // walk the list of A records, to mark the ones to be deleted,
  175. // if nArraySize == 0, all of them well be marked for removal
  176. for( pos = pNSInfoList->GetHeadPosition(); pos != NULL; )
  177. {
  178. CDNSRecordNodeEditInfo* pCurrentInfo = pNSInfoList->GetNext(pos);
  179. ASSERT(pCurrentInfo->m_pRecordNode != NULL);
  180. ASSERT(pCurrentInfo->m_pRecord != NULL);
  181. ASSERT(pCurrentInfo->m_pRecord->GetType() == DNS_TYPE_A);
  182. CDNS_A_Record* pARecord = (CDNS_A_Record*)pCurrentInfo->m_pRecord;
  183. BOOL bFound = FALSE;
  184. for (int k=0; k<nArraySize; k++)
  185. {
  186. if (pARecord->m_ipAddress == pArr[k])
  187. {
  188. bFound = TRUE;
  189. break;
  190. }
  191. }
  192. if (!bFound)
  193. {
  194. bDirty = TRUE;
  195. if (pCurrentInfo->m_bExisting)
  196. {
  197. pCurrentInfo->m_action = CDNSRecordNodeEditInfo::remove; // mark as deleted
  198. }
  199. else
  200. {
  201. NSInfoRemoveList.AddTail(pCurrentInfo);
  202. }
  203. }
  204. } // for
  205. // This gives NSInfoRemoveList ownership of all memory management for all nodes
  206. // removed from the pNSInfoList
  207. POSITION listPos = NSInfoRemoveList.GetHeadPosition();
  208. while (listPos != NULL)
  209. {
  210. CDNSRecordNodeEditInfo* pCurrentInfo = NSInfoRemoveList.GetNext(listPos);
  211. ASSERT(pCurrentInfo != NULL);
  212. POSITION removePos = pNSInfoList->Find(pCurrentInfo);
  213. pNSInfoList->RemoveAt(removePos);
  214. }
  215. // Remove and delete all nodes that were removed from the pNSInfoList
  216. NSInfoRemoveList.RemoveAllNodes();
  217. // walk the list of addresses, to look for matching A records to add
  218. // if nArraySize == 0, loop skipped, nothing to add
  219. for (int k=0; k<nArraySize; k++)
  220. {
  221. BOOL bFound = FALSE;
  222. for( pos = pNSInfoList->GetHeadPosition(); pos != NULL; )
  223. {
  224. CDNSRecordNodeEditInfo* pCurrentInfo = pNSInfoList->GetNext(pos);
  225. ASSERT(pCurrentInfo->m_pRecordNode != NULL);
  226. ASSERT(pCurrentInfo->m_pRecord != NULL);
  227. ASSERT(pCurrentInfo->m_pRecord->GetType() == DNS_TYPE_A);
  228. CDNS_A_Record* pARecord = (CDNS_A_Record*)pCurrentInfo->m_pRecord;
  229. if (pARecord->m_ipAddress == pArr[k])
  230. {
  231. bFound = TRUE;
  232. if (pCurrentInfo->m_action == CDNSRecordNodeEditInfo::remove) // we got it already, resuscitate it
  233. {
  234. bDirty = TRUE;
  235. if(pCurrentInfo->m_bExisting)
  236. pCurrentInfo->m_action = CDNSRecordNodeEditInfo::edit;
  237. else
  238. pCurrentInfo->m_action = CDNSRecordNodeEditInfo::add;
  239. }
  240. break;
  241. }
  242. }
  243. if (!bFound)
  244. {
  245. // A record not found, need to create one
  246. CDNSRecordNodeEditInfo* pNewInfo = new CDNSRecordNodeEditInfo;
  247. if (pNewInfo)
  248. {
  249. pNewInfo->CreateFromNewRecord(new CDNS_A_RecordNode);
  250. CDNS_A_Record* pARecord = (CDNS_A_Record*)pNewInfo->m_pRecord;
  251. pARecord->m_ipAddress = pArr[k];
  252. pNewInfo->m_pRecordNode->m_bAtTheNode = FALSE;
  253. pNewInfo->m_pRecordNode->SetRecordName(pNSRecord->m_szNameNode, FALSE /*bAtTheNode*/);
  254. // inherit the TTL of the NS record
  255. pNewInfo->m_pRecord->m_dwTtlSeconds = pNSInfo->m_pRecord->m_dwTtlSeconds;
  256. pNSInfoList->AddTail(pNewInfo);
  257. bDirty = TRUE;
  258. }
  259. }
  260. } // for
  261. if (pArr)
  262. {
  263. free(pArr);
  264. }
  265. return bDirty;
  266. }
  267. BEGIN_MESSAGE_MAP(CDNS_NS_RecordDialog, CPropertyPage)
  268. ON_WM_CREATE()
  269. ON_EN_CHANGE(IDC_SERVER_NAME_EDIT, OnServerNameChange)
  270. ON_BN_CLICKED(IDC_BROWSE_BUTTON, OnBrowse)
  271. ON_BN_CLICKED(IDC_QUERY_BUTTON, OnQuery)
  272. ON_WM_HELPINFO()
  273. END_MESSAGE_MAP()
  274. CDNS_NS_RecordDialog::CDNS_NS_RecordDialog(CDNSNameServersPropertyPage* pNSPage, BOOL bNew)
  275. : CPropertyPage(IDD_RR_NS_EDIT),
  276. m_RecordAddressesEditor(this)
  277. {
  278. ASSERT(pNSPage != NULL);
  279. m_pNSPage = pNSPage;
  280. m_pNSWiz = NULL;
  281. m_bNew = bNew;
  282. m_bDirty = FALSE;
  283. m_pNSInfo = NULL;
  284. m_hWndOKButton = m_hWndQueryButton = NULL;
  285. }
  286. CDNS_NS_RecordDialog::CDNS_NS_RecordDialog(CDNSNameServersWizardPage* pNSWiz, BOOL bNew)
  287. : CPropertyPage(IDD_RR_NS_EDIT),
  288. m_RecordAddressesEditor(this)
  289. {
  290. ASSERT(pNSWiz != NULL);
  291. m_pNSPage = NULL;
  292. m_pNSWiz = pNSWiz;
  293. m_bNew = bNew;
  294. m_bDirty = FALSE;
  295. m_pNSInfo = NULL;
  296. m_hWndOKButton = m_hWndQueryButton = NULL;
  297. }
  298. CDNS_NS_RecordDialog::~CDNS_NS_RecordDialog()
  299. {
  300. }
  301. int CDNS_NS_RecordDialog::OnCreate(LPCREATESTRUCT lpCreateStruct)
  302. {
  303. int res = CPropertyPage::OnCreate(lpCreateStruct);
  304. DWORD dwStyle = ::GetWindowLong(::GetParent(GetSafeHwnd()), GWL_EXSTYLE);
  305. dwStyle |= WS_EX_CONTEXTHELP; // force the [?] button
  306. ::SetWindowLong(::GetParent(GetSafeHwnd()), GWL_EXSTYLE, dwStyle);
  307. return res;
  308. }
  309. BOOL CDNS_NS_RecordDialog::OnHelpInfo(HELPINFO* pHelpInfo)
  310. {
  311. CComponentDataObject* pComponentData = GetPage()->GetHolder()->GetComponentData();
  312. ASSERT(pComponentData != NULL);
  313. pComponentData->OnDialogContextHelp(m_nIDHelp, pHelpInfo);
  314. return TRUE;
  315. }
  316. void CDNS_NS_RecordDialog::EnableTTLCtrl(BOOL bShow)
  317. {
  318. CDNSTTLControl* pCtrl = GetTTLCtrl();
  319. ASSERT(pCtrl != NULL);
  320. pCtrl->EnableWindow(bShow);
  321. pCtrl->ShowWindow(bShow);
  322. CWnd* pWnd = GetDlgItem(IDC_STATIC_TTL);
  323. ASSERT(pWnd != NULL);
  324. pWnd->EnableWindow(bShow);
  325. pWnd->ShowWindow(bShow);
  326. }
  327. BOOL CDNS_NS_RecordDialog::OnInitDialog()
  328. {
  329. CPropertyPage::OnInitDialog();
  330. ASSERT(m_pNSInfo != NULL);
  331. ASSERT(m_pNSInfo->m_pRecord != NULL);
  332. ASSERT(m_hWnd != NULL);
  333. ASSERT(::IsWindow(m_hWnd));
  334. HWND hParent = ::GetParent(m_hWnd);
  335. ASSERT(hParent);
  336. GetPage()->GetHolder()->PushDialogHWnd(hParent);
  337. //
  338. // OK button on the sheet
  339. //
  340. m_hWndOKButton = ::GetDlgItem(hParent, IDOK);
  341. ASSERT(::IsWindow(m_hWndOKButton));
  342. //
  343. // query button handle
  344. //
  345. m_hWndQueryButton = :: GetDlgItem(m_hWnd, IDC_QUERY_BUTTON);
  346. ASSERT(::IsWindow(m_hWndQueryButton));
  347. //
  348. // initialize IP editor
  349. //
  350. VERIFY(m_RecordAddressesEditor.Initialize(this,
  351. GetParent(),
  352. IDC_BUTTON_UP,
  353. IDC_BUTTON_DOWN,
  354. IDC_BUTTON_ADD,
  355. IDC_BUTTON_REMOVE,
  356. IDC_IPEDIT,
  357. IDC_LIST));
  358. //
  359. // Load Data in the UI
  360. //
  361. m_RecordAddressesEditor.SetIpAddresses(m_pNSInfo);
  362. GetServerEdit()->LimitText(MAX_DNS_NAME_LEN);
  363. GetServerEdit()->SetWindowText(GetNSRecord()->m_szNameNode);
  364. GetTTLCtrl()->SetTTL(m_pNSInfo->m_pRecord->m_dwTtlSeconds);
  365. // need to decide if we want to show the TTL control
  366. CDNSRootData* pRootData = (CDNSRootData*)GetPage()->GetHolder()->GetComponentData()->GetRootData();
  367. ASSERT(pRootData != NULL);
  368. BOOL bEnableTTLCtrl;
  369. if (m_pNSPage != NULL)
  370. {
  371. bEnableTTLCtrl = m_pNSPage->HasMeaningfulTTL() && pRootData->IsAdvancedView();
  372. }
  373. else
  374. {
  375. bEnableTTLCtrl = m_pNSWiz->HasMeaningfulTTL() && pRootData->IsAdvancedView();
  376. }
  377. EnableTTLCtrl(bEnableTTLCtrl);
  378. return TRUE; // return TRUE unless you set the focus to a control
  379. }
  380. void CDNS_NS_RecordDialog::GetNSServerName(CString& szNameNode)
  381. {
  382. GetServerEdit()->GetWindowText(szNameNode);
  383. szNameNode.TrimLeft();
  384. szNameNode.TrimRight();
  385. if (szNameNode[szNameNode.GetLength()-1] != TEXT('.'))
  386. szNameNode += TEXT('.');
  387. }
  388. void CDNS_NS_RecordDialog::SyncUIButtons()
  389. {
  390. CString szServerName;
  391. GetServerEdit()->GetWindowText(szServerName);
  392. szServerName.TrimLeft();
  393. szServerName.TrimRight();
  394. DWORD dwNameChecking = 0;
  395. if (m_pNSWiz)
  396. {
  397. dwNameChecking = m_pNSWiz->GetDomainNode()->GetServerNode()->GetNameCheckFlag();
  398. }
  399. else if (m_pNSPage)
  400. {
  401. dwNameChecking = m_pNSPage->GetDomainNode()->GetServerNode()->GetNameCheckFlag();
  402. }
  403. //
  404. // Enable OK button if it is a valid name
  405. //
  406. BOOL bIsValidName = (0 == ValidateDnsNameAgainstServerFlags(szServerName,
  407. DnsNameDomain,
  408. dwNameChecking));
  409. ::EnableWindow(m_hWndOKButton, bIsValidName &&
  410. m_RecordAddressesEditor. GetCount() > 0);
  411. ::EnableWindow(m_hWndQueryButton, bIsValidName);
  412. }
  413. void CDNS_NS_RecordDialog::OnOK()
  414. {
  415. ASSERT(m_pNSInfo->m_pRecord != NULL);
  416. CString szNameNode;
  417. GetNSServerName(szNameNode);
  418. // compare (case insensitive) with old name to see if it changed,
  419. // NOTICE: CDNSDomainNode::UpdateARecordsOfNSInfoHelper() will then
  420. // take care of regenerating the list of A records
  421. m_bDirty = _wcsicmp((LPCWSTR)szNameNode,
  422. (LPCWSTR)GetNSRecord()->m_szNameNode);
  423. if (m_bDirty)
  424. GetNSRecord()->m_szNameNode = szNameNode;
  425. // update list of IP addresses
  426. if (m_bNew)
  427. {
  428. // the dialog is used to create a new entry
  429. ASSERT(!m_pNSInfo->m_bExisting);
  430. m_pNSInfo->m_action = CDNSRecordNodeEditInfo::add;
  431. }
  432. else
  433. {
  434. // the dialog is used to edit
  435. if (m_pNSInfo->m_bExisting)
  436. {
  437. // an existing entry
  438. m_pNSInfo->m_action = CDNSRecordNodeEditInfo::edit;
  439. }
  440. else
  441. {
  442. // a newly created entry, edited before committing
  443. m_pNSInfo->m_action = CDNSRecordNodeEditInfo::add;
  444. }
  445. }
  446. // this call migth mark the info as remove, if no IP addresses are found
  447. if (m_RecordAddressesEditor.GetIpAddresses(m_pNSInfo))
  448. m_bDirty = TRUE;
  449. DWORD dwTTL;
  450. GetTTLCtrl()->GetTTL(&dwTTL);
  451. if (m_pNSInfo->m_pRecord->m_dwTtlSeconds != dwTTL)
  452. {
  453. m_bDirty = TRUE;
  454. m_pNSInfo->m_pRecord->m_dwTtlSeconds = dwTTL;
  455. // Need to change the TTL on all associated A records
  456. CDNSRecordNodeEditInfoList* pNSInfoList = m_pNSInfo->m_pEditInfoList;
  457. for(POSITION pos = pNSInfoList->GetHeadPosition(); pos != NULL; )
  458. {
  459. CDNSRecordNodeEditInfo* pCurrentInfo = pNSInfoList->GetNext(pos);
  460. ASSERT(pCurrentInfo->m_pRecordNode != NULL);
  461. ASSERT(pCurrentInfo->m_pRecord != NULL);
  462. // if slated for removal, don't bother to change
  463. if (pCurrentInfo->m_action != CDNSRecordNodeEditInfo::remove)
  464. {
  465. pCurrentInfo->m_pRecord->m_dwTtlSeconds = m_pNSInfo->m_pRecord->m_dwTtlSeconds;
  466. // if already marked "add" or "edit", leave as is,
  467. // but if unchanged, need to mark as "edit"
  468. if (pCurrentInfo->m_action == CDNSRecordNodeEditInfo::unchanged)
  469. pCurrentInfo->m_action = CDNSRecordNodeEditInfo::edit;
  470. }
  471. }
  472. }
  473. if (m_pNSInfo->m_action == CDNSRecordNodeEditInfo::remove)
  474. {
  475. if (IDNO == DNSMessageBox(IDS_MSG_RECORD_WARNING_NS_NO_IP, MB_YESNO))
  476. return;
  477. }
  478. CPropertyPage::OnOK();
  479. }
  480. void CDNS_NS_RecordDialog::OnServerNameChange()
  481. {
  482. SyncUIButtons();
  483. }
  484. void CDNS_NS_RecordDialog::OnBrowse()
  485. {
  486. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  487. FIX_THREAD_STATE_MFC_BUG();
  488. CComponentDataObject* pComponentDataObject = GetPage()->GetHolder()->GetComponentData();
  489. CDNSBrowserDlg dlg(pComponentDataObject, GetPage()->GetHolder(), RECORD_A_AND_CNAME);
  490. if (IDOK == dlg.DoModal())
  491. {
  492. GetServerEdit()->SetWindowText(dlg.GetSelectionString());
  493. //
  494. // if it is an A record, add the IP address to the IP editor
  495. //
  496. CDNSRecordNodeBase* pRecordNode = reinterpret_cast<CDNSRecordNodeBase*>(dlg.GetSelection());
  497. if ((pRecordNode != NULL) && (pRecordNode->GetType() == DNS_TYPE_A))
  498. {
  499. DWORD ip = ((CDNS_A_RecordNode*)pRecordNode)->GetIPAddress();
  500. m_RecordAddressesEditor.AddAddresses(&ip,1);
  501. }
  502. }
  503. }
  504. void CDNS_NS_RecordDialog::OnQuery()
  505. {
  506. CDNSRecordNodeEditInfo tempNSInfo; // test
  507. CString szNameNode;
  508. GetNSServerName(szNameNode);
  509. CDNSServerNode* pServerNode;
  510. if (m_pNSPage != NULL)
  511. {
  512. pServerNode = m_pNSPage->GetDomainNode()->GetServerNode();
  513. }
  514. else
  515. {
  516. pServerNode = m_pNSWiz->GetDomainNode()->GetServerNode();
  517. }
  518. LPCWSTR lpszZoneName = NULL;
  519. CDNSZoneNode* pZoneNode = NULL;
  520. if (m_pNSPage != NULL)
  521. {
  522. pZoneNode = m_pNSPage->GetDomainNode()->GetZoneNode();
  523. }
  524. else
  525. {
  526. pZoneNode = m_pNSWiz->GetDomainNode()->GetZoneNode();
  527. }
  528. if (pZoneNode != NULL)
  529. {
  530. lpszZoneName = pZoneNode->GetFullName();
  531. }
  532. ASSERT(pServerNode != NULL);
  533. CComponentDataObject* pComponentDataObject =
  534. GetPage()->GetHolder()->GetComponentData();
  535. CDNSRootData* pRootData = (CDNSRootData*)pComponentDataObject->GetRootData();
  536. ASSERT(pRootData != NULL);
  537. DWORD cAddrCount;
  538. PIP_ADDRESS pipAddrs;
  539. pServerNode->GetListenAddressesInfo(&cAddrCount, &pipAddrs);
  540. if (cAddrCount == 0)
  541. {
  542. // listening on all addresses
  543. pServerNode->GetServerAddressesInfo(&cAddrCount, &pipAddrs);
  544. }
  545. CDNSDomainNode::FindARecordsFromNSInfo(pServerNode->GetRPCName(),
  546. pServerNode->GetVersion(),
  547. cAddrCount, pipAddrs,
  548. lpszZoneName,
  549. szNameNode,
  550. tempNSInfo.m_pEditInfoList,
  551. pRootData->IsAdvancedView());
  552. if (tempNSInfo.m_pEditInfoList->GetCount() > 0)
  553. {
  554. // update the list only if we have valid data
  555. m_RecordAddressesEditor.SetIpAddresses(&tempNSInfo);
  556. }
  557. else
  558. {
  559. DNSMessageBox(IDS_MSG_RECORD_NS_RESOLVE_IP, MB_OK | MB_ICONERROR);
  560. }
  561. }
  562. ///////////////////////////////////////////////////////////////////////////////
  563. // CNSListCtrl
  564. BEGIN_MESSAGE_MAP(CNSListCtrl, CListCtrl)
  565. END_MESSAGE_MAP()
  566. void CNSListCtrl::Initialize()
  567. {
  568. // get size of control to help set the column widths
  569. CRect controlRect;
  570. GetClientRect(controlRect);
  571. // get width of control, width of potential scrollbar, width needed for sub-item
  572. // string
  573. int controlWidth = controlRect.Width();
  574. int scrollThumbWidth = ::GetSystemMetrics(SM_CXHTHUMB);
  575. // clean net width
  576. int nNetControlWidth = controlWidth - scrollThumbWidth - 12 * ::GetSystemMetrics(SM_CXBORDER);
  577. // fields widths
  578. int nWidth1 = nNetControlWidth / 2;
  579. int nWidth2 = nNetControlWidth - nWidth1;
  580. //
  581. // set up columns
  582. CString szHeaders;
  583. {
  584. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  585. szHeaders.LoadString(IDS_NSPAGE_LISTVIEW_HEADERS);
  586. }
  587. ASSERT(!szHeaders.IsEmpty());
  588. LPWSTR lpszArr[2];
  589. UINT n;
  590. ParseNewLineSeparatedString(szHeaders.GetBuffer(1), lpszArr, &n);
  591. szHeaders.ReleaseBuffer();
  592. ASSERT(n == 2);
  593. InsertColumn(1, lpszArr[0], LVCFMT_LEFT, nWidth1, 1);
  594. InsertColumn(2, lpszArr[1], LVCFMT_LEFT, nWidth2 + 28, 2);
  595. }
  596. int CNSListCtrl::GetSelection()
  597. {
  598. return GetNextItem(-1, LVIS_SELECTED);
  599. }
  600. void CNSListCtrl::SetSelection(int nSel)
  601. {
  602. VERIFY(SetItemState(nSel, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED));
  603. /*
  604. VERIFY(SetItem(nSel, // nItem
  605. 0, // nSubItem
  606. LVIF_STATE, // nMask
  607. NULL, // lpszItem
  608. 0, // nImage
  609. LVIS_SELECTED | LVIS_FOCUSED, // nState
  610. LVIS_SELECTED | LVIS_FOCUSED, // nStateMask
  611. NULL // lParam
  612. ));
  613. */
  614. }
  615. void CNSListCtrl::UpdateNSRecordEntry(int nItemIndex)
  616. {
  617. CDNSRecordNodeEditInfo* pNSInfo = (CDNSRecordNodeEditInfo*)GetItemData(nItemIndex);
  618. VERIFY(SetItem(nItemIndex, // nItem
  619. 0, // nSubItem
  620. LVIF_TEXT, // nMask
  621. ((CDNS_NS_Record*)pNSInfo->m_pRecord)->m_szNameNode, // lpszItem
  622. 0, // nImage
  623. 0, // nState
  624. 0, // nStateMask
  625. NULL // lParam
  626. ));
  627. CString szTemp;
  628. GetIPAddressString(pNSInfo, szTemp);
  629. SetItemText(nItemIndex, 1, szTemp);
  630. }
  631. CDNSRecordNodeEditInfo* CNSListCtrl::GetSelectionEditInfo()
  632. {
  633. int nSel = GetSelection();
  634. if (nSel == -1)
  635. return NULL; // no selection
  636. return (CDNSRecordNodeEditInfo*)GetItemData(nSel);
  637. }
  638. void CNSListCtrl::BuildIPAddrDisplayString(CDNSRecordNodeEditInfo* pNSInfo, CString& szDisplayData)
  639. {
  640. USES_CONVERSION;
  641. // need to chain the IP addresses in a single string
  642. CString szTemp;
  643. szTemp.GetBuffer(20); // length of an IP string
  644. szTemp.ReleaseBuffer();
  645. szDisplayData.GetBuffer(static_cast<int>(20*pNSInfo->m_pEditInfoList->GetCount()));
  646. szDisplayData.ReleaseBuffer();
  647. POSITION pos;
  648. for( pos = pNSInfo->m_pEditInfoList->GetHeadPosition(); pos != NULL; )
  649. {
  650. CDNSRecordNodeEditInfo* pARecordInfo = pNSInfo->m_pEditInfoList->GetNext(pos);
  651. if (pARecordInfo->m_action != CDNSRecordNodeEditInfo::remove)
  652. {
  653. ASSERT(pARecordInfo != NULL);
  654. ASSERT(pARecordInfo->m_pRecord != NULL);
  655. ASSERT(pARecordInfo->m_pRecord->m_wType == DNS_TYPE_A);
  656. CDNS_A_Record* pARecord = (CDNS_A_Record*)pARecordInfo->m_pRecord;
  657. szDisplayData += _T("[");
  658. FormatIpAddress(szTemp, pARecord->m_ipAddress);
  659. szDisplayData += szTemp;
  660. if (pARecordInfo->m_bFromDnsQuery)
  661. {
  662. szDisplayData += _T("*");
  663. }
  664. szDisplayData += _T("] ");
  665. }
  666. }
  667. }
  668. BOOL CNSListCtrl::InsertNSRecordEntry(CDNSRecordNodeEditInfo* pNSInfo, int nItemIndex)
  669. {
  670. ASSERT(pNSInfo != NULL);
  671. ASSERT( (pNSInfo->m_action == CDNSRecordNodeEditInfo::unchanged) ||
  672. (pNSInfo->m_action == CDNSRecordNodeEditInfo::add) );
  673. ASSERT(pNSInfo->m_pRecord != NULL);
  674. ASSERT(pNSInfo->m_pRecordNode != NULL);
  675. ASSERT(pNSInfo->m_pRecordNode->m_bAtTheNode);
  676. BOOL bAlreadyExists = FALSE;
  677. //
  678. // First check to see if its already there
  679. //
  680. for (int idx = 0; idx < GetItemCount(); idx++)
  681. {
  682. CDNSRecordNodeEditInfo* pIdxInfo = reinterpret_cast<CDNSRecordNodeEditInfo*>(GetItemData(idx));
  683. ASSERT(pIdxInfo != NULL);
  684. if (pIdxInfo == NULL)
  685. {
  686. continue;
  687. }
  688. CDNS_NS_Record* pNSRecord = reinterpret_cast<CDNS_NS_Record*>(pIdxInfo->m_pRecord);
  689. ASSERT(pNSRecord != NULL);
  690. if (pNSRecord == NULL)
  691. {
  692. continue;
  693. }
  694. //
  695. // Adding trailing '.' if not already present
  696. //
  697. CString szUINSName = pNSRecord->m_szNameNode;
  698. CString szNewNSName = ((CDNS_NS_Record*)pNSInfo->m_pRecord)->m_szNameNode;
  699. if (szUINSName[szUINSName.GetLength() - 1] != L'.')
  700. {
  701. szUINSName += L".";
  702. }
  703. if (szNewNSName[szNewNSName.GetLength() - 1] != L'.')
  704. {
  705. szNewNSName += L".";
  706. }
  707. //
  708. // if it exists, just update the existing one
  709. //
  710. if (_wcsicmp(szNewNSName, szUINSName) == 0)
  711. {
  712. bAlreadyExists = TRUE;
  713. //
  714. // Merge the A record lists together
  715. //
  716. POSITION newPos = pNSInfo->m_pEditInfoList->GetHeadPosition();
  717. while (newPos != NULL)
  718. {
  719. CDNSRecordNodeEditInfo* pAInfo = pNSInfo->m_pEditInfoList->GetNext(newPos);
  720. CDNS_A_Record* pARecord = reinterpret_cast<CDNS_A_Record*>(pAInfo->m_pRecord);
  721. ASSERT(pARecord != NULL);
  722. if (pARecord == NULL)
  723. {
  724. continue;
  725. }
  726. BOOL bARecordExists = FALSE;
  727. POSITION IdxPos = pIdxInfo->m_pEditInfoList->GetHeadPosition();
  728. while (IdxPos != NULL)
  729. {
  730. CDNSRecordNodeEditInfo* pIdxAInfo = pIdxInfo->m_pEditInfoList->GetNext(IdxPos);
  731. CDNS_A_Record* pIdxARecord = reinterpret_cast<CDNS_A_Record*>(pIdxAInfo->m_pRecord);
  732. ASSERT(pIdxARecord != NULL);
  733. if (pIdxARecord == NULL)
  734. {
  735. continue;
  736. }
  737. if (pIdxARecord->m_ipAddress == pARecord->m_ipAddress)
  738. {
  739. bARecordExists = TRUE;
  740. break;
  741. }
  742. }
  743. if (!bARecordExists)
  744. {
  745. //
  746. // Add the A record since it doesn't already exist in the list
  747. //
  748. pIdxInfo->m_pEditInfoList->AddTail(pAInfo);
  749. pIdxInfo->m_action = CDNSRecordNodeEditInfo::edit;
  750. UpdateNSRecordEntry(idx);
  751. }
  752. }
  753. }
  754. }
  755. if (!bAlreadyExists)
  756. {
  757. CString szTemp;
  758. GetIPAddressString(pNSInfo, szTemp);
  759. InsertItemHelper(nItemIndex, pNSInfo,
  760. ((CDNS_NS_Record*)pNSInfo->m_pRecord)->m_szNameNode,
  761. (LPCTSTR)szTemp);
  762. //
  763. // Added new item so return TRUE;
  764. //
  765. return TRUE;
  766. }
  767. //
  768. // Updated an existing item so return FALSE
  769. //
  770. return FALSE;
  771. }
  772. void CNSListCtrl::InsertItemHelper(int nIndex, CDNSRecordNodeEditInfo* pNSInfo,
  773. LPCTSTR lpszName, LPCTSTR lpszValue)
  774. {
  775. UINT nState = 0;
  776. if (nIndex == 0 )
  777. nState = LVIS_SELECTED | LVIS_FOCUSED; // have at least one item, select it
  778. VERIFY(-1 != InsertItem(LVIF_TEXT | LVIF_PARAM, nIndex,
  779. lpszName, nState, 0, 0, (LPARAM)pNSInfo));
  780. SetItemText(nIndex, 1, lpszValue);
  781. }
  782. void CNSListCtrl::GetIPAddressString(CDNSRecordNodeEditInfo* pNSInfo, CString& sz)
  783. {
  784. if (pNSInfo->m_pEditInfoList->GetCount() > 0)
  785. {
  786. BuildIPAddrDisplayString(pNSInfo, sz);
  787. }
  788. else
  789. sz.LoadString(IDS_UNKNOWN);
  790. }
  791. ///////////////////////////////////////////////////////////////////////////////
  792. // CDNSNameServersPropertyPage
  793. BEGIN_MESSAGE_MAP(CDNSNameServersPropertyPage, CPropertyPageBase)
  794. ON_BN_CLICKED(IDC_ADD_NS_BUTTON, OnAddButton)
  795. ON_BN_CLICKED(IDC_REMOVE_NS_BUTTON, OnRemoveButton)
  796. ON_BN_CLICKED(IDC_EDIT_NS_BUTTON, OnEditButton)
  797. END_MESSAGE_MAP()
  798. CDNSNameServersPropertyPage::CDNSNameServersPropertyPage(UINT nIDTemplate, UINT nIDCaption)
  799. : CPropertyPageBase(nIDTemplate, nIDCaption)
  800. {
  801. m_pDomainNode = NULL;
  802. m_pCloneInfoList = new CDNSRecordNodeEditInfoList;
  803. m_bReadOnly = FALSE;
  804. m_bMeaningfulTTL = TRUE;
  805. }
  806. CDNSNameServersPropertyPage::~CDNSNameServersPropertyPage()
  807. {
  808. delete m_pCloneInfoList;
  809. }
  810. BOOL CDNSNameServersPropertyPage::WriteNSRecordNodesList()
  811. {
  812. ASSERT(!m_bReadOnly);
  813. ASSERT(m_pCloneInfoList != NULL);
  814. CDNSDomainNode* pDomainNode = GetDomainNode();
  815. return pDomainNode->UpdateNSRecordNodesInfo(m_pCloneInfoList, GetHolder()->GetComponentData());
  816. }
  817. BOOL CDNSNameServersPropertyPage::OnWriteNSRecordNodesListError()
  818. {
  819. ASSERT(!m_bReadOnly);
  820. BOOL bSuccess = TRUE;
  821. // loop for each NS record
  822. POSITION pos;
  823. for( pos = m_pCloneInfoList->GetHeadPosition(); pos != NULL; )
  824. {
  825. CDNSRecordNodeEditInfo* pCurrentInfo = m_pCloneInfoList->GetNext(pos);
  826. if (pCurrentInfo->m_dwErr != 0)
  827. {
  828. if (pCurrentInfo->m_dwErr == DNS_ERROR_RECORD_ALREADY_EXISTS)
  829. {
  830. // ignore if the NS record us already there
  831. pCurrentInfo->m_dwErr = 0;
  832. }
  833. else
  834. {
  835. bSuccess = FALSE;
  836. ASSERT(pCurrentInfo->m_pRecord->GetType() == DNS_TYPE_NS);
  837. CString szNSMsg;
  838. szNSMsg.Format(_T("Failure to write NS record <%s>"),
  839. (((CDNS_NS_Record*)pCurrentInfo->m_pRecord))->m_szNameNode);
  840. DNSErrorDialog(pCurrentInfo->m_dwErr,szNSMsg);
  841. }
  842. }
  843. // loop for each related A record
  844. CDNSRecordNodeEditInfoList* pARecordInfoList = pCurrentInfo->m_pEditInfoList;
  845. ASSERT(pARecordInfoList != NULL);
  846. POSITION posA;
  847. for( posA = pARecordInfoList->GetHeadPosition(); posA != NULL; )
  848. {
  849. CDNSRecordNodeEditInfo* pARecordCurrentInfo = pARecordInfoList->GetNext(posA);
  850. if (pARecordCurrentInfo->m_dwErr != 0)
  851. {
  852. ASSERT(pARecordCurrentInfo->m_pRecord->GetType() == DNS_TYPE_A);
  853. CString szTemp;
  854. FormatIpAddress(szTemp, (((CDNS_A_Record*)pARecordCurrentInfo->m_pRecord))->m_ipAddress);
  855. CString szAMsg;
  856. szAMsg.Format(_T("Failure to write A record <%s>, IP Address %s"),
  857. (((CDNS_NS_Record*)pARecordCurrentInfo->m_pRecord))->m_szNameNode,
  858. (LPCWSTR)szTemp );
  859. DNSErrorDialog(pCurrentInfo->m_dwErr,szAMsg);
  860. }
  861. }
  862. }
  863. return bSuccess;
  864. }
  865. BOOL CDNSNameServersPropertyPage::OnApply()
  866. {
  867. if (m_bReadOnly)
  868. return TRUE;
  869. if (!IsDirty())
  870. return TRUE;
  871. DNS_STATUS err = GetHolder()->NotifyConsole(this);
  872. if ( (err != 0) && OnWriteNSRecordNodesListError() )
  873. {
  874. err = 0; // error was handled and it was not fatal
  875. }
  876. if (err == 0)
  877. {
  878. // refresh data from the zone/domain
  879. LoadUIData();
  880. SetDirty(FALSE);
  881. }
  882. return (err == 0);
  883. }
  884. BOOL CDNSNameServersPropertyPage::OnPropertyChange(BOOL, long*)
  885. {
  886. if (m_bReadOnly)
  887. {
  888. ASSERT(FALSE); // sould not happen
  889. return FALSE;
  890. }
  891. ASSERT(m_pCloneInfoList != NULL);
  892. if (m_pCloneInfoList == NULL)
  893. return FALSE;
  894. BOOL bRes = WriteNSRecordNodesList();
  895. if (!bRes)
  896. GetHolder()->SetError(static_cast<DWORD>(-1)); // something went wrong, error code will be per item
  897. return bRes; // update flag
  898. }
  899. void CDNSNameServersPropertyPage::OnAddButton()
  900. {
  901. if (m_bReadOnly)
  902. {
  903. ASSERT(FALSE); // sould not happen
  904. return;
  905. }
  906. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  907. FIX_THREAD_STATE_MFC_BUG();
  908. ASSERT(m_pCloneInfoList != NULL);
  909. // provide subdialog to add record, for the time being can have just
  910. // dialog to enter the host name
  911. // create an item in the list of changes
  912. // TODO: first check if we can recycle some old stuff in the list
  913. // create new data
  914. CDNSRecordNodeEditInfo* pNewInfo = new CDNSRecordNodeEditInfo;
  915. if (!pNewInfo)
  916. {
  917. return;
  918. }
  919. pNewInfo->m_action = CDNSRecordNodeEditInfo::add;
  920. pNewInfo->CreateFromNewRecord(new CDNS_NS_RecordNode);
  921. // NS records are ALWAYS at the node
  922. CDNSDomainNode* pDomainNode = GetDomainNode();
  923. CDNSRootData* pRootData = (CDNSRootData*)(GetHolder()->GetComponentData()->GetRootData());
  924. ASSERT(pRootData != NULL);
  925. // set name and type flag
  926. pNewInfo->m_pRecordNode->SetRecordName(pDomainNode->GetDisplayName(), TRUE /*bAtTheNode */);
  927. pNewInfo->m_pRecordNode->SetFlagsDown(TN_FLAG_DNS_RECORD_FULL_NAME, !pRootData->IsAdvancedView());
  928. // set TTL
  929. pNewInfo->m_pRecord->m_dwTtlSeconds = pDomainNode->GetDefaultTTL();
  930. CDNS_NS_RecordDialog dlg(this,TRUE);
  931. dlg.m_pNSInfo = pNewInfo;
  932. if (IDOK == dlg.DoModalSheet() && pNewInfo->m_action == CDNSRecordNodeEditInfo::add)
  933. {
  934. //
  935. // add to the list view (at the end)
  936. //
  937. int nCount = m_listCtrl.GetItemCount();
  938. if (m_listCtrl.InsertNSRecordEntry(pNewInfo, nCount))
  939. {
  940. //
  941. // create entry into the record info list
  942. //
  943. m_pCloneInfoList->AddTail(pNewInfo);
  944. //
  945. // set selection and button state on the last inserted
  946. //
  947. m_listCtrl.SetSelection(nCount);
  948. EnableEditorButtons(nCount);
  949. //
  950. // notify count change
  951. //
  952. OnCountChange(nCount+1); // added one
  953. }
  954. //
  955. // set dirty flag. It was either a new record or an update of an old one
  956. //
  957. SetDirty(TRUE);
  958. }
  959. else
  960. {
  961. delete pNewInfo->m_pRecordNode;
  962. pNewInfo->m_pRecordNode = NULL;
  963. delete pNewInfo->m_pRecord;
  964. pNewInfo->m_pRecord = NULL;
  965. delete pNewInfo;
  966. }
  967. }
  968. void CDNSNameServersPropertyPage::OnEditButton()
  969. {
  970. if (m_bReadOnly)
  971. {
  972. ASSERT(FALSE); // sould not happen
  973. return;
  974. }
  975. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  976. FIX_THREAD_STATE_MFC_BUG();
  977. ASSERT(m_pCloneInfoList != NULL);
  978. // get the selection and bring up the dialog with the host name for editing
  979. int nSel = m_listCtrl.GetSelection();
  980. ASSERT(nSel != -1);
  981. if (nSel == -1)
  982. return; // should not happen
  983. CDNSRecordNodeEditInfo* pNSInfo = (CDNSRecordNodeEditInfo*)m_listCtrl.GetItemData(nSel);
  984. ASSERT(pNSInfo != NULL);
  985. CDNS_NS_RecordDialog dlg(this, FALSE);
  986. ASSERT(pNSInfo->m_pRecord->GetType() == DNS_TYPE_NS);
  987. dlg.m_pNSInfo = pNSInfo;
  988. if (IDOK == dlg.DoModalSheet() && dlg.m_bDirty)
  989. {
  990. if (pNSInfo->m_action == CDNSRecordNodeEditInfo::add)
  991. {
  992. // this was a new entry that was edited after creation
  993. // but before committing the change
  994. ASSERT(!pNSInfo->m_bExisting);
  995. // update the listview
  996. m_listCtrl.UpdateNSRecordEntry(nSel);
  997. }
  998. else if (pNSInfo->m_action == CDNSRecordNodeEditInfo::edit)
  999. {
  1000. // this was an existing entry that was changed
  1001. ASSERT(pNSInfo->m_bExisting);
  1002. // update the listview
  1003. m_listCtrl.UpdateNSRecordEntry(nSel);
  1004. }
  1005. else
  1006. {
  1007. // there were no IP addresses, so mark the item for removal
  1008. ASSERT(pNSInfo->m_action == CDNSRecordNodeEditInfo::remove);
  1009. OnRemoveButton();
  1010. }
  1011. // set dirty flag
  1012. SetDirty(TRUE);
  1013. }
  1014. }
  1015. void CDNSNameServersPropertyPage::OnRemoveButton()
  1016. {
  1017. if (m_bReadOnly)
  1018. {
  1019. ASSERT(FALSE); // sould not happen
  1020. return;
  1021. }
  1022. int nSel = m_listCtrl.GetSelection();
  1023. if (nSel == -1)
  1024. {
  1025. ASSERT(FALSE);
  1026. return; // should not happen
  1027. }
  1028. //
  1029. // save focus to restore afterwards, if needed
  1030. //
  1031. CWnd* pWndFocusOld = CWnd::GetFocus();
  1032. ASSERT(pWndFocusOld != NULL);
  1033. //
  1034. // got a selection, delete from listview
  1035. //
  1036. CDNSRecordNodeEditInfo* pNSInfo = (CDNSRecordNodeEditInfo*)m_listCtrl.GetItemData(nSel);
  1037. ASSERT(pNSInfo != NULL);
  1038. m_listCtrl.DeleteItem(nSel);
  1039. //
  1040. // we lost the selection, set it again
  1041. //
  1042. int nNewCount = m_listCtrl.GetItemCount();
  1043. if (nNewCount == nSel)
  1044. {
  1045. //
  1046. // last item in the list was deleted, move selection up
  1047. //
  1048. nSel--;
  1049. }
  1050. if (nSel != -1)
  1051. {
  1052. m_listCtrl.SetSelection(nSel);
  1053. ASSERT(m_listCtrl.GetSelection() == nSel);
  1054. }
  1055. //
  1056. // if there are no items left, need to disable the Edit and Remove buttons
  1057. //
  1058. if (nNewCount == 0)
  1059. {
  1060. CWnd* pCurrentFocusCtrl = CWnd::GetFocus();
  1061. CButton* pRemoveButton = GetRemoveButton();
  1062. CButton* pEditButton = GetEditButton();
  1063. //
  1064. // need to shift focus before disabling buttons
  1065. //
  1066. if ( (pCurrentFocusCtrl == pRemoveButton) ||
  1067. (pCurrentFocusCtrl == pEditButton) )
  1068. {
  1069. CButton* pAddButton = GetAddButton();
  1070. pAddButton->SetFocus();
  1071. // avoid to have the OK button on the sheet to become the default button
  1072. pAddButton->SendMessage(BM_SETSTYLE, BS_DEFPUSHBUTTON,
  1073. MAKELPARAM(/*redraw flag*/ TRUE, 0));
  1074. }
  1075. EnableEditorButtons(nSel); // this will disable both Edit and Remove
  1076. }
  1077. ASSERT(CWnd::GetFocus());
  1078. if (pNSInfo->m_action == CDNSRecordNodeEditInfo::add)
  1079. {
  1080. //
  1081. // mark the item action as none since it was just added without being applied
  1082. //
  1083. pNSInfo->m_action = CDNSRecordNodeEditInfo::none;
  1084. }
  1085. else
  1086. {
  1087. // mark the item as deleted in the list of changes
  1088. pNSInfo->m_action = CDNSRecordNodeEditInfo::remove;
  1089. }
  1090. // set dirty flag, removed a record
  1091. SetDirty(TRUE);
  1092. // notify count change
  1093. OnCountChange(nNewCount);
  1094. }
  1095. BOOL CDNSNameServersPropertyPage::OnInitDialog()
  1096. {
  1097. CPropertyPageBase::OnInitDialog();
  1098. // controls initialization
  1099. VERIFY(m_listCtrl.SubclassDlgItem(IDC_NS_LIST, this));
  1100. m_listCtrl.Initialize();
  1101. // load the data
  1102. LoadUIData();
  1103. // set button state
  1104. if (m_bReadOnly)
  1105. {
  1106. EnableButtons(FALSE);
  1107. }
  1108. else
  1109. {
  1110. // set selection to first item in the list, if there
  1111. int nSel = (m_listCtrl.GetItemCount()>0) ? 0 : -1;
  1112. EnableEditorButtons(nSel);
  1113. }
  1114. return TRUE; // return TRUE unless you set the focus to a control
  1115. // EXCEPTION: OCX Property Pages should return FALSE
  1116. }
  1117. void CDNSNameServersPropertyPage::LoadUIData()
  1118. {
  1119. m_pCloneInfoList->RemoveAllNodes();
  1120. ReadRecordNodesList(); // read from source
  1121. FillNsListView();
  1122. }
  1123. void CDNSNameServersPropertyPage::FillNsListView()
  1124. {
  1125. ASSERT(m_pCloneInfoList != NULL);
  1126. m_listCtrl.DeleteAllItems();
  1127. // loop through the list of NS records and insert
  1128. POSITION pos;
  1129. int itemIndex = 0;
  1130. for( pos = m_pCloneInfoList->GetHeadPosition(); pos != NULL; )
  1131. {
  1132. CDNSRecordNodeEditInfo* pCurrentInfo = m_pCloneInfoList->GetNext(pos);
  1133. if (m_listCtrl.InsertNSRecordEntry(pCurrentInfo, itemIndex))
  1134. {
  1135. if (itemIndex == 0)
  1136. m_listCtrl.SetSelection(0);
  1137. itemIndex++;
  1138. }
  1139. }
  1140. }
  1141. void CDNSNameServersPropertyPage::EnableEditorButtons(int nListBoxSel)
  1142. {
  1143. if (m_bReadOnly)
  1144. return;
  1145. // must have item selected to remove or add
  1146. GetRemoveButton()->EnableWindow(nListBoxSel != -1);
  1147. GetEditButton()->EnableWindow(nListBoxSel != -1);
  1148. }
  1149. void CDNSNameServersPropertyPage::EnableButtons(BOOL bEnable)
  1150. {
  1151. GetAddButton()->EnableWindow(bEnable);
  1152. GetRemoveButton()->EnableWindow(bEnable);
  1153. GetEditButton()->EnableWindow(bEnable);
  1154. }
  1155. //////////////////////////////////////////////////////////////////////////////
  1156. ///////////////////////////////////////////////////////////////////////////////
  1157. // CDNSNameServersWizardPage
  1158. BEGIN_MESSAGE_MAP(CDNSNameServersWizardPage, CPropertyPageBase)
  1159. ON_BN_CLICKED(IDC_ADD_NS_BUTTON, OnAddButton)
  1160. ON_BN_CLICKED(IDC_REMOVE_NS_BUTTON, OnRemoveButton)
  1161. ON_BN_CLICKED(IDC_EDIT_NS_BUTTON, OnEditButton)
  1162. END_MESSAGE_MAP()
  1163. CDNSNameServersWizardPage::CDNSNameServersWizardPage(UINT nIDTemplate)
  1164. : CPropertyPageBase(nIDTemplate)
  1165. {
  1166. InitWiz97(FALSE,IDS_SERVWIZ_ROOTHINTS_TITLE,IDS_SERVWIZ_ROOTHINTS_SUBTITLE);
  1167. m_pDomainNode = NULL;
  1168. m_pCloneInfoList = new CDNSRecordNodeEditInfoList;
  1169. m_bReadOnly = FALSE;
  1170. m_bMeaningfulTTL = TRUE;
  1171. }
  1172. CDNSNameServersWizardPage::~CDNSNameServersWizardPage()
  1173. {
  1174. delete m_pCloneInfoList;
  1175. }
  1176. BOOL CDNSNameServersWizardPage::WriteNSRecordNodesList()
  1177. {
  1178. ASSERT(!m_bReadOnly);
  1179. ASSERT(m_pCloneInfoList != NULL);
  1180. CDNSDomainNode* pDomainNode = GetDomainNode();
  1181. return pDomainNode->UpdateNSRecordNodesInfo(m_pCloneInfoList, GetHolder()->GetComponentData());
  1182. }
  1183. BOOL CDNSNameServersWizardPage::OnWriteNSRecordNodesListError()
  1184. {
  1185. ASSERT(!m_bReadOnly);
  1186. BOOL bSuccess = TRUE;
  1187. // loop for each NS record
  1188. POSITION pos;
  1189. for( pos = m_pCloneInfoList->GetHeadPosition(); pos != NULL; )
  1190. {
  1191. CDNSRecordNodeEditInfo* pCurrentInfo = m_pCloneInfoList->GetNext(pos);
  1192. if (pCurrentInfo->m_dwErr != 0)
  1193. {
  1194. if (pCurrentInfo->m_dwErr == DNS_ERROR_RECORD_ALREADY_EXISTS)
  1195. {
  1196. // ignore if the NS record us already there
  1197. pCurrentInfo->m_dwErr = 0;
  1198. }
  1199. else
  1200. {
  1201. bSuccess = FALSE;
  1202. ASSERT(pCurrentInfo->m_pRecord->GetType() == DNS_TYPE_NS);
  1203. CString szNSMsg;
  1204. szNSMsg.Format(_T("Failure to write NS record <%s>"),
  1205. (((CDNS_NS_Record*)pCurrentInfo->m_pRecord))->m_szNameNode);
  1206. DNSErrorDialog(pCurrentInfo->m_dwErr,szNSMsg);
  1207. }
  1208. }
  1209. // loop for each related A record
  1210. CDNSRecordNodeEditInfoList* pARecordInfoList = pCurrentInfo->m_pEditInfoList;
  1211. ASSERT(pARecordInfoList != NULL);
  1212. POSITION posA;
  1213. for( posA = pARecordInfoList->GetHeadPosition(); posA != NULL; )
  1214. {
  1215. CDNSRecordNodeEditInfo* pARecordCurrentInfo = pARecordInfoList->GetNext(posA);
  1216. if (pARecordCurrentInfo->m_dwErr != 0)
  1217. {
  1218. ASSERT(pARecordCurrentInfo->m_pRecord->GetType() == DNS_TYPE_A);
  1219. CString szTemp;
  1220. FormatIpAddress(szTemp, (((CDNS_A_Record*)pARecordCurrentInfo->m_pRecord))->m_ipAddress);
  1221. CString szAMsg;
  1222. szAMsg.Format(_T("Failure to write A record <%s>, IP Address %s"),
  1223. (((CDNS_NS_Record*)pARecordCurrentInfo->m_pRecord))->m_szNameNode,
  1224. (LPCWSTR)szTemp );
  1225. DNSErrorDialog(pCurrentInfo->m_dwErr,szAMsg);
  1226. }
  1227. }
  1228. }
  1229. return bSuccess;
  1230. }
  1231. BOOL CDNSNameServersWizardPage::OnApply()
  1232. {
  1233. if (m_bReadOnly)
  1234. return TRUE;
  1235. if (!IsDirty())
  1236. return TRUE;
  1237. DNS_STATUS err = GetHolder()->NotifyConsole(this);
  1238. if ( (err != 0) && OnWriteNSRecordNodesListError() )
  1239. {
  1240. err = 0; // error was handled and it was not fatal
  1241. }
  1242. if (err == 0)
  1243. {
  1244. // refresh data from the zone/domain
  1245. LoadUIData();
  1246. SetDirty(FALSE);
  1247. }
  1248. else
  1249. {
  1250. ::SetLastError(err);
  1251. }
  1252. return (err == 0);
  1253. }
  1254. BOOL CDNSNameServersWizardPage::OnPropertyChange(BOOL, long*)
  1255. {
  1256. if (m_bReadOnly)
  1257. {
  1258. ASSERT(FALSE); // sould not happen
  1259. return FALSE;
  1260. }
  1261. ASSERT(m_pCloneInfoList != NULL);
  1262. if (m_pCloneInfoList == NULL)
  1263. return FALSE;
  1264. BOOL bRes = WriteNSRecordNodesList();
  1265. if (!bRes)
  1266. GetHolder()->SetError(static_cast<DWORD>(-1)); // something went wrong, error code will be per item
  1267. return bRes; // update flag
  1268. }
  1269. void CDNSNameServersWizardPage::OnAddButton()
  1270. {
  1271. if (m_bReadOnly)
  1272. {
  1273. ASSERT(FALSE); // sould not happen
  1274. return;
  1275. }
  1276. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  1277. FIX_THREAD_STATE_MFC_BUG();
  1278. ASSERT(m_pCloneInfoList != NULL);
  1279. // provide subdialog to add record, for the time being can have just
  1280. // dialog to enter the host name
  1281. // create an item in the list of changes
  1282. // TODO: first check if we can recycle some old stuff in the list
  1283. // create new data
  1284. CDNSRecordNodeEditInfo* pNewInfo = new CDNSRecordNodeEditInfo;
  1285. if (!pNewInfo)
  1286. {
  1287. return;
  1288. }
  1289. pNewInfo->m_action = CDNSRecordNodeEditInfo::add;
  1290. pNewInfo->CreateFromNewRecord(new CDNS_NS_RecordNode);
  1291. // NS records are ALWAYS at the node
  1292. CDNSDomainNode* pDomainNode = GetDomainNode();
  1293. CDNSRootData* pRootData = (CDNSRootData*)(GetHolder()->GetComponentData()->GetRootData());
  1294. ASSERT(pRootData != NULL);
  1295. // set name and type flag
  1296. pNewInfo->m_pRecordNode->SetRecordName(pDomainNode->GetDisplayName(), TRUE /*bAtTheNode */);
  1297. pNewInfo->m_pRecordNode->SetFlagsDown(TN_FLAG_DNS_RECORD_FULL_NAME, !pRootData->IsAdvancedView());
  1298. // set TTL
  1299. pNewInfo->m_pRecord->m_dwTtlSeconds = pDomainNode->GetDefaultTTL();
  1300. CDNS_NS_RecordDialog dlg(this,TRUE);
  1301. dlg.m_pNSInfo = pNewInfo;
  1302. if (IDOK == dlg.DoModalSheet() && pNewInfo->m_action == CDNSRecordNodeEditInfo::add)
  1303. {
  1304. //
  1305. // add to the list view (at the end)
  1306. //
  1307. int nCount = m_listCtrl.GetItemCount();
  1308. if (m_listCtrl.InsertNSRecordEntry(pNewInfo, nCount))
  1309. {
  1310. //
  1311. // create entry into the record info list
  1312. //
  1313. m_pCloneInfoList->AddTail(pNewInfo);
  1314. //
  1315. // set selection and button state on the last inserted
  1316. //
  1317. m_listCtrl.SetSelection(nCount);
  1318. EnableEditorButtons(nCount);
  1319. //
  1320. // notify count change
  1321. //
  1322. OnCountChange(nCount+1); // added one
  1323. }
  1324. //
  1325. // set dirty flag, it is a new record
  1326. //
  1327. SetDirty(TRUE);
  1328. }
  1329. else
  1330. {
  1331. delete pNewInfo->m_pRecordNode;
  1332. pNewInfo->m_pRecordNode = NULL;
  1333. delete pNewInfo->m_pRecord;
  1334. pNewInfo->m_pRecord = NULL;
  1335. delete pNewInfo;
  1336. }
  1337. }
  1338. void CDNSNameServersWizardPage::OnEditButton()
  1339. {
  1340. if (m_bReadOnly)
  1341. {
  1342. ASSERT(FALSE); // sould not happen
  1343. return;
  1344. }
  1345. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  1346. FIX_THREAD_STATE_MFC_BUG();
  1347. ASSERT(m_pCloneInfoList != NULL);
  1348. // get the selection and bring up the dialog with the host name for editing
  1349. int nSel = m_listCtrl.GetSelection();
  1350. ASSERT(nSel != -1);
  1351. if (nSel == -1)
  1352. return; // should not happen
  1353. CDNSRecordNodeEditInfo* pNSInfo = (CDNSRecordNodeEditInfo*)m_listCtrl.GetItemData(nSel);
  1354. ASSERT(pNSInfo != NULL);
  1355. CDNS_NS_RecordDialog dlg(this, FALSE);
  1356. ASSERT(pNSInfo->m_pRecord->GetType() == DNS_TYPE_NS);
  1357. dlg.m_pNSInfo = pNSInfo;
  1358. if (IDOK == dlg.DoModalSheet() && dlg.m_bDirty)
  1359. {
  1360. if (pNSInfo->m_action == CDNSRecordNodeEditInfo::add)
  1361. {
  1362. // this was a new entry that was edited after creation
  1363. // but before committing the change
  1364. ASSERT(!pNSInfo->m_bExisting);
  1365. // update the listview
  1366. m_listCtrl.UpdateNSRecordEntry(nSel);
  1367. }
  1368. else if (pNSInfo->m_action == CDNSRecordNodeEditInfo::edit)
  1369. {
  1370. // this was an existing entry that was changed
  1371. ASSERT(pNSInfo->m_bExisting);
  1372. // update the listview
  1373. m_listCtrl.UpdateNSRecordEntry(nSel);
  1374. }
  1375. else
  1376. {
  1377. // there were no IP addresses, so mark the item for removal
  1378. ASSERT(pNSInfo->m_action == CDNSRecordNodeEditInfo::remove);
  1379. OnRemoveButton();
  1380. }
  1381. // set dirty flag
  1382. SetDirty(TRUE);
  1383. }
  1384. }
  1385. void CDNSNameServersWizardPage::OnRemoveButton()
  1386. {
  1387. if (m_bReadOnly)
  1388. {
  1389. ASSERT(FALSE); // sould not happen
  1390. return;
  1391. }
  1392. int nSel = m_listCtrl.GetSelection();
  1393. if (nSel == -1)
  1394. {
  1395. ASSERT(FALSE);
  1396. return; // should not happen
  1397. }
  1398. //
  1399. // save focus to restore afterwards, if needed
  1400. //
  1401. CWnd* pWndFocusOld = CWnd::GetFocus();
  1402. ASSERT(pWndFocusOld != NULL);
  1403. //
  1404. // got a selection, delete from listview
  1405. //
  1406. CDNSRecordNodeEditInfo* pNSInfo = (CDNSRecordNodeEditInfo*)m_listCtrl.GetItemData(nSel);
  1407. ASSERT(pNSInfo != NULL);
  1408. m_listCtrl.DeleteItem(nSel);
  1409. //
  1410. // we lost the selection, set it again
  1411. //
  1412. int nNewCount = m_listCtrl.GetItemCount();
  1413. if (nNewCount == nSel)
  1414. {
  1415. //
  1416. // last item in the list was deleted, move selection up
  1417. //
  1418. nSel--;
  1419. }
  1420. if (nSel != -1)
  1421. {
  1422. m_listCtrl.SetSelection(nSel);
  1423. ASSERT(m_listCtrl.GetSelection() == nSel);
  1424. }
  1425. //
  1426. // if there are no items left, need to disable the Edit and Remove buttons
  1427. //
  1428. if (nNewCount == 0)
  1429. {
  1430. CWnd* pCurrentFocusCtrl = CWnd::GetFocus();
  1431. CButton* pRemoveButton = GetRemoveButton();
  1432. CButton* pEditButton = GetEditButton();
  1433. //
  1434. // need to shift focus before disabling buttons
  1435. //
  1436. if ( (pCurrentFocusCtrl == pRemoveButton) ||
  1437. (pCurrentFocusCtrl == pEditButton) )
  1438. {
  1439. CButton* pAddButton = GetAddButton();
  1440. pAddButton->SetFocus();
  1441. // avoid to have the OK button on the sheet to become the default button
  1442. pAddButton->SendMessage(BM_SETSTYLE, BS_DEFPUSHBUTTON,
  1443. MAKELPARAM(/*redraw flag*/ TRUE, 0));
  1444. }
  1445. EnableEditorButtons(nSel); // this will disable both Edit and Remove
  1446. }
  1447. ASSERT(CWnd::GetFocus());
  1448. if (pNSInfo->m_action == CDNSRecordNodeEditInfo::add)
  1449. {
  1450. //
  1451. // mark the item action as none since the item hasn't been added yet anyways
  1452. //
  1453. pNSInfo->m_action = CDNSRecordNodeEditInfo::none;
  1454. }
  1455. else
  1456. {
  1457. // mark the item as deleted in the list of changes
  1458. pNSInfo->m_action = CDNSRecordNodeEditInfo::remove;
  1459. }
  1460. // set dirty flag, removed a record
  1461. SetDirty(TRUE);
  1462. // notify count change
  1463. OnCountChange(nNewCount);
  1464. }
  1465. BOOL CDNSNameServersWizardPage::OnInitDialog()
  1466. {
  1467. CPropertyPageBase::OnInitDialog();
  1468. // controls initialization
  1469. VERIFY(m_listCtrl.SubclassDlgItem(IDC_NS_LIST, this));
  1470. m_listCtrl.Initialize();
  1471. // load the data
  1472. LoadUIData();
  1473. // set button state
  1474. if (m_bReadOnly)
  1475. {
  1476. EnableButtons(FALSE);
  1477. }
  1478. else
  1479. {
  1480. // set selection to first item in the list, if there
  1481. int nSel = (m_listCtrl.GetItemCount()>0) ? 0 : -1;
  1482. EnableEditorButtons(nSel);
  1483. }
  1484. return TRUE; // return TRUE unless you set the focus to a control
  1485. // EXCEPTION: OCX Property Pages should return FALSE
  1486. }
  1487. void CDNSNameServersWizardPage::LoadUIData()
  1488. {
  1489. m_pCloneInfoList->RemoveAllNodes();
  1490. ReadRecordNodesList(); // read from source
  1491. FillNsListView();
  1492. }
  1493. void CDNSNameServersWizardPage::FillNsListView()
  1494. {
  1495. ASSERT(m_pCloneInfoList != NULL);
  1496. m_listCtrl.DeleteAllItems();
  1497. // loop through the list of NS records and insert
  1498. POSITION pos;
  1499. int itemIndex = 0;
  1500. for( pos = m_pCloneInfoList->GetHeadPosition(); pos != NULL; )
  1501. {
  1502. CDNSRecordNodeEditInfo* pCurrentInfo = m_pCloneInfoList->GetNext(pos);
  1503. if (m_listCtrl.InsertNSRecordEntry(pCurrentInfo, itemIndex))
  1504. {
  1505. if (itemIndex == 0)
  1506. m_listCtrl.SetSelection(0);
  1507. itemIndex++;
  1508. }
  1509. }
  1510. }
  1511. void CDNSNameServersWizardPage::EnableEditorButtons(int nListBoxSel)
  1512. {
  1513. if (m_bReadOnly)
  1514. return;
  1515. // must have item selected to remove or add
  1516. GetRemoveButton()->EnableWindow(nListBoxSel != -1);
  1517. GetEditButton()->EnableWindow(nListBoxSel != -1);
  1518. }
  1519. void CDNSNameServersWizardPage::EnableButtons(BOOL bEnable)
  1520. {
  1521. GetAddButton()->EnableWindow(bEnable);
  1522. GetRemoveButton()->EnableWindow(bEnable);
  1523. GetEditButton()->EnableWindow(bEnable);
  1524. }