8614 lines
299 KiB
C++
8614 lines
299 KiB
C++
/**********************************************************************/
|
|
/** Microsoft Windows/NT **/
|
|
/** Copyright(c) Microsoft Corporation, 1997 - 1999 **/
|
|
/**********************************************************************/
|
|
|
|
/*
|
|
scope.cpp
|
|
This file contains all of the implementation for the DHCP
|
|
scope object and all objects that it may contain.
|
|
They include:
|
|
|
|
CDhcpScope
|
|
CDhcpReservations
|
|
CDhcpReservationClient
|
|
CDhcpActiveLeases
|
|
CDhcpAddressPool
|
|
CDhcpScopeOptions
|
|
|
|
FILE HISTORY:
|
|
|
|
*/
|
|
|
|
#include "stdafx.h"
|
|
#include "server.h" // server object
|
|
#include "scope.h" // scope object
|
|
#include "scopepp.h" // scope property page
|
|
#include "addbootp.h" // add BOOTP entry dialog
|
|
#include "addexcl.h" // add exclusion range dialog
|
|
#include "addres.h" // add reservation dialog
|
|
#include "rclntpp.h" // reserved client property page
|
|
#include "nodes.h" // all node (result pane) definitions
|
|
#include "optcfg.h" // option configuration sheet
|
|
#include "dlgrecon.h" // reconcile database dialog
|
|
#include "scopstat.h" // scope statistics
|
|
#include "addtoss.h" // add scope to superscope dialog
|
|
|
|
WORD gwUnicodeHeader = 0xFEFF;
|
|
|
|
// scope options result pane message stuff
|
|
#define SCOPE_OPTIONS_MESSAGE_MAX_STRING 5
|
|
typedef enum _SCOPE_OPTIONS_MESSAGES
|
|
{
|
|
SCOPE_OPTIONS_MESSAGE_NO_OPTIONS,
|
|
SCOPE_OPTIONS_MESSAGE_MAX
|
|
};
|
|
|
|
UINT g_uScopeOptionsMessages[SCOPE_OPTIONS_MESSAGE_MAX][SCOPE_OPTIONS_MESSAGE_MAX_STRING] =
|
|
{
|
|
{IDS_SCOPE_OPTIONS_MESSAGE_TITLE, Icon_Information, IDS_SCOPE_OPTIONS_MESSAGE_BODY, 0, 0}
|
|
};
|
|
|
|
// reservation options result pane message stuff
|
|
#define RES_OPTIONS_MESSAGE_MAX_STRING 5
|
|
typedef enum _RES_OPTIONS_MESSAGES
|
|
{
|
|
RES_OPTIONS_MESSAGE_NO_OPTIONS,
|
|
RES_OPTIONS_MESSAGE_MAX
|
|
};
|
|
|
|
UINT g_uResOptionsMessages[RES_OPTIONS_MESSAGE_MAX][RES_OPTIONS_MESSAGE_MAX_STRING] =
|
|
{
|
|
{IDS_RES_OPTIONS_MESSAGE_TITLE, Icon_Information, IDS_RES_OPTIONS_MESSAGE_BODY, 0, 0}
|
|
};
|
|
|
|
// reservations result pane message stuff
|
|
#define RESERVATIONS_MESSAGE_MAX_STRING 5
|
|
typedef enum _RESERVATIONS_MESSAGES
|
|
{
|
|
RESERVATIONS_MESSAGE_NO_RES,
|
|
RESERVATIONS_MESSAGE_MAX
|
|
};
|
|
|
|
UINT g_uReservationsMessages[RESERVATIONS_MESSAGE_MAX][RESERVATIONS_MESSAGE_MAX_STRING] =
|
|
{
|
|
{IDS_RESERVATIONS_MESSAGE_TITLE, Icon_Information, IDS_RESERVATIONS_MESSAGE_BODY, 0, 0}
|
|
};
|
|
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Class CDhcpScope implementation
|
|
---------------------------------------------------------------------------*/
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::CDhcpScope
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
CDhcpScope::CDhcpScope
|
|
(
|
|
ITFSComponentData * pComponentData,
|
|
DHCP_IP_ADDRESS dhcpScopeIp,
|
|
DHCP_IP_MASK dhcpSubnetMask,
|
|
LPCWSTR pName,
|
|
LPCWSTR pComment,
|
|
DHCP_SUBNET_STATE dhcpSubnetState
|
|
) : CMTDhcpHandler(pComponentData)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
// save off some parameters
|
|
//
|
|
m_dhcpIpAddress = dhcpScopeIp;
|
|
m_dhcpSubnetMask = dhcpSubnetMask;
|
|
m_strName = pName;
|
|
m_strComment = pComment;
|
|
m_dhcpSubnetState = dhcpSubnetState;
|
|
m_bInSuperscope = FALSE;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Function Name Here
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
CDhcpScope::CDhcpScope
|
|
(
|
|
ITFSComponentData * pComponentData,
|
|
LPDHCP_SUBNET_INFO pdhcpSubnetInfo
|
|
) : CMTDhcpHandler(pComponentData)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
// save off some parameters
|
|
//
|
|
m_dhcpIpAddress = pdhcpSubnetInfo->SubnetAddress;
|
|
m_dhcpSubnetMask = pdhcpSubnetInfo->SubnetMask;
|
|
m_strName = pdhcpSubnetInfo->SubnetName;
|
|
m_strComment = pdhcpSubnetInfo->SubnetComment;
|
|
m_dhcpSubnetState = pdhcpSubnetInfo->SubnetState;
|
|
m_bInSuperscope = FALSE;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Function Name Here
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
CDhcpScope::CDhcpScope
|
|
(
|
|
ITFSComponentData * pComponentData,
|
|
CSubnetInfo & subnetInfo
|
|
) : CMTDhcpHandler(pComponentData)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
// save off some parameters
|
|
//
|
|
m_dhcpIpAddress = subnetInfo.SubnetAddress;
|
|
m_dhcpSubnetMask = subnetInfo.SubnetMask;
|
|
m_strName = subnetInfo.SubnetName;
|
|
m_strComment = subnetInfo.SubnetComment;
|
|
m_dhcpSubnetState = subnetInfo.SubnetState;
|
|
m_bInSuperscope = FALSE;
|
|
}
|
|
|
|
CDhcpScope::~CDhcpScope()
|
|
{
|
|
}
|
|
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CDhcpScope::InitializeNode
|
|
Initializes node specific data
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpScope::InitializeNode
|
|
(
|
|
ITFSNode * pNode
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
HRESULT hr = hrOK;
|
|
int nImage;
|
|
|
|
//
|
|
// Create the display name for this scope
|
|
//
|
|
CString strDisplay, strIpAddress;
|
|
|
|
UtilCvtIpAddrToWstr (m_dhcpIpAddress,
|
|
&strIpAddress);
|
|
|
|
BuildDisplayName(&strDisplay, strIpAddress, m_strName);
|
|
|
|
SetDisplayName(strDisplay);
|
|
|
|
//
|
|
// Figure out the correct icon
|
|
//
|
|
if ( !IsEnabled() )
|
|
{
|
|
m_strState.LoadString(IDS_SCOPE_INACTIVE);
|
|
}
|
|
else
|
|
{
|
|
m_strState.LoadString(IDS_SCOPE_ACTIVE);
|
|
}
|
|
|
|
// Make the node immediately visible
|
|
pNode->SetVisibilityState(TFS_VIS_SHOW);
|
|
pNode->SetData(TFS_DATA_IMAGEINDEX, GetImageIndex(FALSE));
|
|
pNode->SetData(TFS_DATA_OPENIMAGEINDEX, GetImageIndex(TRUE));
|
|
pNode->SetData(TFS_DATA_COOKIE, (LPARAM) pNode);
|
|
pNode->SetData(TFS_DATA_USER, (LPARAM) this);
|
|
pNode->SetData(TFS_DATA_TYPE, DHCPSNAP_SCOPE);
|
|
|
|
SetColumnStringIDs(&aColumns[DHCPSNAP_SCOPE][0]);
|
|
SetColumnWidths(&aColumnWidths[DHCPSNAP_SCOPE][0]);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::DestroyHandler
|
|
We need to free up any resources we are holding
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
STDMETHODIMP
|
|
CDhcpScope::DestroyHandler(ITFSNode *pNode)
|
|
{
|
|
// cleanup the stats dialog
|
|
WaitForStatisticsWindow(&m_dlgStats);
|
|
|
|
return CMTDhcpHandler::DestroyHandler(pNode);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::OnCreateNodeId2
|
|
Returns a unique string for this node
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT CDhcpScope::OnCreateNodeId2(ITFSNode * pNode, CString & strId, DWORD * dwFlags)
|
|
{
|
|
const GUID * pGuid = pNode->GetNodeType();
|
|
CString strIpAddress, strGuid;
|
|
|
|
StringFromGUID2(*pGuid, strGuid.GetBuffer(256), 256);
|
|
strGuid.ReleaseBuffer();
|
|
|
|
UtilCvtIpAddrToWstr (m_dhcpIpAddress, &strIpAddress);
|
|
|
|
strId = GetServerObject()->GetName() + strIpAddress + strGuid;
|
|
|
|
return hrOK;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::GetImageIndex
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
int
|
|
CDhcpScope::GetImageIndex(BOOL bOpenImage)
|
|
{
|
|
int nIndex = -1;
|
|
|
|
switch (m_nState)
|
|
{
|
|
// TODO: these need to be updated with new busy state icons
|
|
case loading:
|
|
if (bOpenImage)
|
|
nIndex = (IsEnabled()) ? ICON_IDX_SCOPE_FOLDER_OPEN_BUSY : ICON_IDX_SCOPE_FOLDER_OPEN_BUSY;
|
|
else
|
|
nIndex = (IsEnabled()) ? ICON_IDX_SCOPE_FOLDER_CLOSED_BUSY : ICON_IDX_SCOPE_FOLDER_CLOSED_BUSY;
|
|
return nIndex;
|
|
|
|
case notLoaded:
|
|
case loaded:
|
|
if (bOpenImage)
|
|
nIndex = (IsEnabled()) ? ICON_IDX_SCOPE_FOLDER_OPEN : ICON_IDX_SCOPE_INACTIVE_FOLDER_OPEN;
|
|
else
|
|
nIndex = (IsEnabled()) ? ICON_IDX_SCOPE_FOLDER_CLOSED : ICON_IDX_SCOPE_INACTIVE_FOLDER_CLOSED;
|
|
break;
|
|
|
|
case unableToLoad:
|
|
if (bOpenImage)
|
|
nIndex = (IsEnabled()) ? ICON_IDX_SCOPE_FOLDER_OPEN_LOST_CONNECTION : ICON_IDX_SCOPE_INACTIVE_FOLDER_OPEN_LOST_CONNECTION;
|
|
else
|
|
nIndex = (IsEnabled()) ? ICON_IDX_SCOPE_FOLDER_CLOSED_LOST_CONNECTION : ICON_IDX_SCOPE_INACTIVE_FOLDER_CLOSED_LOST_CONNECTION;
|
|
return nIndex;
|
|
|
|
default:
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
// only calcualte alert/warnings if the scope is enabled.
|
|
if (m_spServerNode && IsEnabled())
|
|
{
|
|
CDhcpServer * pServer = GetServerObject();
|
|
LPDHCP_MIB_INFO pMibInfo = pServer->DuplicateMibInfo();
|
|
|
|
if (!pMibInfo)
|
|
return nIndex;
|
|
|
|
LPSCOPE_MIB_INFO pScopeMibInfo = pMibInfo->ScopeInfo;
|
|
|
|
// walk the list of scopes and find our info
|
|
for (UINT i = 0; i < pMibInfo->Scopes; i++)
|
|
{
|
|
// Find our scope stats
|
|
if (pScopeMibInfo[i].Subnet == m_dhcpIpAddress)
|
|
{
|
|
int nPercentInUse;
|
|
|
|
if ((pScopeMibInfo[i].NumAddressesInuse + pScopeMibInfo[i].NumAddressesFree) == 0)
|
|
nPercentInUse = 0;
|
|
else
|
|
nPercentInUse = (pScopeMibInfo[i].NumAddressesInuse * 100) / (pScopeMibInfo[i].NumAddressesInuse + pScopeMibInfo[i].NumAddressesFree);
|
|
|
|
// look to see if this scope meets the warning or red flag case
|
|
if (pScopeMibInfo[i].NumAddressesFree == 0)
|
|
{
|
|
// red flag case, no addresses free, this is the highest
|
|
// level of warning, so break out of the loop if we set this.
|
|
if (bOpenImage)
|
|
nIndex = ICON_IDX_SCOPE_FOLDER_OPEN_ALERT;
|
|
else
|
|
nIndex = ICON_IDX_SCOPE_FOLDER_CLOSED_ALERT;
|
|
break;
|
|
}
|
|
else
|
|
if (nPercentInUse >= SCOPE_WARNING_LEVEL)
|
|
{
|
|
// warning condition if Num Addresses in use is greater than
|
|
// some pre-defined threshold.
|
|
if (bOpenImage)
|
|
nIndex = ICON_IDX_SCOPE_FOLDER_OPEN_WARNING;
|
|
else
|
|
nIndex = ICON_IDX_SCOPE_FOLDER_CLOSED_WARNING;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
pServer->FreeDupMibInfo(pMibInfo);
|
|
}
|
|
|
|
return nIndex;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Overridden base handler functions
|
|
---------------------------------------------------------------------------*/
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::OnAddMenuItems
|
|
Adds entries to the context sensitive menu
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
STDMETHODIMP
|
|
CDhcpScope::OnAddMenuItems
|
|
(
|
|
ITFSNode * pNode,
|
|
LPCONTEXTMENUCALLBACK pContextMenuCallback,
|
|
LPDATAOBJECT lpDataObject,
|
|
DATA_OBJECT_TYPES type,
|
|
DWORD dwType,
|
|
long * pInsertionAllowed
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
// Get the version of the server
|
|
LONG fFlags = 0;
|
|
LARGE_INTEGER liDhcpVersion;
|
|
CDhcpServer * pServer = GetServerObject();
|
|
pServer->GetVersion(liDhcpVersion);
|
|
|
|
HRESULT hr = S_OK;
|
|
CString strMenuText;
|
|
|
|
if ( (m_nState != loaded) )
|
|
{
|
|
fFlags |= MF_GRAYED;
|
|
}
|
|
|
|
if (type == CCT_SCOPE)
|
|
{
|
|
//
|
|
// these menu items go in the new menu,
|
|
// only visible from scope pane
|
|
//
|
|
if (*pInsertionAllowed & CCM_INSERTIONALLOWED_TOP)
|
|
{
|
|
strMenuText.LoadString(IDS_SCOPE_SHOW_STATISTICS);
|
|
hr = LoadAndAddMenuItem( pContextMenuCallback,
|
|
strMenuText,
|
|
IDS_SCOPE_SHOW_STATISTICS,
|
|
CCM_INSERTIONPOINTID_PRIMARY_TOP,
|
|
fFlags );
|
|
ASSERT( SUCCEEDED(hr) );
|
|
|
|
// separator
|
|
hr = LoadAndAddMenuItem( pContextMenuCallback,
|
|
strMenuText,
|
|
0,
|
|
CCM_INSERTIONPOINTID_PRIMARY_TOP,
|
|
MF_SEPARATOR);
|
|
ASSERT( SUCCEEDED(hr) );
|
|
|
|
// reconcile is only supports for NT4 SP2 and greater.
|
|
if (liDhcpVersion.QuadPart >= DHCP_SP2_VERSION)
|
|
{
|
|
strMenuText.LoadString(IDS_SCOPE_RECONCILE);
|
|
hr = LoadAndAddMenuItem( pContextMenuCallback,
|
|
strMenuText,
|
|
IDS_SCOPE_RECONCILE,
|
|
CCM_INSERTIONPOINTID_PRIMARY_TOP,
|
|
fFlags );
|
|
ASSERT( SUCCEEDED(hr) );
|
|
}
|
|
|
|
// Superscope support only on NT4 SP2 and greater
|
|
if (liDhcpVersion.QuadPart >= DHCP_SP2_VERSION)
|
|
{
|
|
int nID = 0;
|
|
|
|
if (IsInSuperscope())
|
|
{
|
|
nID = IDS_SCOPE_REMOVE_SUPERSCOPE;
|
|
}
|
|
else
|
|
{
|
|
// check to see if there are superscopes to add to
|
|
SPITFSNode spNode;
|
|
pNode->GetParent(&spNode);
|
|
|
|
pServer = GETHANDLER(CDhcpServer, spNode);
|
|
|
|
if (pServer->HasSuperscopes(spNode))
|
|
nID = IDS_SCOPE_ADD_SUPERSCOPE;
|
|
}
|
|
|
|
// load the menu item if we need to
|
|
if (nID)
|
|
{
|
|
strMenuText.LoadString(nID);
|
|
hr = LoadAndAddMenuItem( pContextMenuCallback,
|
|
strMenuText,
|
|
nID,
|
|
CCM_INSERTIONPOINTID_PRIMARY_TOP,
|
|
fFlags );
|
|
ASSERT( SUCCEEDED(hr) );
|
|
}
|
|
}
|
|
|
|
// separator
|
|
hr = LoadAndAddMenuItem( pContextMenuCallback,
|
|
strMenuText,
|
|
0,
|
|
CCM_INSERTIONPOINTID_PRIMARY_TOP,
|
|
MF_SEPARATOR);
|
|
ASSERT( SUCCEEDED(hr) );
|
|
|
|
// activate/deactivate
|
|
if ( !IsEnabled() )
|
|
{
|
|
strMenuText.LoadString(IDS_SCOPE_ACTIVATE);
|
|
hr = LoadAndAddMenuItem( pContextMenuCallback,
|
|
strMenuText,
|
|
IDS_SCOPE_ACTIVATE,
|
|
CCM_INSERTIONPOINTID_PRIMARY_TOP,
|
|
fFlags );
|
|
ASSERT( SUCCEEDED(hr) );
|
|
}
|
|
else
|
|
{
|
|
strMenuText.LoadString(IDS_SCOPE_DEACTIVATE);
|
|
hr = LoadAndAddMenuItem( pContextMenuCallback,
|
|
strMenuText,
|
|
IDS_SCOPE_DEACTIVATE,
|
|
CCM_INSERTIONPOINTID_PRIMARY_TOP,
|
|
fFlags );
|
|
ASSERT( SUCCEEDED(hr) );
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::OnCommand
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
STDMETHODIMP
|
|
CDhcpScope::OnCommand
|
|
(
|
|
ITFSNode * pNode,
|
|
long nCommandId,
|
|
DATA_OBJECT_TYPES type,
|
|
LPDATAOBJECT pDataObject,
|
|
DWORD dwType
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
switch (nCommandId)
|
|
{
|
|
case IDS_ACTIVATE:
|
|
case IDS_DEACTIVATE:
|
|
case IDS_SCOPE_ACTIVATE:
|
|
case IDS_SCOPE_DEACTIVATE:
|
|
OnActivateScope(pNode);
|
|
break;
|
|
|
|
case IDS_REFRESH:
|
|
OnRefresh(pNode, pDataObject, dwType, 0, 0);
|
|
break;
|
|
|
|
case IDS_SCOPE_SHOW_STATISTICS:
|
|
OnShowScopeStats(pNode);
|
|
break;
|
|
|
|
case IDS_SCOPE_RECONCILE:
|
|
OnReconcileScope(pNode);
|
|
break;
|
|
|
|
case IDS_DELETE:
|
|
OnDelete(pNode);
|
|
break;
|
|
|
|
case IDS_SCOPE_ADD_SUPERSCOPE:
|
|
OnAddToSuperscope(pNode);
|
|
break;
|
|
|
|
case IDS_SCOPE_REMOVE_SUPERSCOPE:
|
|
OnRemoveFromSuperscope(pNode);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CDhcpScope::OnDelete
|
|
The base handler calls this when MMC sends a MMCN_DELETE for a
|
|
scope pane item. We just call our delete command handler.
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpScope::OnDelete
|
|
(
|
|
ITFSNode * pNode,
|
|
LPARAM arg,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
return OnDelete(pNode);
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CDhcpScope::HasPropertyPages
|
|
Says whether or not this handler has property pages
|
|
Author: KennT
|
|
---------------------------------------------------------------------------*/
|
|
STDMETHODIMP
|
|
CDhcpScope::HasPropertyPages
|
|
(
|
|
ITFSNode * pNode,
|
|
LPDATAOBJECT pDataObject,
|
|
DATA_OBJECT_TYPES type,
|
|
DWORD dwType
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
HRESULT hr = hrOK;
|
|
|
|
if (dwType & TFS_COMPDATA_CREATE)
|
|
{
|
|
// This is the case where we are asked to bring up property
|
|
// pages when the user is adding a new snapin. These calls
|
|
// are forwarded to the root node to handle.
|
|
// Should never get here!!
|
|
Assert(FALSE);
|
|
hr = S_FALSE;
|
|
}
|
|
else
|
|
{
|
|
// we have property pages in the normal case
|
|
hr = hrOK;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::CreatePropertyPages
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
STDMETHODIMP
|
|
CDhcpScope::CreatePropertyPages
|
|
(
|
|
ITFSNode * pNode,
|
|
LPPROPERTYSHEETCALLBACK lpProvider,
|
|
LPDATAOBJECT pDataObject,
|
|
LONG_PTR handle,
|
|
DWORD dwType
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
HRESULT hr = hrOK;
|
|
DWORD dwError;
|
|
DWORD dwDynDnsFlags;
|
|
SPIComponentData spComponentData;
|
|
LARGE_INTEGER liVersion;
|
|
CDhcpServer * pServer;
|
|
CDhcpIpRange dhcpIpRange;
|
|
|
|
//
|
|
// Create the property page
|
|
//
|
|
m_spNodeMgr->GetComponentData(&spComponentData);
|
|
|
|
CScopeProperties * pScopeProp =
|
|
new CScopeProperties(pNode, spComponentData, m_spTFSCompData, NULL);
|
|
|
|
// Get the Server version and set it in the property sheet
|
|
pServer = GetServerObject();
|
|
pServer->GetVersion(liVersion);
|
|
|
|
pScopeProp->SetVersion(liVersion);
|
|
pScopeProp->SetSupportsDynBootp(pServer->FSupportsDynBootp());
|
|
|
|
// Set scope specific data in the prop sheet
|
|
pScopeProp->m_pageGeneral.m_strName = m_strName;
|
|
pScopeProp->m_pageGeneral.m_strComment = m_strComment;
|
|
|
|
BEGIN_WAIT_CURSOR;
|
|
|
|
dwError = GetIpRange(&dhcpIpRange);
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
::DhcpMessageBox(dwError);
|
|
return hrFalse;
|
|
}
|
|
|
|
pScopeProp->m_pageGeneral.m_dwStartAddress = dhcpIpRange.QueryAddr(TRUE);
|
|
pScopeProp->m_pageGeneral.m_dwEndAddress = dhcpIpRange.QueryAddr(FALSE);
|
|
pScopeProp->m_pageGeneral.m_dwSubnetMask = m_dhcpSubnetMask;
|
|
pScopeProp->m_pageGeneral.m_uImage = GetImageIndex(FALSE);
|
|
pScopeProp->m_pageAdvanced.m_RangeType = dhcpIpRange.GetRangeType();
|
|
|
|
GetLeaseTime(&pScopeProp->m_pageGeneral.m_dwLeaseTime);
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
::DhcpMessageBox(dwError);
|
|
return hrFalse;
|
|
}
|
|
|
|
if (pServer->FSupportsDynBootp())
|
|
{
|
|
GetDynBootpLeaseTime(&pScopeProp->m_pageAdvanced.m_dwLeaseTime);
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
::DhcpMessageBox(dwError);
|
|
return hrFalse;
|
|
}
|
|
}
|
|
|
|
// set the DNS registration option
|
|
dwError = GetDnsRegistration(&dwDynDnsFlags);
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
::DhcpMessageBox(dwError);
|
|
return hrFalse;
|
|
}
|
|
END_WAIT_CURSOR;
|
|
|
|
pScopeProp->SetDnsRegistration(dwDynDnsFlags, DhcpSubnetOptions);
|
|
|
|
//
|
|
// Object gets deleted when the page is destroyed
|
|
//
|
|
Assert(lpProvider != NULL);
|
|
|
|
return pScopeProp->CreateModelessSheet(lpProvider, handle);
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CDhcpScope::GetString
|
|
Returns string information for display in the result pane columns
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
STDMETHODIMP_(LPCTSTR)
|
|
CDhcpScope::GetString
|
|
(
|
|
ITFSNode * pNode,
|
|
int nCol
|
|
)
|
|
{
|
|
switch (nCol)
|
|
{
|
|
case 0:
|
|
return GetDisplayName();
|
|
|
|
case 1:
|
|
return m_strState;
|
|
|
|
case 2:
|
|
return m_strComment;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::OnPropertyChange
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpScope::OnPropertyChange
|
|
(
|
|
ITFSNode * pNode,
|
|
LPDATAOBJECT pDataobject,
|
|
DWORD dwType,
|
|
LPARAM arg,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
CScopeProperties * pScopeProp = reinterpret_cast<CScopeProperties *>(lParam);
|
|
|
|
LONG_PTR changeMask = 0;
|
|
|
|
// tell the property page to do whatever now that we are back on the
|
|
// main thread
|
|
pScopeProp->OnPropertyChange(TRUE, &changeMask);
|
|
|
|
pScopeProp->AcknowledgeNotify();
|
|
|
|
if (changeMask)
|
|
pNode->ChangeNode(changeMask);
|
|
|
|
return hrOK;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CDhcpScope::OnUpdateToolbarButtons
|
|
We override this function to show/hide the correct
|
|
activate/deactivate buttons
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpScope::OnUpdateToolbarButtons
|
|
(
|
|
ITFSNode * pNode,
|
|
LPDHCPTOOLBARNOTIFY pToolbarNotify
|
|
)
|
|
{
|
|
HRESULT hr = hrOK;
|
|
|
|
if (pToolbarNotify->bSelect)
|
|
{
|
|
UpdateToolbarStates();
|
|
}
|
|
|
|
CMTDhcpHandler::OnUpdateToolbarButtons(pNode, pToolbarNotify);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CDhcpScope::UpdateToolbarStates
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
void
|
|
CDhcpScope::UpdateToolbarStates()
|
|
{
|
|
if ( !IsEnabled() )
|
|
{
|
|
g_SnapinButtonStates[DHCPSNAP_SCOPE][TOOLBAR_IDX_ACTIVATE] = ENABLED;
|
|
g_SnapinButtonStates[DHCPSNAP_SCOPE][TOOLBAR_IDX_DEACTIVATE] = HIDDEN;
|
|
}
|
|
else
|
|
{
|
|
g_SnapinButtonStates[DHCPSNAP_SCOPE][TOOLBAR_IDX_ACTIVATE] = HIDDEN;
|
|
g_SnapinButtonStates[DHCPSNAP_SCOPE][TOOLBAR_IDX_DEACTIVATE] = ENABLED;
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Background thread functionality
|
|
---------------------------------------------------------------------------*/
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope:OnHaveData
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
void
|
|
CDhcpScope::OnHaveData
|
|
(
|
|
ITFSNode * pParentNode,
|
|
ITFSNode * pNewNode
|
|
)
|
|
{
|
|
if (pNewNode->GetData(TFS_DATA_TYPE) == DHCPSNAP_ACTIVE_LEASES)
|
|
{
|
|
pParentNode->AddChild(pNewNode);
|
|
m_spActiveLeases.Set(pNewNode);
|
|
}
|
|
else
|
|
if (pNewNode->GetData(TFS_DATA_TYPE) == DHCPSNAP_ADDRESS_POOL)
|
|
{
|
|
pParentNode->AddChild(pNewNode);
|
|
m_spAddressPool.Set(pNewNode);
|
|
}
|
|
else
|
|
if (pNewNode->GetData(TFS_DATA_TYPE) == DHCPSNAP_RESERVATIONS)
|
|
{
|
|
pParentNode->AddChild(pNewNode);
|
|
m_spReservations.Set(pNewNode);
|
|
}
|
|
else
|
|
if (pNewNode->GetData(TFS_DATA_TYPE) == DHCPSNAP_SCOPE_OPTIONS)
|
|
{
|
|
pParentNode->AddChild(pNewNode);
|
|
m_spOptions.Set(pNewNode);
|
|
}
|
|
|
|
// now tell the view to update themselves
|
|
ExpandNode(pParentNode, TRUE);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::OnHaveData
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
void
|
|
CDhcpScope::OnHaveData
|
|
(
|
|
ITFSNode * pParentNode,
|
|
LPARAM Data,
|
|
LPARAM Type
|
|
)
|
|
{
|
|
// This is how we get non-node data back from the background thread.
|
|
|
|
switch (Type)
|
|
{
|
|
case DHCP_QDATA_SUBNET_INFO:
|
|
{
|
|
LONG_PTR changeMask = 0;
|
|
LPDHCP_SUBNET_INFO pdhcpSubnetInfo = reinterpret_cast<LPDHCP_SUBNET_INFO>(Data);
|
|
|
|
// update the scope name and state based on the info
|
|
if (m_strName.CompareNoCase(pdhcpSubnetInfo->SubnetName) != 0)
|
|
{
|
|
CString strDisplay, strIpAddress;
|
|
|
|
m_strName = pdhcpSubnetInfo->SubnetName;
|
|
UtilCvtIpAddrToWstr (m_dhcpIpAddress,
|
|
&strIpAddress);
|
|
|
|
BuildDisplayName(&strDisplay, strIpAddress, m_strName);
|
|
|
|
SetDisplayName(strDisplay);
|
|
|
|
changeMask = SCOPE_PANE_CHANGE_ITEM;
|
|
}
|
|
|
|
if (m_dhcpSubnetState != pdhcpSubnetInfo->SubnetState)
|
|
{
|
|
DHCP_SUBNET_STATE dhcpOldState = m_dhcpSubnetState;
|
|
|
|
m_dhcpSubnetState = pdhcpSubnetInfo->SubnetState;
|
|
|
|
// Tell the scope to update it's state
|
|
DWORD err = SetInfo();
|
|
if (err != 0)
|
|
{
|
|
::DhcpMessageBox(err);
|
|
m_dhcpSubnetState = dhcpOldState;
|
|
}
|
|
else
|
|
{
|
|
pParentNode->SetData(TFS_DATA_IMAGEINDEX, GetImageIndex(FALSE));
|
|
pParentNode->SetData(TFS_DATA_OPENIMAGEINDEX, GetImageIndex(TRUE));
|
|
|
|
// Update the toolbar button
|
|
UpdateToolbarStates();
|
|
SendUpdateToolbar(pParentNode, TRUE);
|
|
|
|
// need to notify the owning superscope to update it's state information
|
|
// this is strictly for UI purposes only.
|
|
if (IsInSuperscope())
|
|
{
|
|
SPITFSNode spSuperscopeNode;
|
|
pParentNode->GetParent(&spSuperscopeNode);
|
|
|
|
CDhcpSuperscope * pSuperscope = GETHANDLER(CDhcpSuperscope, spSuperscopeNode);
|
|
Assert(pSuperscope);
|
|
|
|
pSuperscope->NotifyScopeStateChange(spSuperscopeNode, m_dhcpSubnetState);
|
|
}
|
|
|
|
changeMask = SCOPE_PANE_CHANGE_ITEM;
|
|
}
|
|
}
|
|
|
|
if (pdhcpSubnetInfo)
|
|
::DhcpRpcFreeMemory(pdhcpSubnetInfo);
|
|
|
|
if (changeMask)
|
|
VERIFY(SUCCEEDED(pParentNode->ChangeNode(changeMask)));
|
|
}
|
|
break;
|
|
|
|
case DHCP_QDATA_OPTION_VALUES:
|
|
{
|
|
COptionValueEnum * pOptionValueEnum = reinterpret_cast<COptionValueEnum *>(Data);
|
|
|
|
SetOptionValueEnum(pOptionValueEnum);
|
|
|
|
pOptionValueEnum->RemoveAll();
|
|
delete pOptionValueEnum;
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::OnCreateQuery()
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
ITFSQueryObject*
|
|
CDhcpScope::OnCreateQuery(ITFSNode * pNode)
|
|
{
|
|
CDhcpScopeQueryObj* pQuery =
|
|
new CDhcpScopeQueryObj(m_spTFSCompData, m_spNodeMgr);
|
|
|
|
pQuery->m_strServer = GetServerIpAddress();
|
|
pQuery->m_dhcpScopeAddress = GetAddress();
|
|
|
|
GetServerVersion(pQuery->m_liVersion);
|
|
|
|
return pQuery;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::Execute()
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
STDMETHODIMP
|
|
CDhcpScopeQueryObj::Execute()
|
|
{
|
|
HRESULT hr = hrOK;
|
|
DWORD dwReturn;
|
|
LPDHCP_SUBNET_INFO pdhcpSubnetInfo = NULL;
|
|
DHCP_OPTION_SCOPE_INFO dhcpOptionScopeInfo;
|
|
COptionValueEnum * pOptionValueEnum = NULL;
|
|
|
|
dwReturn = ::DhcpGetSubnetInfo(((LPWSTR) (LPCTSTR)m_strServer),
|
|
m_dhcpScopeAddress,
|
|
&pdhcpSubnetInfo);
|
|
|
|
if (dwReturn == ERROR_SUCCESS && pdhcpSubnetInfo)
|
|
{
|
|
AddToQueue((LPARAM) pdhcpSubnetInfo, DHCP_QDATA_SUBNET_INFO);
|
|
}
|
|
else
|
|
{
|
|
Trace1("CDhcpScopeQueryObj::Execute - DhcpGetSubnetInfo failed! %d\n", dwReturn);
|
|
PostError(dwReturn);
|
|
return hrFalse;
|
|
}
|
|
|
|
// get the option info for this scope
|
|
pOptionValueEnum = new COptionValueEnum();
|
|
|
|
dhcpOptionScopeInfo.ScopeType = DhcpSubnetOptions;
|
|
dhcpOptionScopeInfo.ScopeInfo.SubnetScopeInfo = m_dhcpScopeAddress;
|
|
|
|
pOptionValueEnum->Init(m_strServer, m_liVersion, dhcpOptionScopeInfo);
|
|
dwReturn = pOptionValueEnum->Enum();
|
|
if (dwReturn != ERROR_SUCCESS)
|
|
{
|
|
Trace1("CDhcpScopeQueryObj::Execute - EnumOptions Failed! %d\n", dwReturn);
|
|
m_dwErr = dwReturn;
|
|
PostError(dwReturn);
|
|
|
|
delete pOptionValueEnum;
|
|
}
|
|
else
|
|
{
|
|
pOptionValueEnum->SortById();
|
|
AddToQueue((LPARAM) pOptionValueEnum, DHCP_QDATA_OPTION_VALUES);
|
|
}
|
|
|
|
// now create the scope subcontainers
|
|
CreateSubcontainers();
|
|
|
|
return hrFalse;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::CreateSubcontainers()
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpScopeQueryObj::CreateSubcontainers()
|
|
{
|
|
HRESULT hr = hrOK;
|
|
SPITFSNode spNode;
|
|
|
|
//
|
|
// create the address pool Handler
|
|
//
|
|
CDhcpAddressPool *pAddressPool = new CDhcpAddressPool(m_spTFSCompData);
|
|
CreateContainerTFSNode(&spNode,
|
|
&GUID_DhcpAddressPoolNodeType,
|
|
pAddressPool,
|
|
pAddressPool,
|
|
m_spNodeMgr);
|
|
|
|
// Tell the handler to initialize any specific data
|
|
pAddressPool->InitializeNode((ITFSNode *) spNode);
|
|
|
|
// Add the node as a child to this node
|
|
AddToQueue(spNode);
|
|
pAddressPool->Release();
|
|
|
|
spNode.Set(NULL);
|
|
|
|
//
|
|
// create the Active Leases Handler
|
|
//
|
|
CDhcpActiveLeases *pActiveLeases = new CDhcpActiveLeases(m_spTFSCompData);
|
|
CreateContainerTFSNode(&spNode,
|
|
&GUID_DhcpActiveLeasesNodeType,
|
|
pActiveLeases,
|
|
pActiveLeases,
|
|
m_spNodeMgr);
|
|
|
|
// Tell the handler to initialize any specific data
|
|
pActiveLeases->InitializeNode((ITFSNode *) spNode);
|
|
|
|
// Add the node as a child to this node
|
|
AddToQueue(spNode);
|
|
pActiveLeases->Release();
|
|
|
|
spNode.Set(NULL);
|
|
|
|
//
|
|
// create the reservations Handler
|
|
//
|
|
CDhcpReservations *pReservations = new CDhcpReservations(m_spTFSCompData);
|
|
CreateContainerTFSNode(&spNode,
|
|
&GUID_DhcpReservationsNodeType,
|
|
pReservations,
|
|
pReservations,
|
|
m_spNodeMgr);
|
|
|
|
// Tell the handler to initialize any specific data
|
|
pReservations->InitializeNode((ITFSNode *) spNode);
|
|
|
|
// Add the node as a child to this node
|
|
AddToQueue(spNode);
|
|
pReservations->Release();
|
|
|
|
spNode.Set(NULL);
|
|
|
|
//
|
|
// create the Scope Options Handler
|
|
//
|
|
CDhcpScopeOptions *pScopeOptions = new CDhcpScopeOptions(m_spTFSCompData);
|
|
CreateContainerTFSNode(&spNode,
|
|
&GUID_DhcpScopeOptionsNodeType,
|
|
pScopeOptions,
|
|
pScopeOptions,
|
|
m_spNodeMgr);
|
|
|
|
// Tell the handler to initialize any specific data
|
|
pScopeOptions->InitializeNode((ITFSNode *) spNode);
|
|
|
|
// Add the node as a child to this node
|
|
AddToQueue(spNode);
|
|
pScopeOptions->Release();
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Command handlers
|
|
---------------------------------------------------------------------------*/
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::OnActivateScope
|
|
Message handler for the scope activate/deactivate menu
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CDhcpScope::OnActivateScope
|
|
(
|
|
ITFSNode * pNode
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
DWORD err = 0;
|
|
int nOpenImage, nClosedImage;
|
|
DHCP_SUBNET_STATE dhcpOldState = m_dhcpSubnetState;
|
|
|
|
if ( IsEnabled() )
|
|
{
|
|
// if they want to disable the scope, confirm
|
|
if (AfxMessageBox(IDS_SCOPE_DISABLE_CONFIRM, MB_YESNO) != IDYES)
|
|
{
|
|
return err;
|
|
}
|
|
}
|
|
|
|
SetState(
|
|
IsEnabled()? DhcpSubnetDisabled : DhcpSubnetEnabled );
|
|
|
|
// Tell the scope to update it's state
|
|
err = SetInfo();
|
|
if (err != 0)
|
|
{
|
|
::DhcpMessageBox(err);
|
|
m_dhcpSubnetState = dhcpOldState;
|
|
}
|
|
else
|
|
{
|
|
// update the icon and the status text
|
|
if ( !IsEnabled() )
|
|
{
|
|
nOpenImage = ICON_IDX_SCOPE_INACTIVE_FOLDER_OPEN;
|
|
nClosedImage = ICON_IDX_SCOPE_INACTIVE_FOLDER_CLOSED;
|
|
m_strState.LoadString(IDS_SCOPE_INACTIVE);
|
|
}
|
|
else
|
|
{
|
|
nOpenImage = GetImageIndex(TRUE);
|
|
nClosedImage = GetImageIndex(FALSE);
|
|
m_strState.LoadString(IDS_SCOPE_ACTIVE);
|
|
}
|
|
|
|
pNode->SetData(TFS_DATA_IMAGEINDEX, nClosedImage);
|
|
pNode->SetData(TFS_DATA_OPENIMAGEINDEX, nOpenImage);
|
|
|
|
VERIFY(SUCCEEDED(pNode->ChangeNode(SCOPE_PANE_CHANGE_ITEM)));
|
|
|
|
// Update the toolbar button
|
|
UpdateToolbarStates();
|
|
SendUpdateToolbar(pNode, TRUE);
|
|
|
|
// need to notify the owning superscope to update it's state information
|
|
// this is strictly for UI purposes only.
|
|
if (IsInSuperscope())
|
|
{
|
|
SPITFSNode spSuperscopeNode;
|
|
pNode->GetParent(&spSuperscopeNode);
|
|
|
|
CDhcpSuperscope * pSuperscope = GETHANDLER(CDhcpSuperscope, spSuperscopeNode);
|
|
Assert(pSuperscope);
|
|
|
|
pSuperscope->NotifyScopeStateChange(spSuperscopeNode, m_dhcpSubnetState);
|
|
}
|
|
}
|
|
|
|
TriggerStatsRefresh();
|
|
|
|
return err;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::OnRefreshScope
|
|
Refreshes all of the subnodes of the scope
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpScope::OnRefreshScope
|
|
(
|
|
ITFSNode * pNode,
|
|
LPDATAOBJECT pDataObject,
|
|
DWORD dwType
|
|
)
|
|
{
|
|
HRESULT hr = hrOK;
|
|
|
|
CDhcpReservations * pReservations = GetReservationsObject();
|
|
CDhcpActiveLeases * pActiveLeases = GetActiveLeasesObject();
|
|
CDhcpAddressPool * pAddressPool = GetAddressPoolObject();
|
|
CDhcpScopeOptions * pScopeOptions = GetScopeOptionsObject();
|
|
|
|
Assert(pReservations);
|
|
Assert(pActiveLeases);
|
|
Assert(pAddressPool);
|
|
Assert(pScopeOptions);
|
|
|
|
if (pReservations)
|
|
pReservations->OnRefresh(m_spReservations, pDataObject, dwType, 0, 0);
|
|
|
|
if (pActiveLeases)
|
|
pActiveLeases->OnRefresh(m_spActiveLeases, pDataObject, dwType, 0, 0);
|
|
|
|
if (pAddressPool)
|
|
pAddressPool->OnRefresh(m_spAddressPool, pDataObject, dwType, 0, 0);
|
|
|
|
if (pScopeOptions)
|
|
pScopeOptions->OnRefresh(m_spOptions, pDataObject, dwType, 0, 0);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::OnReconcileScope
|
|
Reconciles the active leases database for this scope
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpScope::OnReconcileScope
|
|
(
|
|
ITFSNode * pNode
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
CReconcileDlg dlgRecon(pNode);
|
|
|
|
dlgRecon.DoModal();
|
|
|
|
return hrOK;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::OnShowScopeStats()
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpScope::OnShowScopeStats
|
|
(
|
|
ITFSNode * pNode
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
HRESULT hr = S_OK;
|
|
CString strScopeAddress;
|
|
|
|
// Fill in some information in the stats object.
|
|
// CreateNewStatisticsWindow handles the case if the window is
|
|
// already visible.
|
|
m_dlgStats.SetNode(pNode);
|
|
m_dlgStats.SetServer(GetServerIpAddress());
|
|
m_dlgStats.SetScope(m_dhcpIpAddress);
|
|
|
|
CreateNewStatisticsWindow(&m_dlgStats,
|
|
::FindMMCMainWindow(),
|
|
IDD_STATS_NARROW);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::OnDelete()
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpScope::OnDelete(ITFSNode * pNode)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
HRESULT hr = S_OK;
|
|
SPITFSNode spServer;
|
|
SPITFSNode spSuperscopeNode;
|
|
int nVisible = 0, nTotal = 0;
|
|
int nResponse;
|
|
|
|
LONG err = 0 ;
|
|
|
|
if (IsInSuperscope())
|
|
{
|
|
pNode->GetParent(&spSuperscopeNode);
|
|
|
|
spSuperscopeNode->GetChildCount(&nVisible, &nTotal);
|
|
}
|
|
|
|
if (nTotal == 1)
|
|
{
|
|
// warn the user that this is the last scope in the superscope
|
|
// and the superscope will be removed.
|
|
nResponse = AfxMessageBox(IDS_DELETE_LAST_SCOPE_FROM_SS, MB_YESNO);
|
|
}
|
|
else
|
|
{
|
|
nResponse = ::DhcpMessageBox( IsEnabled() ?
|
|
IDS_MSG_DELETE_ACTIVE : IDS_MSG_DELETE_SCOPE,
|
|
MB_YESNO | MB_DEFBUTTON2 | MB_ICONQUESTION);
|
|
}
|
|
|
|
if (nResponse == IDYES)
|
|
{
|
|
SPITFSNode spTemp;
|
|
|
|
if (IsInSuperscope())
|
|
{
|
|
// superscope
|
|
spTemp.Set(spSuperscopeNode);
|
|
}
|
|
else
|
|
{
|
|
spTemp.Set(pNode);
|
|
}
|
|
|
|
spTemp->GetParent(&spServer);
|
|
|
|
CDhcpServer * pServer = GETHANDLER(CDhcpServer, spServer);
|
|
err = pServer->DeleteScope(pNode);
|
|
|
|
if (err == ERROR_SUCCESS &&
|
|
nTotal == 1)
|
|
{
|
|
// gotta remove the superscope
|
|
spServer->RemoveChild(spSuperscopeNode);
|
|
}
|
|
}
|
|
|
|
// trigger the statistics to refresh only if we removed this scope
|
|
if (spServer)
|
|
{
|
|
TriggerStatsRefresh();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::OnAddToSuperscope()
|
|
Adds this scope to a superscope
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpScope::OnAddToSuperscope
|
|
(
|
|
ITFSNode * pNode
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
CString strTitle, strAddress;
|
|
UtilCvtIpAddrToWstr(m_dhcpIpAddress, &strAddress);
|
|
|
|
AfxFormatString1(strTitle, IDS_ADD_SCOPE_DLG_TITLE, strAddress);
|
|
|
|
CAddScopeToSuperscope dlgAddScope(pNode, strTitle);
|
|
|
|
dlgAddScope.DoModal();
|
|
|
|
return hrOK;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::OnRemoveFromSuperscope()
|
|
Removes this scope from a superscope
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpScope::OnRemoveFromSuperscope
|
|
(
|
|
ITFSNode * pNode
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
int nVisible, nTotal, nResponse;
|
|
SPITFSNode spSuperscopeNode;
|
|
|
|
pNode->GetParent(&spSuperscopeNode);
|
|
|
|
spSuperscopeNode->GetChildCount(&nVisible, &nTotal);
|
|
if (nTotal == 1)
|
|
{
|
|
// warn the user that this is the last scope in the superscope
|
|
// and the superscope will be removed.
|
|
nResponse = AfxMessageBox(IDS_REMOVE_LAST_SCOPE_FROM_SS, MB_YESNO);
|
|
}
|
|
else
|
|
{
|
|
nResponse = AfxMessageBox(IDS_REMOVE_SCOPE_FROM_SS, MB_YESNO);
|
|
}
|
|
|
|
if (nResponse == IDYES)
|
|
{
|
|
// set the superscope for this scope to be NULL
|
|
// effectively removing it from the scope.
|
|
DWORD dwError = SetSuperscope(NULL, TRUE);
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
::DhcpMessageBox(dwError);
|
|
return hrFalse;
|
|
}
|
|
|
|
// now move the scope out of the supersope in the UI
|
|
spSuperscopeNode->ExtractChild(pNode);
|
|
|
|
// now put the scope node back in at the server level.
|
|
SPITFSNode spServerNode;
|
|
spSuperscopeNode->GetParent(&spServerNode);
|
|
|
|
CDhcpServer * pServer = GETHANDLER(CDhcpServer, spServerNode);
|
|
pServer->AddScopeSorted(spServerNode, pNode);
|
|
|
|
SetInSuperscope(FALSE);
|
|
|
|
if (nTotal == 1)
|
|
{
|
|
// now delete the superscope.
|
|
spServerNode->RemoveChild(spSuperscopeNode);
|
|
}
|
|
}
|
|
|
|
return hrOK;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::UpdateStatistics
|
|
Notification that stats are now available. Update stats for the
|
|
node and give all subnodes a chance to update.
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CDhcpScope::UpdateStatistics
|
|
(
|
|
ITFSNode * pNode
|
|
)
|
|
{
|
|
HRESULT hr = hrOK;
|
|
SPITFSNodeEnum spNodeEnum;
|
|
SPITFSNode spCurrentNode;
|
|
ULONG nNumReturned;
|
|
HWND hStatsWnd;
|
|
BOOL bChangeIcon = FALSE;
|
|
|
|
// Check to see if this node has a stats sheet up.
|
|
hStatsWnd = m_dlgStats.GetSafeHwnd();
|
|
if (hStatsWnd != NULL)
|
|
{
|
|
PostMessage(hStatsWnd, WM_NEW_STATS_AVAILABLE, 0, 0);
|
|
}
|
|
|
|
if (!IsEnabled())
|
|
return hr;
|
|
|
|
// check to see if the image index has changed and only
|
|
// switch it if we have to--this avoids flickering.
|
|
LONG_PTR nOldIndex = pNode->GetData(TFS_DATA_IMAGEINDEX);
|
|
int nNewIndex = GetImageIndex(FALSE);
|
|
|
|
if (nOldIndex != nNewIndex)
|
|
{
|
|
pNode->SetData(TFS_DATA_IMAGEINDEX, GetImageIndex(FALSE));
|
|
pNode->SetData(TFS_DATA_OPENIMAGEINDEX, GetImageIndex(TRUE));
|
|
pNode->ChangeNode(SCOPE_PANE_CHANGE_ITEM_ICON);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Scope manipulation functions
|
|
---------------------------------------------------------------------------*/
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::SetState
|
|
Sets the state for this scope - updates cached information and
|
|
display string
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
void
|
|
CDhcpScope::SetState
|
|
(
|
|
DHCP_SUBNET_STATE dhcpSubnetState
|
|
)
|
|
{
|
|
BOOL fSwitched = FALSE;
|
|
|
|
if( m_dhcpSubnetState != DhcpSubnetEnabled &&
|
|
m_dhcpSubnetState != DhcpSubnetDisabled ) {
|
|
fSwitched = TRUE;
|
|
}
|
|
|
|
if( fSwitched ) {
|
|
if( dhcpSubnetState == DhcpSubnetEnabled ) {
|
|
dhcpSubnetState = DhcpSubnetEnabledSwitched;
|
|
} else {
|
|
dhcpSubnetState = DhcpSubnetDisabledSwitched;
|
|
}
|
|
}
|
|
|
|
m_dhcpSubnetState = dhcpSubnetState;
|
|
|
|
// update the status text
|
|
if ( !IsEnabled() )
|
|
{
|
|
m_strState.LoadString(IDS_SCOPE_INACTIVE);
|
|
}
|
|
else
|
|
{
|
|
m_strState.LoadString(IDS_SCOPE_ACTIVE);
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::CreateReservation
|
|
Creates a reservation for this scope
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CDhcpScope::CreateReservation
|
|
(
|
|
const CDhcpClient * pClient
|
|
)
|
|
{
|
|
SPITFSNode spResClientNode, spActiveLeaseNode;
|
|
DWORD err = 0;
|
|
|
|
//
|
|
// Tell the DHCP server to create this client
|
|
//
|
|
err = CreateClient(pClient);
|
|
if (err != 0)
|
|
return err;
|
|
|
|
//
|
|
// Now that we have this reservation on the server, create the UI object
|
|
// in both the reservation folder and the ActiveLeases folder
|
|
|
|
//
|
|
// create the Reservation client folder
|
|
//
|
|
CDhcpReservations * pRes = GETHANDLER(CDhcpReservations, m_spReservations);
|
|
CDhcpActiveLeases * pActLeases = GETHANDLER(CDhcpActiveLeases, m_spActiveLeases);
|
|
|
|
// only add to the UI if the node is expanded. MMC will fail the call if
|
|
// we try to add a child to a node that hasn't been expanded. If we don't add
|
|
// it now, it will be enumerated when the user selects the node.
|
|
if (pRes->m_bExpanded)
|
|
{
|
|
CDhcpReservationClient * pNewResClient =
|
|
new CDhcpReservationClient(m_spTFSCompData, (CDhcpClient&) *pClient);
|
|
|
|
CreateContainerTFSNode(&spResClientNode,
|
|
&GUID_DhcpReservationClientNodeType,
|
|
pNewResClient,
|
|
pNewResClient,
|
|
m_spNodeMgr);
|
|
|
|
// Tell the handler to initialize any specific data
|
|
pNewResClient->InitializeNode((ITFSNode *) spResClientNode);
|
|
|
|
// Add the node as a child to this node
|
|
CDhcpReservations * pReservations = GETHANDLER(CDhcpReservations, m_spReservations);
|
|
pReservations->AddReservationSorted(m_spReservations, spResClientNode);
|
|
pNewResClient->Release();
|
|
}
|
|
|
|
//
|
|
// Active Lease record
|
|
//
|
|
if (pActLeases->m_bExpanded)
|
|
{
|
|
CDhcpActiveLease * pNewLease =
|
|
new CDhcpActiveLease(m_spTFSCompData, (CDhcpClient&) *pClient);
|
|
|
|
CreateLeafTFSNode(&spActiveLeaseNode,
|
|
&GUID_DhcpActiveLeaseNodeType,
|
|
pNewLease,
|
|
pNewLease,
|
|
m_spNodeMgr);
|
|
|
|
// Tell the handler to initialize any specific data
|
|
pNewLease->InitializeNode((ITFSNode *) spActiveLeaseNode);
|
|
|
|
// Add the node as a child to the Active Leases container
|
|
m_spActiveLeases->AddChild(spActiveLeaseNode);
|
|
pNewLease->Release();
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::UpdateReservation
|
|
Creates a reservation for this scope
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CDhcpScope::UpdateReservation
|
|
(
|
|
const CDhcpClient * pClient,
|
|
COptionValueEnum * pOptionValueEnum
|
|
)
|
|
{
|
|
DWORD err = 0;
|
|
const CByteArray & baHardwareAddress = pClient->QueryHardwareAddress();
|
|
SPITFSNode spResClientNode, spActiveLeaseNode;
|
|
|
|
//
|
|
// To update a reservation we need to remove the old one and update it
|
|
// with the new information. This is mostly for the client type field.
|
|
//
|
|
err = DeleteReservation((CByteArray&) baHardwareAddress,
|
|
pClient->QueryIpAddress());
|
|
|
|
// now add the updated one
|
|
err = AddReservation(pClient);
|
|
if (err != ERROR_SUCCESS)
|
|
return err;
|
|
|
|
// restore the options for this reserved client
|
|
err = RestoreReservationOptions(pClient, pOptionValueEnum);
|
|
if (err != ERROR_SUCCESS)
|
|
return err;
|
|
|
|
// Now update the client info record associated with this.
|
|
err = SetClientInfo(pClient);
|
|
|
|
return err;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::RestoreReservationOptions
|
|
Restores options when updating a reservation becuase the only
|
|
way to update the reservation is to remove it and re-add it.
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CDhcpScope::RestoreReservationOptions
|
|
(
|
|
const CDhcpClient * pClient,
|
|
COptionValueEnum * pOptionValueEnum
|
|
)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
CDhcpOption * pCurOption;
|
|
LARGE_INTEGER liVersion;
|
|
|
|
GetServerVersion(liVersion);
|
|
|
|
// start at the top of the list
|
|
pOptionValueEnum->Reset();
|
|
|
|
// loop through all the options, re-adding them
|
|
while (pCurOption = pOptionValueEnum->Next())
|
|
{
|
|
CDhcpOptionValue optValue = pCurOption->QueryValue();
|
|
DHCP_OPTION_DATA * pOptData;
|
|
|
|
dwErr = optValue.CreateOptionDataStruct(&pOptData);
|
|
if (dwErr != ERROR_SUCCESS)
|
|
break;
|
|
|
|
if ( liVersion.QuadPart >= DHCP_NT5_VERSION )
|
|
{
|
|
LPCTSTR pClassName = pCurOption->IsClassOption() ? pCurOption->GetClassName() : NULL;
|
|
|
|
dwErr = ::DhcpSetOptionValueV5((LPTSTR) GetServerIpAddress(),
|
|
pCurOption->IsVendor() ? DHCP_FLAGS_OPTION_IS_VENDOR : 0,
|
|
pCurOption->QueryId(),
|
|
(LPTSTR) pClassName,
|
|
(LPTSTR) pCurOption->GetVendor(),
|
|
&pOptionValueEnum->m_dhcpOptionScopeInfo,
|
|
pOptData);
|
|
}
|
|
else
|
|
{
|
|
dwErr = ::DhcpSetOptionValue((LPTSTR) GetServerIpAddress(),
|
|
pCurOption->QueryId(),
|
|
&pOptionValueEnum->m_dhcpOptionScopeInfo,
|
|
pOptData);
|
|
}
|
|
|
|
if (dwErr != ERROR_SUCCESS)
|
|
break;
|
|
}
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::AddReservation
|
|
Deletes a reservation
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CDhcpScope::AddReservation
|
|
(
|
|
const CDhcpClient * pClient
|
|
)
|
|
{
|
|
DWORD err = 0 ;
|
|
|
|
DHCP_SUBNET_ELEMENT_DATA_V4 dhcSubElData;
|
|
DHCP_IP_RESERVATION_V4 dhcpIpReservation;
|
|
DHCP_CLIENT_UID dhcpClientUID;
|
|
const CByteArray& baHardwareAddress = pClient->QueryHardwareAddress();
|
|
|
|
dhcpClientUID.DataLength = (DWORD) baHardwareAddress.GetSize();
|
|
dhcpClientUID.Data = (BYTE *) baHardwareAddress.GetData();
|
|
|
|
dhcpIpReservation.ReservedIpAddress = pClient->QueryIpAddress();
|
|
dhcpIpReservation.ReservedForClient = &dhcpClientUID;
|
|
|
|
dhcSubElData.ElementType = DhcpReservedIps;
|
|
dhcSubElData.Element.ReservedIp = &dhcpIpReservation;
|
|
|
|
dhcpIpReservation.bAllowedClientTypes = pClient->QueryClientType();
|
|
|
|
LARGE_INTEGER liVersion;
|
|
GetServerVersion(liVersion);
|
|
|
|
if (liVersion.QuadPart >= DHCP_SP2_VERSION)
|
|
{
|
|
err = AddElementV4( &dhcSubElData );
|
|
}
|
|
else
|
|
{
|
|
err = AddElement( reinterpret_cast<DHCP_SUBNET_ELEMENT_DATA *>(&dhcSubElData) );
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::DeleteReservation
|
|
Deletes a reservation
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CDhcpScope::DeleteReservation
|
|
(
|
|
CByteArray& baHardwareAddress,
|
|
DHCP_IP_ADDRESS dhcpReservedIpAddress
|
|
)
|
|
{
|
|
DHCP_SUBNET_ELEMENT_DATA dhcpSubnetElementData;
|
|
DHCP_IP_RESERVATION dhcpIpReservation;
|
|
DHCP_CLIENT_UID dhcpClientUID;
|
|
|
|
dhcpClientUID.DataLength = (DWORD) baHardwareAddress.GetSize();
|
|
dhcpClientUID.Data = baHardwareAddress.GetData();
|
|
|
|
dhcpIpReservation.ReservedIpAddress = dhcpReservedIpAddress;
|
|
dhcpIpReservation.ReservedForClient = &dhcpClientUID;
|
|
|
|
dhcpSubnetElementData.ElementType = DhcpReservedIps;
|
|
dhcpSubnetElementData.Element.ReservedIp = &dhcpIpReservation;
|
|
|
|
return RemoveElement(&dhcpSubnetElementData, TRUE);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::DeleteReservation
|
|
Deletes a reservation
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CDhcpScope::DeleteReservation
|
|
(
|
|
DHCP_CLIENT_UID &dhcpClientUID,
|
|
DHCP_IP_ADDRESS dhcpReservedIpAddress
|
|
)
|
|
{
|
|
DHCP_SUBNET_ELEMENT_DATA dhcpSubnetElementData;
|
|
DHCP_IP_RESERVATION dhcpIpReservation;
|
|
|
|
dhcpIpReservation.ReservedIpAddress = dhcpReservedIpAddress;
|
|
dhcpIpReservation.ReservedForClient = &dhcpClientUID;
|
|
|
|
dhcpSubnetElementData.ElementType = DhcpReservedIps;
|
|
dhcpSubnetElementData.Element.ReservedIp = &dhcpIpReservation;
|
|
|
|
return RemoveElement(&dhcpSubnetElementData, TRUE);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::GetClientInfo
|
|
Gets a clients detailed information
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CDhcpScope::GetClientInfo
|
|
(
|
|
DHCP_IP_ADDRESS dhcpClientIpAddress,
|
|
LPDHCP_CLIENT_INFO *ppdhcpClientInfo
|
|
)
|
|
{
|
|
DHCP_SEARCH_INFO dhcpSearchInfo;
|
|
|
|
dhcpSearchInfo.SearchType = DhcpClientIpAddress;
|
|
dhcpSearchInfo.SearchInfo.ClientIpAddress = dhcpClientIpAddress;
|
|
|
|
return ::DhcpGetClientInfo(GetServerIpAddress(), &dhcpSearchInfo, ppdhcpClientInfo);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::CreateClient
|
|
CreateClient() creates a reservation for a client. The act
|
|
of adding a new reserved IP address causes the DHCP server
|
|
to create a new client record; we then set the client info
|
|
for this newly created client.
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CDhcpScope::CreateClient
|
|
(
|
|
const CDhcpClient * pClient
|
|
)
|
|
{
|
|
DWORD err = 0;
|
|
|
|
do
|
|
{
|
|
err = AddReservation( pClient );
|
|
if (err != ERROR_SUCCESS)
|
|
break;
|
|
|
|
err = SetClientInfo( pClient );
|
|
}
|
|
while (FALSE);
|
|
|
|
return err;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::SetClientInfo
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CDhcpScope::SetClientInfo
|
|
(
|
|
const CDhcpClient * pClient
|
|
)
|
|
{
|
|
DWORD err = 0 ;
|
|
DHCP_CLIENT_INFO_V4 dhcpClientInfo;
|
|
const CByteArray& baHardwareAddress = pClient->QueryHardwareAddress();
|
|
LARGE_INTEGER liVersion;
|
|
|
|
GetServerVersion(liVersion);
|
|
|
|
dhcpClientInfo.ClientIpAddress = pClient->QueryIpAddress();
|
|
dhcpClientInfo.SubnetMask = pClient->QuerySubnet();
|
|
dhcpClientInfo.ClientHardwareAddress.DataLength = (DWORD) baHardwareAddress.GetSize();
|
|
dhcpClientInfo.ClientHardwareAddress.Data = (BYTE *) baHardwareAddress.GetData();
|
|
dhcpClientInfo.ClientName = (LPTSTR) ((LPCTSTR) pClient->QueryName());
|
|
dhcpClientInfo.ClientComment = (LPTSTR) ((LPCTSTR) pClient->QueryComment());
|
|
dhcpClientInfo.ClientLeaseExpires = pClient->QueryExpiryDateTime();
|
|
dhcpClientInfo.OwnerHost.IpAddress = 0;
|
|
dhcpClientInfo.OwnerHost.HostName = NULL;
|
|
dhcpClientInfo.OwnerHost.NetBiosName = NULL;
|
|
|
|
if (liVersion.QuadPart >= DHCP_SP2_VERSION)
|
|
{
|
|
dhcpClientInfo.bClientType = pClient->QueryClientType();
|
|
|
|
err = ::DhcpSetClientInfoV4(GetServerIpAddress(),
|
|
&dhcpClientInfo);
|
|
}
|
|
else
|
|
{
|
|
err = ::DhcpSetClientInfo(GetServerIpAddress(),
|
|
reinterpret_cast<LPDHCP_CLIENT_INFO>(&dhcpClientInfo));
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::DeleteClient
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CDhcpScope::DeleteClient
|
|
(
|
|
DHCP_IP_ADDRESS dhcpClientIpAddress
|
|
)
|
|
{
|
|
DHCP_SEARCH_INFO dhcpClientInfo;
|
|
|
|
dhcpClientInfo.SearchType = DhcpClientIpAddress;
|
|
dhcpClientInfo.SearchInfo.ClientIpAddress = dhcpClientIpAddress;
|
|
|
|
return ::DhcpDeleteClientInfo((LPWSTR) GetServerIpAddress(),
|
|
&dhcpClientInfo);
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::SetInfo()
|
|
Updates the scope's information
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CDhcpScope::SetInfo()
|
|
{
|
|
DWORD err = 0 ;
|
|
|
|
DHCP_SUBNET_INFO dhcpSubnetInfo;
|
|
|
|
dhcpSubnetInfo.SubnetAddress = m_dhcpIpAddress;
|
|
dhcpSubnetInfo.SubnetMask = m_dhcpSubnetMask;
|
|
dhcpSubnetInfo.SubnetName = (LPTSTR) ((LPCTSTR) m_strName);
|
|
dhcpSubnetInfo.SubnetComment = (LPTSTR) ((LPCTSTR) m_strComment);
|
|
dhcpSubnetInfo.SubnetState = m_dhcpSubnetState;
|
|
|
|
GetServerIpAddress(&dhcpSubnetInfo.PrimaryHost.IpAddress);
|
|
|
|
// Review : ericdav - do we need to fill these in?
|
|
dhcpSubnetInfo.PrimaryHost.NetBiosName = NULL;
|
|
dhcpSubnetInfo.PrimaryHost.HostName = NULL;
|
|
|
|
err = ::DhcpSetSubnetInfo(GetServerIpAddress(),
|
|
m_dhcpIpAddress,
|
|
&dhcpSubnetInfo);
|
|
|
|
return err;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::GetIpRange()
|
|
returns the scope's allocation range. Connects to the server
|
|
to get the information
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CDhcpScope::GetIpRange
|
|
(
|
|
CDhcpIpRange * pdhipr
|
|
)
|
|
{
|
|
BOOL bAlloced = FALSE;
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
|
|
pdhipr->SetAddr(0, TRUE);
|
|
pdhipr->SetAddr(0, FALSE);
|
|
|
|
CDhcpAddressPool * pAddressPool = GetAddressPoolObject();
|
|
|
|
if (pAddressPool == NULL)
|
|
{
|
|
// the address pool folder isn't there yet...
|
|
// Create a temporary one for now...
|
|
pAddressPool = new CDhcpAddressPool(m_spTFSCompData);
|
|
bAlloced = TRUE;
|
|
}
|
|
|
|
// Get a query object from the address pool handler
|
|
CDhcpAddressPoolQueryObj * pQueryObject =
|
|
reinterpret_cast<CDhcpAddressPoolQueryObj *>(pAddressPool->OnCreateQuery(m_spAddressPool));
|
|
|
|
// if we created an address pool handler, then free it up now
|
|
if (bAlloced)
|
|
{
|
|
pQueryObject->m_strServer = GetServerIpAddress();
|
|
pQueryObject->m_dhcpScopeAddress = GetAddress();
|
|
pQueryObject->m_fSupportsDynBootp = GetServerObject()->FSupportsDynBootp();
|
|
pAddressPool->Release();
|
|
}
|
|
|
|
// tell the query object to get the ip ranges
|
|
pQueryObject->EnumerateIpRanges();
|
|
|
|
// check to see if there was any problems getting the information
|
|
dwError = pQueryObject->m_dwError;
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
return dwError;
|
|
}
|
|
|
|
LPQUEUEDATA pQD;
|
|
while (pQD = pQueryObject->RemoveFromQueue())
|
|
{
|
|
Assert (pQD->Type == QDATA_PNODE);
|
|
SPITFSNode p;
|
|
p = reinterpret_cast<ITFSNode *>(pQD->Data);
|
|
delete pQD;
|
|
|
|
CDhcpAllocationRange * pAllocRange = GETHANDLER(CDhcpAllocationRange, p);
|
|
|
|
*pdhipr = *pAllocRange;
|
|
pdhipr->SetRangeType(pAllocRange->GetRangeType());
|
|
|
|
p.Release();
|
|
}
|
|
|
|
pQueryObject->Release();
|
|
|
|
return dwError;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::UpdateIpRange()
|
|
This function updates the IP range on the server. We also need
|
|
to remove any exclusion ranges that fall outside of the new
|
|
allocation range.
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CDhcpScope::UpdateIpRange
|
|
(
|
|
DHCP_IP_RANGE * pdhipr
|
|
)
|
|
{
|
|
return SetIpRange(pdhipr, TRUE);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::QueryIpRange()
|
|
Returns the scope's allocation range (doesn't talk to the server
|
|
directly, only returns internally cached information).
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
void
|
|
CDhcpScope::QueryIpRange
|
|
(
|
|
DHCP_IP_RANGE * pdhipr
|
|
)
|
|
{
|
|
pdhipr->StartAddress = 0;
|
|
pdhipr->EndAddress = 0;
|
|
|
|
SPITFSNodeEnum spNodeEnum;
|
|
SPITFSNode spCurrentNode;
|
|
ULONG nNumReturned = 0;
|
|
|
|
m_spAddressPool->GetEnum(&spNodeEnum);
|
|
|
|
spNodeEnum->Next(1, &spCurrentNode, &nNumReturned);
|
|
while (nNumReturned)
|
|
{
|
|
if (spCurrentNode->GetData(TFS_DATA_TYPE) == DHCPSNAP_ALLOCATION_RANGE)
|
|
{
|
|
// found the address
|
|
//
|
|
CDhcpAllocationRange * pAllocRange = GETHANDLER(CDhcpAllocationRange, spCurrentNode);
|
|
|
|
pdhipr->StartAddress = pAllocRange->QueryAddr(TRUE);
|
|
pdhipr->EndAddress = pAllocRange->QueryAddr(FALSE);
|
|
}
|
|
|
|
spCurrentNode.Release();
|
|
spNodeEnum->Next(1, &spCurrentNode, &nNumReturned);
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::SetIpRange
|
|
Set's the allocation range for this scope
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CDhcpScope::SetIpRange
|
|
(
|
|
DHCP_IP_RANGE * pdhcpIpRange,
|
|
BOOL bUpdateOnServer
|
|
)
|
|
{
|
|
CDhcpIpRange dhcpIpRange = *pdhcpIpRange;
|
|
|
|
return SetIpRange(dhcpIpRange, bUpdateOnServer);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::SetIpRange
|
|
Set's the allocation range for this scope
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CDhcpScope::SetIpRange
|
|
(
|
|
CDhcpIpRange & dhcpIpRange,
|
|
BOOL bUpdateOnServer
|
|
)
|
|
{
|
|
DWORD err = 0;
|
|
|
|
if (bUpdateOnServer)
|
|
{
|
|
DHCP_SUBNET_ELEMENT_DATA dhcSubElData;
|
|
CDhcpIpRange dhipOldRange;
|
|
DHCP_IP_RANGE dhcpTempIpRange;
|
|
|
|
err = GetIpRange(&dhipOldRange);
|
|
if (err != ERROR_SUCCESS)
|
|
{
|
|
return err;
|
|
}
|
|
|
|
dhcpTempIpRange.StartAddress = dhipOldRange.QueryAddr(TRUE);
|
|
dhcpTempIpRange.EndAddress = dhipOldRange.QueryAddr(FALSE);
|
|
|
|
dhcSubElData.ElementType = DhcpIpRanges;
|
|
dhcSubElData.Element.IpRange = &dhcpTempIpRange;
|
|
|
|
//
|
|
// First update the information on the server
|
|
//
|
|
if (dhcpIpRange.GetRangeType() != 0)
|
|
{
|
|
// Dynamic BOOTP stuff...
|
|
DHCP_SUBNET_ELEMENT_DATA_V5 dhcSubElDataV5;
|
|
DHCP_BOOTP_IP_RANGE dhcpNewIpRange = {0};
|
|
|
|
dhcpNewIpRange.StartAddress = dhcpIpRange.QueryAddr(TRUE);
|
|
dhcpNewIpRange.EndAddress = dhcpIpRange.QueryAddr(FALSE);
|
|
dhcpNewIpRange.BootpAllocated = 0;
|
|
|
|
// this field could be set to allow X number of dyn bootp clients from a scope.
|
|
dhcpNewIpRange.MaxBootpAllowed = -1;
|
|
|
|
dhcSubElDataV5.Element.IpRange = &dhcpNewIpRange;
|
|
dhcSubElDataV5.ElementType = (DHCP_SUBNET_ELEMENT_TYPE) dhcpIpRange.GetRangeType();
|
|
|
|
err = AddElementV5(&dhcSubElDataV5);
|
|
if (err != ERROR_SUCCESS)
|
|
{
|
|
DHCP_BOOTP_IP_RANGE dhcpOldIpRange = {0};
|
|
|
|
// something bad happened, try to put the old range back
|
|
dhcpOldIpRange.StartAddress = dhipOldRange.QueryAddr(TRUE);
|
|
dhcpOldIpRange.EndAddress = dhipOldRange.QueryAddr(FALSE);
|
|
|
|
dhcSubElDataV5.Element.IpRange = &dhcpOldIpRange;
|
|
dhcSubElDataV5.ElementType = (DHCP_SUBNET_ELEMENT_TYPE) dhipOldRange.GetRangeType();
|
|
|
|
if (AddElementV5(&dhcSubElDataV5) != ERROR_SUCCESS)
|
|
{
|
|
Trace0("SetIpRange - cannot return ip range back to old state!!");
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Remove the old IP range; allow "not found" error in new scope.
|
|
//
|
|
(void)RemoveElement(&dhcSubElData);
|
|
|
|
DHCP_IP_RANGE dhcpNewIpRange = {0};
|
|
dhcpNewIpRange.StartAddress = dhcpIpRange.QueryAddr(TRUE);
|
|
dhcpNewIpRange.EndAddress = dhcpIpRange.QueryAddr(FALSE);
|
|
|
|
dhcSubElData.Element.IpRange = &dhcpNewIpRange;
|
|
|
|
err = AddElement( & dhcSubElData );
|
|
if (err != ERROR_SUCCESS)
|
|
{
|
|
// something bad happened, try to put the old range back
|
|
dhcpTempIpRange.StartAddress = dhipOldRange.QueryAddr(TRUE);
|
|
dhcpTempIpRange.EndAddress = dhipOldRange.QueryAddr(FALSE);
|
|
|
|
dhcSubElData.Element.IpRange = &dhcpTempIpRange;
|
|
|
|
if (AddElement(&dhcSubElData) != ERROR_SUCCESS)
|
|
{
|
|
Trace0("SetIpRange - cannot return ip range back to old state!!");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Find the address pool folder and update the UI object
|
|
//
|
|
SPITFSNodeEnum spNodeEnum;
|
|
SPITFSNode spCurrentNode;
|
|
ULONG nNumReturned = 0;
|
|
|
|
if (m_spAddressPool == NULL)
|
|
return err;
|
|
|
|
m_spAddressPool->GetEnum(&spNodeEnum);
|
|
|
|
spNodeEnum->Next(1, &spCurrentNode, &nNumReturned);
|
|
while (nNumReturned)
|
|
{
|
|
if (spCurrentNode->GetData(TFS_DATA_TYPE) == DHCPSNAP_ALLOCATION_RANGE)
|
|
{
|
|
// found the address
|
|
//
|
|
CDhcpAllocationRange * pAllocRange = GETHANDLER(CDhcpAllocationRange, spCurrentNode);
|
|
|
|
// now set them
|
|
//
|
|
pAllocRange->SetAddr(dhcpIpRange.QueryAddr(TRUE), TRUE);
|
|
pAllocRange->SetAddr(dhcpIpRange.QueryAddr(FALSE), FALSE);
|
|
|
|
// tell the UI to update
|
|
spCurrentNode->ChangeNode(RESULT_PANE_CHANGE_ITEM_DATA);
|
|
}
|
|
|
|
spCurrentNode.Release();
|
|
spNodeEnum->Next(1, &spCurrentNode, &nNumReturned);
|
|
}
|
|
|
|
return err ;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::IsOverlappingRange
|
|
determines if the exclusion overlaps an existing range
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
BOOL
|
|
CDhcpScope::IsOverlappingRange
|
|
(
|
|
CDhcpIpRange & dhcpIpRange
|
|
)
|
|
{
|
|
SPITFSNodeEnum spNodeEnum;
|
|
SPITFSNode spCurrentNode;
|
|
ULONG nNumReturned = 0;
|
|
BOOL bOverlap = FALSE;
|
|
|
|
m_spActiveLeases->GetEnum(&spNodeEnum);
|
|
|
|
spNodeEnum->Next(1, &spCurrentNode, &nNumReturned);
|
|
while (nNumReturned)
|
|
{
|
|
if (spCurrentNode->GetData(TFS_DATA_TYPE) == DHCPSNAP_EXCLUSION_RANGE)
|
|
{
|
|
// found the address
|
|
//
|
|
CDhcpExclusionRange * pExclusion = GETHANDLER(CDhcpExclusionRange, spCurrentNode);
|
|
|
|
if ( bOverlap = pExclusion->IsOverlap( dhcpIpRange ) )
|
|
{
|
|
spCurrentNode.Release();
|
|
break;
|
|
}
|
|
}
|
|
|
|
spCurrentNode.Release();
|
|
spNodeEnum->Next(1, &spCurrentNode, &nNumReturned);
|
|
}
|
|
|
|
return bOverlap ;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::IsValidExclusion
|
|
determines if the exclusion is valid for this scope
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CDhcpScope::IsValidExclusion
|
|
(
|
|
CDhcpIpRange & dhcpExclusionRange
|
|
)
|
|
{
|
|
DWORD err = 0;
|
|
CDhcpIpRange dhcpScopeRange;
|
|
|
|
err = GetIpRange (&dhcpScopeRange);
|
|
|
|
//
|
|
// Get the data into a range object.
|
|
//
|
|
if ( IsOverlappingRange( dhcpExclusionRange ) )
|
|
{
|
|
//
|
|
// Walk the current list, determining if the new range is valid.
|
|
// Then, if OK, verify that it's really a sub-range of the current range.
|
|
//
|
|
err = IDS_ERR_IP_RANGE_OVERLAP ;
|
|
}
|
|
else if ( ! dhcpExclusionRange.IsSubset( dhcpScopeRange ) )
|
|
{
|
|
//
|
|
// Guarantee that the new range is an (improper) subset of the scope's range
|
|
//
|
|
err = IDS_ERR_IP_RANGE_NOT_SUBSET ;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::StoreExceptionList
|
|
Adds a bunch of exclusions to the scope
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
LONG
|
|
CDhcpScope::StoreExceptionList
|
|
(
|
|
CExclusionList * plistExclusions
|
|
)
|
|
{
|
|
DHCP_SUBNET_ELEMENT_DATA dhcElement ;
|
|
DHCP_IP_RANGE dhipr ;
|
|
CDhcpIpRange * pobIpRange ;
|
|
DWORD err = 0, err1 = 0;
|
|
POSITION pos;
|
|
|
|
pos = plistExclusions->GetHeadPosition();
|
|
while ( pos )
|
|
{
|
|
pobIpRange = plistExclusions->GetNext(pos);
|
|
|
|
err1 = AddExclusion( *pobIpRange ) ;
|
|
if ( err1 != 0 )
|
|
{
|
|
err = err1;
|
|
Trace1("CDhcpScope::StoreExceptionList error adding range %d\n", err);
|
|
}
|
|
}
|
|
|
|
return err ;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::AddExclusion
|
|
Adds an individual exclusion to the server
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CDhcpScope::AddExclusion
|
|
(
|
|
CDhcpIpRange & dhcpIpRange,
|
|
BOOL bAddToUI
|
|
)
|
|
{
|
|
DHCP_SUBNET_ELEMENT_DATA dhcElement ;
|
|
DHCP_IP_RANGE dhipr ;
|
|
DWORD err = 0;
|
|
|
|
dhcElement.ElementType = DhcpExcludedIpRanges ;
|
|
dhipr = dhcpIpRange ;
|
|
dhcElement.Element.ExcludeIpRange = & dhipr ;
|
|
|
|
Trace2("CDhcpScope::AddExclusion add excluded range %lx %lx\n", dhipr.StartAddress, dhipr.EndAddress );
|
|
|
|
err = AddElement( & dhcElement ) ;
|
|
//if ( err != 0 && err != ERROR_DHCP_INVALID_RANGE)
|
|
if ( err != 0 )
|
|
{
|
|
Trace1("CDhcpScope::AddExclusion error removing range %d\n", err);
|
|
}
|
|
|
|
if (m_spAddressPool != NULL)
|
|
{
|
|
CDhcpAddressPool * pAddrPool = GETHANDLER(CDhcpAddressPool, m_spAddressPool);
|
|
|
|
if (!err && bAddToUI && pAddrPool->m_bExpanded)
|
|
{
|
|
SPITFSNode spNewExclusion;
|
|
|
|
CDhcpExclusionRange * pExclusion =
|
|
new CDhcpExclusionRange(m_spTFSCompData, &((DHCP_IP_RANGE) dhcpIpRange));
|
|
|
|
CreateLeafTFSNode(&spNewExclusion,
|
|
&GUID_DhcpExclusionNodeType,
|
|
pExclusion,
|
|
pExclusion,
|
|
m_spNodeMgr);
|
|
|
|
// Tell the handler to initialize any specific data
|
|
pExclusion->InitializeNode((ITFSNode *) spNewExclusion);
|
|
|
|
// Add the node as a child to this node
|
|
m_spAddressPool->AddChild(spNewExclusion);
|
|
pExclusion->Release();
|
|
}
|
|
}
|
|
|
|
TriggerStatsRefresh();
|
|
|
|
return err;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::RemoveExclusion
|
|
Removes and exclusion from the server
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CDhcpScope::RemoveExclusion
|
|
(
|
|
CDhcpIpRange & dhcpIpRange
|
|
)
|
|
{
|
|
DHCP_SUBNET_ELEMENT_DATA dhcElement ;
|
|
DHCP_IP_RANGE dhipr ;
|
|
DWORD err = 0;
|
|
|
|
dhcElement.ElementType = DhcpExcludedIpRanges ;
|
|
dhipr = dhcpIpRange ;
|
|
dhcElement.Element.ExcludeIpRange = & dhipr ;
|
|
|
|
Trace2("CDhcpScope::RemoveExclusion remove excluded range %lx %lx\n", dhipr.StartAddress, dhipr.EndAddress);
|
|
|
|
err = RemoveElement( & dhcElement ) ;
|
|
//if ( err != 0 && err != ERROR_DHCP_INVALID_RANGE)
|
|
if ( err != 0 )
|
|
{
|
|
Trace1("CDhcpScope::RemoveExclusion error removing range %d\n", err);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::GetLeaseTime
|
|
Gets the least time for this scope
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CDhcpScope::GetLeaseTime
|
|
(
|
|
LPDWORD pdwLeaseTime
|
|
)
|
|
{
|
|
//
|
|
// Check option 51 -- the lease duration
|
|
//
|
|
DWORD dwLeaseTime = 0;
|
|
DHCP_OPTION_VALUE * poptValue = NULL;
|
|
DWORD err = GetOptionValue(OPTION_LEASE_DURATION,
|
|
DhcpSubnetOptions,
|
|
&poptValue);
|
|
|
|
if (err != ERROR_SUCCESS)
|
|
{
|
|
Trace0("CDhcpScope::GetLeaseTime - couldn't get lease duration -- \
|
|
this scope may have been created by a pre-release version of the admin tool\n");
|
|
|
|
//
|
|
// The scope doesn't have a lease duration, maybe there's
|
|
// a global option that can come to the rescue here...
|
|
//
|
|
if ((err = GetOptionValue(OPTION_LEASE_DURATION,
|
|
DhcpGlobalOptions,
|
|
&poptValue)) != ERROR_SUCCESS)
|
|
{
|
|
Trace0("CDhcpScope::GetLeaseTime - No global lease duration either -- \
|
|
assuming permanent lease duration\n");
|
|
dwLeaseTime = 0;
|
|
}
|
|
}
|
|
|
|
if (err == ERROR_SUCCESS)
|
|
{
|
|
if (poptValue->Value.Elements != NULL)
|
|
dwLeaseTime = poptValue->Value.Elements[0].Element.DWordOption;
|
|
}
|
|
|
|
if (poptValue)
|
|
::DhcpRpcFreeMemory(poptValue);
|
|
|
|
*pdwLeaseTime = dwLeaseTime;
|
|
return err;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::SetLeaseTime
|
|
Sets the least time for this scope
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CDhcpScope::SetLeaseTime
|
|
(
|
|
DWORD dwLeaseTime
|
|
)
|
|
{
|
|
DWORD err = 0;
|
|
|
|
//
|
|
// Set lease duration (option 51)
|
|
//
|
|
CDhcpOption dhcpOption (OPTION_LEASE_DURATION, DhcpDWordOption , _T(""), _T(""));
|
|
dhcpOption.QueryValue().SetNumber(dwLeaseTime);
|
|
|
|
err = SetOptionValue(&dhcpOption, DhcpSubnetOptions);
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::GetDynBootpLeaseTime
|
|
Gets the least time for this scope
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CDhcpScope::GetDynBootpLeaseTime
|
|
(
|
|
LPDWORD pdwLeaseTime
|
|
)
|
|
{
|
|
//
|
|
// Check option 51 -- the lease duration
|
|
//
|
|
DWORD dwLeaseTime = 0;
|
|
DHCP_OPTION_VALUE * poptValue = NULL;
|
|
|
|
CString strName;
|
|
GetDynBootpClassName(strName);
|
|
|
|
DWORD err = GetOptionValue(OPTION_LEASE_DURATION,
|
|
DhcpSubnetOptions,
|
|
&poptValue,
|
|
0,
|
|
strName,
|
|
NULL);
|
|
|
|
if (err != ERROR_SUCCESS)
|
|
{
|
|
Trace0("CDhcpScope::GetDynBootpLeaseTime - couldn't get lease duration -- \
|
|
this scope may have been created by a pre-release version of the admin tool\n");
|
|
|
|
//
|
|
// The scope doesn't have a lease duration, maybe there's
|
|
// a global option that can come to the rescue here...
|
|
//
|
|
if ((err = GetOptionValue(OPTION_LEASE_DURATION,
|
|
DhcpGlobalOptions,
|
|
&poptValue,
|
|
0,
|
|
strName,
|
|
NULL)) != ERROR_SUCCESS)
|
|
{
|
|
Trace0("CDhcpScope::GetDynBootpLeaseTime - No global lease duration either -- \
|
|
assuming permanent lease duration\n");
|
|
dwLeaseTime = 0;
|
|
}
|
|
}
|
|
|
|
if (err == ERROR_SUCCESS)
|
|
{
|
|
if (poptValue->Value.Elements != NULL)
|
|
dwLeaseTime = poptValue->Value.Elements[0].Element.DWordOption;
|
|
}
|
|
else
|
|
{
|
|
// none specified, using default
|
|
dwLeaseTime = UtilConvertLeaseTime(DYN_BOOTP_DFAULT_LEASE_DAYS,
|
|
DYN_BOOTP_DFAULT_LEASE_HOURS,
|
|
DYN_BOOTP_DFAULT_LEASE_MINUTES);
|
|
}
|
|
|
|
if (poptValue)
|
|
::DhcpRpcFreeMemory(poptValue);
|
|
|
|
*pdwLeaseTime = dwLeaseTime;
|
|
|
|
return err;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::SetDynBootpLeaseTime
|
|
Sets the least time for this scope
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CDhcpScope::SetDynBootpLeaseTime
|
|
(
|
|
DWORD dwLeaseTime
|
|
)
|
|
{
|
|
DWORD err = 0;
|
|
|
|
//
|
|
// Set lease duration (option 51)
|
|
//
|
|
CDhcpOption dhcpOption (OPTION_LEASE_DURATION, DhcpDWordOption , _T(""), _T(""));
|
|
dhcpOption.QueryValue().SetNumber(dwLeaseTime);
|
|
|
|
CString strName;
|
|
GetDynBootpClassName(strName);
|
|
err = SetOptionValue(&dhcpOption, DhcpSubnetOptions, 0, strName, NULL);
|
|
|
|
return err;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::GetDynBootpClassName
|
|
returns the user class name to be used to set the lease time
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
void
|
|
CDhcpScope::GetDynBootpClassName(CString & strName)
|
|
{
|
|
// use DHCP_BOOTP_CLASS_TXT as the class data to search for
|
|
CClassInfoArray classInfoArray;
|
|
|
|
GetServerObject()->GetClassInfoArray(classInfoArray);
|
|
|
|
for (int i = 0; i < classInfoArray.GetSize(); i++)
|
|
{
|
|
// check to make sure same size
|
|
if (classInfoArray[i].IsDynBootpClass())
|
|
{
|
|
// found it!
|
|
strName = classInfoArray[i].strName;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
DWORD
|
|
CDhcpScope::SetDynamicBootpInfo(UINT uRangeType, DWORD dwLeaseTime)
|
|
{
|
|
DWORD dwErr = 0;
|
|
|
|
// set the range type
|
|
CDhcpIpRange dhcpIpRange;
|
|
GetIpRange(&dhcpIpRange);
|
|
|
|
dhcpIpRange.SetRangeType(uRangeType);
|
|
|
|
// this updates the type
|
|
dwErr = SetIpRange(dhcpIpRange, TRUE);
|
|
if (dwErr != ERROR_SUCCESS)
|
|
return dwErr;
|
|
|
|
// set the lease time
|
|
dwErr = SetDynBootpLeaseTime(dwLeaseTime);
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::GetDnsRegistration
|
|
Gets the DNS registration option value
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CDhcpScope::GetDnsRegistration
|
|
(
|
|
LPDWORD pDnsRegOption
|
|
)
|
|
{
|
|
//
|
|
// Check option 81 -- the DNS registration option
|
|
//
|
|
DHCP_OPTION_VALUE * poptValue = NULL;
|
|
DWORD err = GetOptionValue(OPTION_DNS_REGISTATION,
|
|
DhcpSubnetOptions,
|
|
&poptValue);
|
|
|
|
// this is the default
|
|
if (pDnsRegOption)
|
|
*pDnsRegOption = DHCP_DYN_DNS_DEFAULT;
|
|
|
|
if (err == ERROR_SUCCESS)
|
|
{
|
|
if ((poptValue->Value.Elements != NULL) &&
|
|
(pDnsRegOption))
|
|
{
|
|
*pDnsRegOption = poptValue->Value.Elements[0].Element.DWordOption;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Trace0("CDhcpScope::GetDnsRegistration - couldn't get DNS reg value, option may not be defined, Getting Server value.\n");
|
|
|
|
CDhcpServer * pServer = GETHANDLER(CDhcpServer, m_spServerNode);
|
|
|
|
err = pServer->GetDnsRegistration(pDnsRegOption);
|
|
}
|
|
|
|
if (poptValue)
|
|
::DhcpRpcFreeMemory(poptValue);
|
|
|
|
return err;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::SetDnsRegistration
|
|
Sets the DNS Registration option for this scope
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CDhcpScope::SetDnsRegistration
|
|
(
|
|
DWORD DnsRegOption
|
|
)
|
|
{
|
|
DWORD err = 0;
|
|
|
|
//
|
|
// Set DNS name registration (option 81)
|
|
//
|
|
CDhcpOption dhcpOption (OPTION_DNS_REGISTATION, DhcpDWordOption , _T(""), _T(""));
|
|
dhcpOption.QueryValue().SetNumber(DnsRegOption);
|
|
|
|
err = SetOptionValue(&dhcpOption, DhcpSubnetOptions);
|
|
|
|
return err;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::SetOptionValue
|
|
Sets the least time for this scope
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CDhcpScope::SetOptionValue
|
|
(
|
|
CDhcpOption * pdhcType,
|
|
DHCP_OPTION_SCOPE_TYPE dhcOptType,
|
|
DHCP_IP_ADDRESS dhipaReservation,
|
|
LPCTSTR pClassName,
|
|
LPCTSTR pVendorName
|
|
)
|
|
{
|
|
DWORD err = 0;
|
|
DHCP_OPTION_DATA * pdhcOptionData;
|
|
DHCP_OPTION_SCOPE_INFO dhcScopeInfo;
|
|
CDhcpOptionValue * pcOptionValue = NULL;
|
|
|
|
ZeroMemory( & dhcScopeInfo, sizeof(dhcScopeInfo) );
|
|
|
|
CATCH_MEM_EXCEPTION
|
|
{
|
|
pcOptionValue = new CDhcpOptionValue( & pdhcType->QueryValue() ) ;
|
|
|
|
//if ( (err = pcOptionValue->QueryError()) == 0 )
|
|
if ( pcOptionValue )
|
|
{
|
|
dhcScopeInfo.ScopeType = dhcOptType ;
|
|
|
|
//
|
|
// Provide the sub-net address if this is a scope-level operation
|
|
//
|
|
if ( dhcOptType == DhcpSubnetOptions )
|
|
{
|
|
dhcScopeInfo.ScopeInfo.SubnetScopeInfo = m_dhcpIpAddress;
|
|
}
|
|
else if ( dhcOptType == DhcpReservedOptions )
|
|
{
|
|
dhcScopeInfo.ScopeInfo.ReservedScopeInfo.ReservedIpAddress = dhipaReservation;
|
|
dhcScopeInfo.ScopeInfo.ReservedScopeInfo.ReservedIpSubnetAddress = m_dhcpIpAddress;
|
|
}
|
|
|
|
pcOptionValue->CreateOptionDataStruct(&pdhcOptionData, TRUE);
|
|
|
|
if (pClassName || pVendorName)
|
|
{
|
|
err = (DWORD) ::DhcpSetOptionValueV5((LPTSTR) GetServerIpAddress(),
|
|
0,
|
|
pdhcType->QueryId(),
|
|
(LPTSTR) pClassName,
|
|
(LPTSTR) pVendorName,
|
|
&dhcScopeInfo,
|
|
pdhcOptionData);
|
|
}
|
|
else
|
|
{
|
|
err = (DWORD) ::DhcpSetOptionValue(GetServerIpAddress(),
|
|
pdhcType->QueryId(),
|
|
&dhcScopeInfo,
|
|
pdhcOptionData);
|
|
}
|
|
}
|
|
}
|
|
END_MEM_EXCEPTION(err) ;
|
|
|
|
delete pcOptionValue ;
|
|
return err ;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::GetValue
|
|
Gets an option value for this scope
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CDhcpScope::GetOptionValue
|
|
(
|
|
DHCP_OPTION_ID OptionID,
|
|
DHCP_OPTION_SCOPE_TYPE dhcOptType,
|
|
DHCP_OPTION_VALUE ** ppdhcOptionValue,
|
|
DHCP_IP_ADDRESS dhipaReservation,
|
|
LPCTSTR pClassName,
|
|
LPCTSTR pVendorName
|
|
)
|
|
{
|
|
DWORD err = 0 ;
|
|
|
|
DHCP_OPTION_SCOPE_INFO dhcScopeInfo ;
|
|
|
|
ZeroMemory( &dhcScopeInfo, sizeof(dhcScopeInfo) );
|
|
|
|
CATCH_MEM_EXCEPTION
|
|
{
|
|
dhcScopeInfo.ScopeType = dhcOptType ;
|
|
|
|
//
|
|
// Provide the sub-net address if this is a scope-level operation
|
|
//
|
|
if ( dhcOptType == DhcpSubnetOptions )
|
|
{
|
|
dhcScopeInfo.ScopeInfo.SubnetScopeInfo = m_dhcpIpAddress;
|
|
}
|
|
else if ( dhcOptType == DhcpReservedOptions )
|
|
{
|
|
dhcScopeInfo.ScopeInfo.ReservedScopeInfo.ReservedIpAddress = dhipaReservation;
|
|
dhcScopeInfo.ScopeInfo.ReservedScopeInfo.ReservedIpSubnetAddress = m_dhcpIpAddress;
|
|
}
|
|
|
|
if (pClassName || pVendorName)
|
|
{
|
|
err = (DWORD) ::DhcpGetOptionValueV5((LPTSTR) GetServerIpAddress(),
|
|
0,
|
|
OptionID,
|
|
(LPTSTR) pClassName,
|
|
(LPTSTR) pVendorName,
|
|
&dhcScopeInfo,
|
|
ppdhcOptionValue );
|
|
}
|
|
else
|
|
{
|
|
err = (DWORD) ::DhcpGetOptionValue(GetServerIpAddress(),
|
|
OptionID,
|
|
&dhcScopeInfo,
|
|
ppdhcOptionValue );
|
|
}
|
|
|
|
}
|
|
END_MEM_EXCEPTION(err) ;
|
|
|
|
return err ;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::RemoveValue
|
|
Removes an option
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CDhcpScope::RemoveOptionValue
|
|
(
|
|
DHCP_OPTION_ID dhcOptId,
|
|
DHCP_OPTION_SCOPE_TYPE dhcOptType,
|
|
DHCP_IP_ADDRESS dhipaReservation
|
|
)
|
|
{
|
|
DHCP_OPTION_SCOPE_INFO dhcScopeInfo;
|
|
|
|
ZeroMemory( &dhcScopeInfo, sizeof(dhcScopeInfo) );
|
|
|
|
dhcScopeInfo.ScopeType = dhcOptType;
|
|
|
|
//
|
|
// Provide the sub-net address if this is a scope-level operation
|
|
//
|
|
if ( dhcOptType == DhcpSubnetOptions )
|
|
{
|
|
dhcScopeInfo.ScopeInfo.SubnetScopeInfo = m_dhcpIpAddress;
|
|
}
|
|
else if ( dhcOptType == DhcpReservedOptions )
|
|
{
|
|
dhcScopeInfo.ScopeInfo.ReservedScopeInfo.ReservedIpAddress = dhipaReservation;
|
|
dhcScopeInfo.ScopeInfo.ReservedScopeInfo.ReservedIpSubnetAddress = m_dhcpIpAddress;
|
|
}
|
|
|
|
return (DWORD) ::DhcpRemoveOptionValue(GetServerIpAddress(),
|
|
dhcOptId,
|
|
&dhcScopeInfo);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::AddElement
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CDhcpScope::AddElement
|
|
(
|
|
DHCP_SUBNET_ELEMENT_DATA * pdhcpSubnetElementData
|
|
)
|
|
{
|
|
return ::DhcpAddSubnetElement(GetServerIpAddress(),
|
|
m_dhcpIpAddress,
|
|
pdhcpSubnetElementData);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::RemoveElement
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CDhcpScope::RemoveElement
|
|
(
|
|
DHCP_SUBNET_ELEMENT_DATA * pdhcpSubnetElementData,
|
|
BOOL bForce
|
|
)
|
|
{
|
|
return ::DhcpRemoveSubnetElement(GetServerIpAddress(),
|
|
m_dhcpIpAddress,
|
|
pdhcpSubnetElementData,
|
|
bForce ? DhcpFullForce : DhcpNoForce);
|
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::AddElementV4
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CDhcpScope::AddElementV4
|
|
(
|
|
DHCP_SUBNET_ELEMENT_DATA_V4 * pdhcpSubnetElementData
|
|
)
|
|
{
|
|
return ::DhcpAddSubnetElementV4(GetServerIpAddress(),
|
|
m_dhcpIpAddress,
|
|
pdhcpSubnetElementData);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::RemoveElementV4
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CDhcpScope::RemoveElementV4
|
|
(
|
|
DHCP_SUBNET_ELEMENT_DATA_V4 * pdhcpSubnetElementData,
|
|
BOOL bForce
|
|
)
|
|
{
|
|
return ::DhcpRemoveSubnetElementV4(GetServerIpAddress(),
|
|
m_dhcpIpAddress,
|
|
pdhcpSubnetElementData,
|
|
bForce ? DhcpFullForce : DhcpNoForce);
|
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::AddElementV5
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CDhcpScope::AddElementV5
|
|
(
|
|
DHCP_SUBNET_ELEMENT_DATA_V5 * pdhcpSubnetElementData
|
|
)
|
|
{
|
|
return ::DhcpAddSubnetElementV5(GetServerIpAddress(),
|
|
m_dhcpIpAddress,
|
|
pdhcpSubnetElementData);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::RemoveElementV5
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CDhcpScope::RemoveElementV5
|
|
(
|
|
DHCP_SUBNET_ELEMENT_DATA_V5 * pdhcpSubnetElementData,
|
|
BOOL bForce
|
|
)
|
|
{
|
|
return ::DhcpRemoveSubnetElementV5(GetServerIpAddress(),
|
|
m_dhcpIpAddress,
|
|
pdhcpSubnetElementData,
|
|
bForce ? DhcpFullForce : DhcpNoForce);
|
|
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::GetServerIpAddress()
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
LPCWSTR
|
|
CDhcpScope::GetServerIpAddress()
|
|
{
|
|
CDhcpServer * pServer = GetServerObject();
|
|
|
|
return pServer->GetIpAddress();
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::GetServerIpAddress
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
void
|
|
CDhcpScope::GetServerIpAddress(DHCP_IP_ADDRESS * pdhcpIpAddress)
|
|
{
|
|
CDhcpServer * pServer = GetServerObject();
|
|
|
|
pServer->GetIpAddress(pdhcpIpAddress);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::GetServerVersion
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
void
|
|
CDhcpScope::GetServerVersion
|
|
(
|
|
LARGE_INTEGER& liVersion
|
|
)
|
|
{
|
|
CDhcpServer * pServer = GetServerObject();
|
|
pServer->GetVersion(liVersion);
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::SetSuperscope
|
|
Sets this scope as part of the given superscope name
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CDhcpScope::SetSuperscope
|
|
(
|
|
LPCTSTR pSuperscopeName,
|
|
BOOL bRemove
|
|
)
|
|
{
|
|
DWORD dwReturn = 0;
|
|
|
|
dwReturn = ::DhcpSetSuperScopeV4(GetServerIpAddress(),
|
|
GetAddress(),
|
|
(LPWSTR) pSuperscopeName,
|
|
bRemove);
|
|
|
|
if (dwReturn != ERROR_SUCCESS)
|
|
{
|
|
Trace1("CDhcpScope::SetSuperscope - DhcpSetSuperScopeV4 failed!! %d\n", dwReturn);
|
|
}
|
|
|
|
return dwReturn;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Helper functions
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpScope::BuildDisplayName
|
|
(
|
|
CString * pstrDisplayName,
|
|
LPCTSTR pIpAddress,
|
|
LPCTSTR pName
|
|
)
|
|
{
|
|
if (pstrDisplayName)
|
|
{
|
|
CString strStandard, strIpAddress, strName;
|
|
|
|
strIpAddress = pIpAddress;
|
|
strName = pName;
|
|
|
|
strStandard.LoadString(IDS_SCOPE_FOLDER);
|
|
|
|
*pstrDisplayName = strStandard + L" [" + strIpAddress + L"] " + strName;
|
|
}
|
|
|
|
return hrOK;
|
|
}
|
|
|
|
HRESULT
|
|
CDhcpScope::SetName
|
|
(
|
|
LPCWSTR pName
|
|
)
|
|
{
|
|
if (pName != NULL)
|
|
{
|
|
m_strName = pName;
|
|
}
|
|
|
|
CString strIpAddress, strDisplayName;
|
|
|
|
//
|
|
// Create the display name for this scope
|
|
// Convert DHCP_IP_ADDRES to a string and initialize this object
|
|
//
|
|
UtilCvtIpAddrToWstr (m_dhcpIpAddress,
|
|
&strIpAddress);
|
|
|
|
BuildDisplayName(&strDisplayName, strIpAddress, pName);
|
|
|
|
SetDisplayName(strDisplayName);
|
|
|
|
return hrOK;
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::GetAddressPoolObject()
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
CDhcpAddressPool *
|
|
CDhcpScope::GetAddressPoolObject()
|
|
{
|
|
if (m_spAddressPool)
|
|
return GETHANDLER(CDhcpAddressPool, m_spAddressPool);
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::GetReservationsObject()
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
CDhcpReservations *
|
|
CDhcpScope::GetReservationsObject()
|
|
{
|
|
if ( m_spReservations )
|
|
return GETHANDLER(CDhcpReservations, m_spReservations);
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::GetReservationsObject()
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
CDhcpActiveLeases *
|
|
CDhcpScope::GetActiveLeasesObject()
|
|
{
|
|
if (m_spActiveLeases)
|
|
return GETHANDLER(CDhcpActiveLeases, m_spActiveLeases);
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::GetScopeOptionsContainer()
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
CDhcpScopeOptions *
|
|
CDhcpScope::GetScopeOptionsObject()
|
|
{
|
|
if (m_spOptions)
|
|
return GETHANDLER(CDhcpScopeOptions, m_spOptions);
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScope::TriggerStatsRefresh()
|
|
Calls into the server object to update the stats
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpScope::TriggerStatsRefresh()
|
|
{
|
|
GetServerObject()->TriggerStatsRefresh(m_spServerNode);
|
|
|
|
return hrOK;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpReservations Implementation
|
|
---------------------------------------------------------------------------*/
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpReservations::CDhcpReservations()
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
CDhcpReservations::CDhcpReservations
|
|
(
|
|
ITFSComponentData * pComponentData
|
|
) : CMTDhcpHandler(pComponentData)
|
|
{
|
|
}
|
|
|
|
//
|
|
// copy all the resrved ips to an array and qsort it
|
|
// when matching an entry that is read from dhcp db
|
|
// we can do a binary search on the qsorted array
|
|
// a better algorithm for large n ( n number of active clients ) is to
|
|
// go through the active clients once for each m ( reserved ip ) where m >
|
|
// 100 but << n
|
|
|
|
BOOL
|
|
CDhcpReservationsQueryObj::AddReservedIPsToArray( )
|
|
{
|
|
|
|
DHCP_RESUME_HANDLE dhcpResumeHandle = NULL;
|
|
DWORD dwElementsRead = 0, dwElementsTotal = 0, dwTotalRead = 0;
|
|
DWORD dwError = ERROR_MORE_DATA;
|
|
DWORD dwResvThreshold = 100;
|
|
|
|
m_resvMap.RemoveAll();
|
|
m_subnetElements = NULL;
|
|
|
|
while (dwError == ERROR_MORE_DATA)
|
|
{
|
|
|
|
dwError = ::DhcpEnumSubnetElementsV4(((LPWSTR) (LPCTSTR)m_strServer),
|
|
m_dhcpScopeAddress,
|
|
DhcpReservedIps,
|
|
&dhcpResumeHandle,
|
|
-1,
|
|
&m_subnetElements,
|
|
&dwElementsRead,
|
|
&dwElementsTotal);
|
|
|
|
Trace3("BuildReservationList: Scope %lx Reservations read %d, total %d\n", m_dhcpScopeAddress, dwElementsRead, dwElementsTotal );
|
|
|
|
//
|
|
// If number of reservations is less than 100 handle it the old way
|
|
//
|
|
|
|
if ( dwElementsTotal <= dwResvThreshold )
|
|
{
|
|
m_totalResvs = dwElementsTotal;
|
|
return( FALSE );
|
|
}
|
|
|
|
if (dwElementsRead && dwElementsTotal && m_subnetElements )
|
|
{
|
|
|
|
//
|
|
// Loop through the array that was returned
|
|
//
|
|
|
|
|
|
for (DWORD i = 0; i < m_subnetElements->NumElements; i++)
|
|
{
|
|
m_resvMap.SetAt( m_subnetElements->Elements[i].Element.ReservedIp->ReservedIpAddress,
|
|
&m_subnetElements->Elements[ i ]);
|
|
}
|
|
|
|
dwTotalRead += dwElementsRead;
|
|
if ( dwTotalRead <= dwElementsTotal )
|
|
{
|
|
m_totalResvs = dwTotalRead;
|
|
}
|
|
else
|
|
{
|
|
m_totalResvs = dwElementsTotal;
|
|
}
|
|
}
|
|
|
|
} // while
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
CDhcpReservations::~CDhcpReservations()
|
|
{
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CDhcpReservations::InitializeNode
|
|
Initializes node specific data
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpReservations::InitializeNode
|
|
(
|
|
ITFSNode * pNode
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
HRESULT hr = hrOK;
|
|
|
|
//
|
|
// Create the display name for this scope
|
|
//
|
|
CString strTemp;
|
|
strTemp.LoadString(IDS_RESERVATIONS_FOLDER);
|
|
|
|
SetDisplayName(strTemp);
|
|
|
|
// Make the node immediately visible
|
|
pNode->SetVisibilityState(TFS_VIS_SHOW);
|
|
pNode->SetData(TFS_DATA_IMAGEINDEX, GetImageIndex(FALSE));
|
|
pNode->SetData(TFS_DATA_OPENIMAGEINDEX, GetImageIndex(TRUE));
|
|
pNode->SetData(TFS_DATA_COOKIE, (LPARAM) pNode);
|
|
pNode->SetData(TFS_DATA_USER, (LPARAM) this);
|
|
pNode->SetData(TFS_DATA_TYPE, DHCPSNAP_RESERVATIONS);
|
|
|
|
SetColumnStringIDs(&aColumns[DHCPSNAP_RESERVATIONS][0]);
|
|
SetColumnWidths(&aColumnWidths[DHCPSNAP_RESERVATIONS][0]);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpReservations::OnCreateNodeId2
|
|
Returns a unique string for this node
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT CDhcpReservations::OnCreateNodeId2(ITFSNode * pNode, CString & strId, DWORD * dwFlags)
|
|
{
|
|
const GUID * pGuid = pNode->GetNodeType();
|
|
|
|
CString strIpAddress, strGuid;
|
|
|
|
StringFromGUID2(*pGuid, strGuid.GetBuffer(256), 256);
|
|
strGuid.ReleaseBuffer();
|
|
|
|
DHCP_IP_ADDRESS dhcpIpAddress = GetScopeObject(pNode)->GetAddress();
|
|
|
|
UtilCvtIpAddrToWstr (dhcpIpAddress, &strIpAddress);
|
|
|
|
strId = GetServerName(pNode) + strIpAddress + strGuid;
|
|
|
|
return hrOK;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpReservations::GetImageIndex
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
int
|
|
CDhcpReservations::GetImageIndex(BOOL bOpenImage)
|
|
{
|
|
int nIndex = -1;
|
|
switch (m_nState)
|
|
{
|
|
case notLoaded:
|
|
case loaded:
|
|
if (bOpenImage)
|
|
nIndex = ICON_IDX_RESERVATIONS_FOLDER_OPEN;
|
|
else
|
|
nIndex = ICON_IDX_RESERVATIONS_FOLDER_CLOSED;
|
|
break;
|
|
|
|
case loading:
|
|
if (bOpenImage)
|
|
nIndex = ICON_IDX_RESERVATIONS_FOLDER_OPEN_BUSY;
|
|
else
|
|
nIndex = ICON_IDX_RESERVATIONS_FOLDER_CLOSED_BUSY;
|
|
break;
|
|
|
|
case unableToLoad:
|
|
if (bOpenImage)
|
|
nIndex = ICON_IDX_RESERVATIONS_FOLDER_OPEN_LOST_CONNECTION;
|
|
else
|
|
nIndex = ICON_IDX_RESERVATIONS_FOLDER_CLOSED_LOST_CONNECTION;
|
|
break;
|
|
|
|
default:
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
return nIndex;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CDhcpReservations::RemoveReservationFromUI
|
|
Initializes node specific data
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CDhcpReservations::RemoveReservationFromUI
|
|
(
|
|
ITFSNode * pReservationsNode,
|
|
DHCP_IP_ADDRESS dhcpReservationIp
|
|
)
|
|
{
|
|
DWORD dwError = E_UNEXPECTED;
|
|
CDhcpReservationClient * pReservationClient = NULL;
|
|
SPITFSNodeEnum spNodeEnum;
|
|
SPITFSNode spCurrentNode;
|
|
ULONG nNumReturned = 0;
|
|
|
|
pReservationsNode->GetEnum(&spNodeEnum);
|
|
|
|
spNodeEnum->Next(1, &spCurrentNode, &nNumReturned);
|
|
while (nNumReturned)
|
|
{
|
|
pReservationClient = GETHANDLER(CDhcpReservationClient, spCurrentNode);
|
|
|
|
if (dhcpReservationIp == pReservationClient->GetIpAddress())
|
|
{
|
|
//
|
|
// Tell this reservation to delete itself
|
|
//
|
|
pReservationsNode->RemoveChild(spCurrentNode);
|
|
spCurrentNode.Release();
|
|
dwError = ERROR_SUCCESS;
|
|
|
|
break;
|
|
}
|
|
|
|
spCurrentNode.Release();
|
|
spNodeEnum->Next(1, &spCurrentNode, &nNumReturned);
|
|
}
|
|
|
|
return dwError;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Overridden base handler functions
|
|
---------------------------------------------------------------------------*/
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpReservations::OnAddMenuItems
|
|
Adds entries to the context sensitive menu
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
STDMETHODIMP
|
|
CDhcpReservations::OnAddMenuItems
|
|
(
|
|
ITFSNode * pNode,
|
|
LPCONTEXTMENUCALLBACK pContextMenuCallback,
|
|
LPDATAOBJECT lpDataObject,
|
|
DATA_OBJECT_TYPES type,
|
|
DWORD dwType,
|
|
long * pInsertionAllowed
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
LONG fFlags = 0;
|
|
HRESULT hr = S_OK;
|
|
CString strMenuText;
|
|
|
|
if ( (m_nState != loaded) )
|
|
{
|
|
fFlags |= MF_GRAYED;
|
|
}
|
|
|
|
if (type == CCT_SCOPE)
|
|
{
|
|
if (*pInsertionAllowed & CCM_INSERTIONALLOWED_TOP)
|
|
{
|
|
// these menu items go in the new menu,
|
|
// only visible from scope pane
|
|
strMenuText.LoadString(IDS_CREATE_NEW_RESERVATION);
|
|
hr = LoadAndAddMenuItem( pContextMenuCallback,
|
|
strMenuText,
|
|
IDS_CREATE_NEW_RESERVATION,
|
|
CCM_INSERTIONPOINTID_PRIMARY_TOP,
|
|
fFlags );
|
|
ASSERT( SUCCEEDED(hr) );
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpReservations::OnCommand
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
STDMETHODIMP
|
|
CDhcpReservations::OnCommand
|
|
(
|
|
ITFSNode * pNode,
|
|
long nCommandId,
|
|
DATA_OBJECT_TYPES type,
|
|
LPDATAOBJECT pDataObject,
|
|
DWORD dwType
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
switch (nCommandId)
|
|
{
|
|
case IDS_CREATE_NEW_RESERVATION:
|
|
OnCreateNewReservation(pNode);
|
|
break;
|
|
|
|
case IDS_REFRESH:
|
|
OnRefresh(pNode, pDataObject, dwType, 0, 0);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpReservations::CompareItems
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
STDMETHODIMP_(int)
|
|
CDhcpReservations::CompareItems
|
|
(
|
|
ITFSComponent * pComponent,
|
|
MMC_COOKIE cookieA,
|
|
MMC_COOKIE cookieB,
|
|
int nCol
|
|
)
|
|
{
|
|
SPITFSNode spNode1, spNode2;
|
|
|
|
m_spNodeMgr->FindNode(cookieA, &spNode1);
|
|
m_spNodeMgr->FindNode(cookieB, &spNode2);
|
|
|
|
int nCompare = 0;
|
|
|
|
CDhcpReservationClient *pDhcpRC1 = GETHANDLER(CDhcpReservationClient, spNode1);
|
|
CDhcpReservationClient *pDhcpRC2 = GETHANDLER(CDhcpReservationClient, spNode2);
|
|
|
|
switch (nCol)
|
|
{
|
|
case 0:
|
|
{
|
|
// IP address compare
|
|
//
|
|
DHCP_IP_ADDRESS dhcpIp1 = pDhcpRC1->GetIpAddress();
|
|
DHCP_IP_ADDRESS dhcpIp2 = pDhcpRC2->GetIpAddress();
|
|
|
|
if (dhcpIp1 < dhcpIp2)
|
|
nCompare = -1;
|
|
else
|
|
if (dhcpIp1 > dhcpIp2)
|
|
nCompare = 1;
|
|
|
|
// default is that they are equal
|
|
}
|
|
break;
|
|
}
|
|
|
|
return nCompare;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CDhcpReservations::OnGetResultViewType
|
|
MMC calls this to get the result view information
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpReservations::OnGetResultViewType
|
|
(
|
|
ITFSComponent * pComponent,
|
|
MMC_COOKIE cookie,
|
|
LPOLESTR * ppViewType,
|
|
long * pViewOptions
|
|
)
|
|
{
|
|
HRESULT hr = hrOK;
|
|
|
|
// call the base class to see if it is handling this
|
|
if (CMTDhcpHandler::OnGetResultViewType(pComponent, cookie, ppViewType, pViewOptions) != S_OK)
|
|
{
|
|
*pViewOptions = MMC_VIEW_OPTIONS_MULTISELECT;
|
|
hr = S_FALSE;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CDhcpReservations::OnResultSelect
|
|
Update the verbs and the result pane message
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT CDhcpReservations::OnResultSelect(ITFSComponent *pComponent, LPDATAOBJECT pDataObject, MMC_COOKIE cookie, LPARAM arg, LPARAM lParam)
|
|
{
|
|
HRESULT hr = hrOK;
|
|
SPITFSNode spNode;
|
|
|
|
CORg(CMTDhcpHandler::OnResultSelect(pComponent, pDataObject, cookie, arg, lParam));
|
|
|
|
CORg (pComponent->GetSelectedNode(&spNode));
|
|
|
|
if ( spNode != 0 ) {
|
|
UpdateResultMessage(spNode);
|
|
}
|
|
|
|
Error:
|
|
return hr;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CDhcpReservations::UpdateResultMessage
|
|
Figures out what message to put in the result pane, if any
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
void CDhcpReservations::UpdateResultMessage(ITFSNode * pNode)
|
|
{
|
|
HRESULT hr = hrOK;
|
|
int nMessage = -1; // default
|
|
int nVisible, nTotal;
|
|
int i;
|
|
|
|
CString strTitle, strBody, strTemp;
|
|
|
|
if (!m_dwErr)
|
|
{
|
|
pNode->GetChildCount(&nVisible, &nTotal);
|
|
|
|
// determine what message to display
|
|
if ( (m_nState == notLoaded) ||
|
|
(m_nState == loading) )
|
|
{
|
|
nMessage = -1;
|
|
}
|
|
else
|
|
if (nTotal == 0)
|
|
{
|
|
nMessage = RESERVATIONS_MESSAGE_NO_RES;
|
|
}
|
|
|
|
// build the strings
|
|
if (nMessage != -1)
|
|
{
|
|
// now build the text strings
|
|
// first entry is the title
|
|
strTitle.LoadString(g_uReservationsMessages[nMessage][0]);
|
|
|
|
// second entry is the icon
|
|
// third ... n entries are the body strings
|
|
|
|
for (i = 2; g_uReservationsMessages[nMessage][i] != 0; i++)
|
|
{
|
|
strTemp.LoadString(g_uReservationsMessages[nMessage][i]);
|
|
strBody += strTemp;
|
|
}
|
|
}
|
|
}
|
|
|
|
// show the message
|
|
if (nMessage == -1)
|
|
{
|
|
ClearMessage(pNode);
|
|
}
|
|
else
|
|
{
|
|
ShowMessage(pNode, strTitle, strBody, (IconIdentifier) g_uReservationsMessages[nMessage][1]);
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Message handlers
|
|
---------------------------------------------------------------------------*/
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpReservations::OnCreateNewReservation
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CDhcpReservations::OnCreateNewReservation
|
|
(
|
|
ITFSNode * pNode
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
SPITFSNode spScopeNode;
|
|
pNode->GetParent(&spScopeNode);
|
|
|
|
CDhcpScope * pScope = GETHANDLER(CDhcpScope, spScopeNode);
|
|
LARGE_INTEGER liVersion;
|
|
|
|
pScope->GetServerVersion(liVersion);
|
|
|
|
CAddReservation dlgAddReservation(spScopeNode, liVersion);
|
|
|
|
dlgAddReservation.DoModal();
|
|
|
|
GetScopeObject(pNode)->TriggerStatsRefresh();
|
|
|
|
UpdateResultMessage(pNode);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Background thread functionality
|
|
---------------------------------------------------------------------------*/
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpReservations::OnHaveData
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
void
|
|
CDhcpReservations::OnHaveData
|
|
(
|
|
ITFSNode * pParentNode,
|
|
ITFSNode * pNewNode
|
|
)
|
|
{
|
|
AddReservationSorted(pParentNode, pNewNode);
|
|
|
|
// update the view
|
|
ExpandNode(pParentNode, TRUE);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpReservations::AddReservationSorted
|
|
Adding reservation after sorting it by comparing against the resvname
|
|
takes too much time.
|
|
Adds a scope node to the UI sorted
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpReservations::AddReservationSorted
|
|
(
|
|
ITFSNode * pReservationsNode,
|
|
ITFSNode * pResClientNode
|
|
)
|
|
{
|
|
|
|
HRESULT hr = hrOK;
|
|
SPITFSNodeEnum spNodeEnum;
|
|
SPITFSNode spCurrentNode;
|
|
SPITFSNode spPrevNode;
|
|
ULONG nNumReturned = 0;
|
|
|
|
CDhcpReservationClient * pResClient;
|
|
|
|
// get our target address
|
|
pResClient = GETHANDLER(CDhcpReservationClient, pResClientNode);
|
|
|
|
// get the enumerator for this node
|
|
CORg(pReservationsNode->GetEnum(&spNodeEnum));
|
|
|
|
CORg(spNodeEnum->Next(1, &spCurrentNode, &nNumReturned));
|
|
while (nNumReturned)
|
|
{
|
|
pResClient = GETHANDLER(CDhcpReservationClient, spCurrentNode);
|
|
|
|
// get the next node in the list
|
|
spPrevNode.Set(spCurrentNode);
|
|
|
|
spCurrentNode.Release();
|
|
spNodeEnum->Next(1, &spCurrentNode, &nNumReturned);
|
|
}
|
|
|
|
// Add the node in based on the PrevNode pointer
|
|
if (spPrevNode)
|
|
{
|
|
if (m_bExpanded)
|
|
{
|
|
pResClientNode->SetData(TFS_DATA_RELATIVE_FLAGS, SDI_PREVIOUS);
|
|
pResClientNode->SetData(TFS_DATA_RELATIVE_SCOPEID, spPrevNode->GetData(TFS_DATA_SCOPEID));
|
|
}
|
|
|
|
CORg(pReservationsNode->InsertChild(spPrevNode, pResClientNode));
|
|
}
|
|
else
|
|
{
|
|
// add to the head
|
|
if (m_bExpanded)
|
|
{
|
|
pResClientNode->SetData(TFS_DATA_RELATIVE_FLAGS, SDI_FIRST);
|
|
}
|
|
|
|
CORg(pReservationsNode->AddChild(pResClientNode));
|
|
}
|
|
|
|
Error:
|
|
return hr;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpReservations::OnCreateQuery()
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
ITFSQueryObject*
|
|
CDhcpReservations::OnCreateQuery(ITFSNode * pNode)
|
|
{
|
|
CDhcpReservationsQueryObj* pQuery =
|
|
new CDhcpReservationsQueryObj(m_spTFSCompData, m_spNodeMgr);
|
|
|
|
pQuery->m_strServer = GetServerIpAddress(pNode);
|
|
|
|
pQuery->m_dhcpScopeAddress = GetScopeObject(pNode)->GetAddress();
|
|
pQuery->m_dhcpResumeHandle = NULL;
|
|
pQuery->m_dwPreferredMax = 2000;
|
|
pQuery->m_resvMap.RemoveAll();
|
|
pQuery->m_totalResvs = 0;
|
|
pQuery->m_subnetElements = NULL;
|
|
GetScopeObject(pNode)->GetServerVersion(pQuery->m_liVersion);
|
|
|
|
return pQuery;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpReservationsQueryObj::Execute()
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
STDMETHODIMP
|
|
CDhcpReservationsQueryObj::Execute()
|
|
{
|
|
HRESULT hr = hrOK;
|
|
|
|
if (m_liVersion.QuadPart >= DHCP_SP2_VERSION)
|
|
{
|
|
|
|
if ( AddReservedIPsToArray( ) )
|
|
{
|
|
//
|
|
//
|
|
// this should handle the case where there are a large # of resvs.
|
|
//
|
|
//
|
|
|
|
hr = EnumerateReservationsV4();
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// a typical corporation doesnt have more than 100 resvs
|
|
// handle it here
|
|
//
|
|
|
|
hr = EnumerateReservationsForLessResvsV4( );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = EnumerateReservations();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CDhcpReservationsQueryObj::EnumerateReservationsForLessResvsV4( )
|
|
{
|
|
|
|
DWORD dwError = ERROR_MORE_DATA;
|
|
LPDHCP_SUBNET_ELEMENT_INFO_ARRAY_V4 pdhcpSubnetElementArray = NULL;
|
|
DWORD dwElementsRead = 0, dwElementsTotal = 0;
|
|
HRESULT hr = hrOK;
|
|
|
|
while (dwError == ERROR_MORE_DATA)
|
|
{
|
|
dwError = ::DhcpEnumSubnetElementsV4(((LPWSTR) (LPCTSTR)m_strServer),
|
|
m_dhcpScopeAddress,
|
|
DhcpReservedIps,
|
|
&m_dhcpResumeHandle,
|
|
m_dwPreferredMax,
|
|
&pdhcpSubnetElementArray,
|
|
&dwElementsRead,
|
|
&dwElementsTotal);
|
|
|
|
Trace3("Scope %lx Reservations read %d, total %d\n", m_dhcpScopeAddress, dwElementsRead, dwElementsTotal);
|
|
|
|
if (dwElementsRead && dwElementsTotal && pdhcpSubnetElementArray)
|
|
{
|
|
//
|
|
// Loop through the array that was returned
|
|
//
|
|
for (DWORD i = 0; i < pdhcpSubnetElementArray->NumElements; i++)
|
|
{
|
|
//
|
|
// For each reservation, we need to get the client info
|
|
//
|
|
DWORD dwReturn;
|
|
LPDHCP_CLIENT_INFO_V4 pClientInfo = NULL;
|
|
DHCP_SEARCH_INFO dhcpSearchInfo;
|
|
|
|
dhcpSearchInfo.SearchType = DhcpClientIpAddress;
|
|
dhcpSearchInfo.SearchInfo.ClientIpAddress =
|
|
pdhcpSubnetElementArray->Elements[i].Element.ReservedIp->ReservedIpAddress;
|
|
|
|
dwReturn = ::DhcpGetClientInfoV4(m_strServer,
|
|
&dhcpSearchInfo,
|
|
&pClientInfo);
|
|
if (dwReturn == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// Create the result pane item for this element
|
|
//
|
|
SPITFSNode spNode;
|
|
CDhcpReservationClient * pDhcpReservationClient;
|
|
|
|
COM_PROTECT_TRY
|
|
{
|
|
pDhcpReservationClient =
|
|
new CDhcpReservationClient(m_spTFSCompData, pClientInfo);
|
|
|
|
// Tell the reservation what the client type is
|
|
pDhcpReservationClient->SetClientType(pdhcpSubnetElementArray->Elements[i].Element.ReservedIp->bAllowedClientTypes);
|
|
|
|
CreateContainerTFSNode(&spNode,
|
|
&GUID_DhcpReservationClientNodeType,
|
|
pDhcpReservationClient,
|
|
pDhcpReservationClient,
|
|
m_spNodeMgr);
|
|
|
|
// Tell the handler to initialize any specific data
|
|
pDhcpReservationClient->InitializeNode(spNode);
|
|
|
|
AddToQueue(spNode);
|
|
pDhcpReservationClient->Release();
|
|
}
|
|
COM_PROTECT_CATCH
|
|
|
|
::DhcpRpcFreeMemory(pClientInfo);
|
|
}
|
|
else
|
|
{
|
|
// REVIEW: ericdav - do we need to post the error back here?
|
|
Trace1("EnumReservationsV4 - GetClientInfoV4 failed! %d\n", dwReturn);
|
|
}
|
|
}
|
|
|
|
::DhcpRpcFreeMemory(pdhcpSubnetElementArray);
|
|
|
|
pdhcpSubnetElementArray = NULL;
|
|
dwElementsRead = 0;
|
|
dwElementsTotal = 0;
|
|
}
|
|
|
|
// Check the abort flag on the thread
|
|
if (FCheckForAbort() == hrOK)
|
|
break;
|
|
|
|
// check to see if we have an error and post it to the main thread if we do..
|
|
if (dwError != ERROR_NO_MORE_ITEMS &&
|
|
dwError != ERROR_SUCCESS &&
|
|
dwError != ERROR_MORE_DATA)
|
|
{
|
|
Trace1("DHCP snapin: EnumerateReservationsV4 error: %d\n", dwError);
|
|
m_dwErr = dwError;
|
|
PostError(dwError);
|
|
}
|
|
}
|
|
|
|
return hrFalse;
|
|
|
|
|
|
}
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpReservationsQueryObj::EnumerateReservationsV4()
|
|
Enumerates leases for NT4 SP2 and newer servers
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpReservationsQueryObj::EnumerateReservationsV4()
|
|
{
|
|
|
|
DWORD dwError = ERROR_MORE_DATA;
|
|
LPDHCP_CLIENT_INFO_ARRAY_V5 pdhcpClientArrayV5 = NULL;
|
|
LPDHCP_SUBNET_ELEMENT_DATA_V4 pSubnetData = NULL;
|
|
DWORD dwClientsRead = 0, dwClientsTotal = 0;
|
|
DWORD dwResvsHandled = 0;
|
|
DWORD dwEnumedClients = 0;
|
|
DWORD dwResvThreshold = 1000;
|
|
DWORD i = 0;
|
|
DWORD k = 0;
|
|
DWORD *j = NULL;
|
|
HRESULT hr = hrOK;
|
|
|
|
|
|
while (dwError == ERROR_MORE_DATA)
|
|
{
|
|
dwError = ::DhcpEnumSubnetClientsV5(((LPWSTR) (LPCTSTR)m_strServer),
|
|
m_dhcpScopeAddress,
|
|
&m_dhcpResumeHandle,
|
|
-1,
|
|
&pdhcpClientArrayV5,
|
|
&dwClientsRead,
|
|
&dwClientsTotal);
|
|
|
|
|
|
if ( dwClientsRead && dwClientsTotal && pdhcpClientArrayV5 )
|
|
|
|
{
|
|
|
|
//
|
|
// we do a binary search for a reservation
|
|
// that is present in the table.
|
|
//
|
|
|
|
for( i = 0; i < dwClientsRead; i ++ )
|
|
{
|
|
|
|
//
|
|
// do binary search against each client that was read to see
|
|
// if it is a reservation.
|
|
//
|
|
|
|
k = pdhcpClientArrayV5 -> Clients[i] -> ClientIpAddress;
|
|
|
|
if ( m_resvMap.Lookup( k, pSubnetData ))
|
|
{
|
|
|
|
//
|
|
// Create the result pane item for this element
|
|
//
|
|
|
|
SPITFSNode spNode;
|
|
CDhcpReservationClient * pDhcpReservationClient;
|
|
|
|
COM_PROTECT_TRY
|
|
{
|
|
|
|
pDhcpReservationClient =
|
|
new CDhcpReservationClient( m_spTFSCompData, reinterpret_cast<LPDHCP_CLIENT_INFO_V4>(pdhcpClientArrayV5 -> Clients[ i ] ));
|
|
pDhcpReservationClient->SetClientType( pSubnetData->Element.ReservedIp->bAllowedClientTypes );
|
|
|
|
CreateContainerTFSNode(&spNode,
|
|
&GUID_DhcpReservationClientNodeType,
|
|
pDhcpReservationClient,
|
|
pDhcpReservationClient,
|
|
m_spNodeMgr);
|
|
|
|
//
|
|
// Tell the handler to initialize any specific data
|
|
//
|
|
|
|
pDhcpReservationClient->InitializeNode(spNode);
|
|
|
|
AddToQueue(spNode);
|
|
pDhcpReservationClient->Release();
|
|
}
|
|
COM_PROTECT_CATCH
|
|
|
|
} // end of if that adds a reservation
|
|
|
|
} // end of for
|
|
|
|
::DhcpRpcFreeMemory(pdhcpClientArrayV5);
|
|
|
|
pdhcpClientArrayV5 = NULL;
|
|
dwEnumedClients += dwClientsRead;
|
|
dwClientsRead = 0;
|
|
dwClientsTotal = 0;
|
|
|
|
} // end of main if that checks if read succeeded.
|
|
|
|
// Check the abort flag on the thread
|
|
if (FCheckForAbort() == hrOK)
|
|
break;
|
|
|
|
// check to see if we have an error and post it to the main thread if we do..
|
|
if (dwError != ERROR_NO_MORE_ITEMS &&
|
|
dwError != ERROR_SUCCESS &&
|
|
dwError != ERROR_MORE_DATA)
|
|
{
|
|
Trace1("DHCP snapin: EnumerateReservationsV4 error: %d\n", dwError);
|
|
m_dwErr = dwError;
|
|
PostError(dwError);
|
|
}
|
|
}
|
|
|
|
DhcpRpcFreeMemory( m_subnetElements );
|
|
m_subnetElements = NULL;
|
|
m_totalResvs = 0;
|
|
m_resvMap.RemoveAll();
|
|
|
|
return hrFalse;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpReservationsQueryObj::Execute()
|
|
Enumerates reservations for pre NT4 SP2 servers
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpReservationsQueryObj::EnumerateReservations()
|
|
{
|
|
DWORD dwError = ERROR_MORE_DATA;
|
|
LPDHCP_SUBNET_ELEMENT_INFO_ARRAY pdhcpSubnetElementArray = NULL;
|
|
DWORD dwElementsRead = 0, dwElementsTotal = 0;
|
|
|
|
while (dwError == ERROR_MORE_DATA)
|
|
{
|
|
dwError = ::DhcpEnumSubnetElements(((LPWSTR) (LPCTSTR)m_strServer),
|
|
m_dhcpScopeAddress,
|
|
DhcpReservedIps,
|
|
&m_dhcpResumeHandle,
|
|
m_dwPreferredMax,
|
|
&pdhcpSubnetElementArray,
|
|
&dwElementsRead,
|
|
&dwElementsTotal);
|
|
|
|
Trace3("Scope %lx Reservations read %d, total %d\n", m_dhcpScopeAddress, dwElementsRead, dwElementsTotal);
|
|
|
|
if (dwElementsRead && dwElementsTotal && pdhcpSubnetElementArray)
|
|
{
|
|
//
|
|
// Loop through the array that was returned
|
|
//
|
|
for (DWORD i = 0; i < pdhcpSubnetElementArray->NumElements; i++)
|
|
{
|
|
//
|
|
// For each reservation, we need to get the client info
|
|
//
|
|
DWORD dwReturn;
|
|
LPDHCP_CLIENT_INFO pClientInfo = NULL;
|
|
DHCP_SEARCH_INFO dhcpSearchInfo;
|
|
|
|
dhcpSearchInfo.SearchType = DhcpClientIpAddress;
|
|
dhcpSearchInfo.SearchInfo.ClientIpAddress =
|
|
pdhcpSubnetElementArray->Elements[i].Element.ReservedIp->ReservedIpAddress;
|
|
|
|
dwReturn = ::DhcpGetClientInfo(m_strServer,
|
|
&dhcpSearchInfo,
|
|
&pClientInfo);
|
|
if (dwReturn == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// Create the result pane item for this element
|
|
//
|
|
SPITFSNode spNode;
|
|
CDhcpReservationClient * pDhcpReservationClient;
|
|
|
|
pDhcpReservationClient =
|
|
new CDhcpReservationClient(m_spTFSCompData, reinterpret_cast<LPDHCP_CLIENT_INFO>(pClientInfo));
|
|
|
|
CreateContainerTFSNode(&spNode,
|
|
&GUID_DhcpReservationClientNodeType,
|
|
pDhcpReservationClient,
|
|
pDhcpReservationClient,
|
|
m_spNodeMgr);
|
|
|
|
// Tell the handler to initialize any specific data
|
|
pDhcpReservationClient->InitializeNode(spNode);
|
|
|
|
AddToQueue(spNode);
|
|
pDhcpReservationClient->Release();
|
|
|
|
::DhcpRpcFreeMemory(pClientInfo);
|
|
}
|
|
}
|
|
|
|
::DhcpRpcFreeMemory(pdhcpSubnetElementArray);
|
|
|
|
pdhcpSubnetElementArray = NULL;
|
|
dwElementsRead = 0;
|
|
dwElementsTotal = 0;
|
|
}
|
|
|
|
// Check the abort flag on the thread
|
|
if (FCheckForAbort() == hrOK)
|
|
break;
|
|
|
|
// check to see if we have an error and post it to the main thread if we do..
|
|
if (dwError != ERROR_NO_MORE_ITEMS &&
|
|
dwError != ERROR_SUCCESS &&
|
|
dwError != ERROR_MORE_DATA)
|
|
{
|
|
Trace1("DHCP snapin: EnumerateReservations error: %d\n", dwError);
|
|
m_dwErr = dwError;
|
|
PostError(dwError);
|
|
}
|
|
}
|
|
|
|
return hrFalse;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CDhcpReservations::OnNotifyExiting
|
|
CMTDhcpHandler overridden functionality
|
|
allows us to know when the background thread is done
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
STDMETHODIMP
|
|
CDhcpReservations::OnNotifyExiting
|
|
(
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
SPITFSNode spNode;
|
|
spNode.Set(m_spNode); // save this off because OnNotifyExiting will release it
|
|
|
|
HRESULT hr = CMTDhcpHandler::OnNotifyExiting(lParam);
|
|
|
|
UpdateResultMessage(spNode);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpReservationClient implementation
|
|
---------------------------------------------------------------------------*/
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Function Name Here
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
CDhcpReservationClient::CDhcpReservationClient
|
|
(
|
|
ITFSComponentData * pComponentData,
|
|
LPDHCP_CLIENT_INFO pDhcpClientInfo
|
|
) : CMTDhcpHandler(pComponentData)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
InitializeData(pDhcpClientInfo);
|
|
|
|
//
|
|
// Intialize our client type
|
|
//
|
|
m_bClientType = CLIENT_TYPE_UNSPECIFIED;
|
|
|
|
m_fResProp = TRUE;
|
|
}
|
|
|
|
CDhcpReservationClient::CDhcpReservationClient
|
|
(
|
|
ITFSComponentData * pComponentData,
|
|
LPDHCP_CLIENT_INFO_V4 pDhcpClientInfo
|
|
) : CMTDhcpHandler(pComponentData)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
InitializeData(reinterpret_cast<LPDHCP_CLIENT_INFO>(pDhcpClientInfo));
|
|
|
|
//
|
|
// Intialize our client type
|
|
//
|
|
m_bClientType = pDhcpClientInfo->bClientType;
|
|
|
|
m_fResProp = TRUE;
|
|
}
|
|
|
|
CDhcpReservationClient::CDhcpReservationClient
|
|
(
|
|
ITFSComponentData * pComponentData,
|
|
CDhcpClient & dhcpClient
|
|
) : CMTDhcpHandler(pComponentData)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
m_dhcpClientIpAddress = dhcpClient.QueryIpAddress();
|
|
|
|
//
|
|
// Copy data out if it's there
|
|
//
|
|
if (dhcpClient.QueryName().GetLength() > 0)
|
|
{
|
|
m_pstrClientName = new CString (dhcpClient.QueryName());
|
|
}
|
|
else
|
|
{
|
|
m_pstrClientName = NULL;
|
|
}
|
|
|
|
if (dhcpClient.QueryComment().GetLength() > 0)
|
|
{
|
|
m_pstrClientComment = new CString(dhcpClient.QueryComment());
|
|
}
|
|
else
|
|
{
|
|
m_pstrClientComment = NULL;
|
|
}
|
|
|
|
//
|
|
// build the clients hardware address
|
|
//
|
|
if (dhcpClient.QueryHardwareAddress().GetSize() > 0)
|
|
{
|
|
m_baHardwareAddress.Copy(dhcpClient.QueryHardwareAddress());
|
|
}
|
|
|
|
if ( (dhcpClient.QueryExpiryDateTime().dwLowDateTime == 0) &&
|
|
(dhcpClient.QueryExpiryDateTime().dwHighDateTime == 0) )
|
|
{
|
|
//
|
|
// This is an inactive reservation
|
|
//
|
|
m_strLeaseExpires.LoadString(IDS_DHCP_INFINITE_LEASE_INACTIVE);
|
|
}
|
|
else
|
|
{
|
|
m_strLeaseExpires.LoadString(IDS_DHCP_INFINITE_LEASE_ACTIVE);
|
|
}
|
|
|
|
//
|
|
// Intialize our client type
|
|
//
|
|
m_bClientType = dhcpClient.QueryClientType();
|
|
|
|
m_fResProp = TRUE;
|
|
}
|
|
|
|
CDhcpReservationClient::~CDhcpReservationClient()
|
|
{
|
|
if (m_pstrClientName)
|
|
{
|
|
delete m_pstrClientName;
|
|
}
|
|
|
|
if (m_pstrClientComment)
|
|
{
|
|
delete m_pstrClientComment;
|
|
}
|
|
}
|
|
|
|
void
|
|
CDhcpReservationClient::InitializeData
|
|
(
|
|
LPDHCP_CLIENT_INFO pDhcpClientInfo
|
|
)
|
|
{
|
|
Assert(pDhcpClientInfo);
|
|
|
|
m_dhcpClientIpAddress = pDhcpClientInfo->ClientIpAddress;
|
|
|
|
//
|
|
// Copy data out if it's there
|
|
//
|
|
if (pDhcpClientInfo->ClientName)
|
|
{
|
|
m_pstrClientName = new CString (pDhcpClientInfo->ClientName);
|
|
}
|
|
else
|
|
{
|
|
m_pstrClientName = NULL;
|
|
}
|
|
|
|
if (pDhcpClientInfo->ClientComment)
|
|
{
|
|
m_pstrClientComment = new CString(pDhcpClientInfo->ClientComment);
|
|
}
|
|
else
|
|
{
|
|
m_pstrClientComment = NULL;
|
|
}
|
|
|
|
// build a copy of the hardware address
|
|
if (pDhcpClientInfo->ClientHardwareAddress.DataLength)
|
|
{
|
|
for (DWORD i = 0; i < pDhcpClientInfo->ClientHardwareAddress.DataLength; i++)
|
|
{
|
|
m_baHardwareAddress.Add(pDhcpClientInfo->ClientHardwareAddress.Data[i]);
|
|
}
|
|
}
|
|
|
|
if ( (pDhcpClientInfo->ClientLeaseExpires.dwLowDateTime == 0) &&
|
|
(pDhcpClientInfo->ClientLeaseExpires.dwHighDateTime == 0) )
|
|
{
|
|
//
|
|
// This is an inactive reservation
|
|
//
|
|
m_strLeaseExpires.LoadString(IDS_DHCP_INFINITE_LEASE_INACTIVE);
|
|
}
|
|
else
|
|
{
|
|
m_strLeaseExpires.LoadString(IDS_DHCP_INFINITE_LEASE_ACTIVE);
|
|
}
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CDhcpReservationClient::InitializeNode
|
|
Initializes node specific data
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpReservationClient::InitializeNode
|
|
(
|
|
ITFSNode * pNode
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
HRESULT hr = hrOK;
|
|
CString strIpAddress, strDisplayName;
|
|
|
|
//
|
|
// Create the display name for this scope
|
|
// Convert DHCP_IP_ADDRES to a string and initialize this object
|
|
//
|
|
UtilCvtIpAddrToWstr (m_dhcpClientIpAddress,
|
|
&strIpAddress);
|
|
|
|
BuildDisplayName(&strDisplayName, strIpAddress, *m_pstrClientName);
|
|
|
|
SetDisplayName(strDisplayName);
|
|
|
|
// Make the node immediately visible
|
|
pNode->SetVisibilityState(TFS_VIS_SHOW);
|
|
pNode->SetData(TFS_DATA_IMAGEINDEX, GetImageIndex(FALSE));
|
|
pNode->SetData(TFS_DATA_OPENIMAGEINDEX, GetImageIndex(TRUE));
|
|
pNode->SetData(TFS_DATA_COOKIE, (LPARAM) pNode);
|
|
pNode->SetData(TFS_DATA_USER, (LPARAM) this);
|
|
pNode->SetData(TFS_DATA_TYPE, DHCPSNAP_RESERVATION_CLIENT);
|
|
pNode->SetData(TFS_DATA_SCOPE_LEAF_NODE, TRUE);
|
|
|
|
SetColumnStringIDs(&aColumns[DHCPSNAP_RESERVATION_CLIENT][0]);
|
|
SetColumnWidths(&aColumnWidths[DHCPSNAP_RESERVATION_CLIENT][0]);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpReservationClient::OnCreateNodeId2
|
|
Returns a unique string for this node
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT CDhcpReservationClient::OnCreateNodeId2(ITFSNode * pNode, CString & strId, DWORD * dwFlags)
|
|
{
|
|
const GUID * pGuid = pNode->GetNodeType();
|
|
|
|
CString strScopeIpAddress, strResIpAddress, strGuid;
|
|
|
|
StringFromGUID2(*pGuid, strGuid.GetBuffer(256), 256);
|
|
strGuid.ReleaseBuffer();
|
|
|
|
DHCP_IP_ADDRESS dhcpIpAddress = GetScopeObject(pNode, TRUE)->GetAddress();
|
|
|
|
UtilCvtIpAddrToWstr (dhcpIpAddress, &strScopeIpAddress);
|
|
UtilCvtIpAddrToWstr (m_dhcpClientIpAddress, &strResIpAddress);
|
|
|
|
strId = GetServerName(pNode, TRUE) + strScopeIpAddress + strResIpAddress + strGuid;
|
|
|
|
return hrOK;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpReservationClient::GetImageIndex
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
int
|
|
CDhcpReservationClient::GetImageIndex(BOOL bOpenImage)
|
|
{
|
|
int nIndex = -1;
|
|
switch (m_nState)
|
|
{
|
|
case notLoaded:
|
|
case loaded:
|
|
if (bOpenImage)
|
|
nIndex = ICON_IDX_CLIENT_OPTION_FOLDER_OPEN;
|
|
else
|
|
nIndex = ICON_IDX_CLIENT_OPTION_FOLDER_CLOSED;
|
|
break;
|
|
|
|
case loading:
|
|
if (bOpenImage)
|
|
nIndex = ICON_IDX_CLIENT_OPTION_FOLDER_OPEN_BUSY;
|
|
else
|
|
nIndex = ICON_IDX_CLIENT_OPTION_FOLDER_CLOSED_BUSY;
|
|
break;
|
|
|
|
case unableToLoad:
|
|
if (bOpenImage)
|
|
nIndex = ICON_IDX_CLIENT_OPTION_FOLDER_OPEN_LOST_CONNECTION;
|
|
else
|
|
nIndex = ICON_IDX_CLIENT_OPTION_FOLDER_CLOSED_LOST_CONNECTION;
|
|
break;
|
|
|
|
default:
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
return nIndex;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Overridden base handler functions
|
|
---------------------------------------------------------------------------*/
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpReservationClient::OnAddMenuItems
|
|
Adds entries to the context sensitive menu
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
STDMETHODIMP
|
|
CDhcpReservationClient::OnAddMenuItems
|
|
(
|
|
ITFSNode * pNode,
|
|
LPCONTEXTMENUCALLBACK pContextMenuCallback,
|
|
LPDATAOBJECT lpDataObject,
|
|
DATA_OBJECT_TYPES type,
|
|
DWORD dwType,
|
|
long * pInsertionAllowed
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
LONG fFlags = 0;
|
|
HRESULT hr = S_OK;
|
|
CString strMenuText;
|
|
|
|
if ( (m_nState != loaded) )
|
|
{
|
|
fFlags |= MF_GRAYED;
|
|
}
|
|
|
|
if (type == CCT_SCOPE)
|
|
{
|
|
if (*pInsertionAllowed & CCM_INSERTIONALLOWED_TOP)
|
|
{
|
|
strMenuText.LoadString(IDS_CREATE_OPTION_RESERVATION);
|
|
hr = LoadAndAddMenuItem( pContextMenuCallback,
|
|
strMenuText,
|
|
IDS_CREATE_OPTION_RESERVATION,
|
|
CCM_INSERTIONPOINTID_PRIMARY_TOP,
|
|
fFlags );
|
|
ASSERT( SUCCEEDED(hr) );
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpReservationClient::OnCommand
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
STDMETHODIMP
|
|
CDhcpReservationClient::OnCommand
|
|
(
|
|
ITFSNode * pNode,
|
|
long nCommandId,
|
|
DATA_OBJECT_TYPES type,
|
|
LPDATAOBJECT pDataObject,
|
|
DWORD dwType
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
switch (nCommandId)
|
|
{
|
|
case IDS_REFRESH:
|
|
OnRefresh(pNode, pDataObject, dwType, 0, 0);
|
|
break;
|
|
|
|
case IDS_DELETE:
|
|
OnDelete(pNode);
|
|
break;
|
|
|
|
case IDS_CREATE_OPTION_RESERVATION:
|
|
OnCreateNewOptions(pNode);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpReservationClient::CompareItems
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
STDMETHODIMP_(int)
|
|
CDhcpReservationClient::CompareItems
|
|
(
|
|
ITFSComponent * pComponent,
|
|
MMC_COOKIE cookieA,
|
|
MMC_COOKIE cookieB,
|
|
int nCol
|
|
)
|
|
{
|
|
SPITFSNode spNode1, spNode2;
|
|
|
|
m_spNodeMgr->FindNode(cookieA, &spNode1);
|
|
m_spNodeMgr->FindNode(cookieB, &spNode2);
|
|
|
|
int nCompare = 0;
|
|
|
|
CDhcpOptionItem *pOpt1 = GETHANDLER(CDhcpOptionItem, spNode1);
|
|
CDhcpOptionItem *pOpt2 = GETHANDLER(CDhcpOptionItem, spNode2);
|
|
|
|
switch (nCol)
|
|
{
|
|
case 0:
|
|
{
|
|
//
|
|
// Name compare - use the option #
|
|
//
|
|
LONG_PTR uImage1 = spNode1->GetData(TFS_DATA_IMAGEINDEX);
|
|
LONG_PTR uImage2 = spNode2->GetData(TFS_DATA_IMAGEINDEX);
|
|
|
|
nCompare = UtilGetOptionPriority((int) uImage1, (int) uImage2);
|
|
if (nCompare == 0)
|
|
{
|
|
DHCP_OPTION_ID id1 = pOpt1->GetOptionId();
|
|
DHCP_OPTION_ID id2 = pOpt2->GetOptionId();
|
|
|
|
if (id1 < id2)
|
|
nCompare = -1;
|
|
else
|
|
if (id1 > id2)
|
|
nCompare = 1;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 1:
|
|
{
|
|
// compare the vendor strings
|
|
CString str1, str2;
|
|
str1 = pOpt1->GetVendorDisplay();
|
|
str2 = pOpt2->GetVendorDisplay();
|
|
|
|
nCompare = str1.CompareNoCase(str2);
|
|
}
|
|
break;
|
|
|
|
case 2: {
|
|
// compare the printable values
|
|
CString str1, str2;
|
|
str1 = pOpt1->GetString( pComponent, cookieA, nCol );
|
|
str2 = pOpt2->GetString( pComponent, cookieB, nCol );
|
|
|
|
nCompare = str1.CompareNoCase( str2 );
|
|
break;
|
|
}
|
|
|
|
case 3:
|
|
{
|
|
CString str1, str2;
|
|
str1 = pOpt1->GetClassName();
|
|
str2 = pOpt2->GetClassName();
|
|
|
|
nCompare = str1.CompareNoCase(str2);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return nCompare;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CDhcpReservationClient::OnResultSelect
|
|
Update the verbs and the result pane message
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT CDhcpReservationClient::OnResultSelect(ITFSComponent *pComponent, LPDATAOBJECT pDataObject, MMC_COOKIE cookie, LPARAM arg, LPARAM lParam)
|
|
{
|
|
HRESULT hr = hrOK;
|
|
SPITFSNode spNode;
|
|
|
|
CORg(CMTDhcpHandler::OnResultSelect(pComponent, pDataObject, cookie, arg, lParam));
|
|
|
|
CORg (pComponent->GetSelectedNode(&spNode));
|
|
|
|
if ( spNode != 0 ) {
|
|
UpdateResultMessage(spNode);
|
|
}
|
|
|
|
Error:
|
|
return hr;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CDhcpReservationClient::UpdateResultMessage
|
|
Figures out what message to put in the result pane, if any
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
void CDhcpReservationClient::UpdateResultMessage(ITFSNode * pNode)
|
|
{
|
|
HRESULT hr = hrOK;
|
|
int nMessage = -1; // default
|
|
int nVisible, nTotal;
|
|
int i;
|
|
|
|
CString strTitle, strBody, strTemp;
|
|
|
|
if (!m_dwErr)
|
|
{
|
|
pNode->GetChildCount(&nVisible, &nTotal);
|
|
|
|
// determine what message to display
|
|
if ( (m_nState == notLoaded) ||
|
|
(m_nState == loading) )
|
|
{
|
|
nMessage = -1;
|
|
}
|
|
else
|
|
if (nTotal == 0)
|
|
{
|
|
nMessage = RES_OPTIONS_MESSAGE_NO_OPTIONS;
|
|
}
|
|
|
|
// build the strings
|
|
if (nMessage != -1)
|
|
{
|
|
// now build the text strings
|
|
// first entry is the title
|
|
strTitle.LoadString(g_uResOptionsMessages[nMessage][0]);
|
|
|
|
// second entry is the icon
|
|
// third ... n entries are the body strings
|
|
|
|
for (i = 2; g_uResOptionsMessages[nMessage][i] != 0; i++)
|
|
{
|
|
strTemp.LoadString(g_uResOptionsMessages[nMessage][i]);
|
|
strBody += strTemp;
|
|
}
|
|
}
|
|
}
|
|
|
|
// show the message
|
|
if (nMessage == -1)
|
|
{
|
|
ClearMessage(pNode);
|
|
}
|
|
else
|
|
{
|
|
ShowMessage(pNode, strTitle, strBody, (IconIdentifier) g_uResOptionsMessages[nMessage][1]);
|
|
}
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CDhcpReservationClient::OnDelete
|
|
The base handler calls this when MMC sends a MMCN_DELETE for a
|
|
scope pane item. We just call our delete command handler.
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpReservationClient::OnDelete
|
|
(
|
|
ITFSNode * pNode,
|
|
LPARAM arg,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
return OnDelete(pNode);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Command handlers
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpReservationClient::OnCreateNewOptions
|
|
(
|
|
ITFSNode * pNode
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
CPropertyPageHolderBase * pPropSheet;
|
|
CString strOptCfgTitle, strOptType;
|
|
SPITFSNode spServerNode;
|
|
SPIComponentData spComponentData;
|
|
COptionsConfig * pOptCfg;
|
|
DHCP_OPTION_SCOPE_INFO dhcpScopeInfo;
|
|
HRESULT hr = hrOK;
|
|
|
|
COM_PROTECT_TRY
|
|
{
|
|
CString strOptCfgTitle, strOptType;
|
|
SPIComponentData spComponentData;
|
|
BOOL fFound = FALSE;
|
|
|
|
strOptType.LoadString(IDS_CONFIGURE_OPTIONS_CLIENT);
|
|
AfxFormatString1(strOptCfgTitle, IDS_CONFIGURE_OPTIONS_TITLE, strOptType);
|
|
|
|
// this gets kinda weird because we implemented the option config page
|
|
// as a property page, so technically this node has two property pages.
|
|
//
|
|
// search the open prop pages to see if the option config is up
|
|
// if it's up, set it active instead of creating a new one.
|
|
for (int i = 0; i < HasPropSheetsOpen(); i++)
|
|
{
|
|
GetOpenPropSheet(i, &pPropSheet);
|
|
|
|
HWND hwnd = pPropSheet->GetSheetWindow();
|
|
CString strTitle;
|
|
|
|
::GetWindowText(hwnd, strTitle.GetBuffer(256), 256);
|
|
strTitle.ReleaseBuffer();
|
|
|
|
if (strTitle == strOptCfgTitle)
|
|
{
|
|
pPropSheet->SetActiveWindow();
|
|
fFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!fFound)
|
|
{
|
|
m_spNodeMgr->GetComponentData(&spComponentData);
|
|
|
|
m_fResProp = FALSE;
|
|
|
|
hr = DoPropertiesOurselvesSinceMMCSucks(pNode, spComponentData, strOptCfgTitle);
|
|
|
|
m_fResProp = TRUE;
|
|
}
|
|
}
|
|
COM_PROTECT_CATCH;
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpReservationClient::OnDelete
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CDhcpReservationClient::OnDelete
|
|
(
|
|
ITFSNode * pNode
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
CString strMessage, strTemp;
|
|
DWORD dwError = 0;
|
|
|
|
CDhcpReservations *pResrv;
|
|
pResrv = GETHANDLER( CDhcpReservations, pNode );
|
|
|
|
// Check for any open property sheets
|
|
if ( pResrv->HasPropSheetsOpen()) {
|
|
AfxMessageBox( IDS_MSG_CLOSE_PROPSHEET );
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
|
|
UtilCvtIpAddrToWstr (m_dhcpClientIpAddress,
|
|
&strTemp);
|
|
|
|
AfxFormatString1(strMessage, IDS_DELETE_RESERVATION, (LPCTSTR) strTemp);
|
|
|
|
if (AfxMessageBox(strMessage, MB_YESNO) == IDYES) {
|
|
BEGIN_WAIT_CURSOR;
|
|
|
|
dwError = GetScopeObject(pNode, TRUE)->DeleteReservation(m_baHardwareAddress, m_dhcpClientIpAddress);
|
|
if (dwError != 0) {
|
|
//
|
|
// OOOpss. Something happened, reservation not
|
|
// deleted, so don't remove from UI and put up a message box
|
|
//
|
|
::DhcpMessageBox(dwError);
|
|
}
|
|
else {
|
|
CDhcpScope * pScope = NULL;
|
|
SPITFSNode spActiveLeasesNode;
|
|
|
|
pScope = GetScopeObject(pNode, TRUE);
|
|
pScope->GetActiveLeasesNode(&spActiveLeasesNode);
|
|
|
|
pScope->GetActiveLeasesObject()->DeleteClient(spActiveLeasesNode, m_dhcpClientIpAddress);
|
|
|
|
SPITFSNode spReservationsNode;
|
|
pNode->GetParent(&spReservationsNode);
|
|
|
|
spReservationsNode->RemoveChild(pNode);
|
|
|
|
// update stats
|
|
pScope->TriggerStatsRefresh();
|
|
} // else
|
|
|
|
END_WAIT_CURSOR;
|
|
} // if
|
|
|
|
return dwError;
|
|
} // CDhcpReservationClient::OnDelete()
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpReservationClient::OnResultPropertyChange
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpReservationClient::OnResultPropertyChange
|
|
(
|
|
ITFSComponent * pComponent,
|
|
LPDATAOBJECT pDataObject,
|
|
MMC_COOKIE cookie,
|
|
LPARAM arg,
|
|
LPARAM param
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
SPITFSNode spNode;
|
|
m_spNodeMgr->FindNode(cookie, &spNode);
|
|
COptionsConfig * pOptCfg = reinterpret_cast<COptionsConfig *>(param);
|
|
|
|
LPARAM changeMask = 0;
|
|
|
|
// tell the property page to do whatever now that we are back on the
|
|
// main thread
|
|
pOptCfg->OnPropertyChange(TRUE, &changeMask);
|
|
|
|
pOptCfg->AcknowledgeNotify();
|
|
|
|
if (changeMask)
|
|
spNode->ChangeNode(changeMask);
|
|
|
|
return hrOK;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpReservationClient::CreatePropertyPages
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
STDMETHODIMP
|
|
CDhcpReservationClient::CreatePropertyPages
|
|
(
|
|
ITFSNode * pNode,
|
|
LPPROPERTYSHEETCALLBACK lpProvider,
|
|
LPDATAOBJECT pDataObject,
|
|
LONG_PTR handle,
|
|
DWORD dwType
|
|
)
|
|
{
|
|
HRESULT hr = hrOK;
|
|
|
|
if (m_fResProp)
|
|
{
|
|
hr = DoResPages(pNode, lpProvider, pDataObject, handle, dwType);
|
|
}
|
|
else
|
|
{
|
|
hr = DoOptCfgPages(pNode, lpProvider, pDataObject, handle, dwType);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CDhcpReservationClient::DoResPages
|
|
(
|
|
ITFSNode * pNode,
|
|
LPPROPERTYSHEETCALLBACK lpProvider,
|
|
LPDATAOBJECT pDataObject,
|
|
LONG_PTR handle,
|
|
DWORD dwType
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
//
|
|
// Create the property page
|
|
//
|
|
SPIComponentData spComponentData;
|
|
m_spNodeMgr->GetComponentData(&spComponentData);
|
|
|
|
CReservedClientProperties * pResClientProp =
|
|
new CReservedClientProperties(pNode, spComponentData, m_spTFSCompData, NULL);
|
|
|
|
// Get the Server version and set it in the property sheet
|
|
LARGE_INTEGER liVersion;
|
|
CDhcpServer * pServer = GetScopeObject(pNode, TRUE)->GetServerObject();
|
|
pServer->GetVersion(liVersion);
|
|
|
|
pResClientProp->SetVersion(liVersion);
|
|
|
|
// fill in the data for the prop page
|
|
pResClientProp->m_pageGeneral.m_dwClientAddress = m_dhcpClientIpAddress;
|
|
|
|
if (m_pstrClientName)
|
|
pResClientProp->m_pageGeneral.m_strName = *m_pstrClientName;
|
|
|
|
if (m_pstrClientComment)
|
|
pResClientProp->m_pageGeneral.m_strComment = *m_pstrClientComment;
|
|
|
|
pResClientProp->SetClientType(m_bClientType);
|
|
|
|
// fill in the UID string
|
|
UtilCvtByteArrayToString(m_baHardwareAddress, pResClientProp->m_pageGeneral.m_strUID);
|
|
|
|
// set the DNS registration option
|
|
DWORD dwDynDnsFlags;
|
|
DWORD dwError;
|
|
|
|
BEGIN_WAIT_CURSOR;
|
|
|
|
dwError = GetDnsRegistration(pNode, &dwDynDnsFlags);
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
::DhcpMessageBox(dwError);
|
|
return hrFalse;
|
|
}
|
|
|
|
END_WAIT_CURSOR;
|
|
|
|
pResClientProp->SetDnsRegistration(dwDynDnsFlags, DhcpReservedOptions);
|
|
|
|
//
|
|
// Object gets deleted when the page is destroyed
|
|
//
|
|
Assert(lpProvider != NULL);
|
|
|
|
return pResClientProp->CreateModelessSheet(lpProvider, handle);
|
|
}
|
|
|
|
HRESULT
|
|
CDhcpReservationClient::DoOptCfgPages
|
|
(
|
|
ITFSNode * pNode,
|
|
LPPROPERTYSHEETCALLBACK lpProvider,
|
|
LPDATAOBJECT pDataObject,
|
|
LONG_PTR handle,
|
|
DWORD dwType
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
DWORD dwError;
|
|
DWORD dwDynDnsFlags;
|
|
HRESULT hr = hrOK;
|
|
COptionsConfig * pOptCfg;
|
|
CString strOptCfgTitle, strOptType;
|
|
SPITFSNode spServerNode;
|
|
SPIComponentData spComponentData;
|
|
COptionValueEnum * pOptionValueEnum;
|
|
|
|
//
|
|
// Create the property page
|
|
//
|
|
COM_PROTECT_TRY
|
|
{
|
|
m_spNodeMgr->GetComponentData(&spComponentData);
|
|
|
|
BEGIN_WAIT_CURSOR;
|
|
|
|
strOptType.LoadString(IDS_CONFIGURE_OPTIONS_CLIENT);
|
|
AfxFormatString1(strOptCfgTitle, IDS_CONFIGURE_OPTIONS_TITLE, strOptType);
|
|
|
|
GetScopeObject(pNode, TRUE)->GetServerNode(&spServerNode);
|
|
|
|
pOptCfg = new COptionsConfig(pNode,
|
|
spServerNode,
|
|
spComponentData,
|
|
m_spTFSCompData,
|
|
GetOptionValueEnum(),
|
|
strOptCfgTitle);
|
|
|
|
END_WAIT_CURSOR;
|
|
|
|
//
|
|
// Object gets deleted when the page is destroyed
|
|
//
|
|
Assert(lpProvider != NULL);
|
|
|
|
hr = pOptCfg->CreateModelessSheet(lpProvider, handle);
|
|
}
|
|
COM_PROTECT_CATCH
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpReservationClient::OnPropertyChange
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpReservationClient::OnPropertyChange
|
|
(
|
|
ITFSNode * pNode,
|
|
LPDATAOBJECT pDataobject,
|
|
DWORD dwType,
|
|
LPARAM arg,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
CPropertyPageHolderBase * pProp =
|
|
reinterpret_cast<CPropertyPageHolderBase *>(lParam);
|
|
|
|
LONG_PTR changeMask = 0;
|
|
|
|
// tell the property page to do whatever now that we are back on the
|
|
// main thread
|
|
pProp->OnPropertyChange(TRUE, &changeMask);
|
|
|
|
pProp->AcknowledgeNotify();
|
|
|
|
if (changeMask)
|
|
pNode->ChangeNode(changeMask);
|
|
|
|
return hrOK;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpReservationClient::OnResultDelete
|
|
This function is called when we are supposed to delete result
|
|
pane items. We build a list of selected items and then delete them.
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpReservationClient::OnResultDelete
|
|
(
|
|
ITFSComponent * pComponent,
|
|
LPDATAOBJECT pDataObject,
|
|
MMC_COOKIE cookie,
|
|
LPARAM arg,
|
|
LPARAM param
|
|
)
|
|
{
|
|
HRESULT hr = hrOK;
|
|
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
// translate the cookie into a node pointer
|
|
SPITFSNode spResClient, spSelectedNode;
|
|
DWORD dwError;
|
|
|
|
m_spNodeMgr->FindNode(cookie, &spResClient);
|
|
pComponent->GetSelectedNode(&spSelectedNode);
|
|
|
|
Assert(spSelectedNode == spResClient);
|
|
if (spSelectedNode != spResClient)
|
|
return hr;
|
|
|
|
// build the list of selected nodes
|
|
CTFSNodeList listNodesToDelete;
|
|
hr = BuildSelectedItemList(pComponent, &listNodesToDelete);
|
|
|
|
//
|
|
// Confirm with the user
|
|
//
|
|
CString strMessage, strTemp;
|
|
int nNodes = (int) listNodesToDelete.GetCount();
|
|
if (nNodes > 1)
|
|
{
|
|
strTemp.Format(_T("%d"), nNodes);
|
|
AfxFormatString1(strMessage, IDS_DELETE_ITEMS, (LPCTSTR) strTemp);
|
|
}
|
|
else
|
|
{
|
|
strMessage.LoadString(IDS_DELETE_ITEM);
|
|
}
|
|
|
|
if (AfxMessageBox(strMessage, MB_YESNO) == IDNO)
|
|
{
|
|
return NOERROR;
|
|
}
|
|
|
|
// check to make sure we are deleting just scope options
|
|
POSITION pos = listNodesToDelete.GetHeadPosition();
|
|
while (pos)
|
|
{
|
|
ITFSNode * pNode = listNodesToDelete.GetNext(pos);
|
|
if (pNode->GetData(TFS_DATA_IMAGEINDEX) != ICON_IDX_CLIENT_OPTION_LEAF)
|
|
{
|
|
// this option is not scope option. Put up a dialog telling the user what to do
|
|
AfxMessageBox(IDS_CANNOT_DELETE_OPTION_RES);
|
|
return NOERROR;
|
|
}
|
|
}
|
|
|
|
CString strServer = GetServerIpAddress(spResClient, TRUE);
|
|
|
|
DHCP_OPTION_SCOPE_INFO dhcpOptionScopeInfo;
|
|
dhcpOptionScopeInfo.ScopeType = DhcpReservedOptions;
|
|
dhcpOptionScopeInfo.ScopeInfo.ReservedScopeInfo.ReservedIpAddress = m_dhcpClientIpAddress;
|
|
|
|
CDhcpScope * pScope = GetScopeObject(spResClient, TRUE);
|
|
dhcpOptionScopeInfo.ScopeInfo.ReservedScopeInfo.ReservedIpSubnetAddress = pScope->GetAddress();
|
|
|
|
//
|
|
// Loop through all items deleting
|
|
//
|
|
BEGIN_WAIT_CURSOR;
|
|
|
|
while (listNodesToDelete.GetCount() > 0)
|
|
{
|
|
SPITFSNode spOptionNode;
|
|
spOptionNode = listNodesToDelete.RemoveHead();
|
|
|
|
CDhcpOptionItem * pOptItem = GETHANDLER(CDhcpOptionItem, spOptionNode);
|
|
|
|
//
|
|
// Try to remove it from the server
|
|
//
|
|
|
|
if (pOptItem->IsVendorOption() ||
|
|
pOptItem->IsClassOption())
|
|
{
|
|
LPCTSTR pClassName = pOptItem->GetClassName();
|
|
if (lstrlen(pClassName) == 0)
|
|
pClassName = NULL;
|
|
|
|
dwError = ::DhcpRemoveOptionValueV5((LPTSTR) ((LPCTSTR) strServer),
|
|
pOptItem->IsVendorOption() ? DHCP_FLAGS_OPTION_IS_VENDOR : 0,
|
|
pOptItem->GetOptionId(),
|
|
(LPTSTR) pClassName,
|
|
(LPTSTR) pOptItem->GetVendor(),
|
|
&dhcpOptionScopeInfo);
|
|
}
|
|
else
|
|
{
|
|
dwError = ::DhcpRemoveOptionValue(strServer,
|
|
pOptItem->GetOptionId(),
|
|
&dhcpOptionScopeInfo);
|
|
}
|
|
|
|
if (dwError != 0)
|
|
{
|
|
::DhcpMessageBox(dwError);
|
|
RESTORE_WAIT_CURSOR;
|
|
|
|
hr = E_FAIL;
|
|
continue;
|
|
}
|
|
|
|
GetOptionValueEnum()->Remove(pOptItem->GetOptionId(), pOptItem->GetVendor(), pOptItem->GetClassName());
|
|
|
|
//
|
|
// Remove from UI now
|
|
//
|
|
spResClient->RemoveChild(spOptionNode);
|
|
spOptionNode.Release();
|
|
}
|
|
|
|
END_WAIT_CURSOR;
|
|
|
|
UpdateResultMessage(spResClient);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CDhcpReservationClient::OnGetResultViewType
|
|
MMC calls this to get the result view information
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpReservationClient::OnGetResultViewType
|
|
(
|
|
ITFSComponent * pComponent,
|
|
MMC_COOKIE cookie,
|
|
LPOLESTR * ppViewType,
|
|
long * pViewOptions
|
|
)
|
|
{
|
|
HRESULT hr = hrOK;
|
|
|
|
// call the base class to see if it is handling this
|
|
if (CMTDhcpHandler::OnGetResultViewType(pComponent, cookie, ppViewType, pViewOptions) != S_OK)
|
|
{
|
|
*pViewOptions = MMC_VIEW_OPTIONS_MULTISELECT;
|
|
|
|
hr = S_FALSE;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CDhcpReservationClient::OnHaveData
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
void
|
|
CDhcpReservationClient::OnHaveData
|
|
(
|
|
ITFSNode * pParentNode,
|
|
LPARAM Data,
|
|
LPARAM Type
|
|
)
|
|
{
|
|
// This is how we get non-node data back from the background thread.
|
|
switch (Type)
|
|
{
|
|
case DHCP_QDATA_OPTION_VALUES:
|
|
{
|
|
HRESULT hr = hrOK;
|
|
SPIComponentData spCompData;
|
|
SPIConsole spConsole;
|
|
SPIDataObject spDataObject;
|
|
IDataObject * pDataObject;
|
|
COptionValueEnum * pOptionValueEnum = reinterpret_cast<COptionValueEnum *>(Data);
|
|
|
|
SetOptionValueEnum(pOptionValueEnum);
|
|
|
|
pOptionValueEnum->RemoveAll();
|
|
delete pOptionValueEnum;
|
|
|
|
// now tell the view to update themselves
|
|
m_spNodeMgr->GetComponentData(&spCompData);
|
|
|
|
CORg ( spCompData->QueryDataObject((MMC_COOKIE) pParentNode, CCT_SCOPE, &pDataObject) );
|
|
spDataObject = pDataObject;
|
|
|
|
CORg ( m_spNodeMgr->GetConsole(&spConsole) );
|
|
CORg ( spConsole->UpdateAllViews(pDataObject, (LPARAM) pParentNode, DHCPSNAP_UPDATE_OPTIONS) );
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
Error:
|
|
return;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CDhcpReservationClient::OnNotifyExiting
|
|
CMTDhcpHandler overridden functionality
|
|
allows us to know when the background thread is done
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
STDMETHODIMP
|
|
CDhcpReservationClient::OnNotifyExiting
|
|
(
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
SPITFSNode spNode;
|
|
spNode.Set(m_spNode); // save this off because OnNotifyExiting will release it
|
|
|
|
HRESULT hr = CMTDhcpHandler::OnNotifyExiting(lParam);
|
|
|
|
UpdateResultMessage(spNode);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CDhcpReservationClient::OnResultUpdateView
|
|
Implementation of ITFSResultHandler::OnResultUpdateView
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT CDhcpReservationClient::OnResultUpdateView
|
|
(
|
|
ITFSComponent *pComponent,
|
|
LPDATAOBJECT pDataObject,
|
|
LPARAM data,
|
|
LPARAM hint
|
|
)
|
|
{
|
|
HRESULT hr = hrOK;
|
|
SPITFSNode spSelectedNode;
|
|
|
|
pComponent->GetSelectedNode(&spSelectedNode);
|
|
if (spSelectedNode == NULL)
|
|
return S_OK; // no selection for our IComponentData
|
|
|
|
if ( hint == DHCPSNAP_UPDATE_OPTIONS )
|
|
{
|
|
SPINTERNAL spInternal = ExtractInternalFormat(pDataObject);
|
|
ITFSNode * pNode = reinterpret_cast<ITFSNode *>(spInternal->m_cookie);
|
|
SPITFSNode spSelectedNode;
|
|
|
|
pComponent->GetSelectedNode(&spSelectedNode);
|
|
|
|
EnumerateResultPane(pComponent, (MMC_COOKIE) spSelectedNode.p, 0, 0);
|
|
}
|
|
else
|
|
{
|
|
// we don't handle this message, let the base class do it.
|
|
return CMTDhcpHandler::OnResultUpdateView(pComponent, pDataObject, data, hint);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CDhcpReservationClient::EnumerateResultPane
|
|
We override this function for the options nodes for one reason.
|
|
Whenever an option class is deleted, then all options defined for
|
|
that class will be removed as well. Since there are multiple places
|
|
that these options may show up, it's easier to just not show any
|
|
options that don't have a class defined for it.
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpReservationClient::EnumerateResultPane
|
|
(
|
|
ITFSComponent * pComponent,
|
|
MMC_COOKIE cookie,
|
|
LPARAM arg,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
CClassInfoArray ClassInfoArray;
|
|
SPITFSNode spContainer, spServerNode;
|
|
CDhcpServer * pServer;
|
|
COptionValueEnum * aEnum[3];
|
|
int aImages[3] = {ICON_IDX_CLIENT_OPTION_LEAF, ICON_IDX_SCOPE_OPTION_LEAF, ICON_IDX_SERVER_OPTION_LEAF};
|
|
|
|
m_spNodeMgr->FindNode(cookie, &spContainer);
|
|
|
|
spServerNode = GetServerNode(spContainer, TRUE);
|
|
pServer = GETHANDLER(CDhcpServer, spServerNode);
|
|
|
|
pServer->GetClassInfoArray(ClassInfoArray);
|
|
|
|
aEnum[0] = GetOptionValueEnum();
|
|
aEnum[1] = GetScopeObject(spContainer, TRUE)->GetOptionValueEnum();
|
|
aEnum[2] = pServer->GetOptionValueEnum();
|
|
|
|
aEnum[0]->Reset();
|
|
aEnum[1]->Reset();
|
|
aEnum[2]->Reset();
|
|
|
|
return OnResultUpdateOptions(pComponent, spContainer, &ClassInfoArray, aEnum, aImages, 3);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Helper functions
|
|
---------------------------------------------------------------------------*/
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpReservationClient::GetDnsRegistration
|
|
Gets the DNS registration option value
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CDhcpReservationClient::GetDnsRegistration
|
|
(
|
|
ITFSNode * pNode,
|
|
LPDWORD pDnsRegOption
|
|
)
|
|
{
|
|
//
|
|
// Check option 81 -- the DNS registration option
|
|
//
|
|
CDhcpScope * pScope = GetScopeObject(pNode, TRUE);
|
|
|
|
DHCP_OPTION_VALUE * poptValue = NULL;
|
|
DWORD err = pScope->GetOptionValue(OPTION_DNS_REGISTATION,
|
|
DhcpReservedOptions,
|
|
&poptValue,
|
|
m_dhcpClientIpAddress);
|
|
|
|
// this is the default
|
|
if (pDnsRegOption)
|
|
*pDnsRegOption = DHCP_DYN_DNS_DEFAULT;
|
|
|
|
if (err == ERROR_SUCCESS)
|
|
{
|
|
if ((poptValue->Value.Elements != NULL) &&
|
|
(pDnsRegOption))
|
|
{
|
|
*pDnsRegOption = poptValue->Value.Elements[0].Element.DWordOption;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Trace0("CDhcpReservationClient::GetDnsRegistration - couldn't get DNS reg value -- \
|
|
option may not be defined, Getting Scope value.\n");
|
|
|
|
err = pScope->GetDnsRegistration(pDnsRegOption);
|
|
}
|
|
|
|
if (poptValue)
|
|
::DhcpRpcFreeMemory(poptValue);
|
|
|
|
return err;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpReservationClient::SetDnsRegistration
|
|
Sets the DNS Registration option for this scope
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CDhcpReservationClient::SetDnsRegistration
|
|
(
|
|
ITFSNode * pNode,
|
|
DWORD DnsRegOption
|
|
)
|
|
{
|
|
CDhcpScope * pScope = GetScopeObject(pNode, TRUE);
|
|
DWORD err = 0;
|
|
|
|
//
|
|
// Set DNS name registration (option 81)
|
|
//
|
|
CDhcpOption dhcpOption (OPTION_DNS_REGISTATION, DhcpDWordOption , _T(""), _T(""));
|
|
dhcpOption.QueryValue().SetNumber(DnsRegOption);
|
|
|
|
err = pScope->SetOptionValue(&dhcpOption, DhcpReservedOptions, m_dhcpClientIpAddress);
|
|
|
|
return err;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpReservationClient::BuildDisplayName
|
|
Builds the display name string
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpReservationClient::BuildDisplayName
|
|
(
|
|
CString * pstrDisplayName,
|
|
LPCTSTR pIpAddress,
|
|
LPCTSTR pName
|
|
)
|
|
{
|
|
if (pstrDisplayName)
|
|
{
|
|
CString strTemp = pIpAddress;
|
|
strTemp = L"[" + strTemp + L"]";
|
|
|
|
if (pName)
|
|
{
|
|
CString strName = pName;
|
|
strTemp += L" " + strName;
|
|
}
|
|
|
|
*pstrDisplayName = strTemp;
|
|
}
|
|
|
|
return hrOK;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpReservationClient::BuildDisplayName
|
|
Updates the cached name for this reservation and updates the UI
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpReservationClient::SetName
|
|
(
|
|
LPCTSTR pName
|
|
)
|
|
{
|
|
if (pName != NULL)
|
|
{
|
|
if (m_pstrClientName)
|
|
{
|
|
*m_pstrClientName = pName;
|
|
}
|
|
else
|
|
{
|
|
m_pstrClientName = new CString(pName);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (m_pstrClientName)
|
|
{
|
|
delete m_pstrClientName;
|
|
m_pstrClientName = NULL;
|
|
}
|
|
}
|
|
|
|
CString strIpAddress, strDisplayName;
|
|
|
|
//
|
|
// Create the display name for this scope
|
|
// Convert DHCP_IP_ADDRES to a string and initialize this object
|
|
//
|
|
UtilCvtIpAddrToWstr (m_dhcpClientIpAddress,
|
|
&strIpAddress);
|
|
|
|
BuildDisplayName(&strDisplayName, strIpAddress, pName);
|
|
|
|
SetDisplayName(strDisplayName);
|
|
|
|
return hrOK;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpReservationClient::BuildDisplayName
|
|
Updates the cached comment for this reservation
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpReservationClient::SetComment
|
|
(
|
|
LPCTSTR pComment
|
|
)
|
|
{
|
|
if (pComment != NULL)
|
|
{
|
|
if (m_pstrClientComment)
|
|
{
|
|
*m_pstrClientComment = pComment;
|
|
}
|
|
else
|
|
{
|
|
m_pstrClientComment = new CString(pComment);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (m_pstrClientComment)
|
|
{
|
|
delete m_pstrClientComment;
|
|
m_pstrClientComment = NULL;
|
|
}
|
|
}
|
|
|
|
return hrOK;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpReservationClient::SetUID
|
|
Updates the cached unique ID for this reservation
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpReservationClient::SetUID
|
|
(
|
|
const CByteArray & baClientUID
|
|
)
|
|
{
|
|
m_baHardwareAddress.Copy(baClientUID);
|
|
|
|
return hrOK;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpReservationClient::SetClientType
|
|
Updates the cached client type for this record
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
BYTE
|
|
CDhcpReservationClient::SetClientType
|
|
(
|
|
BYTE bClientType
|
|
)
|
|
{
|
|
BYTE bRet = m_bClientType;
|
|
m_bClientType = bClientType;
|
|
|
|
return bRet;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Background thread functionality
|
|
---------------------------------------------------------------------------*/
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpReservationClient::OnCreateQuery()
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
ITFSQueryObject*
|
|
CDhcpReservationClient::OnCreateQuery(ITFSNode * pNode)
|
|
{
|
|
CDhcpReservationClientQueryObj* pQuery =
|
|
new CDhcpReservationClientQueryObj(m_spTFSCompData, m_spNodeMgr);
|
|
|
|
pQuery->m_strServer = GetServerIpAddress(pNode, TRUE);
|
|
pQuery->m_dhcpScopeAddress = GetScopeObject(pNode, TRUE)->GetAddress();
|
|
pQuery->m_dhcpClientIpAddress = m_dhcpClientIpAddress;
|
|
|
|
GetScopeObject(pNode, TRUE)->GetServerVersion(pQuery->m_liDhcpVersion);
|
|
GetScopeObject(pNode, TRUE)->GetDynBootpClassName(pQuery->m_strDynBootpClassName);
|
|
|
|
pQuery->m_dhcpResumeHandle = NULL;
|
|
pQuery->m_dwPreferredMax = 0xFFFFFFFF;
|
|
|
|
return pQuery;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpReservationClientQueryObj::Execute()
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
STDMETHODIMP
|
|
CDhcpReservationClientQueryObj::Execute()
|
|
{
|
|
DWORD dwErr;
|
|
COptionNodeEnum OptionNodeEnum(m_spTFSCompData, m_spNodeMgr);
|
|
DHCP_OPTION_SCOPE_INFO dhcpOptionScopeInfo;
|
|
|
|
COptionValueEnum * pOptionValueEnum = new COptionValueEnum;
|
|
pOptionValueEnum->m_strDynBootpClassName = m_strDynBootpClassName;
|
|
|
|
dhcpOptionScopeInfo.ScopeType = DhcpReservedOptions;
|
|
dhcpOptionScopeInfo.ScopeInfo.ReservedScopeInfo.ReservedIpAddress = m_dhcpClientIpAddress;
|
|
dhcpOptionScopeInfo.ScopeInfo.ReservedScopeInfo.ReservedIpSubnetAddress = m_dhcpScopeAddress;
|
|
|
|
pOptionValueEnum->Init(m_strServer, m_liDhcpVersion, dhcpOptionScopeInfo);
|
|
dwErr = pOptionValueEnum->Enum();
|
|
|
|
// add all of the nodes
|
|
if (dwErr != ERROR_SUCCESS)
|
|
{
|
|
Trace1("CDhcpReservationClientQueryObj::Execute - Enum Failed! %d\n", dwErr);
|
|
m_dwErr = dwErr;
|
|
PostError(dwErr);
|
|
|
|
delete pOptionValueEnum;
|
|
}
|
|
else
|
|
{
|
|
pOptionValueEnum->SortById();
|
|
AddToQueue((LPARAM) pOptionValueEnum, DHCP_QDATA_OPTION_VALUES);
|
|
}
|
|
|
|
return hrFalse;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CDhcpActiveLeases implementation
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Function Name Here
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
CDhcpActiveLeases::CDhcpActiveLeases
|
|
(
|
|
ITFSComponentData * pComponentData
|
|
) : CMTDhcpHandler(pComponentData)
|
|
{
|
|
}
|
|
|
|
CDhcpActiveLeases::~CDhcpActiveLeases()
|
|
{
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CDhcpActiveLeases::InitializeNode
|
|
Initializes node specific data
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpActiveLeases::InitializeNode
|
|
(
|
|
ITFSNode * pNode
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
HRESULT hr = hrOK;
|
|
|
|
//
|
|
// Create the display name for this scope
|
|
//
|
|
CString strTemp;
|
|
strTemp.LoadString(IDS_ACTIVE_LEASES_FOLDER);
|
|
|
|
SetDisplayName(strTemp);
|
|
|
|
// Make the node immediately visible
|
|
pNode->SetVisibilityState(TFS_VIS_SHOW);
|
|
pNode->SetData(TFS_DATA_IMAGEINDEX, GetImageIndex(FALSE));
|
|
pNode->SetData(TFS_DATA_OPENIMAGEINDEX, GetImageIndex(TRUE));
|
|
pNode->SetData(TFS_DATA_COOKIE, (LPARAM) pNode);
|
|
pNode->SetData(TFS_DATA_USER, (LPARAM) this);
|
|
pNode->SetData(TFS_DATA_TYPE, DHCPSNAP_ACTIVE_LEASES);
|
|
pNode->SetData(TFS_DATA_SCOPE_LEAF_NODE, TRUE);
|
|
|
|
SetColumnStringIDs(&aColumns[DHCPSNAP_ACTIVE_LEASES][0]);
|
|
SetColumnWidths(&aColumnWidths[DHCPSNAP_ACTIVE_LEASES][0]);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpActiveLeases::OnCreateNodeId2
|
|
Returns a unique string for this node
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT CDhcpActiveLeases::OnCreateNodeId2(ITFSNode * pNode, CString & strId, DWORD * dwFlags)
|
|
{
|
|
const GUID * pGuid = pNode->GetNodeType();
|
|
|
|
CString strIpAddress, strGuid;
|
|
|
|
StringFromGUID2(*pGuid, strGuid.GetBuffer(256), 256);
|
|
strGuid.ReleaseBuffer();
|
|
|
|
DHCP_IP_ADDRESS dhcpIpAddress = GetScopeObject(pNode)->GetAddress();
|
|
|
|
UtilCvtIpAddrToWstr (dhcpIpAddress, &strIpAddress);
|
|
|
|
strId = GetServerName(pNode) + strIpAddress + strGuid;
|
|
|
|
return hrOK;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpActiveLeases::GetImageIndex
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
int
|
|
CDhcpActiveLeases::GetImageIndex(BOOL bOpenImage)
|
|
{
|
|
int nIndex = -1;
|
|
switch (m_nState)
|
|
{
|
|
case notLoaded:
|
|
case loaded:
|
|
if (bOpenImage)
|
|
nIndex = ICON_IDX_ACTIVE_LEASES_FOLDER_OPEN;
|
|
else
|
|
nIndex = ICON_IDX_ACTIVE_LEASES_FOLDER_CLOSED;
|
|
break;
|
|
|
|
case loading:
|
|
if (bOpenImage)
|
|
nIndex = ICON_IDX_ACTIVE_LEASES_FOLDER_OPEN_BUSY;
|
|
else
|
|
nIndex = ICON_IDX_ACTIVE_LEASES_FOLDER_CLOSED_BUSY;
|
|
break;
|
|
|
|
case unableToLoad:
|
|
if (bOpenImage)
|
|
nIndex = ICON_IDX_ACTIVE_LEASES_FOLDER_OPEN_LOST_CONNECTION;
|
|
else
|
|
nIndex = ICON_IDX_ACTIVE_LEASES_FOLDER_CLOSED_LOST_CONNECTION;
|
|
break;
|
|
|
|
default:
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
return nIndex;
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Overridden base handler functions
|
|
---------------------------------------------------------------------------*/
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpActiveLeases::OnAddMenuItems
|
|
Adds entries to the context sensitive menu
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
STDMETHODIMP
|
|
CDhcpActiveLeases::OnAddMenuItems
|
|
(
|
|
ITFSNode * pNode,
|
|
LPCONTEXTMENUCALLBACK pContextMenuCallback,
|
|
LPDATAOBJECT lpDataObject,
|
|
DATA_OBJECT_TYPES type,
|
|
DWORD dwType,
|
|
long * pInsertionAllowed
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
LONG fFlags = 0;
|
|
HRESULT hr = S_OK;
|
|
CString strMenuText;
|
|
|
|
if ( (m_nState != loaded) )
|
|
{
|
|
fFlags |= MF_GRAYED;
|
|
}
|
|
|
|
if (type == CCT_SCOPE)
|
|
{
|
|
if (*pInsertionAllowed & CCM_INSERTIONALLOWED_TOP)
|
|
{
|
|
/* removed, using new MMC save list functionality
|
|
strMenuText.LoadString(IDS_EXPORT_LEASE_INFO);
|
|
hr = LoadAndAddMenuItem( pContextMenuCallback,
|
|
strMenuText,
|
|
IDS_EXPORT_LEASE_INFO,
|
|
CCM_INSERTIONPOINTID_PRIMARY_TOP,
|
|
fFlags );
|
|
ASSERT( SUCCEEDED(hr) );
|
|
*/
|
|
}
|
|
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpActiveLeases::OnCommand
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
STDMETHODIMP
|
|
CDhcpActiveLeases::OnCommand
|
|
(
|
|
ITFSNode * pNode,
|
|
long nCommandId,
|
|
DATA_OBJECT_TYPES type,
|
|
LPDATAOBJECT pDataObject,
|
|
DWORD dwType
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
switch (nCommandId)
|
|
{
|
|
case IDS_REFRESH:
|
|
OnRefresh(pNode, pDataObject, dwType, 0, 0);
|
|
break;
|
|
|
|
case IDS_EXPORT_LEASE_INFO:
|
|
OnExportLeases(pNode);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpActiveLeases::OnResultDelete
|
|
This function is called when we are supposed to delete result
|
|
pane items. We build a list of selected items and then delete them.
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpActiveLeases::OnResultDelete
|
|
(
|
|
ITFSComponent * pComponent,
|
|
LPDATAOBJECT pDataObject,
|
|
MMC_COOKIE cookie,
|
|
LPARAM arg,
|
|
LPARAM param
|
|
)
|
|
{
|
|
HRESULT hr = hrOK;
|
|
BOOL bIsRes, bIsActive, bBadAddress;
|
|
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
// translate the cookie into a node pointer
|
|
SPITFSNode spActiveLeases, spSelectedNode;
|
|
m_spNodeMgr->FindNode(cookie, &spActiveLeases);
|
|
pComponent->GetSelectedNode(&spSelectedNode);
|
|
|
|
Assert(spSelectedNode == spActiveLeases);
|
|
if (spSelectedNode != spActiveLeases)
|
|
return hr;
|
|
|
|
// build the list of selected nodes
|
|
CTFSNodeList listNodesToDelete;
|
|
hr = BuildSelectedItemList(pComponent, &listNodesToDelete);
|
|
|
|
//
|
|
// Confirm with the user
|
|
//
|
|
CString strMessage, strTemp;
|
|
int nNodes = (int) listNodesToDelete.GetCount();
|
|
if (nNodes > 1)
|
|
{
|
|
strTemp.Format(_T("%d"), nNodes);
|
|
AfxFormatString1(strMessage, IDS_DELETE_ITEMS, (LPCTSTR) strTemp);
|
|
}
|
|
else
|
|
{
|
|
strMessage.LoadString(IDS_DELETE_ITEM);
|
|
}
|
|
|
|
if (AfxMessageBox(strMessage, MB_YESNO) == IDNO)
|
|
{
|
|
return NOERROR;
|
|
}
|
|
|
|
//
|
|
// Loop through all items deleting
|
|
//
|
|
BEGIN_WAIT_CURSOR;
|
|
|
|
while (listNodesToDelete.GetCount() > 0)
|
|
{
|
|
SPITFSNode spActiveLeaseNode;
|
|
spActiveLeaseNode = listNodesToDelete.RemoveHead();
|
|
CDhcpActiveLease * pActiveLease = GETHANDLER(CDhcpActiveLease, spActiveLeaseNode);
|
|
|
|
//
|
|
// delete the node, check to see if it is a reservation
|
|
//
|
|
bIsRes = pActiveLease->IsReservation(&bIsActive, &bBadAddress);
|
|
if (bIsRes && !bBadAddress)
|
|
{
|
|
//
|
|
// Delete the reservation
|
|
//
|
|
LPDHCP_CLIENT_INFO pdhcpClientInfo;
|
|
|
|
DWORD dwError = GetScopeObject(spActiveLeases)->GetClientInfo(pActiveLease->GetIpAddress(), &pdhcpClientInfo);
|
|
if (dwError == ERROR_SUCCESS)
|
|
{
|
|
dwError = GetScopeObject(spActiveLeases)->DeleteReservation(pdhcpClientInfo->ClientHardwareAddress,
|
|
pdhcpClientInfo->ClientIpAddress);
|
|
if (dwError == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// Tell the reservations folder to remove this from it's list
|
|
//
|
|
SPITFSNode spReservationsNode;
|
|
GetScopeObject(spActiveLeases)->GetReservationsNode(&spReservationsNode);
|
|
|
|
GetScopeObject(spActiveLeases)->GetReservationsObject()->
|
|
RemoveReservationFromUI((ITFSNode *) spReservationsNode, pActiveLease->GetIpAddress());
|
|
|
|
spActiveLeases->RemoveChild(spActiveLeaseNode);
|
|
}
|
|
else
|
|
{
|
|
UtilCvtIpAddrToWstr(pActiveLease->GetIpAddress(), &strTemp);
|
|
AfxFormatString1(strMessage, IDS_ERROR_DELETING_RECORD, (LPCTSTR) strTemp);
|
|
|
|
if (::DhcpMessageBoxEx(dwError, strMessage, MB_OKCANCEL) == IDCANCEL)
|
|
{
|
|
break;
|
|
}
|
|
RESTORE_WAIT_CURSOR;
|
|
|
|
Trace1("Delete reservation failed %lx\n", dwError);
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
::DhcpRpcFreeMemory(pdhcpClientInfo);
|
|
}
|
|
else
|
|
{
|
|
UtilCvtIpAddrToWstr(pActiveLease->GetIpAddress(), &strTemp);
|
|
AfxFormatString1(strMessage, IDS_ERROR_DELETING_RECORD, (LPCTSTR) strTemp);
|
|
|
|
if (::DhcpMessageBoxEx(dwError, strMessage, MB_OKCANCEL) == IDCANCEL)
|
|
{
|
|
break;
|
|
}
|
|
RESTORE_WAIT_CURSOR;
|
|
|
|
Trace1("GetClientInfo failed %lx\n", dwError);
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
DWORD dwError = GetScopeObject(spActiveLeases)->DeleteClient(pActiveLease->GetIpAddress());
|
|
if (dwError == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// Client gone, now remove from UI
|
|
//
|
|
spActiveLeases->RemoveChild(spActiveLeaseNode);
|
|
|
|
// if we are deleting a lot of addresses, then we can hit the server hard..
|
|
// lets take a short time out to smooth out the process
|
|
Sleep(5);
|
|
}
|
|
else
|
|
{
|
|
UtilCvtIpAddrToWstr(pActiveLease->GetIpAddress(), &strTemp);
|
|
AfxFormatString1(strMessage, IDS_ERROR_DELETING_RECORD, (LPCTSTR) strTemp);
|
|
|
|
if (::DhcpMessageBoxEx(dwError, strMessage, MB_OKCANCEL) == IDCANCEL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
RESTORE_WAIT_CURSOR;
|
|
|
|
Trace1("DhcpDeleteClientInfo failed %lx\n", dwError);
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
|
|
spActiveLeaseNode.Release();
|
|
}
|
|
|
|
// update stats
|
|
GetScopeObject(spActiveLeases)->TriggerStatsRefresh();
|
|
|
|
END_WAIT_CURSOR;
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpActiveLeases::DeleteClient
|
|
The reservations object will call this when a reservation is
|
|
deleted. Since a reservation also has an active lease record,
|
|
we have to delete it as well.
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CDhcpActiveLeases::DeleteClient
|
|
(
|
|
ITFSNode * pActiveLeasesNode,
|
|
DHCP_IP_ADDRESS dhcpIpAddress
|
|
)
|
|
{
|
|
DWORD dwError = E_UNEXPECTED;
|
|
CDhcpActiveLease * pActiveLease = NULL;
|
|
|
|
SPITFSNodeEnum spNodeEnum;
|
|
SPITFSNode spCurrentNode;
|
|
ULONG nNumReturned = 0;
|
|
|
|
pActiveLeasesNode->GetEnum(&spNodeEnum);
|
|
|
|
spNodeEnum->Next(1, &spCurrentNode, &nNumReturned);
|
|
while (nNumReturned)
|
|
{
|
|
pActiveLease = GETHANDLER(CDhcpActiveLease, spCurrentNode);
|
|
|
|
if (dhcpIpAddress == pActiveLease->GetIpAddress())
|
|
{
|
|
//
|
|
// Tell this reservation to delete itself
|
|
//
|
|
pActiveLeasesNode->RemoveChild(spCurrentNode);
|
|
spCurrentNode.Release();
|
|
dwError = ERROR_SUCCESS;
|
|
|
|
break;
|
|
}
|
|
|
|
spCurrentNode.Release();
|
|
spNodeEnum->Next(1, &spCurrentNode, &nNumReturned);
|
|
}
|
|
|
|
return dwError;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CDhcpActiveLeases::OnGetResultViewType
|
|
MMC calls this to get the result view information
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT CDhcpActiveLeases::OnGetResultViewType
|
|
(
|
|
ITFSComponent * pComponent,
|
|
MMC_COOKIE cookie,
|
|
LPOLESTR * ppViewType,
|
|
long * pViewOptions
|
|
)
|
|
{
|
|
*pViewOptions = MMC_VIEW_OPTIONS_MULTISELECT;
|
|
|
|
// we still want the default MMC result pane view, we just want
|
|
// multiselect, so return S_FALSE
|
|
|
|
return S_FALSE;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpActiveLeases::CompareItems
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
STDMETHODIMP_(int)
|
|
CDhcpActiveLeases::CompareItems
|
|
(
|
|
ITFSComponent * pComponent,
|
|
MMC_COOKIE cookieA,
|
|
MMC_COOKIE cookieB,
|
|
int nCol
|
|
)
|
|
{
|
|
SPITFSNode spNode1, spNode2;
|
|
|
|
m_spNodeMgr->FindNode(cookieA, &spNode1);
|
|
m_spNodeMgr->FindNode(cookieB, &spNode2);
|
|
|
|
int nCompare = 0;
|
|
|
|
CDhcpActiveLease *pDhcpAL1 = GETHANDLER(CDhcpActiveLease, spNode1);
|
|
CDhcpActiveLease *pDhcpAL2 = GETHANDLER(CDhcpActiveLease, spNode2);
|
|
|
|
switch (nCol)
|
|
{
|
|
case 0:
|
|
{
|
|
// IP address compare
|
|
//
|
|
nCompare = CompareIpAddresses(pDhcpAL1, pDhcpAL2);
|
|
}
|
|
break;
|
|
|
|
case 1:
|
|
{
|
|
// Client Name compare
|
|
//
|
|
CString strAL1 = pDhcpAL1->GetString(pComponent, cookieA, nCol);
|
|
CString strAL2 = pDhcpAL2->GetString(pComponent, cookieA, nCol);
|
|
|
|
nCompare = strAL1.CompareNoCase(strAL2);
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
{
|
|
// Lease expiration compare
|
|
//
|
|
BOOL bIsActive1, bIsActive2;
|
|
BOOL bIsBad1, bIsBad2;
|
|
|
|
BOOL bIsRes1 = pDhcpAL1->IsReservation(&bIsActive1, &bIsBad1);
|
|
BOOL bIsRes2 = pDhcpAL2->IsReservation(&bIsActive2, &bIsBad2);
|
|
|
|
//
|
|
// Check to see if these are reservations
|
|
//
|
|
if (bIsRes1 && bIsRes2)
|
|
{
|
|
//
|
|
// Figure out if this is a bad address
|
|
// They go first
|
|
//
|
|
if (bIsBad1 && bIsBad2)
|
|
{
|
|
//
|
|
// Sort by IP Address
|
|
//
|
|
nCompare = CompareIpAddresses(pDhcpAL1, pDhcpAL2);
|
|
}
|
|
else
|
|
if (bIsBad1)
|
|
nCompare = -1;
|
|
else
|
|
if (bIsBad2)
|
|
nCompare = 1;
|
|
else
|
|
if ((bIsActive1 && bIsActive2) ||
|
|
(!bIsActive1 && !bIsActive2))
|
|
{
|
|
//
|
|
// if both reservations are either active/inactive
|
|
// sort by IP address
|
|
//
|
|
nCompare = CompareIpAddresses(pDhcpAL1, pDhcpAL2);
|
|
}
|
|
else
|
|
if (bIsActive1)
|
|
nCompare = -1;
|
|
else
|
|
nCompare = 1;
|
|
}
|
|
else
|
|
if (bIsRes1)
|
|
{
|
|
nCompare = -1;
|
|
}
|
|
else
|
|
if (bIsRes2)
|
|
{
|
|
nCompare = 1;
|
|
}
|
|
else
|
|
{
|
|
CTime timeAL1, timeAL2;
|
|
|
|
pDhcpAL1->GetLeaseExpirationTime(timeAL1);
|
|
pDhcpAL2->GetLeaseExpirationTime(timeAL2);
|
|
|
|
if (timeAL1 < timeAL2)
|
|
nCompare = -1;
|
|
else
|
|
if (timeAL1 > timeAL2)
|
|
nCompare = 1;
|
|
}
|
|
|
|
// default is that they are equal
|
|
}
|
|
break;
|
|
|
|
case 3:
|
|
{
|
|
// Client Type Compare
|
|
CString strAL1 = pDhcpAL1->GetString(pComponent, cookieA, nCol);
|
|
CString strAL2 = pDhcpAL2->GetString(pComponent, cookieA, nCol);
|
|
|
|
nCompare = strAL1.Compare(strAL2);
|
|
}
|
|
break;
|
|
|
|
case 4:
|
|
{
|
|
CString strUID1 = pDhcpAL1->GetUID();
|
|
|
|
nCompare = strUID1.CompareNoCase(pDhcpAL2->GetUID());
|
|
}
|
|
break;
|
|
|
|
case 5:
|
|
{
|
|
CString strComment1 = pDhcpAL1->GetComment();
|
|
|
|
nCompare = strComment1.CompareNoCase(pDhcpAL2->GetComment());
|
|
}
|
|
break;
|
|
}
|
|
|
|
return nCompare;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Function Name Here
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
int
|
|
CDhcpActiveLeases::CompareIpAddresses
|
|
(
|
|
CDhcpActiveLease * pDhcpAL1,
|
|
CDhcpActiveLease * pDhcpAL2
|
|
)
|
|
{
|
|
int nCompare = 0;
|
|
|
|
DHCP_IP_ADDRESS dhcpIp1 = pDhcpAL1->GetIpAddress();
|
|
DHCP_IP_ADDRESS dhcpIp2 = pDhcpAL2->GetIpAddress();
|
|
|
|
if (dhcpIp1 < dhcpIp2)
|
|
nCompare = -1;
|
|
else
|
|
if (dhcpIp1 > dhcpIp2)
|
|
nCompare = 1;
|
|
|
|
return nCompare;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpActiveLeases::OnExportLeases()
|
|
-
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpActiveLeases::OnExportLeases(ITFSNode * pNode)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
HRESULT hr = hrOK;
|
|
|
|
// Bring up the Save Dialog
|
|
SPITFSNodeEnum spNodeEnum;
|
|
SPITFSNode spCurrentNode;
|
|
ULONG nNumReturned = 0;
|
|
|
|
CString strType;
|
|
CString strDefFileName;
|
|
CString strFilter;
|
|
CString strTitle;
|
|
CString strFileName;
|
|
|
|
strType.LoadString(IDS_FILE_EXTENSION);
|
|
strDefFileName.LoadString(IDS_FILE_DEFNAME);
|
|
strFilter.LoadString(IDS_STR_EXPORTFILE_FILTER);
|
|
|
|
CFileDialog cFileDlg(FALSE, strType, strDefFileName, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, strFilter);//_T("Comma Separated Files (*.csv)|*.csv||") );
|
|
|
|
strTitle.LoadString(IDS_EXPFILE_TITLE);
|
|
cFileDlg.m_ofn.lpstrTitle = strTitle;
|
|
|
|
// put up the file dialog
|
|
if( cFileDlg.DoModal() != IDOK )
|
|
return hrFalse;
|
|
|
|
strFileName = cFileDlg.GetPathName();
|
|
|
|
COM_PROTECT_TRY
|
|
{
|
|
CString strContent;
|
|
CString strLine;
|
|
CString strTemp;
|
|
CString strDelim = _T(',');
|
|
CString strNewLine = _T("\r\n");
|
|
int nCount = 0;
|
|
|
|
// create a file named "WinsExp.txt" in the current directory
|
|
CFile cFileExp(strFileName, CFile::modeCreate | CFile::modeRead | CFile::modeWrite);
|
|
|
|
// this is a unicode file, write the unicde lead bytes (2)
|
|
cFileExp.Write(&gwUnicodeHeader, sizeof(WORD));
|
|
|
|
// write the header
|
|
for (int i = 0; i < MAX_COLUMNS; i++)
|
|
{
|
|
if (aColumns[DHCPSNAP_ACTIVE_LEASES][i])
|
|
{
|
|
if (!strLine.IsEmpty())
|
|
strLine += strDelim;
|
|
|
|
strTemp.LoadString(aColumns[DHCPSNAP_ACTIVE_LEASES][i]);
|
|
strLine += strTemp;
|
|
}
|
|
}
|
|
|
|
strLine += strNewLine;
|
|
cFileExp.Write(strLine, strLine.GetLength()*sizeof(TCHAR));
|
|
cFileExp.SeekToEnd();
|
|
|
|
BEGIN_WAIT_CURSOR
|
|
|
|
#ifdef DEBUG
|
|
CTime timeStart, timeFinish;
|
|
timeStart = CTime::GetCurrentTime();
|
|
#endif
|
|
|
|
// enumerate all the leases and output
|
|
pNode->GetEnum(&spNodeEnum);
|
|
|
|
spNodeEnum->Next(1, &spCurrentNode, &nNumReturned);
|
|
while (nNumReturned)
|
|
{
|
|
CDhcpActiveLease * pLease = GETHANDLER(CDhcpActiveLease, spCurrentNode);
|
|
|
|
strLine.Empty();
|
|
|
|
// ipaddr, name, type, lease exp, UID, comment
|
|
for (int j = 0; j < 6; j++)
|
|
{
|
|
if (!strLine.IsEmpty())
|
|
strLine += strDelim;
|
|
strLine += pLease->GetString(NULL, NULL, j);
|
|
}
|
|
|
|
strLine += strNewLine;
|
|
strContent += strLine;
|
|
|
|
nCount++;
|
|
|
|
//optimize
|
|
// write to the file for every 1000 records converted
|
|
if( nCount % 1000 == 0)
|
|
{
|
|
cFileExp.Write(strContent, strContent.GetLength() * (sizeof(TCHAR)) );
|
|
cFileExp.SeekToEnd();
|
|
|
|
// clear all the strings now
|
|
strContent.Empty();
|
|
}
|
|
|
|
spCurrentNode.Release();
|
|
spNodeEnum->Next(1, &spCurrentNode, &nNumReturned);
|
|
}
|
|
|
|
// write to the file
|
|
cFileExp.Write(strContent, strContent.GetLength() * (sizeof(TCHAR)) );
|
|
cFileExp.Close();
|
|
|
|
#ifdef DEBUG
|
|
timeFinish = CTime::GetCurrentTime();
|
|
CTimeSpan timeDelta = timeFinish - timeStart;
|
|
Trace2("ActiveLeases - Export Entries: %d records written, total time %s\n", nCount, timeDelta.Format(_T("%H:%M:%S")));
|
|
#endif
|
|
|
|
END_WAIT_CURSOR
|
|
}
|
|
COM_PROTECT_CATCH
|
|
|
|
CString strDisp;
|
|
AfxFormatString1(strDisp, IDS_EXPORT_SUCCESS, strFileName);
|
|
|
|
AfxMessageBox(strDisp, MB_ICONINFORMATION );
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Background thread functionality
|
|
---------------------------------------------------------------------------*/
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpActiveLeases::OnCreateQuery()
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
ITFSQueryObject*
|
|
CDhcpActiveLeases::OnCreateQuery(ITFSNode * pNode)
|
|
{
|
|
CDhcpActiveLeasesQueryObj* pQuery =
|
|
new CDhcpActiveLeasesQueryObj(m_spTFSCompData, m_spNodeMgr);
|
|
|
|
pQuery->m_strServer = GetServerIpAddress(pNode);
|
|
|
|
pQuery->m_dhcpScopeAddress = GetScopeObject(pNode)->GetAddress();
|
|
pQuery->m_dhcpResumeHandle = NULL;
|
|
pQuery->m_dwPreferredMax = 2000;
|
|
GetServerVersion(pNode, pQuery->m_liDhcpVersion);
|
|
|
|
return pQuery;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpActiveLeasesQueryObj::Execute()
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
STDMETHODIMP
|
|
CDhcpActiveLeasesQueryObj::Execute()
|
|
{
|
|
HRESULT hr;
|
|
|
|
BuildReservationList();
|
|
|
|
if (m_liDhcpVersion.QuadPart >= DHCP_NT5_VERSION)
|
|
{
|
|
hr = EnumerateLeasesV5();
|
|
}
|
|
else
|
|
if (m_liDhcpVersion.QuadPart >= DHCP_SP2_VERSION)
|
|
{
|
|
hr = EnumerateLeasesV4();
|
|
}
|
|
else
|
|
{
|
|
hr = EnumerateLeases();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpActiveLeasesQueryObj::IsReservation()
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
BOOL
|
|
CDhcpActiveLeasesQueryObj::IsReservation(DWORD dwIp)
|
|
{
|
|
BOOL fIsRes = FALSE;
|
|
|
|
for (int i = 0; i < m_ReservationArray.GetSize(); i++)
|
|
{
|
|
if (m_ReservationArray[i] == dwIp)
|
|
{
|
|
fIsRes = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return fIsRes;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpActiveLeasesQueryObj::BuildReservationList()
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpActiveLeasesQueryObj::BuildReservationList()
|
|
{
|
|
LPDHCP_SUBNET_ELEMENT_INFO_ARRAY pdhcpSubnetElementArray = NULL;
|
|
DHCP_RESUME_HANDLE dhcpResumeHandle = NULL;
|
|
DWORD dwElementsRead = 0, dwElementsTotal = 0;
|
|
DWORD dwError = ERROR_MORE_DATA;
|
|
|
|
while (dwError == ERROR_MORE_DATA)
|
|
{
|
|
dwError = ::DhcpEnumSubnetElements(((LPWSTR) (LPCTSTR)m_strServer),
|
|
m_dhcpScopeAddress,
|
|
DhcpReservedIps,
|
|
&dhcpResumeHandle,
|
|
-1,
|
|
&pdhcpSubnetElementArray,
|
|
&dwElementsRead,
|
|
&dwElementsTotal);
|
|
|
|
Trace3("BuildReservationList: Scope %lx Reservations read %d, total %d\n", m_dhcpScopeAddress, dwElementsRead, dwElementsTotal);
|
|
|
|
if (dwElementsRead && dwElementsTotal && pdhcpSubnetElementArray)
|
|
{
|
|
//
|
|
// Loop through the array that was returned
|
|
//
|
|
for (DWORD i = 0; i < pdhcpSubnetElementArray->NumElements; i++)
|
|
{
|
|
m_ReservationArray.Add(pdhcpSubnetElementArray->Elements[i].Element.ReservedIp->ReservedIpAddress);
|
|
}
|
|
}
|
|
|
|
// Check the abort flag on the thread
|
|
if (FCheckForAbort() == hrOK)
|
|
break;
|
|
|
|
// check to see if we have an error and post it to the main thread if we do..
|
|
if (dwError != ERROR_NO_MORE_ITEMS &&
|
|
dwError != ERROR_SUCCESS &&
|
|
dwError != ERROR_MORE_DATA)
|
|
{
|
|
Trace1("DHCP snapin: BuildReservationList error: %d\n", dwError);
|
|
m_dwErr = dwError;
|
|
PostError(dwError);
|
|
}
|
|
}
|
|
|
|
return hrFalse;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpActiveLeasesQueryObj::EnumerateLeasesV5()
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpActiveLeasesQueryObj::EnumerateLeasesV5()
|
|
{
|
|
DWORD dwError = ERROR_MORE_DATA;
|
|
LPDHCP_CLIENT_INFO_ARRAY_V5 pdhcpClientArrayV5 = NULL;
|
|
DWORD dwClientsRead = 0, dwClientsTotal = 0;
|
|
DWORD dwEnumedClients = 0;
|
|
|
|
while (dwError == ERROR_MORE_DATA)
|
|
{
|
|
dwError = ::DhcpEnumSubnetClientsV5(((LPWSTR) (LPCTSTR)m_strServer),
|
|
m_dhcpScopeAddress,
|
|
&m_dhcpResumeHandle,
|
|
m_dwPreferredMax,
|
|
&pdhcpClientArrayV5,
|
|
&dwClientsRead,
|
|
&dwClientsTotal);
|
|
if (dwClientsRead && dwClientsTotal && pdhcpClientArrayV5)
|
|
{
|
|
//
|
|
// loop through all of the elements that were returned
|
|
//
|
|
for (DWORD i = 0; i < dwClientsRead; i++)
|
|
{
|
|
CDhcpActiveLease * pDhcpActiveLease;
|
|
|
|
//
|
|
// Create the result pane item for this element
|
|
//
|
|
SPITFSNode spNode;
|
|
pDhcpActiveLease =
|
|
new CDhcpActiveLease(m_spTFSCompData, pdhcpClientArrayV5->Clients[i]);
|
|
|
|
// filter these types of records out
|
|
if (pDhcpActiveLease->IsUnreg())
|
|
{
|
|
delete pDhcpActiveLease;
|
|
continue;
|
|
}
|
|
|
|
if (IsReservation(pdhcpClientArrayV5->Clients[i]->ClientIpAddress))
|
|
pDhcpActiveLease->SetReservation(TRUE);
|
|
|
|
CreateLeafTFSNode(&spNode,
|
|
&GUID_DhcpActiveLeaseNodeType,
|
|
pDhcpActiveLease,
|
|
pDhcpActiveLease,
|
|
m_spNodeMgr);
|
|
|
|
// Tell the handler to initialize any specific data
|
|
pDhcpActiveLease->InitializeNode(spNode);
|
|
|
|
AddToQueue(spNode);
|
|
pDhcpActiveLease->Release();
|
|
}
|
|
|
|
::DhcpRpcFreeMemory(pdhcpClientArrayV5);
|
|
|
|
dwEnumedClients += dwClientsRead;
|
|
dwClientsRead = 0;
|
|
dwClientsTotal = 0;
|
|
pdhcpClientArrayV5 = NULL;
|
|
}
|
|
|
|
// Check the abort flag on the thread
|
|
if (FCheckForAbort() == hrOK)
|
|
break;
|
|
|
|
// check to see if we have an error and post it to the main thread if we do..
|
|
if (dwError != ERROR_NO_MORE_ITEMS &&
|
|
dwError != ERROR_SUCCESS &&
|
|
dwError != ERROR_MORE_DATA)
|
|
{
|
|
Trace1("DHCP snapin: EnumerateLeasesV5 error: %d\n", dwError);
|
|
m_dwErr = dwError;
|
|
PostError(dwError);
|
|
}
|
|
}
|
|
|
|
Trace1("DHCP snapin: V5 Leases enumerated: %d\n", dwEnumedClients);
|
|
return hrFalse;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpActiveLeasesQueryObj::EnumerateLeasesV4()
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpActiveLeasesQueryObj::EnumerateLeasesV4()
|
|
{
|
|
DWORD dwError = ERROR_MORE_DATA;
|
|
LPDHCP_CLIENT_INFO_ARRAY_V4 pdhcpClientArrayV4 = NULL;
|
|
DWORD dwClientsRead = 0, dwClientsTotal = 0;
|
|
DWORD dwEnumedClients = 0;
|
|
|
|
while (dwError == ERROR_MORE_DATA)
|
|
{
|
|
dwError = ::DhcpEnumSubnetClientsV4(((LPWSTR) (LPCTSTR)m_strServer),
|
|
m_dhcpScopeAddress,
|
|
&m_dhcpResumeHandle,
|
|
m_dwPreferredMax,
|
|
&pdhcpClientArrayV4,
|
|
&dwClientsRead,
|
|
&dwClientsTotal);
|
|
|
|
if (dwClientsRead && dwClientsTotal && pdhcpClientArrayV4)
|
|
{
|
|
//
|
|
// loop through all of the elements that were returned
|
|
//
|
|
//for (DWORD i = 0; i < pdhcpClientArrayV4->NumElements; i++)
|
|
for (DWORD i = 0; i < dwClientsRead; i++)
|
|
{
|
|
CDhcpActiveLease * pDhcpActiveLease;
|
|
|
|
//
|
|
// Create the result pane item for this element
|
|
//
|
|
SPITFSNode spNode;
|
|
pDhcpActiveLease =
|
|
new CDhcpActiveLease(m_spTFSCompData, pdhcpClientArrayV4->Clients[i]);
|
|
|
|
// filter these types of records out
|
|
if (pDhcpActiveLease->IsGhost() ||
|
|
pDhcpActiveLease->IsUnreg() ||
|
|
pDhcpActiveLease->IsDoomed() )
|
|
{
|
|
delete pDhcpActiveLease;
|
|
continue;
|
|
}
|
|
|
|
if (IsReservation(pdhcpClientArrayV4->Clients[i]->ClientIpAddress))
|
|
pDhcpActiveLease->SetReservation(TRUE);
|
|
|
|
CreateLeafTFSNode(&spNode,
|
|
&GUID_DhcpActiveLeaseNodeType,
|
|
pDhcpActiveLease,
|
|
pDhcpActiveLease,
|
|
m_spNodeMgr);
|
|
|
|
// Tell the handler to initialize any specific data
|
|
pDhcpActiveLease->InitializeNode(spNode);
|
|
|
|
AddToQueue(spNode);
|
|
pDhcpActiveLease->Release();
|
|
}
|
|
|
|
::DhcpRpcFreeMemory(pdhcpClientArrayV4);
|
|
|
|
dwEnumedClients += dwClientsRead;
|
|
dwClientsRead = 0;
|
|
dwClientsTotal = 0;
|
|
pdhcpClientArrayV4 = NULL;
|
|
}
|
|
|
|
// Check the abort flag on the thread
|
|
if (FCheckForAbort() == hrOK)
|
|
break;
|
|
|
|
// check to see if we have an error and post it to the main thread if we do..
|
|
if (dwError != ERROR_NO_MORE_ITEMS &&
|
|
dwError != ERROR_SUCCESS &&
|
|
dwError != ERROR_MORE_DATA)
|
|
{
|
|
Trace1("DHCP snapin: EnumerateLeasesV4 error: %d\n", dwError);
|
|
m_dwErr = dwError;
|
|
PostError(dwError);
|
|
}
|
|
}
|
|
|
|
Trace1("DHCP snapin: V4 Leases enumerated: %d\n", dwEnumedClients);
|
|
return hrFalse;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpActiveLeasesQueryObj::EnumerateLeases()
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpActiveLeasesQueryObj::EnumerateLeases()
|
|
{
|
|
DWORD dwError = ERROR_MORE_DATA;
|
|
LPDHCP_CLIENT_INFO_ARRAY pdhcpClientArray = NULL;
|
|
DWORD dwClientsRead = 0, dwClientsTotal = 0;
|
|
DWORD dwEnumedClients = 0;
|
|
|
|
while (dwError == ERROR_MORE_DATA)
|
|
{
|
|
dwError = ::DhcpEnumSubnetClients(((LPWSTR) (LPCTSTR)m_strServer),
|
|
m_dhcpScopeAddress,
|
|
&m_dhcpResumeHandle,
|
|
m_dwPreferredMax,
|
|
&pdhcpClientArray,
|
|
&dwClientsRead,
|
|
&dwClientsTotal);
|
|
if (dwClientsRead && dwClientsTotal && pdhcpClientArray)
|
|
{
|
|
//
|
|
// loop through all of the elements that were returned
|
|
//
|
|
for (DWORD i = 0; i < pdhcpClientArray->NumElements; i++)
|
|
{
|
|
CDhcpActiveLease * pDhcpActiveLease;
|
|
|
|
//
|
|
// Create the result pane item for this element
|
|
//
|
|
SPITFSNode spNode;
|
|
pDhcpActiveLease =
|
|
new CDhcpActiveLease(m_spTFSCompData,pdhcpClientArray->Clients[i]);
|
|
|
|
// filter these types of records out
|
|
if (pDhcpActiveLease->IsGhost() ||
|
|
pDhcpActiveLease->IsUnreg() ||
|
|
pDhcpActiveLease->IsDoomed() )
|
|
{
|
|
delete pDhcpActiveLease;
|
|
continue;
|
|
}
|
|
|
|
if (IsReservation(pdhcpClientArray->Clients[i]->ClientIpAddress))
|
|
pDhcpActiveLease->SetReservation(TRUE);
|
|
|
|
CreateLeafTFSNode(&spNode,
|
|
&GUID_DhcpActiveLeaseNodeType,
|
|
pDhcpActiveLease,
|
|
pDhcpActiveLease,
|
|
m_spNodeMgr);
|
|
|
|
// Tell the handler to initialize any specific data
|
|
pDhcpActiveLease->InitializeNode(spNode);
|
|
|
|
AddToQueue(spNode);
|
|
pDhcpActiveLease->Release();
|
|
}
|
|
|
|
::DhcpRpcFreeMemory(pdhcpClientArray);
|
|
|
|
dwEnumedClients += dwClientsRead;
|
|
|
|
dwClientsRead = 0;
|
|
dwClientsTotal = 0;
|
|
pdhcpClientArray = NULL;
|
|
}
|
|
|
|
// Check the abort flag on the thread
|
|
if (FCheckForAbort() == hrOK)
|
|
break;
|
|
|
|
// check to see if we have an error and post it to the main thread if we do..
|
|
if (dwError != ERROR_NO_MORE_ITEMS &&
|
|
dwError != ERROR_SUCCESS &&
|
|
dwError != ERROR_MORE_DATA)
|
|
{
|
|
Trace1("DHCP snapin: EnumerateLeases error: %d\n", dwError);
|
|
m_dwErr = dwError;
|
|
PostError(dwError);
|
|
}
|
|
}
|
|
|
|
Trace1("DHCP snpain: Leases enumerated: %d\n", dwEnumedClients);
|
|
return hrFalse;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Class CDhcpAddressPool implementation
|
|
---------------------------------------------------------------------------*/
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Function Name Here
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
CDhcpAddressPool::CDhcpAddressPool
|
|
(
|
|
ITFSComponentData * pComponentData
|
|
) : CMTDhcpHandler(pComponentData)
|
|
{
|
|
}
|
|
|
|
CDhcpAddressPool::~CDhcpAddressPool()
|
|
{
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CDhcpAddressPool::InitializeNode
|
|
Initializes node specific data
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpAddressPool::InitializeNode
|
|
(
|
|
ITFSNode * pNode
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
HRESULT hr = hrOK;
|
|
|
|
//
|
|
// Create the display name for this scope
|
|
//
|
|
CString strTemp;
|
|
strTemp.LoadString(IDS_ADDRESS_POOL_FOLDER);
|
|
|
|
SetDisplayName(strTemp);
|
|
|
|
// Make the node immediately visible
|
|
pNode->SetVisibilityState(TFS_VIS_SHOW);
|
|
pNode->SetData(TFS_DATA_IMAGEINDEX, GetImageIndex(FALSE));
|
|
pNode->SetData(TFS_DATA_OPENIMAGEINDEX, GetImageIndex(TRUE));
|
|
pNode->SetData(TFS_DATA_COOKIE, (LPARAM) pNode);
|
|
pNode->SetData(TFS_DATA_USER, (LPARAM) this);
|
|
pNode->SetData(TFS_DATA_TYPE, DHCPSNAP_ADDRESS_POOL);
|
|
pNode->SetData(TFS_DATA_SCOPE_LEAF_NODE, TRUE);
|
|
|
|
SetColumnStringIDs(&aColumns[DHCPSNAP_ADDRESS_POOL][0]);
|
|
SetColumnWidths(&aColumnWidths[DHCPSNAP_ADDRESS_POOL][0]);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpAddressPool::OnCreateNodeId2
|
|
Returns a unique string for this node
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT CDhcpAddressPool::OnCreateNodeId2(ITFSNode * pNode, CString & strId, DWORD * dwFlags)
|
|
{
|
|
const GUID * pGuid = pNode->GetNodeType();
|
|
|
|
CString strIpAddress, strGuid;
|
|
|
|
StringFromGUID2(*pGuid, strGuid.GetBuffer(256), 256);
|
|
strGuid.ReleaseBuffer();
|
|
|
|
DHCP_IP_ADDRESS dhcpIpAddress = GetScopeObject(pNode)->GetAddress();
|
|
|
|
UtilCvtIpAddrToWstr (dhcpIpAddress, &strIpAddress);
|
|
|
|
strId = GetServerName(pNode) + strIpAddress + strGuid;
|
|
|
|
return hrOK;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpAddressPool::GetImageIndex
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
int
|
|
CDhcpAddressPool::GetImageIndex(BOOL bOpenImage)
|
|
{
|
|
int nIndex = -1;
|
|
switch (m_nState)
|
|
{
|
|
case notLoaded:
|
|
case loaded:
|
|
if (bOpenImage)
|
|
nIndex = ICON_IDX_ADDR_POOL_FOLDER_OPEN;
|
|
else
|
|
nIndex = ICON_IDX_ADDR_POOL_FOLDER_CLOSED;
|
|
break;
|
|
|
|
case loading:
|
|
if (bOpenImage)
|
|
nIndex = ICON_IDX_ADDR_POOL_FOLDER_OPEN_BUSY;
|
|
else
|
|
nIndex = ICON_IDX_ADDR_POOL_FOLDER_CLOSED_BUSY;
|
|
break;
|
|
|
|
case unableToLoad:
|
|
if (bOpenImage)
|
|
nIndex = ICON_IDX_ADDR_POOL_FOLDER_OPEN_LOST_CONNECTION;
|
|
else
|
|
nIndex = ICON_IDX_ADDR_POOL_FOLDER_CLOSED_LOST_CONNECTION;
|
|
break;
|
|
|
|
default:
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
return nIndex;
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Overridden base handler functions
|
|
---------------------------------------------------------------------------*/
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpAddressPool::OnAddMenuItems
|
|
Adds entries to the context sensitive menu
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
STDMETHODIMP
|
|
CDhcpAddressPool::OnAddMenuItems
|
|
(
|
|
ITFSNode * pNode,
|
|
LPCONTEXTMENUCALLBACK pContextMenuCallback,
|
|
LPDATAOBJECT lpDataObject,
|
|
DATA_OBJECT_TYPES type,
|
|
DWORD dwType,
|
|
long * pInsertionAllowed
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
LONG fFlags = 0;
|
|
HRESULT hr = S_OK;
|
|
CString strMenuText;
|
|
|
|
if ( (m_nState != loaded) )
|
|
{
|
|
fFlags |= MF_GRAYED;
|
|
}
|
|
|
|
if (type == CCT_SCOPE)
|
|
{
|
|
// these menu items go in the new menu,
|
|
// only visible from scope pane
|
|
if (*pInsertionAllowed & CCM_INSERTIONALLOWED_TOP)
|
|
{
|
|
strMenuText.LoadString(IDS_CREATE_NEW_EXCLUSION);
|
|
hr = LoadAndAddMenuItem( pContextMenuCallback,
|
|
strMenuText,
|
|
IDS_CREATE_NEW_EXCLUSION,
|
|
CCM_INSERTIONPOINTID_PRIMARY_TOP,
|
|
fFlags );
|
|
ASSERT( SUCCEEDED(hr) );
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpAddressPool::OnCommand
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
STDMETHODIMP
|
|
CDhcpAddressPool::OnCommand
|
|
(
|
|
ITFSNode * pNode,
|
|
long nCommandId,
|
|
DATA_OBJECT_TYPES type,
|
|
LPDATAOBJECT pDataObject,
|
|
DWORD dwType
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
switch (nCommandId)
|
|
{
|
|
case IDS_CREATE_NEW_EXCLUSION:
|
|
OnCreateNewExclusion(pNode);
|
|
break;
|
|
|
|
case IDS_REFRESH:
|
|
OnRefresh(pNode, pDataObject, dwType, 0, 0);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Message handlers
|
|
---------------------------------------------------------------------------*/
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpAddressPool::OnCreateNewExclusion
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
DWORD
|
|
CDhcpAddressPool::OnCreateNewExclusion
|
|
(
|
|
ITFSNode * pNode
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
SPITFSNode spScopeNode;
|
|
pNode->GetParent(&spScopeNode);
|
|
|
|
CAddExclusion dlgAddExclusion(spScopeNode);
|
|
|
|
dlgAddExclusion.DoModal();
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpAddressPool::OnResultDelete
|
|
This function is called when we are supposed to delete result
|
|
pane items. We build a list of selected items and then delete them.
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpAddressPool::OnResultDelete
|
|
(
|
|
ITFSComponent * pComponent,
|
|
LPDATAOBJECT pDataObject,
|
|
MMC_COOKIE cookie,
|
|
LPARAM arg,
|
|
LPARAM param
|
|
)
|
|
{
|
|
HRESULT hr = NOERROR;
|
|
BOOL bIsRes, bIsActive, bBadAddress;
|
|
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
// translate the cookie into a node pointer
|
|
SPITFSNode spAddressPool, spSelectedNode;
|
|
m_spNodeMgr->FindNode(cookie, &spAddressPool);
|
|
pComponent->GetSelectedNode(&spSelectedNode);
|
|
|
|
Assert(spSelectedNode == spAddressPool);
|
|
if (spSelectedNode != spAddressPool)
|
|
return hr;
|
|
|
|
// build the list of selected nodes
|
|
CTFSNodeList listNodesToDelete;
|
|
hr = BuildSelectedItemList(pComponent, &listNodesToDelete);
|
|
|
|
//
|
|
// Confirm with the user
|
|
//
|
|
CString strMessage, strTemp;
|
|
int nNodes = (int)listNodesToDelete.GetCount();
|
|
if (nNodes > 1)
|
|
{
|
|
strTemp.Format(_T("%d"), nNodes);
|
|
AfxFormatString1(strMessage, IDS_DELETE_ITEMS, (LPCTSTR) strTemp);
|
|
}
|
|
else
|
|
{
|
|
strMessage.LoadString(IDS_DELETE_ITEM);
|
|
}
|
|
|
|
if (AfxMessageBox(strMessage, MB_YESNO) == IDNO)
|
|
{
|
|
return NOERROR;
|
|
}
|
|
|
|
//
|
|
// Loop through all items deleting
|
|
//
|
|
BEGIN_WAIT_CURSOR;
|
|
|
|
while (listNodesToDelete.GetCount() > 0)
|
|
{
|
|
SPITFSNode spExclusionRangeNode;
|
|
spExclusionRangeNode = listNodesToDelete.RemoveHead();
|
|
|
|
CDhcpExclusionRange * pExclusion = GETHANDLER(CDhcpExclusionRange, spExclusionRangeNode);
|
|
|
|
if (spExclusionRangeNode->GetData(TFS_DATA_TYPE) == DHCPSNAP_ALLOCATION_RANGE)
|
|
{
|
|
//
|
|
// This is the allocation range, can't delete
|
|
//
|
|
AfxMessageBox(IDS_CANNOT_DELETE_ALLOCATION_RANGE);
|
|
spExclusionRangeNode.Release();
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Try to remove it from the server
|
|
//
|
|
CDhcpIpRange dhcpIpRange((DHCP_IP_RANGE) *pExclusion);
|
|
|
|
DWORD dwError = GetScopeObject(spAddressPool)->RemoveExclusion(dhcpIpRange);
|
|
if (dwError != 0)
|
|
{
|
|
::DhcpMessageBox(dwError);
|
|
RESTORE_WAIT_CURSOR;
|
|
|
|
hr = E_FAIL;
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Remove from UI now
|
|
//
|
|
spAddressPool->RemoveChild(spExclusionRangeNode);
|
|
spExclusionRangeNode.Release();
|
|
}
|
|
|
|
// update stats
|
|
GetScopeObject(spAddressPool)->TriggerStatsRefresh();
|
|
|
|
END_WAIT_CURSOR;
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CDhcpAddressPool::OnGetResultViewType
|
|
MMC calls this to get the result view information
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpAddressPool::OnGetResultViewType
|
|
(
|
|
ITFSComponent * pComponent,
|
|
MMC_COOKIE cookie,
|
|
LPOLESTR * ppViewType,
|
|
long * pViewOptions
|
|
)
|
|
{
|
|
*pViewOptions = MMC_VIEW_OPTIONS_MULTISELECT;
|
|
|
|
// we still want the default MMC result pane view, we just want
|
|
// multiselect, so return S_FALSE
|
|
|
|
return S_FALSE;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Background thread functionality
|
|
---------------------------------------------------------------------------*/
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpAddressPool::OnCreateQuery()
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
ITFSQueryObject*
|
|
CDhcpAddressPool::OnCreateQuery(ITFSNode * pNode)
|
|
{
|
|
CDhcpAddressPoolQueryObj* pQuery =
|
|
new CDhcpAddressPoolQueryObj(m_spTFSCompData, m_spNodeMgr);
|
|
|
|
pQuery->m_strServer = GetServerIpAddress(pNode);
|
|
|
|
CDhcpScope * pScope = GetScopeObject(pNode);
|
|
if (pScope)
|
|
{
|
|
pQuery->m_dhcpScopeAddress = pScope->GetAddress();
|
|
pQuery->m_fSupportsDynBootp = pScope->GetServerObject()->FSupportsDynBootp();
|
|
}
|
|
|
|
pQuery->m_dhcpExclResumeHandle = NULL;
|
|
pQuery->m_dwExclPreferredMax = 0xFFFFFFFF;
|
|
|
|
pQuery->m_dhcpIpResumeHandle = NULL;
|
|
pQuery->m_dwIpPreferredMax = 0xFFFFFFFF;
|
|
|
|
return pQuery;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpAddressPoolQueryObj::Execute()
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
STDMETHODIMP
|
|
CDhcpAddressPoolQueryObj::Execute()
|
|
{
|
|
HRESULT hr1 = EnumerateIpRanges();
|
|
HRESULT hr2 = EnumerateExcludedIpRanges();
|
|
|
|
if (hr1 == hrOK || hr2 == hrOK)
|
|
return hrOK;
|
|
else
|
|
return hrFalse;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Function Name Here
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpAddressPoolQueryObj::EnumerateExcludedIpRanges()
|
|
{
|
|
DWORD dwError = ERROR_MORE_DATA;
|
|
DHCP_RESUME_HANDLE dhcpResumeHandle = 0;
|
|
LPDHCP_SUBNET_ELEMENT_INFO_ARRAY pdhcpSubnetElementArray = NULL;
|
|
DWORD dwElementsRead = 0, dwElementsTotal = 0;
|
|
|
|
while (dwError == ERROR_MORE_DATA)
|
|
{
|
|
dwError = ::DhcpEnumSubnetElements((LPWSTR) ((LPCTSTR) m_strServer),
|
|
m_dhcpScopeAddress,
|
|
DhcpExcludedIpRanges,
|
|
&m_dhcpExclResumeHandle,
|
|
m_dwExclPreferredMax,
|
|
&pdhcpSubnetElementArray,
|
|
&dwElementsRead,
|
|
&dwElementsTotal);
|
|
|
|
Trace3("Scope %lx Excluded Ip Ranges read %d, total %d\n", m_dhcpScopeAddress, dwElementsRead, dwElementsTotal);
|
|
|
|
if (dwElementsRead && dwElementsTotal && pdhcpSubnetElementArray)
|
|
{
|
|
//
|
|
// loop through all of the elements that were returned
|
|
//
|
|
for (DWORD i = 0; i < pdhcpSubnetElementArray->NumElements; i++)
|
|
{
|
|
//
|
|
// Create the result pane item for this element
|
|
//
|
|
SPITFSNode spNode;
|
|
CDhcpExclusionRange * pDhcpExclusionRange =
|
|
new CDhcpExclusionRange(m_spTFSCompData,
|
|
pdhcpSubnetElementArray->Elements[i].Element.ExcludeIpRange);
|
|
|
|
CreateLeafTFSNode(&spNode,
|
|
&GUID_DhcpExclusionNodeType,
|
|
pDhcpExclusionRange,
|
|
pDhcpExclusionRange,
|
|
m_spNodeMgr);
|
|
|
|
// Tell the handler to initialize any specific data
|
|
pDhcpExclusionRange->InitializeNode(spNode);
|
|
|
|
AddToQueue(spNode);
|
|
pDhcpExclusionRange->Release();
|
|
}
|
|
|
|
// Free up the memory from the RPC call
|
|
//
|
|
::DhcpRpcFreeMemory(pdhcpSubnetElementArray);
|
|
}
|
|
|
|
// Check the abort flag on the thread
|
|
if (FCheckForAbort() == hrOK)
|
|
break;
|
|
|
|
// check to see if we have an error and post it to the main thread if we do..
|
|
if (dwError != ERROR_NO_MORE_ITEMS &&
|
|
dwError != ERROR_SUCCESS &&
|
|
dwError != ERROR_MORE_DATA)
|
|
{
|
|
Trace1("DHCP snapin: EnumerateExcludedIpRanges error: %d\n", dwError);
|
|
m_dwErr = dwError;
|
|
PostError(dwError);
|
|
}
|
|
}
|
|
|
|
return hrFalse;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Function Name Here
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpAddressPoolQueryObj::EnumerateIpRanges()
|
|
{
|
|
DWORD dwError = ERROR_MORE_DATA;
|
|
LPDHCP_SUBNET_ELEMENT_INFO_ARRAY pdhcpSubnetElementArray = NULL;
|
|
DWORD dwElementsRead = 0, dwElementsTotal = 0;
|
|
|
|
if (m_fSupportsDynBootp)
|
|
{
|
|
return EnumerateIpRangesV5();
|
|
}
|
|
|
|
while (dwError == ERROR_MORE_DATA)
|
|
{
|
|
dwError = ::DhcpEnumSubnetElements((LPWSTR) ((LPCTSTR) m_strServer),
|
|
m_dhcpScopeAddress,
|
|
DhcpIpRanges,
|
|
&m_dhcpIpResumeHandle,
|
|
m_dwIpPreferredMax,
|
|
&pdhcpSubnetElementArray,
|
|
&dwElementsRead,
|
|
&dwElementsTotal);
|
|
|
|
Trace4("Scope %lx allocation ranges read %d, total %d, dwError = %lx\n",
|
|
m_dhcpScopeAddress, dwElementsRead, dwElementsTotal, dwError);
|
|
|
|
if ((dwError == ERROR_MORE_DATA) ||
|
|
( (dwElementsRead) && (dwError == ERROR_SUCCESS) ))
|
|
{
|
|
//
|
|
// Loop through the array that was returned
|
|
//
|
|
for (DWORD i = 0; i < pdhcpSubnetElementArray->NumElements; i++)
|
|
{
|
|
//
|
|
// Create the result pane item for this element
|
|
//
|
|
SPITFSNode spNode;
|
|
CDhcpAllocationRange * pDhcpAllocRange =
|
|
new CDhcpAllocationRange(m_spTFSCompData,
|
|
pdhcpSubnetElementArray->Elements[i].Element.IpRange);
|
|
|
|
CreateLeafTFSNode(&spNode,
|
|
&GUID_DhcpAllocationNodeType,
|
|
pDhcpAllocRange,
|
|
pDhcpAllocRange,
|
|
m_spNodeMgr);
|
|
|
|
// Tell the handler to initialize any specific data
|
|
pDhcpAllocRange->InitializeNode(spNode);
|
|
|
|
AddToQueue(spNode);
|
|
pDhcpAllocRange->Release();
|
|
}
|
|
|
|
::DhcpRpcFreeMemory(pdhcpSubnetElementArray);
|
|
}
|
|
else
|
|
if (dwError != ERROR_SUCCESS &&
|
|
dwError != ERROR_NO_MORE_ITEMS)
|
|
{
|
|
// set the error variable so that it can be looked at later
|
|
m_dwError = dwError;
|
|
}
|
|
|
|
// Check the abort flag on the thread
|
|
if (FCheckForAbort() == hrOK)
|
|
break;
|
|
|
|
// check to see if we have an error and post it to the main thread if we do..
|
|
if (dwError != ERROR_NO_MORE_ITEMS &&
|
|
dwError != ERROR_SUCCESS &&
|
|
dwError != ERROR_MORE_DATA)
|
|
{
|
|
Trace1("DHCP snapin: EnumerateAllocationRanges error: %d\n", dwError);
|
|
m_dwErr = dwError;
|
|
PostError(dwError);
|
|
}
|
|
}
|
|
|
|
return hrFalse;
|
|
}
|
|
|
|
HRESULT
|
|
CDhcpAddressPoolQueryObj::EnumerateIpRangesV5()
|
|
{
|
|
DWORD dwError = ERROR_MORE_DATA;
|
|
LPDHCP_SUBNET_ELEMENT_INFO_ARRAY_V5 pdhcpSubnetElementArray = NULL;
|
|
DWORD dwElementsRead = 0, dwElementsTotal = 0;
|
|
|
|
while (dwError == ERROR_MORE_DATA)
|
|
{
|
|
dwError = ::DhcpEnumSubnetElementsV5((LPWSTR) ((LPCTSTR) m_strServer),
|
|
m_dhcpScopeAddress,
|
|
DhcpIpRangesDhcpBootp,
|
|
&m_dhcpIpResumeHandle,
|
|
m_dwIpPreferredMax,
|
|
&pdhcpSubnetElementArray,
|
|
&dwElementsRead,
|
|
&dwElementsTotal);
|
|
|
|
Trace4("EnumerateIpRangesV5: Scope %lx allocation ranges read %d, total %d, dwError = %lx\n",
|
|
m_dhcpScopeAddress, dwElementsRead, dwElementsTotal, dwError);
|
|
|
|
if ((dwError == ERROR_MORE_DATA) ||
|
|
( (dwElementsRead) && (dwError == ERROR_SUCCESS) ))
|
|
{
|
|
//
|
|
// Loop through the array that was returned
|
|
//
|
|
for (DWORD i = 0; i < pdhcpSubnetElementArray->NumElements; i++)
|
|
{
|
|
//
|
|
// Create the result pane item for this element
|
|
//
|
|
SPITFSNode spNode;
|
|
CDhcpAllocationRange * pDhcpAllocRange =
|
|
new CDhcpAllocationRange(m_spTFSCompData,
|
|
pdhcpSubnetElementArray->Elements[i].Element.IpRange);
|
|
pDhcpAllocRange->SetRangeType(pdhcpSubnetElementArray->Elements[i].ElementType);
|
|
|
|
CreateLeafTFSNode(&spNode,
|
|
&GUID_DhcpAllocationNodeType,
|
|
pDhcpAllocRange,
|
|
pDhcpAllocRange,
|
|
m_spNodeMgr);
|
|
|
|
// Tell the handler to initialize any specific data
|
|
pDhcpAllocRange->InitializeNode(spNode);
|
|
|
|
AddToQueue(spNode);
|
|
pDhcpAllocRange->Release();
|
|
}
|
|
|
|
::DhcpRpcFreeMemory(pdhcpSubnetElementArray);
|
|
}
|
|
else
|
|
if (dwError != ERROR_SUCCESS &&
|
|
dwError != ERROR_NO_MORE_ITEMS)
|
|
{
|
|
// set the error variable so that it can be looked at later
|
|
m_dwError = dwError;
|
|
}
|
|
|
|
// Check the abort flag on the thread
|
|
if (FCheckForAbort() == hrOK)
|
|
break;
|
|
|
|
// check to see if we have an error and post it to the main thread if we do..
|
|
if (dwError != ERROR_NO_MORE_ITEMS &&
|
|
dwError != ERROR_SUCCESS &&
|
|
dwError != ERROR_MORE_DATA)
|
|
{
|
|
Trace1("DHCP snapin: EnumerateAllocationRanges error: %d\n", dwError);
|
|
m_dwErr = dwError;
|
|
PostError(dwError);
|
|
}
|
|
}
|
|
|
|
return hrFalse;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpAddressPool::CompareItems
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
STDMETHODIMP_(int)
|
|
CDhcpAddressPool::CompareItems
|
|
(
|
|
ITFSComponent * pComponent,
|
|
MMC_COOKIE cookieA,
|
|
MMC_COOKIE cookieB,
|
|
int nCol
|
|
)
|
|
{
|
|
SPITFSNode spNode1, spNode2;
|
|
|
|
m_spNodeMgr->FindNode(cookieA, &spNode1);
|
|
m_spNodeMgr->FindNode(cookieB, &spNode2);
|
|
|
|
int nCompare = 0;
|
|
|
|
CDhcpAllocationRange *pDhcpAR1 = GETHANDLER(CDhcpAllocationRange, spNode1);
|
|
CDhcpAllocationRange *pDhcpAR2 = GETHANDLER(CDhcpAllocationRange, spNode2);
|
|
|
|
switch (nCol)
|
|
{
|
|
case 0:
|
|
{
|
|
// Start IP address compare
|
|
//
|
|
DHCP_IP_ADDRESS dhcpIp1 = pDhcpAR1->QueryAddr(TRUE);
|
|
DHCP_IP_ADDRESS dhcpIp2 = pDhcpAR2->QueryAddr(TRUE);
|
|
|
|
if (dhcpIp1 < dhcpIp2)
|
|
nCompare = -1;
|
|
else
|
|
if (dhcpIp1 > dhcpIp2)
|
|
nCompare = 1;
|
|
|
|
// default is that they are equal
|
|
}
|
|
break;
|
|
|
|
case 1:
|
|
{
|
|
// End IP address compare
|
|
//
|
|
DHCP_IP_ADDRESS dhcpIp1 = pDhcpAR1->QueryAddr(FALSE);
|
|
DHCP_IP_ADDRESS dhcpIp2 = pDhcpAR2->QueryAddr(FALSE);
|
|
|
|
if (dhcpIp1 < dhcpIp2)
|
|
nCompare = -1;
|
|
else
|
|
if (dhcpIp1 > dhcpIp2)
|
|
nCompare = 1;
|
|
|
|
// default is that they are equal
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
{
|
|
// Description compare
|
|
//
|
|
CString strRange1 = pDhcpAR1->GetString(pComponent, cookieA, nCol);
|
|
CString strRange2 = pDhcpAR2->GetString(pComponent, cookieA, nCol);
|
|
|
|
// Compare should not be case sensitive
|
|
//
|
|
strRange1.MakeUpper();
|
|
strRange2.MakeUpper();
|
|
|
|
nCompare = strRange1.Compare(strRange2);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return nCompare;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScopeOptions Implementation
|
|
---------------------------------------------------------------------------*/
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScopeOptions Constructor and destructor
|
|
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
CDhcpScopeOptions::CDhcpScopeOptions
|
|
(
|
|
ITFSComponentData * pComponentData
|
|
) : CMTDhcpHandler(pComponentData)
|
|
{
|
|
}
|
|
|
|
CDhcpScopeOptions::~CDhcpScopeOptions()
|
|
{
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CDhcpScopeOptions::InitializeNode
|
|
Initializes node specific data
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpScopeOptions::InitializeNode
|
|
(
|
|
ITFSNode * pNode
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
HRESULT hr = hrOK;
|
|
|
|
//
|
|
// Create the display name for this scope
|
|
//
|
|
CString strTemp;
|
|
strTemp.LoadString(IDS_SCOPE_OPTIONS_FOLDER);
|
|
|
|
SetDisplayName(strTemp);
|
|
|
|
// Make the node immediately visible
|
|
pNode->SetVisibilityState(TFS_VIS_SHOW);
|
|
pNode->SetData(TFS_DATA_IMAGEINDEX, GetImageIndex(FALSE));
|
|
pNode->SetData(TFS_DATA_OPENIMAGEINDEX, GetImageIndex(TRUE));
|
|
pNode->SetData(TFS_DATA_COOKIE, (LPARAM) pNode);
|
|
pNode->SetData(TFS_DATA_USER, (LPARAM) this);
|
|
pNode->SetData(TFS_DATA_TYPE, DHCPSNAP_SCOPE_OPTIONS);
|
|
pNode->SetData(TFS_DATA_SCOPE_LEAF_NODE, TRUE);
|
|
|
|
SetColumnStringIDs(&aColumns[DHCPSNAP_SCOPE_OPTIONS][0]);
|
|
SetColumnWidths(&aColumnWidths[DHCPSNAP_SCOPE_OPTIONS][0]);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScopeOptions::OnCreateNodeId2
|
|
Returns a unique string for this node
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT CDhcpScopeOptions::OnCreateNodeId2(ITFSNode * pNode, CString & strId, DWORD * dwFlags)
|
|
{
|
|
const GUID * pGuid = pNode->GetNodeType();
|
|
|
|
CString strIpAddress, strGuid;
|
|
|
|
StringFromGUID2(*pGuid, strGuid.GetBuffer(256), 256);
|
|
strGuid.ReleaseBuffer();
|
|
|
|
DHCP_IP_ADDRESS dhcpIpAddress = GetScopeObject(pNode)->GetAddress();
|
|
|
|
UtilCvtIpAddrToWstr (dhcpIpAddress, &strIpAddress);
|
|
|
|
strId = GetServerName(pNode) + strIpAddress + strGuid;
|
|
|
|
return hrOK;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScopeOptions::GetImageIndex
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
int
|
|
CDhcpScopeOptions::GetImageIndex(BOOL bOpenImage)
|
|
{
|
|
int nIndex = -1;
|
|
switch (m_nState)
|
|
{
|
|
case notLoaded:
|
|
case loaded:
|
|
if (bOpenImage)
|
|
nIndex = ICON_IDX_SCOPE_OPTION_FOLDER_OPEN;
|
|
else
|
|
nIndex = ICON_IDX_SCOPE_OPTION_FOLDER_CLOSED;
|
|
break;
|
|
|
|
case loading:
|
|
if (bOpenImage)
|
|
nIndex = ICON_IDX_SCOPE_OPTION_FOLDER_OPEN_BUSY;
|
|
else
|
|
nIndex = ICON_IDX_SCOPE_OPTION_FOLDER_CLOSED_BUSY;
|
|
break;
|
|
|
|
case unableToLoad:
|
|
if (bOpenImage)
|
|
nIndex = ICON_IDX_SCOPE_OPTION_FOLDER_OPEN_LOST_CONNECTION;
|
|
else
|
|
nIndex = ICON_IDX_SCOPE_OPTION_FOLDER_CLOSED_LOST_CONNECTION;
|
|
break;
|
|
|
|
default:
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
return nIndex;
|
|
}
|
|
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Overridden base handler functions
|
|
---------------------------------------------------------------------------*/
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScopeOptions::OnAddMenuItems
|
|
Adds entries to the context sensitive menu
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
STDMETHODIMP
|
|
CDhcpScopeOptions::OnAddMenuItems
|
|
(
|
|
ITFSNode * pNode,
|
|
LPCONTEXTMENUCALLBACK pContextMenuCallback,
|
|
LPDATAOBJECT lpDataObject,
|
|
DATA_OBJECT_TYPES type,
|
|
DWORD dwType,
|
|
long * pInsertionAllowed
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
LONG fFlags = 0;
|
|
HRESULT hr = S_OK;
|
|
CString strMenuText;
|
|
|
|
if ( (m_nState != loaded) )
|
|
{
|
|
fFlags |= MF_GRAYED;
|
|
}
|
|
|
|
if (type == CCT_SCOPE)
|
|
{
|
|
if (*pInsertionAllowed & CCM_INSERTIONALLOWED_TOP)
|
|
{
|
|
// these menu items go in the new menu,
|
|
// only visible from scope pane
|
|
strMenuText.LoadString(IDS_CREATE_OPTION_SCOPE);
|
|
hr = LoadAndAddMenuItem( pContextMenuCallback,
|
|
strMenuText,
|
|
IDS_CREATE_OPTION_SCOPE,
|
|
CCM_INSERTIONPOINTID_PRIMARY_TOP,
|
|
fFlags );
|
|
ASSERT( SUCCEEDED(hr) );
|
|
}
|
|
}
|
|
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScopeOptions::OnCommand
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
STDMETHODIMP
|
|
CDhcpScopeOptions::OnCommand
|
|
(
|
|
ITFSNode * pNode,
|
|
long nCommandId,
|
|
DATA_OBJECT_TYPES type,
|
|
LPDATAOBJECT pDataObject,
|
|
DWORD dwType
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
switch (nCommandId)
|
|
{
|
|
case IDS_CREATE_OPTION_SCOPE:
|
|
OnCreateNewOptions(pNode);
|
|
break;
|
|
|
|
case IDS_REFRESH:
|
|
OnRefresh(pNode, pDataObject, dwType, 0, 0);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CDhcpScopeOptions::HasPropertyPages
|
|
Implementation of ITFSNodeHandler::HasPropertyPages
|
|
NOTE: the root node handler has to over-ride this function to
|
|
handle the snapin manager property page (wizard) case!!!
|
|
|
|
Author: KennT
|
|
---------------------------------------------------------------------------*/
|
|
STDMETHODIMP
|
|
CDhcpScopeOptions::HasPropertyPages
|
|
(
|
|
ITFSNode * pNode,
|
|
LPDATAOBJECT pDataObject,
|
|
DATA_OBJECT_TYPES type,
|
|
DWORD dwType
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
HRESULT hr = hrOK;
|
|
|
|
// we have property pages in the normal case, but don't put the
|
|
// menu up if we are not loaded yet
|
|
if ( m_nState != loaded )
|
|
{
|
|
hr = hrFalse;
|
|
}
|
|
else
|
|
{
|
|
hr = hrOK;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScopeOptions::CreatePropertyPages
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
STDMETHODIMP
|
|
CDhcpScopeOptions::CreatePropertyPages
|
|
(
|
|
ITFSNode * pNode,
|
|
LPPROPERTYSHEETCALLBACK lpProvider,
|
|
LPDATAOBJECT pDataObject,
|
|
LONG_PTR handle,
|
|
DWORD dwType
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
DWORD dwError;
|
|
DWORD dwDynDnsFlags;
|
|
HRESULT hr = hrOK;
|
|
COptionsConfig * pOptCfg;
|
|
CString strOptCfgTitle, strOptType;
|
|
SPITFSNode spServerNode;
|
|
SPIComponentData spComponentData;
|
|
COptionValueEnum * pOptionValueEnum;
|
|
|
|
//
|
|
// Create the property page
|
|
//
|
|
COM_PROTECT_TRY
|
|
{
|
|
m_spNodeMgr->GetComponentData(&spComponentData);
|
|
|
|
BEGIN_WAIT_CURSOR;
|
|
|
|
strOptType.LoadString(IDS_CONFIGURE_OPTIONS_SCOPE);
|
|
AfxFormatString1(strOptCfgTitle, IDS_CONFIGURE_OPTIONS_TITLE, strOptType);
|
|
|
|
GetScopeObject(pNode)->GetServerNode(&spServerNode);
|
|
pOptionValueEnum = GetScopeObject(pNode)->GetOptionValueEnum();
|
|
|
|
pOptCfg = new COptionsConfig(pNode,
|
|
spServerNode,
|
|
spComponentData,
|
|
m_spTFSCompData,
|
|
pOptionValueEnum,
|
|
strOptCfgTitle);
|
|
|
|
END_WAIT_CURSOR;
|
|
|
|
//
|
|
// Object gets deleted when the page is destroyed
|
|
//
|
|
Assert(lpProvider != NULL);
|
|
|
|
hr = pOptCfg->CreateModelessSheet(lpProvider, handle);
|
|
}
|
|
COM_PROTECT_CATCH
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScopeOptions::OnPropertyChange
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpScopeOptions::OnPropertyChange
|
|
(
|
|
ITFSNode * pNode,
|
|
LPDATAOBJECT pDataobject,
|
|
DWORD dwType,
|
|
LPARAM arg,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
COptionsConfig * pOptCfg = reinterpret_cast<COptionsConfig *>(lParam);
|
|
|
|
LPARAM changeMask = 0;
|
|
|
|
// tell the property page to do whatever now that we are back on the
|
|
// main thread
|
|
pOptCfg->OnPropertyChange(TRUE, &changeMask);
|
|
|
|
pOptCfg->AcknowledgeNotify();
|
|
|
|
if (changeMask)
|
|
pNode->ChangeNode(changeMask);
|
|
|
|
return hrOK;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScopeOptions::OnPropertyChange
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpScopeOptions::OnResultPropertyChange
|
|
(
|
|
ITFSComponent * pComponent,
|
|
LPDATAOBJECT pDataObject,
|
|
MMC_COOKIE cookie,
|
|
LPARAM arg,
|
|
LPARAM param
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
SPITFSNode spNode;
|
|
m_spNodeMgr->FindNode(cookie, &spNode);
|
|
COptionsConfig * pOptCfg = reinterpret_cast<COptionsConfig *>(param);
|
|
|
|
LPARAM changeMask = 0;
|
|
|
|
// tell the property page to do whatever now that we are back on the
|
|
// main thread
|
|
pOptCfg->OnPropertyChange(TRUE, &changeMask);
|
|
|
|
pOptCfg->AcknowledgeNotify();
|
|
|
|
if (changeMask)
|
|
spNode->ChangeNode(changeMask);
|
|
|
|
return hrOK;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScopeOptions::CompareItems
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
STDMETHODIMP_(int)
|
|
CDhcpScopeOptions::CompareItems
|
|
(
|
|
ITFSComponent * pComponent,
|
|
MMC_COOKIE cookieA,
|
|
MMC_COOKIE cookieB,
|
|
int nCol
|
|
)
|
|
{
|
|
SPITFSNode spNode1, spNode2;
|
|
|
|
m_spNodeMgr->FindNode(cookieA, &spNode1);
|
|
m_spNodeMgr->FindNode(cookieB, &spNode2);
|
|
|
|
int nCompare = 0;
|
|
|
|
CDhcpOptionItem *pOpt1 = GETHANDLER(CDhcpOptionItem, spNode1);
|
|
CDhcpOptionItem *pOpt2 = GETHANDLER(CDhcpOptionItem, spNode2);
|
|
|
|
switch (nCol)
|
|
{
|
|
case 0:
|
|
{
|
|
//
|
|
// Name compare - use the option #
|
|
//
|
|
LONG_PTR uImage1 = spNode1->GetData(TFS_DATA_IMAGEINDEX);
|
|
LONG_PTR uImage2 = spNode2->GetData(TFS_DATA_IMAGEINDEX);
|
|
|
|
nCompare = UtilGetOptionPriority((int) uImage1, (int) uImage2);
|
|
if (nCompare == 0)
|
|
{
|
|
DHCP_OPTION_ID id1 = pOpt1->GetOptionId();
|
|
DHCP_OPTION_ID id2 = pOpt2->GetOptionId();
|
|
|
|
if (id1 < id2)
|
|
nCompare = -1;
|
|
else
|
|
if (id1 > id2)
|
|
nCompare = 1;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 1:
|
|
{
|
|
// compare the vendor strings
|
|
CString str1, str2;
|
|
str1 = pOpt1->GetVendorDisplay();
|
|
str2 = pOpt2->GetVendorDisplay();
|
|
|
|
nCompare = str1.CompareNoCase(str2);
|
|
}
|
|
break;
|
|
|
|
case 2: {
|
|
// compare the printable values
|
|
CString str1, str2;
|
|
str1 = pOpt1->GetString( pComponent, cookieA, nCol );
|
|
str2 = pOpt2->GetString( pComponent, cookieB, nCol );
|
|
|
|
nCompare = str1.CompareNoCase( str2 );
|
|
break;
|
|
}
|
|
|
|
case 3:
|
|
{
|
|
CString str1, str2;
|
|
str1 = pOpt1->GetClassName();
|
|
str2 = pOpt2->GetClassName();
|
|
|
|
nCompare = str1.CompareNoCase(str2);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return nCompare;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CDhcpScopeOptions::OnResultSelect
|
|
Update the verbs and the result pane message
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT CDhcpScopeOptions::OnResultSelect(ITFSComponent *pComponent, LPDATAOBJECT pDataObject, MMC_COOKIE cookie, LPARAM arg, LPARAM lParam)
|
|
{
|
|
HRESULT hr = hrOK;
|
|
SPITFSNode spNode;
|
|
|
|
CORg(CMTDhcpHandler::OnResultSelect(pComponent, pDataObject, cookie, arg, lParam));
|
|
|
|
CORg (pComponent->GetSelectedNode(&spNode));
|
|
|
|
if ( spNode != 0 ) {
|
|
UpdateResultMessage(spNode);
|
|
}
|
|
|
|
Error:
|
|
return hr;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScopeOptions::OnResultDelete
|
|
This function is called when we are supposed to delete result
|
|
pane items. We build a list of selected items and then delete them.
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpScopeOptions::OnResultDelete
|
|
(
|
|
ITFSComponent * pComponent,
|
|
LPDATAOBJECT pDataObject,
|
|
MMC_COOKIE cookie,
|
|
LPARAM arg,
|
|
LPARAM param
|
|
)
|
|
{
|
|
HRESULT hr = hrOK;
|
|
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
// translate the cookie into a node pointer
|
|
SPITFSNode spScopeOpt, spSelectedNode;
|
|
m_spNodeMgr->FindNode(cookie, &spScopeOpt);
|
|
pComponent->GetSelectedNode(&spSelectedNode);
|
|
|
|
Assert(spSelectedNode == spScopeOpt);
|
|
if (spSelectedNode != spScopeOpt)
|
|
return hr;
|
|
|
|
// build the list of selected nodes
|
|
CTFSNodeList listNodesToDelete;
|
|
hr = BuildSelectedItemList(pComponent, &listNodesToDelete);
|
|
|
|
//
|
|
// Confirm with the user
|
|
//
|
|
CString strMessage, strTemp;
|
|
int nNodes = (int)listNodesToDelete.GetCount();
|
|
if (nNodes > 1)
|
|
{
|
|
strTemp.Format(_T("%d"), nNodes);
|
|
AfxFormatString1(strMessage, IDS_DELETE_ITEMS, (LPCTSTR) strTemp);
|
|
}
|
|
else
|
|
{
|
|
strMessage.LoadString(IDS_DELETE_ITEM);
|
|
}
|
|
|
|
if (AfxMessageBox(strMessage, MB_YESNO) == IDNO)
|
|
{
|
|
return NOERROR;
|
|
}
|
|
|
|
// check to make sure we are deleting just scope options
|
|
POSITION pos = listNodesToDelete.GetHeadPosition();
|
|
while (pos)
|
|
{
|
|
ITFSNode * pNode = listNodesToDelete.GetNext(pos);
|
|
if (pNode->GetData(TFS_DATA_IMAGEINDEX) != ICON_IDX_SCOPE_OPTION_LEAF)
|
|
{
|
|
// this option is not scope option. Put up a dialog telling the user what to do
|
|
AfxMessageBox(IDS_CANNOT_DELETE_OPTION_SCOPE);
|
|
return NOERROR;
|
|
}
|
|
}
|
|
|
|
CString strServer = GetServerIpAddress(spScopeOpt);
|
|
|
|
DHCP_OPTION_SCOPE_INFO dhcpOptionScopeInfo;
|
|
dhcpOptionScopeInfo.ScopeType = DhcpSubnetOptions;
|
|
dhcpOptionScopeInfo.ScopeInfo.SubnetScopeInfo = GetScopeObject(spScopeOpt)->GetAddress();
|
|
|
|
//
|
|
// Loop through all items deleting
|
|
//
|
|
BEGIN_WAIT_CURSOR;
|
|
|
|
while (listNodesToDelete.GetCount() > 0)
|
|
{
|
|
SPITFSNode spOptionNode;
|
|
spOptionNode = listNodesToDelete.RemoveHead();
|
|
|
|
CDhcpOptionItem * pOptItem = GETHANDLER(CDhcpOptionItem, spOptionNode);
|
|
|
|
//
|
|
// Try to remove it from the server
|
|
//
|
|
DWORD dwError;
|
|
|
|
if (pOptItem->IsVendorOption() ||
|
|
pOptItem->IsClassOption())
|
|
{
|
|
LPCTSTR pClassName = pOptItem->GetClassName();
|
|
if (lstrlen(pClassName) == 0)
|
|
pClassName = NULL;
|
|
|
|
dwError = ::DhcpRemoveOptionValueV5((LPTSTR) ((LPCTSTR) strServer),
|
|
pOptItem->IsVendorOption() ? DHCP_FLAGS_OPTION_IS_VENDOR : 0,
|
|
pOptItem->GetOptionId(),
|
|
(LPTSTR) pClassName,
|
|
(LPTSTR) pOptItem->GetVendor(),
|
|
&dhcpOptionScopeInfo);
|
|
}
|
|
else
|
|
{
|
|
dwError = ::DhcpRemoveOptionValue(strServer,
|
|
pOptItem->GetOptionId(),
|
|
&dhcpOptionScopeInfo);
|
|
}
|
|
|
|
if (dwError != 0)
|
|
{
|
|
::DhcpMessageBox(dwError);
|
|
RESTORE_WAIT_CURSOR;
|
|
|
|
hr = E_FAIL;
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// remove from our internal list
|
|
//
|
|
GetScopeObject(spScopeOpt)->GetOptionValueEnum()->Remove(pOptItem->GetOptionId(), pOptItem->GetVendor(), pOptItem->GetClassName());
|
|
|
|
//
|
|
// Remove from UI now
|
|
//
|
|
spScopeOpt->RemoveChild(spOptionNode);
|
|
spOptionNode.Release();
|
|
}
|
|
|
|
END_WAIT_CURSOR;
|
|
|
|
UpdateResultMessage(spScopeOpt);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CDhcpScopeOptions::OnHaveData
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
void
|
|
CDhcpScopeOptions::OnHaveData
|
|
(
|
|
ITFSNode * pParentNode,
|
|
LPARAM Data,
|
|
LPARAM Type
|
|
)
|
|
{
|
|
// This is how we get non-node data back from the background thread.
|
|
switch (Type)
|
|
{
|
|
case DHCP_QDATA_OPTION_VALUES:
|
|
{
|
|
HRESULT hr = hrOK;
|
|
SPIComponentData spCompData;
|
|
SPIConsole spConsole;
|
|
SPIDataObject spDataObject;
|
|
IDataObject * pDataObject;
|
|
CDhcpScope * pScope = GetScopeObject(pParentNode);
|
|
COptionValueEnum * pOptionValueEnum = reinterpret_cast<COptionValueEnum *>(Data);
|
|
|
|
pScope->SetOptionValueEnum(pOptionValueEnum);
|
|
|
|
pOptionValueEnum->RemoveAll();
|
|
delete pOptionValueEnum;
|
|
|
|
// now tell the view to update themselves
|
|
m_spNodeMgr->GetComponentData(&spCompData);
|
|
|
|
CORg ( spCompData->QueryDataObject((MMC_COOKIE) pParentNode, CCT_SCOPE, &pDataObject) );
|
|
spDataObject = pDataObject;
|
|
|
|
CORg ( m_spNodeMgr->GetConsole(&spConsole) );
|
|
CORg ( spConsole->UpdateAllViews(pDataObject, (LPARAM) pParentNode, DHCPSNAP_UPDATE_OPTIONS) );
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
Error:
|
|
return;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CDhcpScopeOptions::OnResultUpdateView
|
|
Implementation of ITFSResultHandler::OnResultUpdateView
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT CDhcpScopeOptions::OnResultUpdateView
|
|
(
|
|
ITFSComponent *pComponent,
|
|
LPDATAOBJECT pDataObject,
|
|
LPARAM data,
|
|
LPARAM hint
|
|
)
|
|
{
|
|
HRESULT hr = hrOK;
|
|
SPITFSNode spSelectedNode;
|
|
|
|
pComponent->GetSelectedNode(&spSelectedNode);
|
|
if (spSelectedNode == NULL)
|
|
return S_OK; // no selection for our IComponentData
|
|
|
|
if ( hint == DHCPSNAP_UPDATE_OPTIONS )
|
|
{
|
|
SPINTERNAL spInternal = ExtractInternalFormat(pDataObject);
|
|
ITFSNode * pNode = reinterpret_cast<ITFSNode *>(spInternal->m_cookie);
|
|
SPITFSNode spSelectedNode;
|
|
|
|
pComponent->GetSelectedNode(&spSelectedNode);
|
|
|
|
EnumerateResultPane(pComponent, (MMC_COOKIE) spSelectedNode.p, 0, 0);
|
|
}
|
|
else
|
|
{
|
|
// we don't handle this message, let the base class do it.
|
|
return CMTDhcpHandler::OnResultUpdateView(pComponent, pDataObject, data, hint);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CDhcpScopeOptions::OnGetResultViewType
|
|
MMC calls this to get the result view information
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpScopeOptions::OnGetResultViewType
|
|
(
|
|
ITFSComponent * pComponent,
|
|
MMC_COOKIE cookie,
|
|
LPOLESTR * ppViewType,
|
|
long * pViewOptions
|
|
)
|
|
{
|
|
HRESULT hr = hrOK;
|
|
|
|
// call the base class to see if it is handling this
|
|
if (CMTDhcpHandler::OnGetResultViewType(pComponent, cookie, ppViewType, pViewOptions) != S_OK)
|
|
{
|
|
*pViewOptions = MMC_VIEW_OPTIONS_MULTISELECT;
|
|
|
|
hr = S_FALSE;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CDhcpScopeOptions::UpdateResultMessage
|
|
Figures out what message to put in the result pane, if any
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
void CDhcpScopeOptions::UpdateResultMessage(ITFSNode * pNode)
|
|
{
|
|
HRESULT hr = hrOK;
|
|
int nMessage = -1; // default
|
|
int nVisible, nTotal;
|
|
int i;
|
|
|
|
CString strTitle, strBody, strTemp;
|
|
|
|
if (!m_dwErr)
|
|
{
|
|
pNode->GetChildCount(&nVisible, &nTotal);
|
|
|
|
// determine what message to display
|
|
if ( (m_nState == notLoaded) ||
|
|
(m_nState == loading) )
|
|
{
|
|
nMessage = -1;
|
|
}
|
|
else
|
|
if (nTotal == 0)
|
|
{
|
|
nMessage = SCOPE_OPTIONS_MESSAGE_NO_OPTIONS;
|
|
}
|
|
|
|
// build the strings
|
|
if (nMessage != -1)
|
|
{
|
|
// now build the text strings
|
|
// first entry is the title
|
|
strTitle.LoadString(g_uScopeOptionsMessages[nMessage][0]);
|
|
|
|
// second entry is the icon
|
|
// third ... n entries are the body strings
|
|
|
|
for (i = 2; g_uScopeOptionsMessages[nMessage][i] != 0; i++)
|
|
{
|
|
strTemp.LoadString(g_uScopeOptionsMessages[nMessage][i]);
|
|
strBody += strTemp;
|
|
}
|
|
}
|
|
}
|
|
|
|
// show the message
|
|
if (nMessage == -1)
|
|
{
|
|
ClearMessage(pNode);
|
|
}
|
|
else
|
|
{
|
|
ShowMessage(pNode, strTitle, strBody, (IconIdentifier) g_uScopeOptionsMessages[nMessage][1]);
|
|
}
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CDhcpScopeOptions::EnumerateResultPane
|
|
We override this function for the options nodes for one reason.
|
|
Whenever an option class is deleted, then all options defined for
|
|
that class will be removed as well. Since there are multiple places
|
|
that these options may show up, it's easier to just not show any
|
|
options that don't have a class defined for it.
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpScopeOptions::EnumerateResultPane
|
|
(
|
|
ITFSComponent * pComponent,
|
|
MMC_COOKIE cookie,
|
|
LPARAM arg,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
CClassInfoArray ClassInfoArray;
|
|
SPITFSNode spContainer, spServerNode;
|
|
CDhcpServer * pServer;
|
|
COptionValueEnum * aEnum[2];
|
|
int aImages[2] = {ICON_IDX_SCOPE_OPTION_LEAF, ICON_IDX_SERVER_OPTION_LEAF};
|
|
|
|
m_spNodeMgr->FindNode(cookie, &spContainer);
|
|
|
|
spServerNode = GetServerNode(spContainer);
|
|
pServer = GETHANDLER(CDhcpServer, spServerNode);
|
|
|
|
pServer->GetClassInfoArray(ClassInfoArray);
|
|
|
|
aEnum[0] = GetScopeObject(spContainer)->GetOptionValueEnum();
|
|
aEnum[1] = pServer->GetOptionValueEnum();
|
|
|
|
aEnum[0]->Reset();
|
|
aEnum[1]->Reset();
|
|
|
|
return OnResultUpdateOptions(pComponent, spContainer, &ClassInfoArray, aEnum, aImages, 2);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Command handlers
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CDhcpScopeOptions::OnCreateNewOptions
|
|
(
|
|
ITFSNode * pNode
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
CPropertyPageHolderBase * pPropSheet;
|
|
HRESULT hr = hrOK;
|
|
|
|
COM_PROTECT_TRY
|
|
{
|
|
if (HasPropSheetsOpen())
|
|
{
|
|
GetOpenPropSheet(0, &pPropSheet);
|
|
|
|
pPropSheet->SetActiveWindow();
|
|
}
|
|
else
|
|
{
|
|
CString strOptCfgTitle, strOptType;
|
|
SPIComponentData spComponentData;
|
|
|
|
strOptType.LoadString(IDS_CONFIGURE_OPTIONS_SCOPE);
|
|
AfxFormatString1(strOptCfgTitle, IDS_CONFIGURE_OPTIONS_TITLE, strOptType);
|
|
|
|
m_spNodeMgr->GetComponentData(&spComponentData);
|
|
|
|
hr = DoPropertiesOurselvesSinceMMCSucks(pNode, spComponentData, strOptCfgTitle);
|
|
}
|
|
}
|
|
COM_PROTECT_CATCH
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Background thread functionality
|
|
---------------------------------------------------------------------------*/
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScopeOptions::OnCreateQuery()
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
ITFSQueryObject*
|
|
CDhcpScopeOptions::OnCreateQuery(ITFSNode * pNode)
|
|
{
|
|
CDhcpScopeOptionsQueryObj* pQuery =
|
|
new CDhcpScopeOptionsQueryObj(m_spTFSCompData, m_spNodeMgr);
|
|
|
|
pQuery->m_strServer = GetServerIpAddress(pNode);
|
|
|
|
pQuery->m_dhcpScopeAddress = GetScopeObject(pNode)->GetAddress();
|
|
pQuery->m_dhcpResumeHandle = NULL;
|
|
pQuery->m_dwPreferredMax = 0xFFFFFFFF;
|
|
|
|
GetScopeObject(pNode)->GetDynBootpClassName(pQuery->m_strDynBootpClassName);
|
|
GetScopeObject(pNode)->GetServerVersion(pQuery->m_liDhcpVersion);
|
|
|
|
return pQuery;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CDhcpScopeOptionsQueryObj::Execute()
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
STDMETHODIMP
|
|
CDhcpScopeOptionsQueryObj::Execute()
|
|
{
|
|
DWORD dwErr;
|
|
DHCP_OPTION_SCOPE_INFO dhcpOptionScopeInfo;
|
|
COptionValueEnum * pOptionValueEnum;
|
|
|
|
pOptionValueEnum = new COptionValueEnum();
|
|
pOptionValueEnum->m_strDynBootpClassName = m_strDynBootpClassName;
|
|
|
|
dhcpOptionScopeInfo.ScopeType = DhcpSubnetOptions;
|
|
dhcpOptionScopeInfo.ScopeInfo.SubnetScopeInfo = m_dhcpScopeAddress;
|
|
|
|
pOptionValueEnum->Init(m_strServer, m_liDhcpVersion, dhcpOptionScopeInfo);
|
|
dwErr = pOptionValueEnum->Enum();
|
|
|
|
if (dwErr != ERROR_SUCCESS)
|
|
{
|
|
Trace1("CDhcpScopeOptionsQueryObj::Execute - Enum Failed! %d\n", dwErr);
|
|
m_dwErr = dwErr;
|
|
PostError(dwErr);
|
|
|
|
delete pOptionValueEnum;
|
|
}
|
|
else
|
|
{
|
|
pOptionValueEnum->SortById();
|
|
AddToQueue((LPARAM) pOptionValueEnum, DHCP_QDATA_OPTION_VALUES);
|
|
}
|
|
|
|
return hrFalse;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CDhcpScopeOptions::OnNotifyExiting
|
|
CMTDhcpHandler overridden functionality
|
|
allows us to know when the background thread is done
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
STDMETHODIMP
|
|
CDhcpScopeOptions::OnNotifyExiting
|
|
(
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
SPITFSNode spNode;
|
|
spNode.Set(m_spNode); // save this off because OnNotifyExiting will release it
|
|
|
|
HRESULT hr = CMTDhcpHandler::OnNotifyExiting(lParam);
|
|
|
|
UpdateResultMessage(spNode);
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
//
|
|
// qsort comparison routine to compare the ip addresses.
|
|
//
|
|
//
|
|
|
|
int __cdecl QCompare( const void *ip1, const void *ip2 )
|
|
{
|
|
|
|
DWORD *lip1, *lip2;
|
|
|
|
if ( ip1 && ip2 )
|
|
{
|
|
lip1 = (DWORD *)ip1;
|
|
lip2 = (DWORD *)ip2;
|
|
|
|
if ( *lip1 < *lip2 )
|
|
{
|
|
return -1;
|
|
}
|
|
else if ( *lip1 > *lip2 )
|
|
{
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|