windows-nt/Source/XPSP1/NT/admin/snapin/dnsmgr/domain.cpp

2811 lines
78 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1998 - 1999
//
// File: domain.cpp
//
//--------------------------------------------------------------------------
#include "preDNSsn.h"
#include <SnapBase.h>
#include "resource.h"
#include "dnsutil.h"
#include "DNSSnap.h"
#include "snapdata.h"
#include "server.h"
#include "domain.h"
#include "record.h"
#include "zone.h"
#include "delegwiz.h"
#ifdef DEBUG_ALLOCATOR
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#endif
BOOL _match(LPCWSTR lpszNSName,
CDNS_A_RecordNode* pARecordNode)
{
TRACE(_T("NS %s A %s\n"), lpszNSName, pARecordNode->GetString(0));
return DnsNameCompare_W((LPWSTR)lpszNSName, (LPWSTR)pARecordNode->GetString(0));
}
/////////////////////////////////////////////////////////////////////////
// CNewDomainDialog
class CNewDomainDialog : public CHelpDialog
{
// Construction
public:
CNewDomainDialog(CDNSDomainNode* pParentDomainNode,
CComponentDataObject* pComponentData);
enum { IDD = IDD_DOMAIN_ADDNEWDOMAIN };
// Implementation
protected:
virtual BOOL OnInitDialog();
virtual void OnOK();
afx_msg void OnEditChange();
afx_msg void OnIPv4CtrlChange();
afx_msg BOOL OnHelpInfo(HELPINFO* pHelpInfo);
DECLARE_MESSAGE_MAP()
private:
CDNSDomainNode* m_pParentDomainNode;
CComponentDataObject* m_pComponentData;
CEdit* GetDomainEdit() { return (CEdit*)GetDlgItem(IDC_EDIT_DOMAIN_NAME);}
CDNSIPv4Control* GetDomainIPv4Ctrl()
{ return (CDNSIPv4Control*)GetDlgItem(IDC_IPEDIT_DOMAIN_NAME);}
CString m_szDomainName;
BOOL m_bAdvancedView;
int m_nOctects;
int m_nUTF8ParentLen;
};
BEGIN_MESSAGE_MAP(CNewDomainDialog, CHelpDialog)
ON_EN_CHANGE(IDC_EDIT_DOMAIN_NAME,OnEditChange)
ON_EN_CHANGE(IDC_IPEDIT_DOMAIN_NAME, OnIPv4CtrlChange)
END_MESSAGE_MAP()
CNewDomainDialog::CNewDomainDialog(CDNSDomainNode* pParentDomainNode,
CComponentDataObject* pComponentData)
: CHelpDialog(CNewDomainDialog::IDD, pComponentData)
{
ASSERT(pParentDomainNode != NULL);
ASSERT(pComponentData != NULL);
m_pParentDomainNode = pParentDomainNode;
m_pComponentData = pComponentData;
m_bAdvancedView = TRUE;
m_nOctects = -1; // invalid if advanced view
m_nUTF8ParentLen = UTF8StringLen(pParentDomainNode->GetFullName());
}
BOOL CNewDomainDialog::OnInitDialog()
{
CHelpDialog::OnInitDialog();
// move the edit box in place of the IP control
CDNSIPv4Control* pNameIPCtrl = GetDomainIPv4Ctrl();
CEdit* pNameEdit = GetDomainEdit();
pNameEdit->SetLimitText(MAX_DNS_NAME_LEN - m_nUTF8ParentLen - 1);
CRect editRect;
pNameEdit->GetWindowRect(editRect);
ScreenToClient(editRect);
CRect ipRect;
pNameIPCtrl->GetWindowRect(ipRect);
ScreenToClient(ipRect);
ipRect.bottom = editRect.top + ipRect.Height();
ipRect.right = editRect.left + ipRect.Width();
ipRect.top = editRect.top;
ipRect.left = editRect.left;
pNameIPCtrl->MoveWindow(ipRect,TRUE);
// determine if we need/can have advanced view
CDNSRootData* pRootData = (CDNSRootData*)m_pComponentData->GetRootData();
ASSERT(pRootData != NULL);
m_bAdvancedView = pRootData->IsAdvancedView();
// force advanced view if we are in a forward lookup zone
if (!(m_pParentDomainNode->GetZoneNode()->IsReverse()))
m_bAdvancedView = TRUE;
// determine if we can have a normal view representation
CString szDomainName = m_pParentDomainNode->GetFullName();
if (!m_bAdvancedView)
{
// to have normal view we have to have a valid arpa suffix
BOOL bArpa = RemoveInAddrArpaSuffix(szDomainName.GetBuffer(1));
szDomainName.ReleaseBuffer(); // got "77.80.55.157"
if (!bArpa)
{
m_bAdvancedView = TRUE; // no need to toggle
}
else
{
m_nOctects = ReverseIPString(szDomainName.GetBuffer(1));
szDomainName.ReleaseBuffer(); // finally got "157.55.80.77"
// to have a normal view representation we cannot
// have more than 2 octects
if (m_nOctects > 2)
{
m_bAdvancedView = TRUE; // force advanced for classless
}
else
{
ASSERT(m_nOctects > 0);
switch(m_nOctects)
{
case 1: // e.g. "157", now "157._"
szDomainName += _T(".0.0"); // got "157._.0.0"
break;
case 2: // e.g. "157.55"
szDomainName += _T(".0"); // got "157.55._.0"
break;
};
// set the IP control with IP mask value
IP_ADDRESS ipAddr = IPStringToAddr(szDomainName);
ASSERT(ipAddr != INADDR_NONE);
pNameIPCtrl->SetIPv4Val(ipAddr);
for (int k=0; k<4; k++)
pNameIPCtrl->EnableField(k, k == m_nOctects);
}
}
} // if (!m_bAdvancedView)
// toggle text in static control
CDNSToggleTextControlHelper staticTextToggle;
UINT pnButtonStringIDs[2] = { IDS_NEW_DOMAIN_INST1, IDS_NEW_DOMAIN_INST2 };
VERIFY(staticTextToggle.Init(this, IDC_STATIC_TEXT, pnButtonStringIDs));
staticTextToggle.SetToggleState(m_bAdvancedView);
//
// enable/hide appropriate controls
//
if (m_bAdvancedView)
{
pNameIPCtrl->EnableWindow(FALSE);
pNameIPCtrl->ShowWindow(FALSE);
}
else
{
pNameEdit->EnableWindow(FALSE);
pNameEdit->ShowWindow(FALSE);
}
GetDlgItem(IDOK)->EnableWindow(!m_bAdvancedView);
return TRUE; // return TRUE unless you set the focus to a control
}
void CNewDomainDialog::OnEditChange()
{
ASSERT(m_bAdvancedView);
//
// Get new name from control
//
GetDomainEdit()->GetWindowText(m_szDomainName);
//
// Trim white space
//
m_szDomainName.TrimLeft();
m_szDomainName.TrimRight();
//
// Enable OK button if its a valid name
//
CString szFullDomainName;
if (_wcsicmp(m_pParentDomainNode->GetFullName(), L".") == 0)
{
//
// If the parent domain is the root zone just check the name followed by a '.'
//
szFullDomainName.Format(L"%s.", m_szDomainName);
}
else
{
//
// Else append the parent domain name to the new name
//
szFullDomainName.Format(L"%s.%s", m_szDomainName, m_pParentDomainNode->GetFullName());
}
//
// Get server flags
//
DWORD dwNameChecking = m_pParentDomainNode->GetServerNode()->GetNameCheckFlag();
//
// Is valid?
//
BOOL bIsValidName = (0 == ValidateDnsNameAgainstServerFlags(szFullDomainName,
DnsNameDomain,
dwNameChecking));
GetDlgItem(IDOK)->EnableWindow(bIsValidName);
}
void CNewDomainDialog::OnIPv4CtrlChange()
{
ASSERT(!m_bAdvancedView);
CDNSIPv4Control* pNameIPCtrl = GetDomainIPv4Ctrl();
DWORD dwArr[4];
pNameIPCtrl->GetArray(dwArr, 4);
BOOL bEmpty = (dwArr[m_nOctects] == FIELD_EMPTY);
if (!bEmpty)
{
ASSERT(dwArr[m_nOctects] <= 255);
m_szDomainName.Format(_T("%d"), dwArr[m_nOctects]);
}
GetDlgItem(IDOK)->EnableWindow(!bEmpty);
}
void CNewDomainDialog::OnOK()
{
RECORD_SEARCH recordSearch = RECORD_NOT_FOUND;
CDNSDomainNode* pNewParentDomain = NULL;
CString szFullRecordName = m_szDomainName + L"." + m_pParentDomainNode->GetFullName();
CString szNonExistentDomain;
recordSearch = m_pParentDomainNode->GetZoneNode()->DoesContain(szFullRecordName,
m_pComponentData,
&pNewParentDomain,
szNonExistentDomain,
TRUE);
if (recordSearch == RECORD_NOT_FOUND &&
pNewParentDomain != NULL)
{
DNS_STATUS err = pNewParentDomain->CreateSubdomain(m_szDomainName,m_pComponentData);
if (err != 0)
{
// creation error, warn the user and prompt again
DNSErrorDialog(err, IDS_MSG_DOMAIN_FAIL_CREATE);
CEdit* pDomainNameEdit = GetDomainEdit();
pDomainNameEdit->SetSel(0,-1);
pDomainNameEdit->SetFocus();
return;
}
}
else if (recordSearch == NON_EXISTENT_SUBDOMAIN && pNewParentDomain != NULL)
{
CDNSRootData* pRootData = (CDNSRootData*)m_pComponentData->GetRootData();
//
// Create the node on the server
//
CDNSDomainNode* pNewDomainNode = pNewParentDomain->CreateSubdomainNode();
if (pNewDomainNode == NULL)
{
ASSERT(pNewDomainNode != NULL);
return;
}
pNewParentDomain->SetSubdomainName(pNewDomainNode, m_szDomainName, pRootData->IsAdvancedView());
//
// tell the newly created object to write to the server
//
DNS_STATUS err = pNewDomainNode->Create();
if (err != 0)
{
DNSErrorDialog(err, IDS_MSG_DOMAIN_FAIL_CREATE);
return;
}
if (!szNonExistentDomain.IsEmpty())
{
//
// Create the first subdomain because the current domain is already enumerated
// so we have to start the remaining enumeration at the new subdomain that is needed
//
CDNSDomainNode* pSubdomainNode = pNewParentDomain->CreateSubdomainNode();
ASSERT(pSubdomainNode != NULL);
pNewParentDomain->SetSubdomainName(pSubdomainNode, szNonExistentDomain, pRootData->IsAdvancedView());
VERIFY(pNewParentDomain->AddChildToListAndUISorted(pSubdomainNode, m_pComponentData));
m_pComponentData->SetDescriptionBarText(pNewParentDomain);
//
// I don't care what the results of this are, I am just using it
// to do the expansion to the new record
//
recordSearch = pSubdomainNode->GetZoneNode()->DoesContain(szFullRecordName,
m_pComponentData,
&pNewParentDomain,
szNonExistentDomain,
TRUE);
}
}
else if (recordSearch == RECORD_NOT_FOUND_AT_THE_NODE)
{
//
// Do nothing since this is a domain and it already exists
//
}
else
{
DNS_STATUS err = m_pParentDomainNode->CreateSubdomain(m_szDomainName,m_pComponentData);
if (err != 0)
{
// creation error, warn the user and prompt again
DNSErrorDialog(err, IDS_MSG_DOMAIN_FAIL_CREATE);
CEdit* pDomainNameEdit = GetDomainEdit();
pDomainNameEdit->SetSel(0,-1);
pDomainNameEdit->SetFocus();
return;
}
}
CHelpDialog::OnOK();
}
/////////////////////////////////////////////////////////////////////////
// CDNSDomainQueryObj
class CDNSDomainMsg : public CObjBase
{
};
BOOL CDNSDomainQueryObj::Enumerate()
{
USES_CONVERSION;
TRACE(_T("CDNSDomainQueryObj::Enumerate(): Server <%s> Zone/Domain %s Enumerating\n"), (LPCTSTR)m_szServerName, (LPCTSTR)m_szNodeName);
DNS_STATUS err = 0;
// if needed, get the zone info
if (m_bIsZone && !m_bCache)
{
CDNSZoneInfoEx* pZoneInfo = new CDNSZoneInfoEx;
err = pZoneInfo->Query(m_szServerName, m_szFullNodeName, m_dwServerVersion);
if (err != 0)
{
delete pZoneInfo;
pZoneInfo = NULL;
OnError(err);
return FALSE; // no need to enumerate if we have no zone info
}
else
{
VERIFY(AddQueryResult(pZoneInfo));
}
}
// if executing a query for a specific RR type, just do it right away
if (m_wRecordType != DNS_TYPE_ALL)
{
// we assume that a type specific query does not have filtering enabled
ASSERT(m_bGetAll);
ASSERT(m_nFilterOption == DNS_QUERY_FILTER_DISABLED);
err = EnumerateFiltered(m_wRecordType);
if (err != 0)
OnError(err);
return FALSE; // we are done
}
// DO A MULTI PASS QUERY
m_bFirstPass = TRUE;
// there are items that cannot be filtered out for consistency
// (zone info, SOA, Ns, etc.), so we disable any filtering while
// getting them
BOOL bGetAllOld = m_bGetAll;
BOOL nFilterOptionOld = m_nFilterOption;
m_bGetAll = TRUE;
m_nFilterOption = DNS_QUERY_FILTER_DISABLED;
// only zones or the cache have SOA RR's
if (m_bIsZone || m_bCache)
{
err = EnumerateFiltered(DNS_TYPE_SOA);
if (err != 0)
{
OnError(err);
return FALSE;
}
}
// only zones have WINS and NBSTAT RR's
if (m_bIsZone)
{
if (m_bReverse)
err = EnumerateFiltered(DNS_TYPE_NBSTAT);
else
err = EnumerateFiltered(DNS_TYPE_WINS);
if (err != 0)
{
OnError(err);
return FALSE;
}
}
// need also to check for NS (zone or delegation)
err = EnumerateFiltered(DNS_TYPE_NS);
if (err != 0)
{
OnError(err);
return FALSE;
}
// add a message in the queue to signal we are done with
// the first phase
AddQueryResult(new CDNSDomainMsg);
// now query again, for all RR's, but need to filter the
// known types out
m_bFirstPass = FALSE;
// restore the filtering parameters we had before
m_bGetAll = bGetAllOld;
m_nFilterOption = nFilterOptionOld;
err = EnumerateFiltered(DNS_TYPE_ALL);
if (err != 0)
OnError(err);
return FALSE;
}
DNS_STATUS CDNSDomainQueryObj::EnumerateFiltered(WORD wRecordType)
{
DWORD dwSelectFlags = m_dwSelectFlags;
// for single type queries, we do not want subfolders
if (wRecordType != DNS_TYPE_ALL)
dwSelectFlags |= DNS_RPC_VIEW_NO_CHILDREN;
return CDNSDomainNode::EnumerateNodes(m_szServerName,
m_szZoneName.IsEmpty() ? NULL : (LPCWSTR)m_szZoneName,
m_szNodeName,
m_szFullNodeName,
wRecordType,
dwSelectFlags,
m_bIsZone,
m_bReverse,
m_bAdvancedView,
this);
}
BOOL CDNSDomainQueryObj::CanAddRecord(WORD wRecordType, LPCWSTR lpszRecordName)
{
if (m_nFilterOption == DNS_QUERY_FILTER_DISABLED)
return TRUE; // we have no filtering at all
// determine if this is a special record type for filtered queries
BOOL bSpecialType = (wRecordType == DNS_TYPE_SOA) || (wRecordType == DNS_TYPE_NS) ||
(wRecordType == DNS_TYPE_WINS) || (wRecordType == DNS_TYPE_NBSTAT);
// in the first pass only special types allowed
if (m_bFirstPass)
return bSpecialType;
// in the second pass do not allow special types
if (!m_bFirstPass && bSpecialType)
return FALSE;
// we are left with normal types, apply the filtering, if required
if (m_nFilterOption == DNS_QUERY_FILTER_NONE)
return TRUE; // allow all
// need to match the record name
return MatchName(lpszRecordName);
}
/////////////////////////////////////////////////////////////////////////
// CDNSDomainNode
BEGIN_TOOLBAR_MAP(CDNSDomainNode)
TOOLBAR_EVENT(toolbarNewRecord, OnNewRecord)
END_TOOLBAR_MAP()
// {720132BA-44B2-11d1-B92F-00A0C9A06D2D}
const GUID CDNSDomainNode::NodeTypeGUID =
{ 0x720132ba, 0x44b2, 0x11d1, { 0xb9, 0x2f, 0x0, 0xa0, 0xc9, 0xa0, 0x6d, 0x2d } };
CDNSDomainNode::CDNSDomainNode(BOOL bDelegation)
{
m_bDelegation = bDelegation;
m_pZoneNode = NULL;
m_pNSRecordNodeList = new CDNS_NS_RecordNodeList;
ASSERT(m_pNSRecordNodeList != NULL);
m_bHasDataForPropPages = FALSE;
}
CDNSDomainNode::~CDNSDomainNode()
{
TRACE(_T("~CDNSDomainNode(), name <%s>\n"),GetDisplayName());
ASSERT(m_pNSRecordNodeList != NULL);
delete m_pNSRecordNodeList;
m_pNSRecordNodeList = NULL;
}
DWORD CDNSDomainNode::GetDefaultTTL()
{
if ( (m_pZoneNode != NULL) && (m_pZoneNode->GetZoneType() != DNS_ZONE_TYPE_CACHE) )
return m_pZoneNode->GetSOARecordMinTTL();
else
return (DWORD)0; // no info available from SOA RR
}
void CDNSDomainNode::SetFullDNSName(BOOL bIsZone,
BOOL,
LPCTSTR lpszNodeName,
LPCTSTR lpszParentFullName)
{
ASSERT(lpszNodeName != NULL);
ASSERT(lpszParentFullName != NULL);
if (bIsZone)
{
//
// the two names have to be the same, zone parent of itself
//
ASSERT(_wcsicmp(lpszParentFullName, lpszNodeName) == 0);
m_szFullName = lpszParentFullName;
}
else // it is a domain
{
ASSERT(_wcsicmp(lpszParentFullName, lpszNodeName) != 0);
//
// chain the node name to the parent full name to get the node's full name
//
if (lpszParentFullName[0] == L'.' )
{
//
// if parent is "." and name is "bar", get "bar.": this is the case for the root
// if parent is ".com" and name is "bar", get "bar.com":
//
m_szFullName.Format(_T("%s%s"), lpszNodeName,lpszParentFullName);
}
else
{
//
// if parent is "foo.com" and name is "bar", get "bar.foo.com"
//
m_szFullName.Format(_T("%s.%s"), lpszNodeName,lpszParentFullName);
}
}
TRACE(_T("CDNSDomainNode::SetFullDNSName() fullName = <%s>\n"), (LPCTSTR)m_szFullName);
}
void CDNSDomainNode::SetDisplayDNSName(BOOL bIsZone,
BOOL bReverse,
BOOL bAdvancedView,
LPCTSTR lpszNodeName,
LPCTSTR lpszParentFullName)
{
ASSERT(lpszNodeName != NULL);
ASSERT(lpszParentFullName != NULL);
if (_wcsicmp(lpszNodeName, L".") == 0)
{
CString szRootString;
VERIFY(szRootString.LoadString(IDS_ROOT_ZONE_LABEL));
m_szDisplayName = L"." + szRootString;
}
else
{
m_szDisplayName = lpszNodeName;
}
if (bIsZone && bReverse && !bAdvancedView)
{
CDNSZoneNode::SetZoneNormalViewHelper(m_szDisplayName);
}
}
void CDNSDomainNode::SetNames(BOOL bIsZone, BOOL bReverse, BOOL bAdvancedView,
LPCTSTR lpszNodeName, LPCTSTR lpszParentFullName)
{
ASSERT(lpszNodeName != NULL);
ASSERT(lpszParentFullName != NULL);
TRACE(_T("CDNSDomainNode::SetNames(bIsZone=%d, bReverse=%d, bAdvancedView=%d, lpszNodeName=<%s>, lpszParentFullName=<%s>)\n"),
bIsZone, bReverse, bAdvancedView, lpszNodeName,lpszParentFullName);
SetFullDNSName(bIsZone, bReverse, lpszNodeName, lpszParentFullName);
SetDisplayDNSName(bIsZone, bReverse, bAdvancedView, lpszNodeName, lpszParentFullName);
}
void CDNSDomainNode::ChangePTRRecordsViewOption(BOOL bAdvanced,
CComponentDataObject* pComponentDataObject)
{
POSITION pos;
for( pos = m_containerChildList.GetHeadPosition(); pos != NULL; )
{
CTreeNode* pCurrentChild = m_containerChildList.GetNext(pos);
// recurse down the tree
CDNSDomainNode* pDomainNode = dynamic_cast<CDNSDomainNode*>(pCurrentChild);
ASSERT(pDomainNode != NULL);
pDomainNode->ChangePTRRecordsViewOption(bAdvanced, pComponentDataObject);
}
POSITION leafPos;
for ( leafPos = m_leafChildList.GetHeadPosition(); leafPos != NULL; )
{
CTreeNode* pCurrentLeafNode = m_leafChildList.GetNext(leafPos);
CDNSRecordNodeBase* pRecordNode = dynamic_cast<CDNSRecordNodeBase*>(pCurrentLeafNode);
ASSERT(pRecordNode != NULL);
if (DNS_TYPE_PTR == pRecordNode->GetType())
{
CDNS_PTR_RecordNode* pPTRRecordNode = (CDNS_PTR_RecordNode*)pRecordNode;
pPTRRecordNode->ChangeDisplayName(this, bAdvanced);
}
}
}
CQueryObj* CDNSDomainNode::OnCreateQuery()
{
// generic default setting
WORD wRecordType = DNS_TYPE_ALL;
DWORD dwSelectFlags = (m_pZoneNode->GetZoneType() == DNS_ZONE_TYPE_CACHE) ?
DNS_RPC_VIEW_CACHE_DATA : DNS_RPC_VIEW_AUTHORITY_DATA;
if (IsDelegation())
{
// special case the delegation: show only NS records and
// will have no children shown (delegation cut)
wRecordType = DNS_TYPE_NS;
dwSelectFlags = DNS_RPC_VIEW_GLUE_DATA | DNS_RPC_VIEW_NO_CHILDREN;
//dwSelectFlags = DNS_RPC_VIEW_GLUE_DATA |
// DNS_RPC_VIEW_NO_CHILDREN | DNS_RPC_VIEW_ADDITIONAL_DATA;
}
BOOL bCache = GetZoneNode()->GetZoneType() == DNS_ZONE_TYPE_CACHE;
LPCWSTR lpszZoneName = bCache ? NULL : m_pZoneNode->GetFullName();
CDNSRootData* pRootData = (CDNSRootData*)GetRootContainer();
ASSERT(pRootData != NULL);
CDNSDomainQueryObj* pQuery = new
CDNSDomainQueryObj(GetServerNode()->GetRPCName(),
lpszZoneName,
GetServerNode()->GetVersion(),
GetDisplayName(),
m_szFullName,
wRecordType,
dwSelectFlags,
IsZone(),
GetZoneNode()->IsReverse(),
bCache,
pRootData->IsAdvancedView());
// delegations will not have any filtering option (data consistency)
if (!IsDelegation())
{
pQuery->SetFilterOptions(pRootData->GetFilter());
}
return pQuery;
}
BOOL CDNSDomainNode::OnRefresh(CComponentDataObject* pComponentData,
CNodeList* pNodeList)
{
if (pNodeList->GetCount() > 1) // multiple selection
{
BOOL bRet = TRUE;
POSITION pos = pNodeList->GetHeadPosition();
while (pos != NULL)
{
CTreeNode* pNode = pNodeList->GetNext(pos);
ASSERT(pNode != NULL);
CNodeList nodeList;
nodeList.AddTail(pNode);
if (!pNode->OnRefresh(pComponentData, &nodeList))
{
bRet = FALSE;
}
}
return bRet;
}
//
// single selection
//
if (CMTContainerNode::OnRefresh(pComponentData, pNodeList))
{
GetNSRecordNodeList()->RemoveAll();
m_bHasDataForPropPages = FALSE;
return TRUE;
}
return FALSE;
}
void CDNSDomainNode::OnThreadExitingNotification(CComponentDataObject* pComponentDataObject)
{
if (!m_bHasDataForPropPages)
{
// never got a CDNSDomainMsg notification object
// but we are done anyway, so change it back
m_bHasDataForPropPages = TRUE;
}
// call now the base class
CDNSMTContainerNode::OnThreadExitingNotification(pComponentDataObject);
}
void CDNSDomainNode::OnHaveData(CObjBase* pObj, CComponentDataObject* pComponentDataObject)
{
if (IS_CLASS(*pObj, CDNSDomainMsg))
{
// special case for a "message" object sent through to update verbs
TRACE(_T("Got CDNSDomainMsg\n"));
delete pObj;
ASSERT(!m_bHasDataForPropPages); // should get only once
m_bHasDataForPropPages = TRUE;
VERIFY(SUCCEEDED(pComponentDataObject->UpdateVerbState(this)));
return;
}
if (IS_CLASS(*pObj, CDNSDomainNode))
{
// assume all the child containers are derived from this class
CDNSDomainNode* pDomainNode = dynamic_cast<CDNSDomainNode*>(pObj);
pDomainNode->SetServerNode(GetServerNode());
pDomainNode->SetZone(m_pZoneNode);
}
else
{
OnHaveRecord(dynamic_cast<CDNSRecordNodeBase*>(pObj), pComponentDataObject);
}
AddChildToListAndUI(dynamic_cast<CTreeNode*>(pObj), pComponentDataObject);
pComponentDataObject->SetDescriptionBarText(this);
}
void CDNSDomainNode::OnHaveRecord(CDNSRecordNodeBase* pRecordNode,
CComponentDataObject* pComponentDataObject)
{
WORD wType = pRecordNode->GetType();
if (wType == DNS_TYPE_PTR)
{
ASSERT(pComponentDataObject != NULL); // assume this for PTR
CDNSRootData* pRootData = (CDNSRootData*)pComponentDataObject->GetRootData();
ASSERT(pRootData != NULL);
// if we are in normal view, have to change the
// default advanced representation
BOOL bAdvancedView = pRootData->IsAdvancedView();
if (!bAdvancedView)
((CDNS_PTR_RecordNode*)pRecordNode)->ChangeDisplayName(this, bAdvancedView);
}
else if (wType == DNS_TYPE_NS)
{
ASSERT(pRecordNode->IsAtTheNode());
GetNSRecordNodeList()->AddTail((CDNS_NS_RecordNode*)pRecordNode);
}
}
BOOL CDNSDomainNode::OnAddMenuItem(LPCONTEXTMENUITEM2 pContextMenuItem2,
long*)
{
if (pContextMenuItem2->lCommandID == IDM_SNAPIN_ADVANCED_VIEW)
{
pContextMenuItem2->fFlags = ((CDNSRootData*)GetRootContainer())->IsAdvancedView() ? MF_CHECKED : 0;
return TRUE;
}
if (pContextMenuItem2->lCommandID == IDM_SNAPIN_FILTERING)
{
if (((CDNSRootData*)GetRootContainer())->IsFilteringEnabled())
{
pContextMenuItem2->fFlags = MF_CHECKED;
}
return TRUE;
}
DWORD dwType = m_pZoneNode->GetZoneType();
BOOL bIsAutocreated = m_pZoneNode->IsAutocreated();
BOOL bIsSecondaryOrCache = (dwType == DNS_ZONE_TYPE_SECONDARY) ||
(dwType == DNS_ZONE_TYPE_CACHE) ||
(dwType == DNS_ZONE_TYPE_STUB);
BOOL bIsDelegatedDomain = !IsZone() && IsDelegation();
if (bIsSecondaryOrCache || bIsAutocreated || bIsDelegatedDomain)
{
return FALSE;
}
// different add operations depending on the FWD/REV type
if (!GetZoneNode()->IsReverse() &&
(pContextMenuItem2->lCommandID == IDM_DOMAIN_NEW_PTR))
{
// do not add a PTR to a FWD lookup zone
return FALSE;
}
if (GetZoneNode()->IsReverse() &&
((pContextMenuItem2->lCommandID == IDM_DOMAIN_NEW_HOST) ||
(pContextMenuItem2->lCommandID == IDM_DOMAIN_NEW_MX)))
{
// do not add a HOST, MX, ALIAS to a REV lookup zone
return FALSE;
}
// have the menu item added. but it might be grayed out...
if (m_nState != loaded)
{
pContextMenuItem2->fFlags |= MF_GRAYED;
}
return TRUE;
}
HRESULT CDNSDomainNode::OnSetToolbarVerbState(IToolbar* pToolbar,
CNodeList* pNodeList)
{
HRESULT hr = S_OK;
//
// Set the button state for each button on the toolbar
//
hr = pToolbar->SetButtonState(toolbarNewServer, ENABLED, FALSE);
ASSERT(SUCCEEDED(hr));
hr = pToolbar->SetButtonState(toolbarNewZone, ENABLED, FALSE);
ASSERT(SUCCEEDED(hr));
if (pNodeList->GetCount() > 1) // multiple selection
{
hr = pToolbar->SetButtonState(toolbarNewRecord, ENABLED, FALSE);
}
else if (pNodeList->GetCount() == 1) // single selection
{
DWORD dwType = m_pZoneNode->GetZoneType();
BOOL bIsAutocreated = m_pZoneNode->IsAutocreated();
BOOL bIsSecondaryOrCache = (dwType == DNS_ZONE_TYPE_SECONDARY) ||
(dwType == DNS_ZONE_TYPE_CACHE) ||
(dwType == DNS_ZONE_TYPE_STUB);
BOOL bIsDelegatedDomain = !IsZone() && IsDelegation();
BOOL bEnable = TRUE;
if (bIsSecondaryOrCache || bIsAutocreated || bIsDelegatedDomain)
{
bEnable = FALSE;
}
hr = pToolbar->SetButtonState(toolbarNewRecord, ENABLED, bEnable);
}
return hr;
}
BOOL CDNSDomainNode::OnSetDeleteVerbState(DATA_OBJECT_TYPES type,
BOOL* pbHide,
CNodeList* pNodeList)
{
if (pNodeList->GetCount() > 1) // multiple selection
{
BOOL bRet = TRUE;
BOOL bRetHide = FALSE;
*pbHide = FALSE;
POSITION pos = pNodeList->GetHeadPosition();
while (pos != NULL)
{
CTreeNode* pNode = pNodeList->GetNext(pos);
ASSERT(pNode != NULL);
CNodeList nodeList;
nodeList.AddTail(pNode);
if (!pNode->OnSetDeleteVerbState(type, &bRetHide, &nodeList))
{
bRet = FALSE;
break;
}
if (bRetHide)
{
*pbHide = TRUE;
}
}
return bRet;
}
*pbHide = FALSE;
DWORD dwType = m_pZoneNode->GetZoneType();
BOOL bIsAutocreated = m_pZoneNode->IsAutocreated();
if (IsThreadLocked())
{
return FALSE;
}
//
// cannot delete from an autocreate zone/domain
//
if (bIsAutocreated)
{
return FALSE;
}
//
// cannot delete from a secondary or stub zone, but can delete the zone itself
// cannot delete the cache
//
if (
(
( ((dwType == DNS_ZONE_TYPE_SECONDARY) || (dwType == DNS_ZONE_TYPE_STUB)) && !IsZone() ) || // subdomain of secondary
( (dwType == DNS_ZONE_TYPE_CACHE) && IsZone() ) // cache zone itself
)
)
{
return FALSE;
}
return TRUE;
}
BOOL CDNSDomainNode::OnSetRefreshVerbState(DATA_OBJECT_TYPES,
BOOL* pbHide,
CNodeList*)
{
*pbHide = FALSE;
return !IsThreadLocked();
}
HRESULT CDNSDomainNode::OnCommand(long nCommandID,
DATA_OBJECT_TYPES,
CComponentDataObject* pComponentData,
CNodeList* pNodeList)
{
if (pNodeList->GetCount() > 1) // multiple selection
{
return E_FAIL;
}
switch (nCommandID)
{
case IDM_DOMAIN_NEW_DOMAIN:
OnNewDomain(pComponentData);
break;
case IDM_DOMAIN_NEW_DELEGATION:
OnNewDelegation(pComponentData);
break;
case IDM_DOMAIN_NEW_RECORD:
OnNewRecord(pComponentData, pNodeList);
break;
case IDM_DOMAIN_NEW_HOST:
OnNewHost(pComponentData);
break;
case IDM_DOMAIN_NEW_ALIAS:
OnNewAlias(pComponentData);
break;
case IDM_DOMAIN_NEW_MX:
OnNewMailExchanger(pComponentData);
break;
case IDM_DOMAIN_NEW_PTR:
OnNewPointer(pComponentData);
break;
case IDM_SNAPIN_ADVANCED_VIEW:
((CDNSRootData*)pComponentData->GetRootData())->OnViewOptions(pComponentData);
break;
case IDM_SNAPIN_FILTERING:
{
if(((CDNSRootData*)pComponentData->GetRootData())->OnFilteringOptions(pComponentData))
{
pComponentData->SetDescriptionBarText(this);
}
}
break;
default:
ASSERT(FALSE); // Unknown command!
return E_FAIL;
}
return S_OK;
}
LPWSTR CDNSDomainNode::GetDescriptionBarText()
{
static CString szFilterEnabled;
static CString szRecordsFormat;
INT_PTR nContainerCount = GetContainerChildList()->GetCount();
INT_PTR nLeafCount = GetLeafChildList()->GetCount();
//
// If not already loaded, then load the format string L"%d record(s)"
//
if (szRecordsFormat.IsEmpty())
{
szRecordsFormat.LoadString(IDS_FORMAT_RECORDS);
}
//
// Format the child count into the description bar text
//
m_szDescriptionBar.Format(szRecordsFormat, nContainerCount + nLeafCount);
//
// Add L"[Filter Activated]" if the filter is on
//
if(((CDNSRootData*)GetRootContainer())->IsFilteringEnabled())
{
//
// If not already loaded, then load the L"[Filter Activated]" string
//
if (szFilterEnabled.IsEmpty())
{
szFilterEnabled.LoadString(IDS_FILTER_ENABLED);
}
m_szDescriptionBar += szFilterEnabled;
}
return (LPWSTR)(LPCWSTR)m_szDescriptionBar;
}
int CDNSDomainNode::GetImageIndex(BOOL)
{
int nIndex = 0;
BOOL bDelegation = IsDelegation();
switch (m_nState)
{
case notLoaded:
nIndex = bDelegation ? DELEGATED_DOMAIN_IMAGE_NOT_LOADED : DOMAIN_IMAGE_NOT_LOADED;
break;
case loading:
nIndex = bDelegation ? DELEGATED_DOMAIN_IMAGE_LOADING : DOMAIN_IMAGE_LOADING;
break;
case loaded:
nIndex = bDelegation ? DELEGATED_DOMAIN_IMAGE_LOADED : DOMAIN_IMAGE_LOADED;
break;
case unableToLoad:
nIndex = bDelegation ? DELEGATED_DOMAIN_IMAGE_UNABLE_TO_LOAD : DOMAIN_IMAGE_UNABLE_TO_LOAD;
break;
case accessDenied:
nIndex = bDelegation ? DELEGATED_DOMAIN_IMAGE_ACCESS_DENIED : DOMAIN_IMAGE_ACCESS_DENIED;
break;
default:
ASSERT(FALSE);
}
return nIndex;
}
void CDNSDomainNode::OnDelete(CComponentDataObject* pComponentData,
CNodeList* pNodeList)
{
if (pNodeList->GetCount() > 1) // multiple selection
{
OnMultiselectDelete(pComponentData, pNodeList);
return;
}
UINT nRet = DNSConfirmOperation(IDS_MSG_DOMAIN_DELETE, this);
if (IDNO == nRet ||
IDCANCEL == nRet)
{
return;
}
if (IsSheetLocked())
{
if (!CanCloseSheets())
return;
pComponentData->GetPropertyPageHolderTable()->DeleteSheetsOfNode(this);
}
ASSERT(!IsSheetLocked());
DNS_STATUS err = Delete();
if (err != 0)
{
DNSErrorDialog(err, IDS_MSG_DOMAIN_FAIL_DELETE);
return;
}
// now remove from the UI and from the cache
DeleteHelper(pComponentData);
delete this; // gone
}
void CDNSDomainNode::OnMultiselectDelete(CComponentDataObject* pComponentData,
CNodeList* pNodeList)
{
UINT nRet = DNSConfirmOperation(IDS_MSG_DOMAIN_MULTI_DELETE, this);
if (IDCANCEL == nRet ||
IDNO == nRet)
{
return;
}
DNS_STATUS* errArray = new DNS_STATUS[pNodeList->GetCount()];
if (errArray == NULL)
{
DNSErrorDialog(E_OUTOFMEMORY, IDS_MSG_DOMAIN_FAIL_DELETE);
return;
}
memset(errArray, 0, sizeof(DNS_STATUS) * pNodeList->GetCount());
BOOL bErrorOccurred = FALSE;
UINT idx = 0;
POSITION pos = pNodeList->GetHeadPosition();
while (pos != NULL)
{
CTreeNode* pTreeNode = pNodeList->GetNext(pos);
if (pTreeNode != NULL)
{
if (pTreeNode->IsSheetLocked())
{
if (!pTreeNode->CanCloseSheets())
{
idx++;
continue;
}
pComponentData->GetPropertyPageHolderTable()->DeleteSheetsOfNode(pTreeNode);
}
ASSERT(!pTreeNode->IsSheetLocked());
CDNSDomainNode* pDomainNode = dynamic_cast<CDNSDomainNode*>(pTreeNode);
if (pDomainNode != NULL)
{
errArray[idx] = pDomainNode->Delete();
if (errArray[idx] != 0)
{
bErrorOccurred = TRUE;
idx++;
continue;
}
//
// now remove from the UI and from the cache
//
pDomainNode->DeleteHelper(pComponentData);
delete pDomainNode; // gone
}
else
{
//
// If its not a domain node then it must be a record node
//
CDNSRecordNodeBase* pRecordNode = dynamic_cast<CDNSRecordNodeBase*>(pTreeNode);
if (pRecordNode != NULL)
{
errArray[idx] = pRecordNode->DeleteOnServerAndUI(pComponentData);
if (errArray[idx] != 0)
{
bErrorOccurred = TRUE;
idx++;
continue;
}
delete pRecordNode; // gone
}
else
{
//
// What type of node is this???
//
ASSERT(FALSE);
}
}
}
idx++;
}
//
// Now display the errors in some meaningful manner
//
if (bErrorOccurred)
{
CMultiselectErrorDialog dlg;
CString szTitle;
CString szCaption;
CString szColumnHeader;
VERIFY(szTitle.LoadString(IDS_MULTISELECT_ERROR_DIALOG_TITLE));
VERIFY(szCaption.LoadString(IDS_MULTISELECT_ERROR_DIALOG_CAPTION));
VERIFY(szColumnHeader.LoadString(IDS_MULTISELECT_ERROR_DIALOG_COLUMN_HEADER));
HRESULT hr = dlg.Initialize(pNodeList,
errArray,
static_cast<UINT>(pNodeList->GetCount()),
szTitle,
szCaption,
szColumnHeader);
if (SUCCEEDED(hr))
{
dlg.DoModal();
}
}
}
void CDNSDomainNode::OnNewDomain(CComponentDataObject* pComponentData)
{
CNewDomainDialog dlg(this, pComponentData);
// the dialog will do the creation
dlg.DoModal();
}
void CDNSDomainNode::OnNewDelegation(CComponentDataObject* pComponentData)
{
ASSERT(pComponentData != NULL);
CDNSMTContainerNode* pContainerNode = (CDNSMTContainerNode*)GetContainer();
ASSERT(pContainerNode != NULL);
CDNSDelegationWizardHolder* pHolder =
new CDNSDelegationWizardHolder(pContainerNode, this, pComponentData);
ASSERT(pHolder != NULL);
pHolder->DoModalWizard();
}
RECORD_SEARCH CDNSDomainNode::DoesContain(PCWSTR pszRecName,
CComponentDataObject* pComponentData,
CDNSDomainNode** ppDomainNode,
CString& szNonExistentDomain,
BOOL bExpandNodes)
{
#if TRUE
CDNSNameTokenizer recordTokenizer(pszRecName);
CDNSNameTokenizer domainTokenizer((IsZone()) ? GetFullName() : GetDisplayName());
if (!recordTokenizer.Tokenize(L".") || !domainTokenizer.Tokenize(L"."))
{
*ppDomainNode = NULL;
return RECORD_NOT_FOUND;
}
recordTokenizer.RemoveMatchingFromTail(domainTokenizer);
if (recordTokenizer.GetCount() == 0 && domainTokenizer.GetCount() == 0)
{
//
// Record is "At the node"
//
*ppDomainNode = this;
return RECORD_NOT_FOUND_AT_THE_NODE;
}
else if ((recordTokenizer.GetCount() == 0 && domainTokenizer.GetCount() != 0) ||
(recordTokenizer.GetCount() != 0 && domainTokenizer.GetCount() != 0))
{
//
// I don't understand how we got in this situation. It means we are searching in
// the wrong domain.
//
ASSERT(FALSE);
*ppDomainNode = NULL;
return RECORD_NOT_FOUND;
}
else // recordTokenizer.GetCount() != 0 && domainTokenizer.GetCount() == 0
{
//
// Need to search the children lists
//
//
// If the node hasn't been enumerated, do that now
//
if (!IsEnumerated())
{
if (!bExpandNodes)
{
*ppDomainNode = this;
return DOMAIN_NOT_ENUMERATED;
}
else
{
//
// Expand the node
//
HWND hWnd = NULL;
HRESULT hr = pComponentData->GetConsole()->GetMainWindow(&hWnd);
ASSERT(SUCCEEDED(hr));
CWnd* pParentWnd = CWnd::FromHandle(hWnd);
CLongOperationDialog dlg(
new CNodeEnumerationThread(pComponentData, this),
pParentWnd,
IDR_SEARCH_AVI);
dlg.DoModal();
}
}
CString szRemaining;
recordTokenizer.GetRemaining(szRemaining, L".");
//
// Search for domains that match the last token remaining in the record name
//
POSITION pos = m_containerChildList.GetHeadPosition();
while (pos != NULL)
{
CTreeNode* pCurrentChild = m_containerChildList.GetNext(pos);
CDNSDomainNode* pDomainNode = dynamic_cast<CDNSDomainNode*>(pCurrentChild);
if (pDomainNode == NULL)
{
ASSERT(FALSE);
continue;
}
if (_wcsicmp(pDomainNode->GetDisplayName(), recordTokenizer.GetTail()) == 0)
{
//
// Found a sub-domain in the path that we have in the UI
// recurse to see if it or any of its child match pszFullName
//
return pDomainNode->DoesContain(szRemaining, pComponentData, ppDomainNode, szNonExistentDomain, bExpandNodes);
}
}
//
// If the remaining name doesn't match a domain and there
// is still a '.' in it then there is a non-existent domain
//
if (szRemaining.Find(L'.') != -1)
{
szNonExistentDomain = recordTokenizer.GetTail();
*ppDomainNode = this;
return NON_EXISTENT_SUBDOMAIN;
}
//
// Since no domains match, lets check the records
//
pos = m_leafChildList.GetHeadPosition();
while (pos != NULL)
{
CTreeNode* pCurrentChild = m_leafChildList.GetNext(pos);
if (pCurrentChild == NULL)
{
ASSERT(FALSE);
continue;
}
if (_wcsicmp(pCurrentChild->GetDisplayName(), szRemaining) == 0)
{
//
// We found the record and its in this domain
//
*ppDomainNode = this;
return RECORD_FOUND;
}
}
}
*ppDomainNode = this;
return RECORD_NOT_FOUND;
#else
//
// The fast way that doesn't quite work
//
CString szDomainFullName = GetFullName();
CString szFullName = pszFullName;
//
// Check to see if the end of the names are equal
//
int iFindResult = szFullName.Find(szDomainFullName);
if (iFindResult == -1)
{
//
// If they are not we are never going to find them
//
*ppDomainNode = NULL;
return RECORD_NOT_FOUND;
}
if (iFindResult == 0)
{
//
// We found it
//
*ppDomainNode = this;
return RECORD_FOUND;
}
//
// Remove the matching parts plus the trailing dot
// This should leave us with something like foo.bar or just foo
//
CString szRelativeName = szFullName.Left(iFindResult - 1);
ASSERT(!szRelativeName.IsEmpty());
CString szChild;
CString szRemaining;
//
// Now search for a dot starting on the right
//
iFindResult = szRelativeName.ReverseFind(L'.');
if (iFindResult == -1)
{
//
// The relative name doesn't contain a dot so it is the child
// we are looking for
//
szChild = szRelativeName;
}
else
{
szChild = szRelativeName.Right(szRelativeName.GetLength() - iFindResult - 1);
szRemaining = szRelativeName;
}
//
// If the node hasn't been enumerated, do that now
//
if (!IsEnumerated())
{
if (!bExpandNodes)
{
*ppDomainNode = this;
return DOMAIN_NOT_ENUMERATED;
}
else
{
//
// Expand the node
//
HWND hWnd = NULL;
HRESULT hr = pComponentData->GetConsole()->GetMainWindow(&hWnd);
ASSERT(SUCCEEDED(hr));
CWnd* pParentWnd = CWnd::FromHandle(hWnd);
CLongOperationDialog dlg(
new CNodeEnumerationThread(pComponentData, this),
pParentWnd,
IDR_SEARCH_AVI);
dlg.DoModal();
}
}
//
// Search for domains that match this name
//
POSITION pos = m_containerChildList.GetHeadPosition();
while (pos != NULL)
{
CTreeNode* pCurrentChild = m_containerChildList.GetNext(pos);
CDNSDomainNode* pDomainNode = dynamic_cast<CDNSDomainNode*>(pCurrentChild);
if (pDomainNode == NULL)
{
ASSERT(FALSE);
continue;
}
if (_wcsicmp(pDomainNode->GetDisplayName(), szChild) == 0)
{
//
// Found a sub-domain in the path that we have in the UI
// recurse to see if it or any of its child match pszFullName
//
return pDomainNode->DoesContain(pszFullName, pComponentData, ppDomainNode, szNonExistentDomain, bExpandNodes);
}
}
//
// Since no domains match, lets check the records
//
pos = m_leafChildList.GetHeadPosition();
while (pos != NULL)
{
CTreeNode* pCurrentChild = m_leafChildList.GetNext(pos);
if (pCurrentChild == NULL)
{
ASSERT(FALSE);
continue;
}
if (_wcsicmp(pCurrentChild->GetDisplayName(), szChild) == 0)
{
//
// We found the record and its in this domain
//
*ppDomainNode = this;
return RECORD_FOUND;
}
}
//
// Well, we didn't find the record, If the remaining part of the name
// still contains a '.' then we know the domain the that contains the
// record is not in the UI so return NULL. If there isn't a '.' then
// we are at the correct level but just couldn't find the record. Return
// this domain.
//
if (szRemaining.Find(L'.') == -1)
{
*ppDomainNode = this;
return RECORD_NOT_FOUND;
}
else
{
//
// We were not able to find a subdomain that the record should be in
//
*ppDomainNode = this;
return NON_EXISTENT_SUBDOMAIN;
}
return RECORD_NOT_FOUND;
#endif
}
CDNSDomainNode* CDNSDomainNode::FindSubdomainNode(LPCTSTR lpszSubdomainNode)
{
//
// assume the string is the name of the subnode as FQDN
//
//
// Check the current node first since it could be zone that is a delegation of
// one of the protocol domains
//
if (_wcsicmp(GetFullName(), lpszSubdomainNode) == 0)
{
return this;
}
POSITION pos;
for( pos = m_containerChildList.GetHeadPosition(); pos != NULL; )
{
CTreeNode* pCurrentChild = m_containerChildList.GetNext(pos);
CDNSDomainNode* pSubDomainNode = dynamic_cast<CDNSDomainNode*>(pCurrentChild);
ASSERT(pSubDomainNode != NULL);
if (_wcsicmp(pSubDomainNode->GetFullName(), lpszSubdomainNode) == 0)
{
return pSubDomainNode;
}
}
return NULL; // not found
}
CDNSDomainNode* CDNSDomainNode::CreateSubdomainNode(BOOL bDelegation)
{
CDNSDomainNode* pNode = new CDNSDomainNode(bDelegation);
pNode->SetServerNode(GetServerNode());
ASSERT(m_pZoneNode != NULL);
pNode->SetZone(m_pZoneNode);
return pNode;
}
void CDNSDomainNode::SetSubdomainName(CDNSDomainNode* pSubdomainNode,
LPCTSTR lpszSubdomainName, BOOL bAdvancedView)
{
ASSERT(m_pZoneNode != NULL);
ASSERT(pSubdomainNode != NULL);
BOOL bReverse = GetZoneNode()->IsReverse();
pSubdomainNode->SetNames(FALSE, bReverse, bAdvancedView, lpszSubdomainName, GetFullName());
}
DNS_STATUS CDNSDomainNode::CreateSubdomain(CDNSDomainNode* pSubdomainNode,
CComponentDataObject* pComponentData)
{
// tell the newly created object to write to the server
DNS_STATUS err = pSubdomainNode->Create();
if (err == 0)
{
// success, add to the UI
VERIFY(AddChildToListAndUI(pSubdomainNode, pComponentData));
pComponentData->SetDescriptionBarText(this);
}
return err;
}
DNS_STATUS CDNSDomainNode::CreateSubdomain(LPCTSTR lpszDomainName,
CComponentDataObject* pComponentData)
{
CDNSDomainNode* pSubdomainNode = CreateSubdomainNode();
ASSERT(pSubdomainNode != NULL);
CDNSRootData* pRootData = (CDNSRootData*)pComponentData->GetRootData();
SetSubdomainName(pSubdomainNode, lpszDomainName, pRootData->IsAdvancedView());
// tell the newly created object to write to the server
DNS_STATUS err = CreateSubdomain(pSubdomainNode, pComponentData);
if (err != 0)
{
// something went wrong, bail out
delete pSubdomainNode;
}
return err;
}
void CDNSDomainNode::OnNewRecordHelper(CComponentDataObject* pComponentData, WORD wType)
{
ASSERT(pComponentData != NULL);
if (wType == 0)
{
CSelectDNSRecordTypeDialog dlg(this, pComponentData);
dlg.DoModal();
}
else
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
CString szTitle;
szTitle.LoadString(IDS_NEW_RECORD_TITLE);
CDNSRecordPropertyPageHolder recordHolder(this, NULL, pComponentData, wType);
recordHolder.DoModalDialog(szTitle);
}
}
HRESULT CDNSDomainNode::OnNewRecord(CComponentDataObject* pComponentData,
CNodeList* pNodeList)
{
ASSERT(pNodeList->GetCount() == 1);
OnNewRecordHelper(pComponentData, 0);
return S_OK;
}
void CDNSDomainNode::OnNewHost(CComponentDataObject* pComponentData)
{
//AFX_MANAGE_STATE(AfxGetStaticModuleState());
//OnNewRecordHelper(pComponentData, DNS_TYPE_A);
CNewHostDialog dlg(this, pComponentData);
dlg.DoModal();
}
void CDNSDomainNode::OnNewAlias(CComponentDataObject* pComponentData)
{
OnNewRecordHelper(pComponentData, DNS_TYPE_CNAME);
}
void CDNSDomainNode::OnNewMailExchanger(CComponentDataObject* pComponentData)
{
OnNewRecordHelper(pComponentData, DNS_TYPE_MX);
}
void CDNSDomainNode::OnNewPointer(CComponentDataObject* pComponentData)
{
OnNewRecordHelper(pComponentData, DNS_TYPE_PTR);
}
//////////////////////////////////////////////////////////////////////////////////
// display of property pages
BOOL CDNSDomainNode::HasPropertyPages(DATA_OBJECT_TYPES,
BOOL* pbHideVerb,
CNodeList* pNodeList)
{
if (pNodeList->GetCount() > 1) // multiple selection
{
*pbHideVerb = TRUE;
return FALSE;
}
*pbHideVerb = FALSE; // always show the verb
if (!m_bHasDataForPropPages)
return FALSE;
// cannot have property pages only in loaded state
//if (m_nState != loaded)
// return FALSE;
// have pages if it is a delegation
return IsDelegation();
}
HRESULT CDNSDomainNode::CreatePropertyPages(LPPROPERTYSHEETCALLBACK lpProvider,
LONG_PTR handle,
CNodeList* pNodeList)
{
ASSERT(pNodeList->GetCount() == 1); // multi-select not supported
ASSERT(m_bHasDataForPropPages);
ASSERT(IsDelegation() || GetZoneNode()->IsDSIntegrated());
if (GetSheetCount() > 0)
{
CComponentDataObject* pComponentDataObject =
((CRootData*)(GetContainer()->GetRootContainer()))->GetComponentDataObject();
ASSERT(pComponentDataObject != NULL);
pComponentDataObject->GetPropertyPageHolderTable()->BroadcastSelectPage(this, DOMAIN_HOLDER_NS);
return S_OK;
}
return CreatePropertyPagesHelper(lpProvider, handle, DOMAIN_HOLDER_NS);
}
void CDNSDomainNode::Show(BOOL bShow, CComponentDataObject* pComponentData)
{
CDNSMTContainerNode::Show(bShow, pComponentData);
if (!bShow)
GetNSRecordNodeList()->RemoveAll();
}
HRESULT CDNSDomainNode::CreatePropertyPagesHelper(LPPROPERTYSHEETCALLBACK lpProvider,
LONG_PTR handle, long)
{
CComponentDataObject* pComponentDataObject =
((CRootData*)(GetContainer()->GetRootContainer()))->GetComponentDataObject();
ASSERT(pComponentDataObject != NULL);
CDNSDomainPropertyPageHolder* pHolder =
new CDNSDomainPropertyPageHolder((CDNSDomainNode*)GetContainer(), this, pComponentDataObject);
ASSERT(pHolder != NULL);
pHolder->SetSheetTitle(IDS_PROP_SHEET_TITLE_FMT, this);
return pHolder->CreateModelessSheet(lpProvider, handle);
}
//////////////////////////////////////////////////////////////////////////////////
// Record Sorting in result pane
int FieldCompareHelper(CTreeNode* pNodeA, CTreeNode* pNodeB, int nCol)
{
int iRet = 0;
if (nCol == N_HEADER_NAME)
{
//
// If the name column is selected we have to sort PTR records by their
// address
//
CDNS_PTR_RecordNode* pRecNodeA = dynamic_cast<CDNS_PTR_RecordNode*>(pNodeA);
CDNS_PTR_RecordNode* pRecNodeB = dynamic_cast<CDNS_PTR_RecordNode*>(pNodeB);
if (pRecNodeA == NULL && pRecNodeB == NULL)
{
//
// Neither node is a PTR record, process normally
//
LPCTSTR lpszA = pNodeA->GetString(nCol);
LPCTSTR lpszB = pNodeB->GetString(nCol);
//
// cannot process NULL strings, have to use ""
//
if (lpszA == NULL || lpszB == NULL)
{
ASSERT(FALSE);
return -1;
}
iRet = _wcsicmp(lpszA, lpszB);
}
else if (pRecNodeA == NULL)
{
//
// Push non PTR records down in the list
//
iRet = 1;
}
else if (pRecNodeB == NULL)
{
//
// Push non PTR records down in the list
//
iRet = -1;
}
else
{
//
// Both nodes are PTR records, compare their Addresses
// Subtract one from the other
// This will result in < 0 returned if the first one is less than the second
// 0 if they are equal, and > 0 if the first is greater than the second
//
LPCWSTR lpszNameA, lpszNameB;
lpszNameA = pRecNodeA->GetTrueRecordName();
lpszNameB = pRecNodeB->GetTrueRecordName();
if (lpszNameA == NULL)
{
return -1;
}
if (lpszNameB == NULL)
{
return 1;
}
DWORD dwAddrA, dwAddrB;
int iConverts = swscanf(lpszNameA, L"%d", &dwAddrA);
if (iConverts != 1)
{
return -1;
}
iConverts = swscanf(lpszNameB, L"%d", &dwAddrB);
if (iConverts != 1)
{
return 1;
}
iRet = dwAddrA - dwAddrB;
}
}
else if (nCol == N_HEADER_DATA)
{
//
// If the data column is selected we have to check the record type so
// that we can sort by IP address
//
CDNS_A_RecordNode* pRecNodeA = dynamic_cast<CDNS_A_RecordNode*>(pNodeA);
CDNS_A_RecordNode* pRecNodeB = dynamic_cast<CDNS_A_RecordNode*>(pNodeB);
if (pRecNodeA == NULL && pRecNodeB == NULL)
{
//
// Neither node is an A record, process normally
//
LPCTSTR lpszA = pNodeA->GetString(nCol);
LPCTSTR lpszB = pNodeB->GetString(nCol);
//
// cannot process NULL strings, have to use ""
//
if (lpszA == NULL || lpszB == NULL)
{
ASSERT(FALSE);
return -1;
}
iRet = _wcsicmp(lpszA, lpszB);
}
else if (pRecNodeA == NULL)
{
//
// Push non A records down in the list
//
iRet = 1;
}
else if (pRecNodeB == NULL)
{
//
// Push non A records down in the list
//
iRet = -1;
}
else
{
//
// Both nodes are A records, compare their IP Addresses
// Subtract one from the other
// This will result in < 0 returned if the first one is less than the second
// 0 if they are equal, and > 0 if the first is greater than the second
//
DWORD dwIPA, dwIPB;
dwIPA = pRecNodeA->GetIPAddress();
dwIPB = pRecNodeB->GetIPAddress();
UINT nOctetCount = 0;
iRet = 0;
while (iRet == 0 && nOctetCount < 4)
{
iRet = (dwIPA & 0xff) - (dwIPB & 0xff);
dwIPA = dwIPA >> 8;
dwIPB = dwIPB >> 8;
++nOctetCount;
}
}
}
else
{
LPCTSTR lpszA = pNodeA->GetString(nCol);
LPCTSTR lpszB = pNodeB->GetString(nCol);
//
// cannot process NULL strings, have to use ""
//
if (lpszA == NULL || lpszB == NULL)
{
ASSERT(FALSE);
return -1;
}
iRet = _wcsicmp(lpszA, lpszB);
}
return iRet;
}
int CDNSDomainNode::Compare(CTreeNode* pNodeA, CTreeNode* pNodeB, int nCol, long)
{
// sorting rules for secondary fields
int nColSec = N_HEADER_TYPE;
int nColThird = N_HEADER_DATA;
switch (nCol)
{
case N_HEADER_NAME:
nColSec = N_HEADER_TYPE;
nColThird = N_HEADER_DATA;
break;
case N_HEADER_TYPE:
nColSec = N_HEADER_NAME;
nColThird = N_HEADER_DATA;
break;
case N_HEADER_DATA:
nColSec = N_HEADER_NAME;
nColThird = N_HEADER_TYPE;
break;
default:
ASSERT(FALSE);
}
int nResult = FieldCompareHelper(pNodeA, pNodeB, nCol);
if (nResult != 0)
return nResult;
nResult = FieldCompareHelper(pNodeA, pNodeB, nColSec);
if (nResult != 0)
return nResult;
return FieldCompareHelper(pNodeA, pNodeB, nColThird);
}
//////////////////////////////////////////////////////////////////////////////////
// NS record bulk manipulation
// function to the user for confirmation on editing of A records
// associated with an NS record
BOOL _ConfirmEditAction(CDNSRecordNodeEditInfo* pInfo, BOOL bAsk)
{
if (!bAsk)
return TRUE; // silently do it
AFX_MANAGE_STATE(AfxGetStaticModuleState());
ASSERT(pInfo->m_pRecord->GetType() == DNS_TYPE_A);
ASSERT(pInfo->m_pRecord != NULL);
CDNS_A_RecordNode* pARecordNode = (CDNS_A_RecordNode*)pInfo->m_pRecordNode;
// load format message
CString szFmt;
szFmt.LoadString(IDS_MSG_RECORD_DEL_A_FROM_NS);
// compose message
CString szMsg;
szMsg.Format((LPCWSTR)szFmt, pARecordNode->GetString(0), pARecordNode->GetString(2));
return (IDYES == DNSMessageBox(szMsg, MB_YESNO | MB_ICONWARNING ) );
}
void CDNSDomainNode::GetNSRecordNodesInfo(CDNSRecordNodeEditInfoList* pNSInfoList)
{
ASSERT(pNSInfoList != NULL);
if (!pNSInfoList->IsEmpty())
{
ASSERT(FALSE); // should never happen
pNSInfoList->RemoveAllNodes();
}
CDNS_NS_RecordNodeList* pNodeList = GetNSRecordNodeList();
// for each NS record in the list, create an entry in the info list
POSITION pos;
for( pos = pNodeList->GetHeadPosition(); pos != NULL; )
{
CDNS_NS_RecordNode* pCurrNode = pNodeList->GetNext(pos);
ASSERT(pCurrNode != NULL);
CDNSRecordNodeEditInfo* pNSNodeInfo = new CDNSRecordNodeEditInfo();
if (pNSNodeInfo)
{
// set the data for the NS record, already in the list, so we do now own the memory
pNSNodeInfo->CreateFromExistingRecord(pCurrNode, FALSE /*bOwnMemory*/, TRUE /*bUpdateUI*/);
// for the current NS record, find the associated A records
FindARecordsFromNSInfo(pCurrNode->GetString(2),pNSNodeInfo->m_pEditInfoList);
pNSInfoList->AddTail(pNSNodeInfo);
}
}
}
BOOL CDNSDomainNode::HasNSRecords()
{
return GetNSRecordNodeList()->GetCount() > 0;
}
BOOL CDNSDomainNode::UpdateNSRecordNodesInfo(CDNSRecordNodeEditInfoList* pNewInfoList,
CComponentDataObject* pComponentData)
{
ASSERT(pNewInfoList != NULL);
// return false if at least one operation failed
BOOL bRes = TRUE;
CDNS_NS_RecordNodeList* pNSRecordNodeList = GetNSRecordNodeList();
// clear the current state in this domain object
pNSRecordNodeList->RemoveAll();
// rebuild the current list from the new one, while applying the changes
POSITION pos;
for ( pos = pNewInfoList->GetHeadPosition(); pos != NULL; )
{
CDNSRecordNodeEditInfo* pCurrentInfo = pNewInfoList->GetNext(pos);
ASSERT(pCurrentInfo->m_pRecordNode != NULL);
ASSERT(pCurrentInfo->m_pRecord != NULL);
switch (pCurrentInfo->m_action)
{
case CDNSRecordNodeEditInfo::add:
case CDNSRecordNodeEditInfo::edit:
{
if (pCurrentInfo->Update(this, pComponentData) == 0)
{
ASSERT(pCurrentInfo->m_pRecordNode->GetType() == DNS_TYPE_NS);
pNSRecordNodeList->AddTail((CDNS_NS_RecordNode*)pCurrentInfo->m_pRecordNode);
pCurrentInfo->m_bOwnMemory = FALSE; // relinquish ownership
}
else
{
bRes = FALSE;
}
}
break;
case CDNSRecordNodeEditInfo::remove:
{
if (pCurrentInfo->m_bExisting)
{
if (pCurrentInfo->Remove(this, pComponentData) != 0)
bRes = FALSE;
}
}
break;
case CDNSRecordNodeEditInfo::none:
//
// Do nothing if the the node has been added and then removed without having been applied
//
break;
default:
{
ASSERT(pCurrentInfo->m_bOwnMemory == FALSE);
ASSERT(pCurrentInfo->m_action == CDNSRecordNodeEditInfo::unchanged);
//
// We still have to update the NS record because the server needs to
// update the record in memory (bug 23905)
//
if (pCurrentInfo->Update(this, pComponentData) == 0)
{
pNSRecordNodeList->AddTail((CDNS_NS_RecordNode*)pCurrentInfo->m_pRecordNode);
}
}
}; // switch
// now we have to apply the changes in the list of A records
if (pCurrentInfo->m_dwErr == 0 && pCurrentInfo->m_action != CDNSRecordNodeEditInfo::none)
UpdateARecordsOfNSInfo(pCurrentInfo, pComponentData);
} // for
return bRes;
}
// static function
void CDNSDomainNode::UpdateARecordsOfNSInfoHelper(CDNSDomainNode* pDomainNode,
CDNSRecordNodeEditInfo* pNSInfo,
CComponentDataObject* pComponentData,
BOOL bAskConfirmation)
{
ASSERT(pNSInfo->m_dwErr == 0);
ASSERT(pNSInfo->m_pRecordNode != NULL);
ASSERT(pNSInfo->m_pRecordNode->GetType() == DNS_TYPE_NS);
POSITION pos;
// get the list of related A records
CDNSRecordNodeEditInfoList* pNSInfoList = pNSInfo->m_pEditInfoList;
for( pos = pNSInfoList->GetHeadPosition(); pos != NULL; )
{
CDNSRecordNodeEditInfo* pCurrentInfo = pNSInfoList->GetNext(pos);
ASSERT(pCurrentInfo->m_pRecordNode != NULL);
ASSERT(pCurrentInfo->m_pRecord != NULL);
CDNS_A_RecordNode* pARecordNode = (CDNS_A_RecordNode*)pCurrentInfo->m_pRecordNode;
ASSERT(pNSInfo->m_pRecord != NULL);
CDNS_NS_Record* pNSRecord = (CDNS_NS_Record*)pNSInfo->m_pRecord;
BOOL bHostNameChanged = !_match(pNSRecord->m_szNameNode, pARecordNode);
if (bHostNameChanged)
{
// the NS record points to a different host, so need
// to delete the old A RR and create a new one
BOOL bRemoveOld = _ConfirmEditAction(pCurrentInfo, bAskConfirmation);
CDNSRecordNodeEditInfo::actionType oldAction = pCurrentInfo->m_action;
if (pCurrentInfo->m_bExisting && bRemoveOld)
{
// if the A record was an existing one, need to remove first
pCurrentInfo->m_action = CDNSRecordNodeEditInfo::remove;
pCurrentInfo->Remove(pDomainNode, pComponentData);
}
// now decide if have to add
if (oldAction == CDNSRecordNodeEditInfo::remove && bRemoveOld)
{
// it was meant to be removed anyway
pCurrentInfo->m_bOwnMemory = TRUE; // edit info will clean up memory
}
else
{
// it was meant to be edited or added, restore old action code
pCurrentInfo->m_action = oldAction;
// change the name of the record
pCurrentInfo->m_pRecordNode->SetRecordName(pNSRecord->m_szNameNode, FALSE /*bAtTheNode*/);
// add new A record with different FQDN
pCurrentInfo->m_action = CDNSRecordNodeEditInfo::add;
pCurrentInfo->Update(pDomainNode, pComponentData);
pCurrentInfo->m_bOwnMemory = FALSE; // written im master structures
}
}
else // the name is still the same
{
switch(pNSInfo->m_action)
{
case CDNSRecordNodeEditInfo::remove:
{
// NS record marked for deletion means removing the associated A records
if (pCurrentInfo->m_bExisting && _ConfirmEditAction(pCurrentInfo, bAskConfirmation))
{
pCurrentInfo->Remove(pDomainNode, pComponentData);
pCurrentInfo->m_bOwnMemory = TRUE; // it will cleanup itself
}
}
break;
case CDNSRecordNodeEditInfo::add:
{
if (!pCurrentInfo->m_bExisting)
{
pCurrentInfo->Update(pDomainNode, pComponentData);
pCurrentInfo->m_bOwnMemory = FALSE; // written im master structures
}
}
break;
case CDNSRecordNodeEditInfo::edit:
{
// NS host name not changed, just update list of A records
switch(pCurrentInfo->m_action)
{
case CDNSRecordNodeEditInfo::remove:
{
if (pCurrentInfo->m_bExisting && _ConfirmEditAction(pCurrentInfo, bAskConfirmation))
{
pCurrentInfo->Remove(pDomainNode, pComponentData);
pCurrentInfo->m_bOwnMemory = TRUE; // it will cleanup itself
}
}
break;
case CDNSRecordNodeEditInfo::edit:
{
// we just changed the TTL
ASSERT(pCurrentInfo->m_bExisting);
pCurrentInfo->Update(pDomainNode, pComponentData);
pCurrentInfo->m_bOwnMemory = FALSE; // written im master structures
}
break;
case CDNSRecordNodeEditInfo::add:
{
if (!pCurrentInfo->m_bExisting)
{
pCurrentInfo->Update(pDomainNode, pComponentData);
pCurrentInfo->m_bOwnMemory = FALSE; // written im master structures
}
}
break;
}; // switch
}
break;
}; // switch
} // if,else
} // for
}
void CDNSDomainNode::UpdateARecordsOfNSInfo(CDNSRecordNodeEditInfo* pNSInfo,
CComponentDataObject* pComponentData)
{
// create a fake domain object to run a query looking for
// A records that match the given list of NS records
CDNSDummyDomainNode fakeDomain;
fakeDomain.SetServerNode(GetServerNode());
fakeDomain.SetZone(GetZoneNode());
BOOL bAskConfirmation = TRUE; // we migth delete A RR's that we need
UpdateARecordsOfNSInfoHelper(&fakeDomain, pNSInfo, pComponentData, bAskConfirmation);
}
void CDNSDomainNode::FindARecordsFromNSInfo(LPCTSTR lpszNSName,
CDNSRecordNodeEditInfoList* pNSInfoList)
{
// just call the static version
CDNSRootData* pRootData = (CDNSRootData*)GetRootContainer();
ASSERT(pRootData != NULL);
DWORD cAddrCount;
PIP_ADDRESS pipAddrs;
GetServerNode()->GetListenAddressesInfo(&cAddrCount, &pipAddrs);
if (cAddrCount == 0)
{
// listening on all addresses
GetServerNode()->GetServerAddressesInfo(&cAddrCount, &pipAddrs);
}
FindARecordsFromNSInfo(GetServerNode()->GetRPCName(),
GetServerNode()->GetVersion(),
cAddrCount, pipAddrs,
GetZoneNode()->GetFullName(),
lpszNSName,
pNSInfoList,
pRootData->IsAdvancedView());
}
void CDNSDomainNode::FindARecordsFromNSInfo(LPCWSTR lpszServerName, DWORD dwServerVersion,
DWORD cServerAddrCount, PIP_ADDRESS pipServerAddrs,
LPCWSTR lpszZoneName,
LPCWSTR lpszNSName,
CDNSRecordNodeEditInfoList* pNSInfoList,
BOOL bAdvancedView)
{
ASSERT(pNSInfoList != NULL);
ASSERT(pNSInfoList->IsEmpty());
// specifically look for A records matching a given NS name
// set query flags to get all the possible data
DWORD dwSelectFlags = DNS_RPC_VIEW_AUTHORITY_DATA | DNS_RPC_VIEW_GLUE_DATA |
DNS_RPC_VIEW_ADDITIONAL_DATA;
CDNSDomainQueryObj query(lpszServerName,
lpszZoneName,
dwServerVersion,
NULL, // lpszNodeName, no need here
lpszNSName,
DNS_TYPE_A,
dwSelectFlags,
FALSE, // zone
FALSE, // reverse
FALSE, // cache
bAdvancedView);
query.Enumerate();
// get record from the queue into the info
CObjBaseList* pChildList = query.GetQueue();
//int n = pChildList->GetCount();
while (!pChildList->IsEmpty())
{
CTreeNode* pNode = dynamic_cast<CTreeNode*>(pChildList->RemoveHead());
ASSERT(pNode != NULL);
if (!pNode->IsContainer())
{
CDNSRecordNodeBase* pRec = (CDNSRecordNodeBase*)pNode;
if (pRec->GetType() == DNS_TYPE_A)
{
TRACE(_T("Record <%s>\n"), pRec->GetString(2));
pRec->SetRecordName(lpszNSName, FALSE /*bAtTheNode*/);
CDNSRecordNodeEditInfo* pANodeInfo = new CDNSRecordNodeEditInfo;
if (pANodeInfo)
{
// NOTICE: we assume that all the nodes are glue, so we own the memory
pANodeInfo->CreateFromExistingRecord(pRec, TRUE /*bOwnMemory*/, FALSE /*bUpdateUI*/);
pNSInfoList->AddTail(pANodeInfo);
}
}
}
else
delete pNode; // discard
}
if (pNSInfoList->GetCount() > 0)
return; // got the info we needed just using RPC
// Could not find the A records, we need to try DnsQuery to get info outside the server
// search using DnsQuery and convert
PDNS_RECORD pDnsQueryARecordList = NULL;
// if available, use the provided addresses to do a DnsQuery()
PIP_ARRAY pipArr = NULL;
if ( (cServerAddrCount > 0) && (pipServerAddrs != NULL) )
{
pipArr = (PIP_ARRAY)malloc(sizeof(DWORD)+sizeof(IP_ADDRESS)*cServerAddrCount);
if (!pipArr)
{
return;
}
pipArr->AddrCount = cServerAddrCount;
memcpy(pipArr->AddrArray, pipServerAddrs, sizeof(IP_ADDRESS)*cServerAddrCount);
}
DWORD dwErr = ::DnsQuery((LPWSTR)lpszNSName, DNS_TYPE_A,
DNS_QUERY_NO_RECURSION, pipArr, &pDnsQueryARecordList, NULL);
if (pipArr)
{
free(pipArr);
pipArr = 0;
}
// no luck, try a simple query, with no IP addresses specified
if (pDnsQueryARecordList == NULL)
{
dwErr = ::DnsQuery((LPWSTR)lpszNSName, DNS_TYPE_A,
DNS_QUERY_NO_RECURSION, NULL, &pDnsQueryARecordList, NULL);
}
if (pDnsQueryARecordList == NULL)
return; // failed, no way to resolve IP address
PDNS_RECORD pCurrDnsQueryRecord = pDnsQueryARecordList;
while (pCurrDnsQueryRecord)
{
if (pCurrDnsQueryRecord->Flags.S.Section == DNSREC_ANSWER)
{
if (pCurrDnsQueryRecord->wType == DNS_TYPE_A)
{
// create a record node
CDNSRecordNodeBase* pRecordNode =
CDNSRecordInfo::CreateRecordNode(pCurrDnsQueryRecord->wType);
pRecordNode->CreateFromDnsQueryRecord(pCurrDnsQueryRecord, 0x0);
pRecordNode->SetRecordName(lpszNSName, FALSE /*bAtTheNode*/);
CDNSRecordNodeEditInfo* pANodeInfo = new CDNSRecordNodeEditInfo;
if (pANodeInfo)
{
pANodeInfo->m_bFromDnsQuery = TRUE;
//
// NOTICE: we assume that all the nodes are glue, so we own the memory
//
pANodeInfo->CreateFromExistingRecord(pRecordNode, TRUE /*bOwnMemory*/, FALSE /*bUpdateUI*/);
pNSInfoList->AddTail(pANodeInfo);
}
}
}
// goto next record
pCurrDnsQueryRecord = pCurrDnsQueryRecord->pNext;
}
DnsRecordListFree(pDnsQueryARecordList, DnsFreeRecordListDeep);
}
//////////////////////////////////////////////////////////////////////////////////
DNS_STATUS CDNSDomainNode::EnumerateNodes(LPCTSTR lpszServerName,
LPCTSTR lpszZoneName,
LPCTSTR lpszNodeName,
LPCTSTR lpszFullNodeName,
WORD wRecordType,
DWORD dwSelectFlag,
BOOL, BOOL bReverse, BOOL bAdvancedView,
CDNSDomainQueryObj* pQuery)
{
ASSERT(pQuery != NULL);
USES_CONVERSION;
DNS_STATUS err = 0;
CHAR szStartChildAnsi[3*MAX_DNS_NAME_LEN + 1]; // can have multibyte chars, count NULL
szStartChildAnsi[0] = NULL;
WCHAR szStartChild[MAX_DNS_NAME_LEN + 1]; // count NULL
szStartChild[0] = NULL;
CTreeNode* pNodeToInsert = NULL; // delayed insert
CDNSRecordNodeBase* pMoreDataNode = NULL;
// convert to UTF8 names
LPCSTR lpszFullNodeNameAnsi = W_TO_UTF8(lpszFullNodeName);
LPCSTR lpszZoneNameAnsi = W_TO_UTF8(lpszZoneName);
BOOL bTooMuchData = FALSE;
do // while more data
{
// get a chunk of data from RPC call
BYTE* pbRpcBuffer = NULL;
DWORD cbRpcBufferUsed = 0;
err = ::DnssrvEnumRecords(lpszServerName,
lpszZoneNameAnsi,
lpszFullNodeNameAnsi, // e.g. "foo.bar.com."
szStartChildAnsi, // Start Child
wRecordType,
dwSelectFlag,
NULL, // pszFilterStart
NULL, // pszFilterStop
&cbRpcBufferUsed,
&pbRpcBuffer);
if ((err != ERROR_MORE_DATA) && (err != 0))
return err; // bail out if there is an error
// walk the memory and build objects
DNS_RPC_NODE * pDnsNode = (DNS_RPC_NODE *)pbRpcBuffer;
DNS_RPC_RECORD * pDnsRecord;
void* pvEndOfRpcBuffer = pbRpcBuffer + cbRpcBufferUsed;
while ( (!bTooMuchData) && (pDnsNode < pvEndOfRpcBuffer) )
{
// get an ANSI null terminated copy
memcpy(szStartChildAnsi, pDnsNode->dnsNodeName.achName, pDnsNode->dnsNodeName.cchNameLength);
szStartChildAnsi[pDnsNode->dnsNodeName.cchNameLength] = NULL;
//
// get a UNICODE null terminated copy
//
if (szStartChildAnsi[0] == NULL)
{
szStartChild[0] = NULL;
}
else
{
DnsUtf8ToWHelper(szStartChild, szStartChildAnsi, pDnsNode->dnsNodeName.cchNameLength+1);
}
if (pDnsNode->dwChildCount || (pDnsNode->dwFlags & DNS_RPC_NODE_FLAG_STICKY))
{
BOOL bDelegation = ( ((dwSelectFlag & DNS_RPC_VIEW_CACHE_DATA) == 0) &&
((pDnsNode->dwFlags & DNS_RPC_FLAG_ZONE_ROOT) != 0) );
CDNSDomainNode* p = NULL;
if (pQuery->CanAddDomain(szStartChild))
{
bTooMuchData = pQuery->TooMuchData();
if (!bTooMuchData)
{
p = new CDNSDomainNode(bDelegation);
p->SetNames(FALSE, bReverse, bAdvancedView, szStartChild, lpszFullNodeName);
}
}
if (pNodeToInsert != NULL)
{
VERIFY(pQuery->AddQueryResult(pNodeToInsert));
}
pNodeToInsert = p;
}
pDnsRecord = (DNS_RPC_RECORD *)((BYTE *)pDnsNode + NEXT_DWORD(pDnsNode->wLength));
ASSERT(IS_DWORD_ALIGNED(pDnsRecord));
//
// Add the records under that node
//
UINT cRecordCount = pDnsNode->wRecordCount;
while ( (!bTooMuchData) && (cRecordCount--) )
{
CDNSRecordNodeBase* p = NULL;
BOOL bAtTheNode = szStartChild[0] == NULL;
LPCWSTR lpszRecordName = (bAtTheNode) ? lpszNodeName : szStartChild;
if (pQuery->CanAddRecord(pDnsRecord->wType, lpszRecordName))
{
TRACE(_T("\tCan add record %ws\n"), lpszRecordName);
bTooMuchData = pQuery->TooMuchData();
if (!bTooMuchData)
{
if (bAtTheNode)
{
p = CDNSRecordInfo::CreateRecordNodeFromRPCData(
lpszRecordName, pDnsRecord,bAtTheNode);
}
else
{
// filter out the NS records that are not at the node
if (pDnsRecord->wType != DNS_TYPE_NS)
{
p = CDNSRecordInfo::CreateRecordNodeFromRPCData(
lpszRecordName, pDnsRecord,bAtTheNode);
}
}
} // if not too much data
} // if can add
if (p != NULL)
{
p->SetFlagsDown(TN_FLAG_DNS_RECORD_FULL_NAME, !bAdvancedView);
if (pNodeToInsert != NULL)
{
VERIFY(pQuery->AddQueryResult(pNodeToInsert));
}
if (pMoreDataNode != NULL)
{
//
// If there was more data check to see if the new node is the same as the
// last node from the previous batch. Insert it if they are different, delete
// it if they are not
//
CString szMoreDataName = pMoreDataNode->GetDisplayName();
CString szPName = p->GetDisplayName();
if (szMoreDataName == szPName &&
pMoreDataNode->GetType() == p->GetType() &&
_wcsicmp(pMoreDataNode->GetString(3), p->GetString(3)) == 0)
{
delete pMoreDataNode;
}
else
{
VERIFY(pQuery->AddQueryResult(pMoreDataNode));
}
pMoreDataNode = NULL;
}
pNodeToInsert = p;
}
pDnsRecord = DNS_NEXT_RECORD(pDnsRecord);
} // while cRecordCount
// The new node is found at the end of the last record
pDnsNode = (DNS_RPC_NODE *)pDnsRecord;
} // while end of buffer
// we still have a node to insert, but we discard it if there is more data
// because we are going to get it again and we want to avoid duplication
if (pNodeToInsert != NULL)
{
if (bTooMuchData)
{
delete pNodeToInsert;
}
else if (err == ERROR_MORE_DATA)
{
//
// Doesn't matter if this turns out NULL because we only want
// pMoreDataNode to be a record node. If its a domain node we
// can just ignore it
//
pMoreDataNode = dynamic_cast<CDNSRecordNodeBase*>(pNodeToInsert);
}
else
{
VERIFY(pQuery->AddQueryResult(pNodeToInsert));
}
pNodeToInsert = NULL;
}
::DnssrvFreeRecordsBuffer(pbRpcBuffer);
} while ( !bTooMuchData && (err == ERROR_MORE_DATA) ) ;
// we are bailing out because of too much data,
// need to let the main tread know
if (bTooMuchData && (err != ERROR_MORE_DATA))
{
err = ERROR_MORE_DATA;
}
return err;
}
DNS_STATUS CDNSDomainNode::Create()
{
USES_CONVERSION;
LPCWSTR lpszFullZoneName = NULL;
CDNSZoneNode* pZoneNode = GetZoneNode();
if (pZoneNode != NULL)
lpszFullZoneName = pZoneNode->GetFullName();
DNS_STATUS err = ::DnssrvUpdateRecord(GetServerNode()->GetRPCName(),
W_TO_UTF8(lpszFullZoneName),
W_TO_UTF8(GetFullName()),
NULL, NULL);
return err;
}
DNS_STATUS CDNSDomainNode::Delete()
{
USES_CONVERSION;
LPCWSTR lpszFullZoneName = NULL;
CDNSZoneNode* pZoneNode = GetZoneNode();
if (pZoneNode != NULL)
lpszFullZoneName = pZoneNode->GetFullName();
return ::DnssrvDeleteNode(GetServerNode()->GetRPCName(),
W_TO_UTF8(lpszFullZoneName),
W_TO_UTF8(GetFullName()),
TRUE // fDeleteSubtree
);
}
/////////////////////////////////////////////////////////////////////////
// CDNSRootHintsNode
DNS_STATUS CDNSRootHintsNode::QueryForRootHints(LPCTSTR lpszServerName, DWORD dwServerVersion)
{
USES_CONVERSION;
DWORD dwSelectFlags = DNS_RPC_VIEW_ROOT_HINT_DATA | DNS_RPC_VIEW_ADDITIONAL_DATA | DNS_RPC_VIEW_NO_CHILDREN;
CDNSDomainQueryObj query(lpszServerName,
UTF8_TO_W(DNS_ZONE_ROOT_HINTS), //lpszZoneName, needs to be "..RootHints" as defined in dnsrpc.h
dwServerVersion,
GetDisplayName(),
m_szFullName,
DNS_TYPE_NS,
dwSelectFlags,
FALSE, // zone
FALSE, // reverse
FALSE, // cache
FALSE);
query.Enumerate();
DWORD dwErr = query.GetError();
if (dwErr != 0)
return dwErr;
// get record from the queue into the folder
CObjBaseList* pChildList = query.GetQueue();
//int n = pChildList->GetCount();
while (!pChildList->IsEmpty())
{
CTreeNode* pNode = dynamic_cast<CTreeNode*>(pChildList->RemoveHead());
// NOTICE: for NT 4.0 servers, we get bogus container nodes
// that we have to suppress
if(pNode->IsContainer())
{
delete pNode;
}
else
{
OnHaveRecord((CDNSRecordNodeBase*)pNode, NULL); // add to the list of NS records
AddChildToList(pNode);
}
}
return (DNS_STATUS)dwErr;
}
void CDNSRootHintsNode::FindARecordsFromNSInfo(LPCTSTR lpszNSName,
CDNSRecordNodeEditInfoList* pNSInfoList)
{
ASSERT(pNSInfoList != NULL);
//
// for root hints, we have all the records in this folder and we
// can edit them
//
POSITION pos;
for( pos = m_leafChildList.GetHeadPosition(); pos != NULL; )
{
CTreeNode* pCurrentChild = m_leafChildList.GetNext(pos);
ASSERT(!pCurrentChild->IsContainer());
CDNSRecordNodeBase* pRecordNode = (CDNSRecordNodeBase*)pCurrentChild;
if (DNS_TYPE_A == pRecordNode->GetType())
{
CDNS_A_RecordNode* pARecordNode = (CDNS_A_RecordNode*)pRecordNode;
if (_match(lpszNSName, pARecordNode))
{
CDNSRecordNodeEditInfo* pANodeInfo = new CDNSRecordNodeEditInfo;
//
// NOTICE: the root hints folder owns the memory
//
if (pANodeInfo != NULL)
{
pANodeInfo->CreateFromExistingRecord(pARecordNode, FALSE /*bOwnMemory*/, TRUE /*bUpdateUI*/);
pNSInfoList->AddTail(pANodeInfo);
}
else
{
TRACE(_T("Failed to allocate memory in CDNSRootHintsNode::FindARecordsFromNSInfo"));
ASSERT(FALSE);
}
}
}
}
}
void CDNSRootHintsNode::UpdateARecordsOfNSInfo(CDNSRecordNodeEditInfo* pNSInfo,
CComponentDataObject* pComponentData)
{
BOOL bAskConfirmation = FALSE; // need to edit ALL A records
UpdateARecordsOfNSInfoHelper(this, pNSInfo, pComponentData, bAskConfirmation);
}
DNS_STATUS CDNSRootHintsNode::Clear()
{
//
// clear the list of cached NS record pointers
//
GetNSRecordNodeList()->RemoveAll();
//
// remove all the records from the server
//
DNS_STATUS err = 0;
POSITION pos;
for( pos = m_leafChildList.GetHeadPosition(); pos != NULL; )
{
CTreeNode* pCurrentChild = m_leafChildList.GetNext(pos);
ASSERT(!pCurrentChild->IsContainer());
CDNSRecordNodeBase* pRecordNode = (CDNSRecordNodeBase*)pCurrentChild;
DNS_STATUS currErr = pRecordNode->DeleteOnServer();
if (currErr != 0)
{
//
// just ge the last error, if any
//
err = currErr;
}
}
//
// clear the list of children in the folder (we are hidden, so no UI deletions)
//
RemoveAllChildrenFromList();
return err;
}
DNS_STATUS CDNSRootHintsNode::InitializeFromDnsQueryData(PDNS_RECORD pRootHintsRecordList)
{
// need to remove all the previous root hints from the server
// let's be sure we get recent data
// clear the list of children in the folder (we are hidden, so no UI deletions)
RemoveAllChildrenFromList();
// acqure the list of current root hints
CDNSServerNode* pServerNode = GetServerNode();
DNS_STATUS dwErr = QueryForRootHints(pServerNode->GetRPCName(), pServerNode->GetVersion());
if (dwErr != 0)
{
TRACE(_T("Failed to remove old Root Hints, dwErr = %x hex\n"), dwErr);
return dwErr;
}
// remove all the old root hints from server and client side
dwErr = Clear();
if (dwErr != 0)
{
TRACE(_T("Failed to clear Root Hints, dwErr = %x hex\n"), dwErr);
return dwErr;
}
// walk through the list of root hints,
// convert to C++ format,
// write to server and add to the folder list (no UI, folder hidden)
PDNS_RECORD pCurrDnsQueryRecord = pRootHintsRecordList;
while (pCurrDnsQueryRecord != NULL)
{
ASSERT( (pCurrDnsQueryRecord->wType == DNS_TYPE_A) ||
(pCurrDnsQueryRecord->wType == DNS_TYPE_NS) );
// create a record node and read data from DnsQuery format
CDNSRecordNodeBase* pRecordNode =
CDNSRecordInfo::CreateRecordNode(pCurrDnsQueryRecord->wType);
pRecordNode->CreateFromDnsQueryRecord(pCurrDnsQueryRecord, DNS_RPC_RECORD_FLAG_ZONE_ROOT);
// set the record node container
pRecordNode->SetContainer(this);
// set the record node name
BOOL bAtTheNode = (pCurrDnsQueryRecord->wType == DNS_TYPE_NS);
pRecordNode->SetRecordName(pCurrDnsQueryRecord->pName, bAtTheNode);
// write on server
// the default TTL does not apply here
DNS_STATUS err = pRecordNode->Update(NULL, FALSE); // NULL = create new, FALSE = use def TTL
if (err == 0)
VERIFY(AddChildToList(pRecordNode));
else
{
dwErr = err; // mark las error
delete pRecordNode; // something went wrong
}
pCurrDnsQueryRecord = pCurrDnsQueryRecord->pNext;
}
// force a write on the server, to make sure the cache file is written right away
return CDNSZoneNode::WriteToDatabase(pServerNode->GetRPCName(), DNS_ZONE_ROOT_HINTS);
}