mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3398 lines
79 KiB
3398 lines
79 KiB
/**********************************************************************/
|
|
/** Microsoft Windows/NT **/
|
|
/** Copyright(c) Microsoft Corp., 1995 **/
|
|
/**********************************************************************/
|
|
|
|
/*
|
|
dhcpdgen.cpp
|
|
General purpose classes
|
|
|
|
FILE HISTORY:
|
|
|
|
*/
|
|
|
|
#include "stdafx.h"
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char BASED_CODE THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
CDumpContext & operator << ( CDumpContext & out, const DHCP_IP_ADDRESS * pdhipa )
|
|
{
|
|
char szBuf [50] ;
|
|
|
|
ASSERT(pdhipa);
|
|
UtilCvtIpAddrToString( *pdhipa, szBuf, sizeof szBuf ) ;
|
|
|
|
out << "IP: " << szBuf ;
|
|
|
|
return out;
|
|
}
|
|
|
|
CDumpContext & operator << ( CDumpContext & out, const DHCP_IP_RANGE & dhipr )
|
|
{
|
|
char szBuf1 [50],
|
|
szBuf2 [50] ;
|
|
|
|
UtilCvtIpAddrToString( dhipr.StartAddress, szBuf1, sizeof szBuf1 ) ;
|
|
UtilCvtIpAddrToString( dhipr.EndAddress, szBuf2, sizeof szBuf2 ) ;
|
|
|
|
out << "IPR: " << szBuf1 << ".." << szBuf2 ;
|
|
|
|
return out;
|
|
}
|
|
|
|
CDumpContext & operator << ( CDumpContext & out, const CHostName & cHostName )
|
|
{
|
|
return out << "HOST: " << cHostName.QueryWcName() ;
|
|
}
|
|
|
|
CDumpContext & operator << ( CDumpContext & out, const CDhcpScopeId & cScopeId )
|
|
{
|
|
DHCP_IP_ADDRESS dhipa = cScopeId.QueryId() ;
|
|
|
|
return out << "SCOPE: " << cScopeId.QueryWcName()
|
|
<< " -- " << & dhipa ;
|
|
}
|
|
|
|
CDhcpScope :: CDhcpScope (
|
|
CHostName & cHostName,
|
|
const DHCP_SUBNET_INFO * pdhcSubnetInfo
|
|
)
|
|
: m_scope_id( cHostName, pdhcSubnetInfo->SubnetAddress ),
|
|
m_subnet_state( DhcpSubnetDisabled )
|
|
{
|
|
InitInfo( pdhcSubnetInfo ) ;
|
|
}
|
|
|
|
CDhcpScope :: CDhcpScope (
|
|
CDhcpScopeId & cScopeId
|
|
)
|
|
: m_scope_id( cScopeId ),
|
|
m_subnet_state( DhcpSubnetDisabled )
|
|
{
|
|
InitInfo() ;
|
|
}
|
|
|
|
CDhcpScope :: CDhcpScope (
|
|
const CDhcpScope & cScope
|
|
)
|
|
: m_scope_id( cScope.QueryScopeId() ),
|
|
m_subnet_state( DhcpSubnetDisabled )
|
|
{
|
|
InitInfo() ;
|
|
}
|
|
|
|
CDhcpScope :: CDhcpScope (
|
|
CHostName & cHostName,
|
|
DHC_SCOPE_ID dhscid,
|
|
DHC_IP_MASK dhmid,
|
|
const char * pszName,
|
|
const char * pszComment
|
|
)
|
|
: m_scope_id( cHostName, dhscid ),
|
|
m_ip_mask( dhmid ),
|
|
m_str_name( pszName ),
|
|
m_str_comment( pszComment ),
|
|
m_subnet_state( DhcpSubnetDisabled )
|
|
{
|
|
LONG err ;
|
|
CDhcpScopeInfo cScopeInfo( *this ) ;
|
|
|
|
TRACEEOLID( "Create new scope: " << m_scope_id ) ;
|
|
|
|
do
|
|
{
|
|
if ( err = cHostName.CreateScope( cScopeInfo ) )
|
|
{
|
|
break ;
|
|
}
|
|
|
|
if ( ! InitInfo() )
|
|
{
|
|
err = QueryApiErr() ;
|
|
}
|
|
}
|
|
while ( FALSE ) ;
|
|
|
|
if ( err )
|
|
{
|
|
ReportError( err ) ;
|
|
TRACEEOLID( "Create new scope: " << m_scope_id
|
|
<< " FAILED, error = " << err ) ;
|
|
}
|
|
}
|
|
|
|
|
|
CDhcpScope :: ~ CDhcpScope ()
|
|
{
|
|
}
|
|
|
|
void
|
|
CDhcpScope :: AssertValid () const
|
|
{
|
|
|
|
}
|
|
|
|
|
|
LONG
|
|
CDhcpScope :: Update ()
|
|
{
|
|
return IsDirty ? SetInfo() : 0 ;
|
|
}
|
|
|
|
//
|
|
// Return the IP address range owned by this scope
|
|
//
|
|
void
|
|
CDhcpScope :: QueryIpRange (
|
|
DHCP_IP_RANGE * pdhipr
|
|
)
|
|
{
|
|
*pdhipr = m_ip_range ;
|
|
}
|
|
|
|
//
|
|
// Set a new IP address range for the scope
|
|
//
|
|
APIERR
|
|
CDhcpScope :: SetIpRange (
|
|
const CDhcpIpRange & dhipr
|
|
)
|
|
{
|
|
DHCP_SUBNET_ELEMENT_DATA dhcSubElData ;
|
|
DHCP_IP_RANGE dhipRange = m_ip_range ;
|
|
|
|
dhcSubElData.ElementType = DhcpIpRanges ;
|
|
dhcSubElData.Element.IpRange = & dhipRange ;
|
|
|
|
// Remove the old IP range; allow "not found" error in new scope.
|
|
(void)RemoveElement( & dhcSubElData ) ;
|
|
|
|
APIERR err = 0;
|
|
|
|
//if ( err == 0 || err == ERROR_FILE_NOT_FOUND )
|
|
//{
|
|
dhipRange = dhipr ;
|
|
if ( (err = AddElement( & dhcSubElData )) == 0 )
|
|
{
|
|
m_ip_range = dhipr ;
|
|
}
|
|
//}
|
|
return err ;
|
|
}
|
|
|
|
//
|
|
// Update the name of the scope
|
|
//
|
|
void
|
|
CDhcpScope :: SetName (
|
|
const CString & str
|
|
)
|
|
{
|
|
m_str_name = str ;
|
|
SetDirty() ;
|
|
}
|
|
|
|
void
|
|
CDhcpScope :: SetComment (
|
|
const CString & str
|
|
)
|
|
{
|
|
m_str_comment = str ;
|
|
SetDirty() ;
|
|
}
|
|
|
|
//
|
|
// Get the current address allocation policy variables
|
|
//
|
|
void
|
|
CDhcpScope :: QueryAllocationPolicy (
|
|
DWORD * pdwClusterSize,
|
|
DWORD * pdwAddressPreallocate )
|
|
{
|
|
*pdwClusterSize = m_c_cluster_size ;
|
|
*pdwAddressPreallocate = m_c_preallocate ;
|
|
}
|
|
|
|
//
|
|
// Set the address allocation policy variables.
|
|
//
|
|
LONG
|
|
CDhcpScope :: SetAllocationPolicy (
|
|
DWORD dwClusterSize,
|
|
DWORD dwAddressPreallocate
|
|
)
|
|
{
|
|
m_c_cluster_size = dwClusterSize ;
|
|
m_c_preallocate = dwAddressPreallocate ;
|
|
SetDirty() ;
|
|
|
|
return Update() ;
|
|
}
|
|
|
|
|
|
// Build a string representing the display name for a scope
|
|
// eg: "[157.55.0.1] ScopeName"
|
|
void
|
|
CDhcpScope :: QueryDisplayName(OUT CString& strName) const
|
|
{
|
|
static CString strFormat ;
|
|
static BOOL bFirst = TRUE ;
|
|
char szResult [ DHC_STRING_MAX ] ;
|
|
char szIp [ DHC_STRING_MAX ] ;
|
|
|
|
if ( bFirst )
|
|
{
|
|
strFormat.LoadString( IDS_INFO_FORMAT_SCOPE_NAME ) ;
|
|
bFirst = FALSE ;
|
|
}
|
|
::UtilCvtIpAddrToString( m_scope_id.QueryId(), szIp, sizeof szIp ) ;
|
|
|
|
::wsprintf( szResult, strFormat, szIp, (const char *) m_str_name ) ;
|
|
strName = szResult ;
|
|
}
|
|
|
|
BOOL
|
|
CDhcpScope :: operator == (
|
|
const CDhcpScope & cScope
|
|
) const
|
|
{
|
|
return m_scope_id.QueryId() == cScope.QueryId() ;
|
|
}
|
|
|
|
//
|
|
// Update all the "dirty" values in the first list;
|
|
// delete all the defunct values in the other list.
|
|
//
|
|
LONG
|
|
CDhcpScope :: SetValues (
|
|
CObListParamTypes * poblValues,
|
|
CObListParamTypes * poblDefunct,
|
|
DHCP_OPTION_SCOPE_TYPE dhcScopeType,
|
|
DHCP_IP_ADDRESS dhipaReservation,
|
|
CWnd * pwndMsgParent
|
|
)
|
|
{
|
|
LONG err = 0,
|
|
err2 = 0 ;
|
|
CDhcpParamType * pdhcType ;
|
|
|
|
//
|
|
// First, delete the deleted types
|
|
//
|
|
if ( poblDefunct )
|
|
{
|
|
CObListIter obliDeleted( *poblDefunct ) ;
|
|
while ( pdhcType = (CDhcpParamType *) obliDeleted.Next() )
|
|
{
|
|
err2 = RemoveValue( pdhcType->QueryId(), dhcScopeType, dhipaReservation ) ;
|
|
if (err2 = ERROR_FILE_NOT_FOUND)
|
|
{
|
|
//
|
|
// We forgive this error, because we may have added and deleted
|
|
// the item in the same session. In any case, it's gone, which
|
|
// is what we wanted, so it doesn't matter how it came about.
|
|
//
|
|
err2 = ERROR_SUCCESS;
|
|
}
|
|
|
|
if ( err2 != 0 && err == 0 )
|
|
{
|
|
err = err2 ;
|
|
}
|
|
pdhcType->SetApiErr( err2 ) ;
|
|
}
|
|
}
|
|
|
|
/*
|
|
//
|
|
// OLD METHOD:
|
|
//
|
|
//
|
|
// Next, update the altered values. We do this by deleting the old setting
|
|
// and re-adding it.
|
|
//
|
|
CObListIter obli( *poblValues ) ;
|
|
while ( pdhcType = (CDhcpParamType *) obli.Next() )
|
|
{
|
|
if ( pdhcType->IsDirty() )
|
|
{
|
|
err2 = SetValue( pdhcType, dhcScopeType, dhipaReservation ) ;
|
|
if ( err2 != 0 && err == 0 )
|
|
{
|
|
err = err2 ;
|
|
}
|
|
pdhcType->SetApiErr( err2 ) ;
|
|
}
|
|
}
|
|
*/
|
|
//
|
|
// Next, update the altered values. We do this by using the new
|
|
// DhcpCreateOptionValues API, which creates them all in one
|
|
// fell swoop
|
|
//
|
|
|
|
LONG cElements = 0;
|
|
|
|
CObListIter obli( *poblValues ) ;
|
|
|
|
//
|
|
// Check to see how many options need to be added
|
|
//
|
|
while ( pdhcType = (CDhcpParamType *) obli.Next() )
|
|
{
|
|
if ( pdhcType->IsDirty() )
|
|
{
|
|
++cElements;
|
|
}
|
|
}
|
|
|
|
obli.Reset();
|
|
|
|
DHCP_OPTION_VALUE_ARRAY ValuesArray;
|
|
DHCP_OPTION_VALUE *pValues = NULL;
|
|
CDhcpOptionValue ** apOptionValues = NULL;
|
|
|
|
DHCP_OPTION_SCOPE_INFO ScopeInfo;
|
|
|
|
if (cElements > 0)
|
|
{
|
|
CATCH_MEM_EXCEPTION
|
|
{
|
|
apOptionValues = new CDhcpOptionValue *[cElements];
|
|
pValues = new DHCP_OPTION_VALUE[cElements];
|
|
|
|
LONG i = 0;
|
|
while ( pdhcType = (CDhcpParamType *) obli.Next() )
|
|
{
|
|
DHCP_OPTION dhcOption ;
|
|
if ( pdhcType->IsDirty() )
|
|
{
|
|
apOptionValues[i] = NULL ;
|
|
//
|
|
// Create the structure required for RPC; force inclusion of
|
|
// at least one data element to define the data type.
|
|
//
|
|
apOptionValues[i] = new CDhcpOptionValue( & pdhcType->QueryValue(), TRUE ) ;
|
|
|
|
if ( (err = apOptionValues[i]->QueryError()) == 0 )
|
|
{
|
|
dhcOption.OptionID = pdhcType->QueryId() ;
|
|
dhcOption.OptionName = ::UtilWcstrDup( pdhcType->QueryName() );
|
|
dhcOption.OptionComment = ::UtilWcstrDup( pdhcType->QueryComment() ) ;
|
|
dhcOption.DefaultValue = apOptionValues[i]->QueryData() ;
|
|
dhcOption.OptionType = pdhcType->QueryOptType() ;
|
|
|
|
pValues[i].Value = apOptionValues[i]->QueryData();
|
|
pValues[i].OptionID = pdhcType->QueryId() ;
|
|
}
|
|
++i;
|
|
}
|
|
|
|
}
|
|
|
|
ASSERT(i == cElements);
|
|
|
|
ValuesArray.NumElements = cElements;
|
|
ValuesArray.Values = pValues;
|
|
|
|
ScopeInfo.ScopeType = dhcScopeType;
|
|
//
|
|
// Provide the sub-net address if this is a scope-level operation
|
|
//
|
|
if ( dhcScopeType == DhcpSubnetOptions )
|
|
{
|
|
ScopeInfo.ScopeInfo.SubnetScopeInfo = m_scope_id.QueryId() ;
|
|
}
|
|
else
|
|
if ( dhcScopeType == DhcpReservedOptions )
|
|
{
|
|
ScopeInfo.ScopeInfo.ReservedScopeInfo.ReservedIpAddress = dhipaReservation ;
|
|
ScopeInfo.ScopeInfo.ReservedScopeInfo.ReservedIpSubnetAddress = m_scope_id.QueryId() ;
|
|
}
|
|
else
|
|
{
|
|
ScopeInfo.ScopeInfo.GlobalScopeInfo = NULL;
|
|
}
|
|
|
|
err = ::DhcpSetOptionValues(
|
|
m_scope_id.QueryWcName(),
|
|
&ScopeInfo,
|
|
&ValuesArray );
|
|
|
|
//
|
|
// Clean up
|
|
//
|
|
for (i = 0; i < cElements; ++i)
|
|
{
|
|
delete apOptionValues[i];
|
|
}
|
|
|
|
delete[] pValues;
|
|
delete[] apOptionValues;
|
|
}
|
|
END_MEM_EXCEPTION(err)
|
|
}
|
|
|
|
//
|
|
// If there were errors and we're given a window handle, display
|
|
// each error message in some detail.
|
|
//
|
|
if ( err && pwndMsgParent )
|
|
{
|
|
DisplayUpdateErrors( poblValues, poblDefunct, pwndMsgParent ) ;
|
|
}
|
|
return err ;
|
|
}
|
|
|
|
//
|
|
// Create all the types in the given list.
|
|
// poblParamTypes: master param type list (from .CSV file)
|
|
// CreateTypeList was rewritten by JonN in March 1996
|
|
//
|
|
LONG
|
|
CDhcpScope :: CreateTypeList (
|
|
CObListParamTypes * poblParamTypes
|
|
)
|
|
{
|
|
theApp.BeginWaitCursor() ;
|
|
|
|
LONG err = ERROR_SUCCESS,
|
|
err2;
|
|
BOOL fAddedTypes = FALSE;
|
|
|
|
CATCH_MEM_EXCEPTION
|
|
{
|
|
//
|
|
// Ensure that we have a cached list of types for this host
|
|
// Will read in the information if necessary
|
|
// EXCEPTION CAN BE THROWN HERE.
|
|
//
|
|
CObListOfTypesOnHost * poblTypesOnHost = theApp.QueryHostTypeList( *this );
|
|
ASSERT( poblTypesOnHost != NULL );
|
|
CObListParamTypes * poblCachedTypes = poblTypesOnHost->QueryTypeList();
|
|
ASSERT( poblCachedTypes != NULL );
|
|
|
|
//
|
|
// Compare the master list to our cached list.
|
|
// Add master types missing from the cached list to the list
|
|
// on the target host, and mark fAddedTypes to indicate that the
|
|
// cache must be updated.
|
|
//
|
|
CObListIter obliMaster( *poblParamTypes ) ;
|
|
CObListIter obliCached( *poblCachedTypes ) ;
|
|
CDhcpParamType * pdhcMasterType;
|
|
CDhcpParamType * pdhcCachedType = (CDhcpParamType *) obliCached.Next() ;
|
|
#ifdef DEBUG
|
|
DHCP_OPTION_ID idMasterLast = 0;
|
|
DHCP_OPTION_ID idCachedLast = (pdhcCachedType != NULL)
|
|
? pdhcCachedType->QueryId() : 0;
|
|
#endif
|
|
|
|
while ( pdhcMasterType = (CDhcpParamType *) obliMaster.Next() )
|
|
{
|
|
DHCP_OPTION_ID idMaster = pdhcMasterType->QueryId();
|
|
#ifdef DEBUG
|
|
ASSERT( idMaster > idMasterLast );
|
|
idMasterLast = idMaster;
|
|
#endif
|
|
while ( pdhcCachedType != NULL
|
|
&& idMaster > pdhcCachedType->QueryId() )
|
|
{
|
|
// The cached list contains an entry not on the master list.
|
|
// Advance to the next element in the cached list.
|
|
pdhcCachedType = (CDhcpParamType *) obliCached.Next();
|
|
#ifdef DEBUG
|
|
if ( pdhcCachedType != NULL )
|
|
{
|
|
ASSERT( pdhcCachedType->QueryId() > idCachedLast );
|
|
idCachedLast = pdhcCachedType->QueryId();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if ( pdhcCachedType != NULL
|
|
&& idMaster == pdhcCachedType->QueryId() )
|
|
{
|
|
// This entry is on both the cached list and the master list.
|
|
// Advance to the next element in both lists.
|
|
pdhcCachedType = (CDhcpParamType *) obliCached.Next();
|
|
#ifdef DEBUG
|
|
if ( pdhcCachedType != NULL )
|
|
{
|
|
ASSERT( pdhcCachedType->QueryId() > idCachedLast );
|
|
idCachedLast = pdhcCachedType->QueryId();
|
|
}
|
|
#endif
|
|
continue;
|
|
}
|
|
|
|
ASSERT( pdhcCachedType == NULL
|
|
|| idMaster < pdhcCachedType->QueryId() );
|
|
|
|
// There is no DhcpCreateOptions (plural), and DhcpSetValues
|
|
// only initializes OptionValue
|
|
err2 = CreateType( pdhcMasterType ); // ignore error return
|
|
if ( err2 != ERROR_SUCCESS )
|
|
{
|
|
TRACEEOLID( "CDhcpScope: error " << err2
|
|
<< " adding type " << idMaster ) ;
|
|
}
|
|
fAddedTypes = TRUE;
|
|
}
|
|
|
|
// Update cache if necessary
|
|
if ( fAddedTypes )
|
|
{
|
|
if (err == ERROR_SUCCESS)
|
|
err = poblTypesOnHost->UpdateList( *this );
|
|
}
|
|
|
|
}
|
|
END_MEM_EXCEPTION(err)
|
|
|
|
if ( err != ERROR_SUCCESS )
|
|
{
|
|
TRACEEOLID( "CDhcpScope: error " << err << " in CreateTypeList" );
|
|
}
|
|
|
|
theApp.EndWaitCursor() ;
|
|
|
|
return err ;
|
|
}
|
|
|
|
LONG
|
|
CDhcpScope :: UpdateTypeList (
|
|
CObListParamTypes * poblValues, // The list of types/values
|
|
CObListParamTypes * poblDefunct, // The list of deleted types/values
|
|
CWnd * pwndMsgParent // IF !NULL, window for use for popups
|
|
)
|
|
{
|
|
LONG err = 0,
|
|
err2 ;
|
|
CDhcpParamType * pdhcType ;
|
|
|
|
//
|
|
// First, delete the deleted types
|
|
//
|
|
CObListIter obliDeleted( *poblDefunct ) ;
|
|
while ( pdhcType = (CDhcpParamType *) obliDeleted.Next() )
|
|
{
|
|
err2 = DeleteType( pdhcType->QueryId() ) ;
|
|
if ( err2 != 0 )
|
|
{
|
|
if ( err == 0 )
|
|
{
|
|
err = err2 ;
|
|
}
|
|
}
|
|
pdhcType->SetApiErr( err2 ) ;
|
|
}
|
|
|
|
//
|
|
// Next, update the altered values. We do this by deleting the old setting
|
|
// and re adding it.
|
|
//
|
|
CObListIter obli( *poblValues ) ;
|
|
while ( pdhcType = (CDhcpParamType *) obli.Next() )
|
|
{
|
|
if ( pdhcType->IsDirty() )
|
|
{
|
|
//
|
|
// Delete the old value.
|
|
//
|
|
DeleteType( pdhcType->QueryId() ) ;
|
|
|
|
//
|
|
// Recreate it.
|
|
//
|
|
err2 = CreateType( pdhcType ) ;
|
|
if ( err2 != 0 )
|
|
{
|
|
if ( err == 0 )
|
|
{
|
|
err = err2 ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pdhcType->SetDirty( FALSE ) ;
|
|
}
|
|
pdhcType->SetApiErr( err2 ) ;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If there were errors and we're given a window handle, display
|
|
// each error message in some detail.
|
|
//
|
|
if ( err && pwndMsgParent )
|
|
{
|
|
DisplayUpdateErrors( poblValues, poblDefunct, pwndMsgParent ) ;
|
|
}
|
|
|
|
return err ;
|
|
}
|
|
|
|
//
|
|
// Display all the errors associated with a pair of update lists.
|
|
//
|
|
void
|
|
CDhcpScope :: DisplayUpdateErrors (
|
|
CObListParamTypes * poblValues,
|
|
CObListParamTypes * poblDefunct,
|
|
CWnd * pwndMsgParent
|
|
)
|
|
{
|
|
CDhcpParamType * pdhcType ;
|
|
APIERR err ;
|
|
char chBuff [DHC_STRING_MAX] ;
|
|
char chMask [DHC_STRING_MAX] ;
|
|
|
|
::LoadString( AfxGetInstanceHandle(), IDS_INFO_OPTION_REFERENCE,
|
|
chMask, sizeof chMask ) ;
|
|
|
|
if ( poblDefunct )
|
|
{
|
|
CObListIter obliDel( *poblDefunct ) ;
|
|
while ( pdhcType = (CDhcpParamType *) obliDel.Next() )
|
|
{
|
|
if ( err = pdhcType->QueryApiErr() )
|
|
{
|
|
//
|
|
// If we couldn't find the thing in the registry, that's
|
|
// actually OK, because it may never have been saved in
|
|
// the first place, i.e. it may have been added and deleted
|
|
// in the same session of this dialog.
|
|
//
|
|
if ( err == ERROR_FILE_NOT_FOUND )
|
|
{
|
|
err = ERROR_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
::wsprintf( chBuff, chMask, (int) pdhcType->QueryId() ) ;
|
|
theApp.MessageBox( err, MB_OK, chBuff ) ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( poblValues )
|
|
{
|
|
CObListIter oblUpd( *poblValues ) ;
|
|
while ( pdhcType = (CDhcpParamType *) oblUpd.Next() )
|
|
{
|
|
if ( err = pdhcType->QueryApiErr() )
|
|
{
|
|
::wsprintf( chBuff, chMask, (int) pdhcType->QueryId() ) ;
|
|
theApp.MessageBox( err, MB_OK, chBuff ) ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Member function to sort by name. Note that the pointer will REALLY
|
|
// be to another CDhcpScope, but C++ won't match function prototypes
|
|
// if it's declared as such.
|
|
//
|
|
int
|
|
CDhcpScope :: OrderByName (
|
|
const CObjectPlus * pobScope
|
|
) const
|
|
{
|
|
const CDhcpScope * pobs = (CDhcpScope *) pobScope ;
|
|
|
|
return ::lstrcmpi( QueryName(), pobs->QueryName() ) ;
|
|
}
|
|
|
|
int
|
|
CDhcpScope :: OrderById (
|
|
const CObjectPlus * pobScope
|
|
) const
|
|
{
|
|
const CDhcpScope * pobs = (CDhcpScope *) pobScope ;
|
|
|
|
DHC_SCOPE_ID l1 = QueryId();
|
|
DHC_SCOPE_ID l2 = pobs->QueryId();
|
|
|
|
return l2 > l1 ? -1 : l2 == l1 ? 0 : +1;
|
|
}
|
|
|
|
|
|
CDhcpIpRange :: CDhcpIpRange (
|
|
DHCP_IP_RANGE dhipr
|
|
)
|
|
{
|
|
*this = dhipr ;
|
|
}
|
|
|
|
CDhcpIpRange :: CDhcpIpRange ()
|
|
{
|
|
m_ip_range.StartAddress = DHCP_IP_ADDRESS_INVALID ;
|
|
m_ip_range.EndAddress = DHCP_IP_ADDRESS_INVALID ;
|
|
}
|
|
|
|
CDhcpIpRange :: ~ CDhcpIpRange ()
|
|
{
|
|
}
|
|
|
|
//
|
|
// Sort helper function
|
|
//
|
|
int
|
|
CDhcpIpRange :: OrderByAddress (
|
|
const CObjectPlus * pobIpRange
|
|
) const
|
|
{
|
|
const CDhcpIpRange * pipr = (CDhcpIpRange *) pobIpRange ;
|
|
|
|
//
|
|
// Derive a comparison result for the end address
|
|
//
|
|
int iEndResult = QueryAddr( FALSE ) < QueryAddr( FALSE )
|
|
? -1
|
|
: QueryAddr( FALSE ) != QueryAddr( FALSE ) ;
|
|
|
|
//
|
|
// Use start address as major sort key, end address as minor.
|
|
//
|
|
return QueryAddr( TRUE ) < pipr->QueryAddr( TRUE )
|
|
? -1
|
|
: ( QueryAddr( TRUE ) != pipr->QueryAddr( TRUE )
|
|
? 1
|
|
: iEndResult ) ;
|
|
}
|
|
|
|
CDhcpIpRange &
|
|
CDhcpIpRange :: operator = (
|
|
const DHCP_IP_RANGE dhipr
|
|
)
|
|
{
|
|
m_ip_range = dhipr ;
|
|
|
|
return *this ;
|
|
}
|
|
|
|
DHCP_IP_ADDRESS
|
|
CDhcpIpRange :: SetAddr (
|
|
DHCP_IP_ADDRESS dhipa,
|
|
BOOL bStart
|
|
)
|
|
{
|
|
DHCP_IP_ADDRESS dhipaOld ;
|
|
|
|
if ( bStart )
|
|
{
|
|
dhipaOld = m_ip_range.StartAddress ;
|
|
m_ip_range.StartAddress = dhipa ;
|
|
}
|
|
else
|
|
{
|
|
dhipaOld = m_ip_range.EndAddress ;
|
|
m_ip_range.EndAddress = dhipa ;
|
|
}
|
|
|
|
return dhipaOld ;
|
|
}
|
|
|
|
BOOL
|
|
CDhcpIpRange :: IsOverlap (
|
|
DHCP_IP_RANGE dhipr
|
|
)
|
|
{
|
|
BOOL bOverlap = FALSE ;
|
|
if ( m_ip_range.StartAddress <= dhipr.StartAddress )
|
|
{
|
|
if ( m_ip_range.StartAddress == dhipr.StartAddress )
|
|
{
|
|
bOverlap = TRUE ;
|
|
}
|
|
//else if ( m_ip_range.EndAddress >= dhipr.EndAddress )
|
|
else if ( m_ip_range.EndAddress >= dhipr.StartAddress )
|
|
{
|
|
bOverlap = TRUE ;
|
|
}
|
|
}
|
|
//else if ( m_ip_range.StartAddress <= dhipr.EndAddress
|
|
// && m_ip_range.EndAddress >= dhipr.EndAddress )
|
|
else if (m_ip_range.StartAddress <= dhipr.EndAddress)
|
|
{
|
|
bOverlap = TRUE;
|
|
}
|
|
|
|
return bOverlap ;
|
|
}
|
|
|
|
//
|
|
// Return TRUE if this range is an improper subset of the given range.
|
|
//
|
|
BOOL
|
|
CDhcpIpRange :: IsSubset (
|
|
DHCP_IP_RANGE dhipr
|
|
)
|
|
{
|
|
return dhipr.StartAddress <= m_ip_range.StartAddress
|
|
&& dhipr.EndAddress >= m_ip_range.EndAddress ;
|
|
}
|
|
|
|
//
|
|
// Return TRUE if this range is an improper superset of the given range.
|
|
//
|
|
BOOL
|
|
CDhcpIpRange :: IsSuperset (
|
|
DHCP_IP_RANGE dhipr
|
|
)
|
|
{
|
|
return dhipr.StartAddress >= m_ip_range.StartAddress
|
|
&& dhipr.EndAddress <= m_ip_range.EndAddress ;
|
|
}
|
|
|
|
//
|
|
// Initialise static version
|
|
// numbers
|
|
//
|
|
LARGE_INTEGER CHostName::liBadVersion = { 0, 0 };
|
|
LARGE_INTEGER CHostName::liNT35 = { 1, 0 };
|
|
LARGE_INTEGER CHostName::liNT351 = { 1, 1 };
|
|
|
|
//
|
|
// Copy constructor.
|
|
//
|
|
CHostName :: CHostName (
|
|
const CHostName & cHostName
|
|
)
|
|
: m_str_name( cHostName.m_str_name ),
|
|
m_bNetbios( FALSE ),
|
|
m_wc_name( NULL ),
|
|
m_ip_address( cHostName.QueryIpAddress() ),
|
|
m_liDhcpVersion(CDhcpScopeId::liBadVersion)
|
|
{
|
|
SetWcName() ;
|
|
}
|
|
|
|
CHostName :: CHostName (
|
|
const char * pszName,
|
|
BOOL bNetbios
|
|
)
|
|
: m_str_name( pszName ),
|
|
m_bNetbios( bNetbios ),
|
|
m_wc_name( NULL ),
|
|
m_ip_address( DHCP_IP_ADDRESS_INVALID ),
|
|
m_liDhcpVersion(CDhcpScopeId::liBadVersion)
|
|
{
|
|
BOOL bResult = m_bNetbios
|
|
? ::UtilGetNetbiosAddress( pszName, & m_ip_address )
|
|
: ::UtilGetHostAddress( pszName, & m_ip_address ) ;
|
|
|
|
if ( ! bResult )
|
|
{
|
|
m_ip_address = DHCP_IP_ADDRESS_INVALID ;
|
|
}
|
|
else
|
|
{
|
|
SetWcName() ;
|
|
}
|
|
}
|
|
|
|
CHostName :: CHostName (
|
|
DHCP_IP_ADDRESS dhcpIpAddr
|
|
)
|
|
: m_ip_address( dhcpIpAddr ),
|
|
m_wc_name( NULL ),
|
|
m_bNetbios( FALSE ),
|
|
m_liDhcpVersion(CDhcpScopeId::liBadVersion)
|
|
{
|
|
char chName [ DHC_STRING_MAX ] ;
|
|
LONG err = 0 ;
|
|
|
|
::UtilCvtIpAddrToString( m_ip_address, chName, sizeof chName ) ;
|
|
|
|
CATCH_MEM_EXCEPTION
|
|
{
|
|
m_str_name = chName ;
|
|
SetWcName() ;
|
|
}
|
|
END_MEM_EXCEPTION(err)
|
|
|
|
if ( err )
|
|
{
|
|
ReportError( err ) ;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Constructor of empty host name
|
|
//
|
|
CHostName :: CHostName ()
|
|
: m_bNetbios( FALSE ),
|
|
m_wc_name( NULL ),
|
|
m_ip_address( DHCP_IP_ADDRESS_INVALID ),
|
|
m_liDhcpVersion(CDhcpScopeId::liBadVersion)
|
|
{
|
|
m_wc_name = NULL ;
|
|
}
|
|
|
|
CHostName :: ~ CHostName ()
|
|
{
|
|
delete m_wc_name ;
|
|
m_wc_name = NULL ;
|
|
}
|
|
|
|
void
|
|
CHostName :: QueryDisplayName (
|
|
CString & strName
|
|
) const
|
|
{
|
|
static CString strFormat ;
|
|
static BOOL bFirst = TRUE ;
|
|
char szIp [ DHC_STRING_MAX ] ;
|
|
char szResult [ DHC_STRING_MAX ] ;
|
|
|
|
if ( bFirst )
|
|
{
|
|
strFormat.LoadString( IDS_INFO_FORMAT_SERVER_NAME ) ;
|
|
bFirst = FALSE ;
|
|
}
|
|
|
|
::UtilCvtIpAddrToString( m_ip_address, szIp, sizeof szIp ) ;
|
|
::wsprintf( szResult, strFormat, szIp, (const char *) m_str_name ) ;
|
|
strName = szResult ;
|
|
}
|
|
|
|
BOOL
|
|
CHostName :: SetWcName ()
|
|
{
|
|
if ( m_wc_name )
|
|
{
|
|
delete m_wc_name ;
|
|
m_wc_name = NULL ;
|
|
}
|
|
m_wc_name = ::UtilDupIpAddrToWstr( m_ip_address ) ;
|
|
|
|
return m_wc_name != NULL ;
|
|
}
|
|
|
|
//
|
|
// Member function to sort by name. Note that the pointer will REALLY
|
|
// be to another CHostName, but C++ won't match function prototypes
|
|
// if it's declared as such.
|
|
//
|
|
int
|
|
CHostName :: OrderByName (
|
|
const CObjectPlus * pobHost
|
|
) const
|
|
{
|
|
return m_str_name.CompareNoCase( ((CHostName *) pobHost)->m_str_name ) ;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CHostName :: operator == (
|
|
const CHostName & cHost
|
|
) const
|
|
{
|
|
return m_str_name == cHost.m_str_name ;
|
|
}
|
|
|
|
CHostName &
|
|
CHostName :: operator = (
|
|
const CHostName & cHost
|
|
)
|
|
{
|
|
ResetErrors() ;
|
|
m_str_name = cHost.m_str_name ;
|
|
m_bNetbios = cHost.m_bNetbios ;
|
|
m_ip_address = cHost.m_ip_address ;
|
|
delete m_wc_name ;
|
|
m_wc_name = ::UtilWcstrDup( cHost.m_wc_name ) ;
|
|
|
|
return *this ;
|
|
}
|
|
|
|
ENUM_HOST_NAME_TYPE
|
|
CHostName :: CategorizeName (
|
|
const char * pszName
|
|
)
|
|
{
|
|
ENUM_HOST_NAME_TYPE enResult = HNM_TYPE_INVALID ;
|
|
const char chDot = '.' ;
|
|
const char chSlash = '\\' ;
|
|
CString strName( pszName ) ;
|
|
|
|
int cch = strName.GetLength() ;
|
|
|
|
//
|
|
// BUGBUG: Generalize this routine:
|
|
//
|
|
// Does the name begin with two slashes??
|
|
|
|
if ( cch > 2
|
|
&& strName.GetAt(0) == chSlash
|
|
&& strName.GetAt(1) == chSlash )
|
|
{
|
|
enResult = HNM_TYPE_NB ;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Scan the name looking for DNS name or IP address
|
|
//
|
|
int i = 0,
|
|
cDots = 0,
|
|
cAlpha = 0 ;
|
|
char ch ;
|
|
BOOL bOk = TRUE ;
|
|
|
|
for ( ; i < cch ; i++ )
|
|
{
|
|
switch ( ch = strName.GetAt( i ) )
|
|
{
|
|
case chDot:
|
|
if ( ++cDots > 3 )
|
|
{
|
|
bOk = FALSE ;
|
|
}
|
|
break ;
|
|
|
|
default:
|
|
if ( isalpha( ch ) )
|
|
{
|
|
cAlpha++ ;
|
|
}
|
|
else if ( ! isdigit( ch ) )
|
|
{
|
|
bOk = FALSE ;
|
|
}
|
|
break;
|
|
}
|
|
if ( ! bOk )
|
|
{
|
|
break ;
|
|
}
|
|
}
|
|
if ( bOk )
|
|
{
|
|
if ( cAlpha )
|
|
{
|
|
enResult = HNM_TYPE_DNS ;
|
|
}
|
|
else if ( cDots == 3 )
|
|
{
|
|
enResult = HNM_TYPE_IP ;
|
|
}
|
|
}
|
|
}
|
|
|
|
return enResult ;
|
|
}
|
|
|
|
CDhcpScopeId :: CDhcpScopeId (
|
|
DHCP_IP_ADDRESS dhcpHostIpAddr,
|
|
DHC_SCOPE_ID dhcpScopeId
|
|
)
|
|
: CHostName( dhcpHostIpAddr ),
|
|
m_scope_id( dhcpScopeId )
|
|
{
|
|
}
|
|
|
|
CDhcpScopeId :: CDhcpScopeId (
|
|
const CDhcpScopeId & cScopeId
|
|
)
|
|
: CHostName( cScopeId ),
|
|
m_scope_id( cScopeId.QueryId() )
|
|
{
|
|
}
|
|
|
|
CDhcpScopeId :: CDhcpScopeId (
|
|
const CHostName & cHostName,
|
|
DHC_SCOPE_ID dhcpScopeId
|
|
)
|
|
: CHostName( cHostName ),
|
|
m_scope_id( dhcpScopeId )
|
|
{
|
|
}
|
|
|
|
CDhcpScopeId :: ~ CDhcpScopeId ()
|
|
{
|
|
}
|
|
|
|
BOOL
|
|
CDhcpScopeId :: operator == (
|
|
const CDhcpScopeId & cScopeId
|
|
) const
|
|
{
|
|
return ::wcscmp( QueryWcName(), cScopeId.QueryWcName() ) == 0
|
|
&& QueryId() == cScopeId.QueryId() ;
|
|
}
|
|
|
|
|
|
//
|
|
// Constructor taking API data.
|
|
//
|
|
CDhcpOptionValue :: CDhcpOptionValue (
|
|
const DHCP_OPTION_DATA * podData,
|
|
CDWRAP_Type cdovType
|
|
)
|
|
: CDhcpRpcDataWrapper( cdovType ),
|
|
m_data( NULL )
|
|
{
|
|
INT cElem = podData->NumElements ;
|
|
if ( cElem < 1 )
|
|
{
|
|
ReportError( IDS_INVALID_OPTION_DATA ) ;
|
|
return ;
|
|
}
|
|
|
|
m_data_type = podData->Elements[0].OptionType ;
|
|
|
|
//
|
|
// If this is just a wrapper object, we're done.
|
|
//
|
|
if ( m_type == CDWRAP_Simple || m_type == CDWRAP_Rpc )
|
|
{
|
|
//
|
|
// Just wrapper
|
|
//
|
|
m_data = (DHCP_OPTION_DATA *) podData ;
|
|
return ;
|
|
}
|
|
|
|
//
|
|
// Ugh. We have to reconstruct the entire data strucure.
|
|
//
|
|
LONG err = CreateData( podData ) ;
|
|
if ( err )
|
|
{
|
|
ReportError( err ) ;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Conversion operator taking a param value object.
|
|
//
|
|
CDhcpOptionValue :: CDhcpOptionValue (
|
|
const CDhcpParamValue * pdhcpParam,
|
|
BOOL bForceType
|
|
)
|
|
: CDhcpRpcDataWrapper( CDWRAP_Internal ),
|
|
m_data( NULL ),
|
|
m_data_type( pdhcpParam->QueryDataType() )
|
|
{
|
|
LONG err = CreateData( pdhcpParam, bForceType ) ;
|
|
if ( err )
|
|
{
|
|
ReportError( err ) ;
|
|
}
|
|
}
|
|
|
|
CDhcpOptionValue :: ~ CDhcpOptionValue ()
|
|
{
|
|
FreeData() ;
|
|
}
|
|
|
|
BOOL
|
|
CDhcpOptionValue :: CreateBinaryData (
|
|
const DHCP_BINARY_DATA * podBin,
|
|
DHCP_BINARY_DATA * pobData
|
|
)
|
|
{
|
|
//
|
|
// Note: CObject::operator new asserts if data length is zero
|
|
//
|
|
pobData->Data = new BYTE [ podBin->DataLength + 1 ] ;
|
|
if ( pobData == NULL )
|
|
{
|
|
return FALSE ;
|
|
}
|
|
|
|
pobData->DataLength = podBin->DataLength ;
|
|
|
|
::memcpy( pobData->Data, podBin->Data, pobData->DataLength ) ;
|
|
|
|
return TRUE ;
|
|
}
|
|
|
|
BOOL
|
|
CDhcpOptionValue :: CreateBinaryData (
|
|
const CByteArray * paByte,
|
|
DHCP_BINARY_DATA * pobData
|
|
)
|
|
{
|
|
//
|
|
// Note: CObject::operator new asserts if data length is zero
|
|
//
|
|
pobData->Data = new BYTE [ paByte->GetSize() + 1 ] ;
|
|
if ( pobData == NULL )
|
|
{
|
|
return NULL ;
|
|
}
|
|
|
|
pobData->DataLength = paByte->GetSize() ;
|
|
|
|
for ( INT i = 0 ; i < paByte->GetSize() ; i++ )
|
|
{
|
|
pobData->Data[i] = paByte->GetAt( i ) ;
|
|
}
|
|
|
|
return TRUE ;
|
|
}
|
|
|
|
BOOL
|
|
CDhcpOptionValue :: CreateDwordDword (
|
|
const CByteArray * paByte,
|
|
DWORD_DWORD * pdwdw
|
|
)
|
|
{
|
|
INT i = 0,
|
|
c = sizeof DWORD / sizeof BYTE,
|
|
k = 2 * c ;
|
|
|
|
if ( paByte->GetSize() != k )
|
|
{
|
|
return FALSE ;
|
|
}
|
|
|
|
pdwdw->DWord1 = 0 ;
|
|
pdwdw->DWord1 = 0 ;
|
|
DWORD * pdw = & pdwdw->DWord1 ;
|
|
|
|
for ( ; i < k ; i++ )
|
|
{
|
|
pdw[i % c] = (pdw[i % c] << 8) + paByte->GetAt(i) ;
|
|
}
|
|
|
|
return TRUE ;
|
|
}
|
|
|
|
LONG
|
|
CDhcpOptionValue :: CreateData (
|
|
const DHCP_OPTION_DATA * podData
|
|
)
|
|
{
|
|
DHCP_OPTION_DATA * podNew = NULL ;
|
|
DHCP_OPTION_DATA_ELEMENT * podeOld,
|
|
* podeNew ;
|
|
LONG err = 0 ;
|
|
|
|
FreeData() ;
|
|
|
|
INT cElem = podData->NumElements,
|
|
i,
|
|
cBytes ;
|
|
|
|
WCHAR * pwcsz ;
|
|
|
|
if ( cElem <= 0 )
|
|
{
|
|
ASSERT( FALSE ) ;
|
|
return ERROR_INVALID_PARAMETER ;
|
|
}
|
|
|
|
CATCH_MEM_EXCEPTION
|
|
{
|
|
//
|
|
// Allocate the base structure and the array of elements.
|
|
//
|
|
cBytes = sizeof *podNew + (cElem * sizeof *podeNew) ;
|
|
podNew = (DHCP_OPTION_DATA *) new BYTE [ cBytes ] ;
|
|
podeNew = (DHCP_OPTION_DATA_ELEMENT *) ( ((BYTE *) podNew) + sizeof *podNew ) ;
|
|
|
|
ClearToZeroes( podNew, cBytes ) ;
|
|
|
|
//
|
|
// Initialize each element
|
|
//
|
|
podeOld = podData->Elements ;
|
|
|
|
for ( i = 0 ; i < cElem ; i++ )
|
|
{
|
|
podeNew[i].OptionType = podeOld[i].OptionType ;
|
|
|
|
//
|
|
// All data types must match.
|
|
//
|
|
if ( podeNew[i].OptionType != m_type )
|
|
{
|
|
err = IDS_INVALID_OPTION_DATA ;
|
|
break;
|
|
}
|
|
|
|
switch ( podeNew[i].OptionType )
|
|
{
|
|
case DhcpByteOption:
|
|
podeNew[i].Element.ByteOption = podeOld[i].Element.ByteOption ;
|
|
break ;
|
|
|
|
case DhcpWordOption:
|
|
podeNew[i].Element.WordOption = podeOld[i].Element.WordOption ;
|
|
break ;
|
|
|
|
case DhcpDWordOption:
|
|
podeNew[i].Element.DWordOption = podeOld[i].Element.DWordOption ;
|
|
break ;
|
|
|
|
case DhcpDWordDWordOption:
|
|
podeNew[i].Element.DWordDWordOption = podeOld[i].Element.DWordDWordOption ;
|
|
break ;
|
|
|
|
case DhcpIpAddressOption:
|
|
podeNew[i].Element.IpAddressOption = podeOld[i].Element.IpAddressOption ;
|
|
break ;
|
|
|
|
case DhcpStringDataOption:
|
|
pwcsz = ::UtilWcstrDup( podeOld[i].Element.StringDataOption ) ;
|
|
if ( pwcsz == NULL )
|
|
{
|
|
err = ERROR_NOT_ENOUGH_MEMORY ;
|
|
break ;
|
|
}
|
|
podeNew[i].Element.StringDataOption = pwcsz ;
|
|
break ;
|
|
|
|
case DhcpBinaryDataOption:
|
|
case DhcpEncapsulatedDataOption:
|
|
if ( ! CreateBinaryData( & podeOld[i].Element.BinaryDataOption,
|
|
& podeNew[i].Element.BinaryDataOption ) )
|
|
{
|
|
err = ERROR_NOT_ENOUGH_MEMORY ;
|
|
break ;
|
|
}
|
|
break ;
|
|
|
|
default:
|
|
err = IDS_INVALID_OPTION_DATA ;
|
|
break;
|
|
}
|
|
|
|
if ( err )
|
|
{
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
END_MEM_EXCEPTION(err)
|
|
|
|
return err ;
|
|
}
|
|
|
|
//
|
|
// Wrapper the parameter value given. If "bForceType", create an empty
|
|
// element so that the data type is declared.
|
|
//
|
|
LONG
|
|
CDhcpOptionValue :: CreateData (
|
|
const CDhcpParamValue * pdhcpParam,
|
|
BOOL bForceType
|
|
)
|
|
{
|
|
DHCP_OPTION_DATA * podNew = NULL ;
|
|
DHCP_OPTION_DATA_ELEMENT * podeNew ;
|
|
LONG err = 0 ;
|
|
|
|
FreeData() ;
|
|
|
|
INT cElem = pdhcpParam->QueryUpperBound(),
|
|
cElemMin = cElem ? cElem : 1,
|
|
i,
|
|
cBytes ;
|
|
|
|
WCHAR * pwcsz ;
|
|
|
|
if ( cElem < 0 || (cElem < 1 && ! bForceType) )
|
|
{
|
|
//ASSERT( FALSE ) ;
|
|
return ERROR_INVALID_PARAMETER ;
|
|
}
|
|
|
|
CATCH_MEM_EXCEPTION
|
|
{
|
|
//
|
|
// Allocate the base structure and the array of elements.
|
|
//
|
|
cBytes = sizeof *podNew + (cElemMin * sizeof *podeNew) ;
|
|
podNew = (DHCP_OPTION_DATA *) new BYTE [ cBytes ] ;
|
|
podeNew = (DHCP_OPTION_DATA_ELEMENT *) ( ((BYTE *) podNew) + sizeof *podNew ) ;
|
|
|
|
ClearToZeroes( podNew, cBytes ) ;
|
|
|
|
podNew->NumElements = cElem ;
|
|
podNew->Elements = podeNew ;
|
|
|
|
//
|
|
// Initialize each element. If we're forcing an option type def,
|
|
// just initialize to empty data.
|
|
//
|
|
if ( cElem == 0 && bForceType )
|
|
{
|
|
podNew->NumElements = 1 ;
|
|
podeNew[0].OptionType = pdhcpParam->QueryDataType() ;
|
|
switch ( podeNew[0].OptionType )
|
|
{
|
|
case DhcpByteOption:
|
|
case DhcpWordOption:
|
|
case DhcpDWordOption:
|
|
case DhcpIpAddressOption:
|
|
case DhcpDWordDWordOption:
|
|
podeNew[0].Element.DWordDWordOption.DWord1 = 0 ;
|
|
podeNew[0].Element.DWordDWordOption.DWord2 = 0 ;
|
|
break ;
|
|
|
|
case DhcpStringDataOption:
|
|
//
|
|
// BUGBUG: When Madan fixes the API, uses NULL here.
|
|
//
|
|
podeNew[0].Element.StringDataOption = new WCHAR [1] ;
|
|
podeNew[0].Element.StringDataOption[0] = 0 ;
|
|
break ;
|
|
|
|
case DhcpBinaryDataOption:
|
|
case DhcpEncapsulatedDataOption:
|
|
//
|
|
// BUGBUG: When Madan fixes the API, uses NULL here.
|
|
//
|
|
podeNew[0].Element.BinaryDataOption.DataLength = 0 ;
|
|
podeNew[0].Element.BinaryDataOption.Data = new BYTE [1] ;
|
|
break ;
|
|
default:
|
|
err = IDS_INVALID_OPTION_DATA ;
|
|
}
|
|
}
|
|
else
|
|
for ( i = 0 ; i < cElem ; i++ )
|
|
{
|
|
podeNew[i].OptionType = pdhcpParam->QueryDataType() ;
|
|
|
|
switch ( podeNew[i].OptionType )
|
|
{
|
|
case DhcpByteOption:
|
|
podeNew[i].Element.ByteOption = (BYTE) pdhcpParam->QueryNumber( i ) ;
|
|
break ;
|
|
case DhcpWordOption:
|
|
podeNew[i].Element.WordOption = (WORD) pdhcpParam->QueryNumber( i ) ;
|
|
break ;
|
|
case DhcpDWordOption:
|
|
podeNew[i].Element.DWordOption = pdhcpParam->QueryNumber( i ) ;
|
|
break ;
|
|
case DhcpDWordDWordOption:
|
|
CreateDwordDword( pdhcpParam->QueryBinaryArray(),
|
|
& podeNew[i].Element.DWordDWordOption ) ;
|
|
break ;
|
|
case DhcpIpAddressOption:
|
|
podeNew[i].Element.IpAddressOption = pdhcpParam->QueryIpAddr( i ) ;
|
|
break ;
|
|
case DhcpStringDataOption:
|
|
pwcsz = ::UtilWcstrDup( pdhcpParam->QueryString( i ) ) ;
|
|
if ( pwcsz == NULL )
|
|
{
|
|
err = ERROR_NOT_ENOUGH_MEMORY ;
|
|
break ;
|
|
}
|
|
podeNew[i].Element.StringDataOption = pwcsz ;
|
|
break ;
|
|
|
|
case DhcpBinaryDataOption:
|
|
case DhcpEncapsulatedDataOption:
|
|
if ( ! CreateBinaryData( pdhcpParam->QueryBinaryArray(),
|
|
& podeNew[i].Element.BinaryDataOption ) )
|
|
{
|
|
err = ERROR_NOT_ENOUGH_MEMORY ;
|
|
break ;
|
|
}
|
|
break ;
|
|
default:
|
|
err = IDS_INVALID_OPTION_DATA ;
|
|
}
|
|
|
|
if ( err )
|
|
{
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
END_MEM_EXCEPTION(err)
|
|
|
|
if ( err == 0 )
|
|
{
|
|
m_data = podNew ;
|
|
}
|
|
|
|
return err ;
|
|
}
|
|
|
|
LONG
|
|
CDhcpOptionValue :: FreeData ()
|
|
{
|
|
LONG err ;
|
|
|
|
if ( m_data == NULL )
|
|
{
|
|
return 0 ;
|
|
}
|
|
|
|
if ( m_type == CDWRAP_Simple || m_type == CDWRAP_Rpc )
|
|
{
|
|
if ( m_type == CDWRAP_Rpc )
|
|
{
|
|
FreeRpcMemory( m_data ) ;
|
|
}
|
|
m_data = NULL ;
|
|
return 0 ;
|
|
}
|
|
|
|
//
|
|
// We must deconstruct the struct build in CreateData()
|
|
//
|
|
INT cElem = m_data->NumElements ;
|
|
|
|
for ( INT i = 0 ; i < cElem ; i++ )
|
|
{
|
|
switch ( m_data->Elements[i].OptionType )
|
|
{
|
|
case DhcpByteOption:
|
|
case DhcpWordOption:
|
|
case DhcpDWordOption:
|
|
case DhcpDWordDWordOption:
|
|
case DhcpIpAddressOption:
|
|
break;
|
|
|
|
case DhcpStringDataOption:
|
|
delete m_data->Elements[i].Element.StringDataOption ;
|
|
break ;
|
|
|
|
case DhcpBinaryDataOption:
|
|
case DhcpEncapsulatedDataOption:
|
|
delete m_data->Elements[i].Element.BinaryDataOption.Data ;
|
|
break ;
|
|
default:
|
|
err = IDS_INVALID_OPTION_DATA ;
|
|
break;
|
|
}
|
|
if ( err )
|
|
{
|
|
break ;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Finally, delete the main structure
|
|
//
|
|
delete m_data ;
|
|
m_data = NULL ;
|
|
|
|
return err ;
|
|
}
|
|
|
|
|
|
INT
|
|
CDhcpOptionValue ::QueryUpperBound () const
|
|
{
|
|
return m_data
|
|
? m_data->NumElements
|
|
: 0 ;
|
|
}
|
|
|
|
const DHCP_OPTION_DATA_ELEMENT *
|
|
CDhcpOptionValue ::QueryElement (
|
|
INT index
|
|
) const
|
|
{
|
|
return m_data
|
|
? & m_data->Elements[index]
|
|
: NULL ;
|
|
}
|
|
|
|
CDhcpParamValue :: CDhcpParamValue (
|
|
DHCP_OPTION_DATA_TYPE dhcDataType,
|
|
INT cUpperBound
|
|
)
|
|
: m_data_type( dhcDataType ),
|
|
m_bound( -1 )
|
|
{
|
|
m_value_union.pCObj = NULL ;
|
|
LONG err = InitValue( dhcDataType, cUpperBound ) ;
|
|
if ( err )
|
|
{
|
|
ReportError( err ) ;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Copy constructor. The conversion is indirect, using CDhcpOptionValue
|
|
// as an intermediate form, It was done this way because the conversion code
|
|
// would be quite extensive and this was cheap.
|
|
// CODEWORK: Create direct conversion code.
|
|
//
|
|
CDhcpParamValue :: CDhcpParamValue (
|
|
const CDhcpParamValue & cParamValue
|
|
)
|
|
: m_data_type( DhcpByteOption ),
|
|
m_bound( -1 )
|
|
{
|
|
m_value_union.pCObj = NULL ;
|
|
APIERR err = 0 ;
|
|
CDhcpOptionValue dhpValue( & cParamValue ) ;
|
|
|
|
if ( (err = dhpValue.QueryError()) == 0 )
|
|
{
|
|
err = ConvertValue( & dhpValue ) ;
|
|
}
|
|
|
|
if ( err )
|
|
{
|
|
ReportError( err ) ;
|
|
}
|
|
}
|
|
|
|
CDhcpParamValue :: CDhcpParamValue (
|
|
const CDhcpOptionValue * pdhpValue
|
|
)
|
|
: m_data_type( DhcpByteOption ),
|
|
m_bound( -1 )
|
|
{
|
|
LONG err = 0 ;
|
|
m_value_union.pCObj = NULL ;
|
|
|
|
ASSERT( pdhpValue != NULL ) ;
|
|
|
|
if ( err = ConvertValue( pdhpValue ) )
|
|
{
|
|
ReportError( err ) ;
|
|
}
|
|
}
|
|
|
|
CDhcpParamValue :: CDhcpParamValue (
|
|
const DHCP_OPTION & dhpType
|
|
)
|
|
: m_data_type( DhcpByteOption ),
|
|
m_bound( -1 )
|
|
{
|
|
m_value_union.pCObj = NULL ;
|
|
CDhcpOptionValue dhpValue( & dhpType.DefaultValue, CDhcpRpcDataWrapper::CDWRAP_Simple ) ;
|
|
LONG err = ConvertValue( & dhpValue ) ;
|
|
if ( err )
|
|
{
|
|
ReportError( err ) ;
|
|
}
|
|
}
|
|
|
|
CDhcpParamValue :: CDhcpParamValue (
|
|
const DHCP_OPTION_VALUE & dhpOptionValue
|
|
)
|
|
: m_data_type( DhcpByteOption ),
|
|
m_bound( -1 )
|
|
{
|
|
m_value_union.pCObj = NULL ;
|
|
CDhcpOptionValue dhpValue( & dhpOptionValue.Value, CDhcpRpcDataWrapper::CDWRAP_Simple ) ;
|
|
LONG err = ConvertValue( & dhpValue ) ;
|
|
if ( err )
|
|
{
|
|
ReportError( err ) ;
|
|
}
|
|
}
|
|
|
|
|
|
CDhcpParamValue :: ~ CDhcpParamValue ()
|
|
{
|
|
FreeValue() ;
|
|
}
|
|
|
|
CDhcpParamValue & CDhcpParamValue :: operator = (
|
|
const CDhcpOptionValue & dhpValue
|
|
)
|
|
{
|
|
ConvertValue( & dhpValue ) ;
|
|
|
|
return *this ;
|
|
}
|
|
|
|
BOOL
|
|
CDhcpParamValue :: SetDataType (
|
|
DHCP_OPTION_DATA_TYPE dhcType,
|
|
INT cUpperBound
|
|
)
|
|
{
|
|
if ( dhcType > DhcpEncapsulatedDataOption )
|
|
{
|
|
return FALSE ;
|
|
}
|
|
|
|
InitValue( dhcType, cUpperBound ) ;
|
|
|
|
return TRUE ;
|
|
}
|
|
|
|
void
|
|
CDhcpParamValue :: SetUpperBound (
|
|
INT cNewBound
|
|
)
|
|
{
|
|
m_bound = cNewBound ;
|
|
if (cNewBound <= 0)
|
|
cNewBound = 1;
|
|
m_bound = cNewBound ;
|
|
switch ( m_data_type )
|
|
{
|
|
case DhcpByteOption:
|
|
case DhcpWordOption:
|
|
case DhcpDWordOption:
|
|
case DhcpIpAddressOption:
|
|
m_value_union.paDword->SetSize( cNewBound ) ;
|
|
break;
|
|
|
|
case DhcpStringDataOption:
|
|
m_value_union.paString->SetSize( cNewBound ) ;
|
|
break ;
|
|
|
|
case DhcpDWordDWordOption:
|
|
case DhcpBinaryDataOption:
|
|
case DhcpEncapsulatedDataOption:
|
|
m_value_union.paBinary->SetSize( cNewBound ) ;
|
|
break ;
|
|
|
|
default:
|
|
TRACEEOLID( "CDhcpParamValue: attempt to set upper bound on invalid value type" ) ;
|
|
ASSERT( FALSE ) ;
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
BOOL
|
|
CDhcpParamValue :: IsValid () const
|
|
{
|
|
return m_bound > 0 ;
|
|
}
|
|
|
|
void
|
|
CDhcpParamValue :: FreeValue ()
|
|
{
|
|
//
|
|
// If there's not a value, return now.
|
|
//
|
|
if ( m_value_union.pCObj == NULL || m_bound < 0 )
|
|
{
|
|
m_value_union.pCObj = NULL ;
|
|
return ;
|
|
}
|
|
|
|
switch ( m_data_type )
|
|
{
|
|
case DhcpByteOption:
|
|
case DhcpWordOption:
|
|
case DhcpDWordOption:
|
|
case DhcpIpAddressOption:
|
|
delete m_value_union.paDword ;
|
|
break;
|
|
|
|
case DhcpStringDataOption:
|
|
delete m_value_union.paString ;
|
|
break ;
|
|
|
|
case DhcpDWordDWordOption:
|
|
case DhcpBinaryDataOption:
|
|
case DhcpEncapsulatedDataOption:
|
|
delete m_value_union.paBinary ;
|
|
break ;
|
|
|
|
default:
|
|
ASSERT( FALSE ) ;
|
|
delete m_value_union.pCObj ;
|
|
break;
|
|
}
|
|
|
|
m_bound = -1 ;
|
|
m_data_type = DhcpByteOption ;
|
|
m_value_union.pCObj = NULL ;
|
|
}
|
|
|
|
//
|
|
// Initialize the data value properly
|
|
//
|
|
LONG
|
|
CDhcpParamValue :: InitValue (
|
|
DHCP_OPTION_DATA_TYPE dhcDataType, // The type of value
|
|
INT cUpperBound, // Maximum upper bound
|
|
BOOL bProvideDefaultValue // Should an empty default value be provided?
|
|
)
|
|
{
|
|
LONG err = 0 ;
|
|
|
|
//
|
|
// Release any older value.
|
|
//
|
|
FreeValue() ;
|
|
|
|
//
|
|
// Initialize the new value
|
|
//
|
|
m_data_type = dhcDataType ;
|
|
m_bound = cUpperBound <= 0 ? 1 : cUpperBound ;
|
|
|
|
CATCH_MEM_EXCEPTION
|
|
{
|
|
switch ( m_data_type )
|
|
{
|
|
case DhcpByteOption:
|
|
case DhcpWordOption:
|
|
case DhcpDWordOption:
|
|
case DhcpIpAddressOption:
|
|
m_value_union.paDword = new CDWordArray ;
|
|
if ( bProvideDefaultValue)
|
|
{
|
|
m_value_union.paDword->SetAtGrow( 0, 0 ) ;
|
|
}
|
|
break ;
|
|
|
|
case DhcpStringDataOption:
|
|
m_value_union.paString = new CStringArray ;
|
|
if ( bProvideDefaultValue )
|
|
{
|
|
m_value_union.paString->SetAtGrow( 0, "" ) ;
|
|
}
|
|
break ;
|
|
|
|
case DhcpDWordDWordOption:
|
|
case DhcpBinaryDataOption:
|
|
case DhcpEncapsulatedDataOption:
|
|
m_value_union.paBinary = new CByteArray ;
|
|
if ( bProvideDefaultValue )
|
|
{
|
|
m_value_union.paBinary->SetAtGrow( 0, 0 ) ;
|
|
}
|
|
break ;
|
|
|
|
default:
|
|
err = IDS_INVALID_OPTION_DATA ;
|
|
break;
|
|
}
|
|
}
|
|
END_MEM_EXCEPTION(err)
|
|
|
|
return err ;
|
|
}
|
|
|
|
//
|
|
// Convert a value wrapper into our internal CObject-based format
|
|
//
|
|
LONG
|
|
CDhcpParamValue :: ConvertValue (
|
|
const CDhcpOptionValue * pdhpValue
|
|
)
|
|
{
|
|
LONG err = 0;
|
|
|
|
if ( err = InitValue( pdhpValue->QueryDataType(),
|
|
pdhpValue->QueryUpperBound(),
|
|
FALSE ) )
|
|
{
|
|
return err ;
|
|
}
|
|
|
|
CATCH_MEM_EXCEPTION
|
|
{
|
|
for ( INT i = 0 ; i < m_bound ; i++ )
|
|
{
|
|
const DHCP_OPTION_DATA_ELEMENT * pElem = pdhpValue->QueryElement(i) ;
|
|
|
|
switch ( m_data_type )
|
|
{
|
|
case DhcpByteOption:
|
|
m_value_union.paDword->SetAtGrow(i, pElem->Element.ByteOption ) ;
|
|
break ;
|
|
case DhcpWordOption:
|
|
m_value_union.paDword->SetAtGrow(i, pElem->Element.WordOption ) ;
|
|
break ;
|
|
case DhcpDWordOption:
|
|
m_value_union.paDword->SetAtGrow(i, pElem->Element.DWordOption ) ;
|
|
break ;
|
|
case DhcpIpAddressOption:
|
|
m_value_union.paDword->Add(pElem->Element.IpAddressOption );
|
|
break ;
|
|
|
|
case DhcpDWordDWordOption:
|
|
{
|
|
CByteArray * paByte = m_value_union.paBinary ;
|
|
|
|
paByte->SetSize( (sizeof (DWORD) / sizeof (BYTE)) * 2 ) ;
|
|
|
|
DWORD dw = pElem->Element.DWordDWordOption.DWord1 ;
|
|
|
|
for ( INT j = 0 ; j < 4 ; j++ )
|
|
{
|
|
paByte->SetAtGrow(j, (UCHAR)(dw & 0xff) );
|
|
dw >>= 8 ;
|
|
}
|
|
dw = pElem->Element.DWordDWordOption.DWord2 ;
|
|
|
|
for ( ; j < 8 ; j++ )
|
|
{
|
|
paByte->SetAtGrow(j, (UCHAR)(dw & 0xff) );
|
|
dw >>= 8 ;
|
|
}
|
|
}
|
|
break ;
|
|
|
|
case DhcpStringDataOption:
|
|
{
|
|
const WCHAR * pszWchStr = pElem->Element.StringDataOption ;
|
|
if ( pszWchStr == NULL )
|
|
{
|
|
pszWchStr = L"" ;
|
|
}
|
|
CHAR * psz = UtilCstrDup( pszWchStr ) ;
|
|
m_value_union.paString->SetAtGrow(i, psz );
|
|
delete psz ;
|
|
}
|
|
break ;
|
|
|
|
case DhcpBinaryDataOption:
|
|
case DhcpEncapsulatedDataOption:
|
|
{
|
|
CByteArray * paByte = m_value_union.paBinary ;
|
|
INT c = pElem->Element.BinaryDataOption.DataLength ;
|
|
paByte->SetSize( c ) ;
|
|
for ( INT j = 0 ; j < c ; j++ )
|
|
{
|
|
paByte->SetAtGrow(j, pElem->Element.BinaryDataOption.Data[j] ) ;
|
|
}
|
|
}
|
|
break ;
|
|
|
|
default:
|
|
err = IDS_INVALID_OPTION_DATA ;
|
|
} // End switch
|
|
|
|
if ( err )
|
|
{
|
|
break ;
|
|
}
|
|
} // End for
|
|
}
|
|
END_MEM_EXCEPTION(err)
|
|
|
|
return err ;
|
|
}
|
|
|
|
INT
|
|
CDhcpParamValue :: QueryBinary (
|
|
INT index
|
|
) const
|
|
{
|
|
if ( m_value_union.paBinary->GetUpperBound() < index )
|
|
{
|
|
return -1 ;
|
|
}
|
|
|
|
return m_value_union.paBinary->GetAt( index ) ;
|
|
}
|
|
|
|
const CByteArray *
|
|
CDhcpParamValue :: QueryBinaryArray () const
|
|
{
|
|
return m_value_union.paBinary ;
|
|
}
|
|
|
|
//
|
|
// Return a string representation of the current value.
|
|
//
|
|
// If fLineFeed is true, seperate each individual value
|
|
// by a linefeed. Otherwise, by a comma.
|
|
//
|
|
LONG
|
|
CDhcpParamValue :: QueryDisplayString (
|
|
CString & strResult,
|
|
BOOL fLineFeed
|
|
) const
|
|
{
|
|
char chBuff [ DHC_BUFFER_MAX ] ;
|
|
char * chLimit = chBuff + sizeof chBuff - DHC_EDIT_NUM_MAX ;
|
|
INT i;
|
|
|
|
LONG err = 0 ;
|
|
|
|
//
|
|
// BUGBUG: Should these come from resources?
|
|
//
|
|
const char * pszMaskDec = "%ld" ;
|
|
const char * pszMaskHex = "0x%x" ;
|
|
const char * pszMaskStr1 = "%s" ;
|
|
const char * pszMaskStr2 = "\"%s\"" ;
|
|
const char * pszMaskBin = "%2.2x" ;
|
|
const char * pszMask ;
|
|
const char * pszMaskEllipsis = "..." ;
|
|
const char * pszSepComma = ", ";
|
|
const char * pszSepLF = "\r\n";
|
|
|
|
CATCH_MEM_EXCEPTION
|
|
{
|
|
strResult.Empty() ;
|
|
|
|
for ( i = 0 ; i < m_bound ; i++ )
|
|
{
|
|
chBuff[0] = 0 ;
|
|
|
|
if ( i )
|
|
{
|
|
strResult += fLineFeed ? pszSepLF : pszSepComma;
|
|
}
|
|
|
|
switch ( QueryDataType() )
|
|
{
|
|
case DhcpByteOption:
|
|
case DhcpWordOption:
|
|
case DhcpDWordOption:
|
|
pszMask = pszMaskHex ;
|
|
::wsprintf( chBuff, pszMask, QueryNumber(i) ) ;
|
|
break;
|
|
|
|
case DhcpStringDataOption:
|
|
pszMask = m_bound > 1
|
|
? pszMaskStr2
|
|
: pszMaskStr1 ;
|
|
::wsprintf( chBuff, pszMask,
|
|
(const char *) m_value_union.paString->ElementAt( 0 ) ) ;
|
|
break;
|
|
|
|
case DhcpIpAddressOption:
|
|
if (!QueryIpAddr(i))
|
|
{
|
|
// Set the string to "<None>" iff the list is empty
|
|
if (!i)
|
|
strResult.LoadString (IDS_INFO_FORMAT_IP_NONE);
|
|
break;
|
|
}
|
|
::UtilCvtIpAddrToString( QueryIpAddr(i), chBuff, sizeof chBuff ) ;
|
|
break;
|
|
|
|
case DhcpBinaryDataOption:
|
|
case DhcpEncapsulatedDataOption:
|
|
|
|
//for ( c = 0 ; c < m_value_union.paBinary->GetSize() ; c++ )
|
|
//{
|
|
//BYTE cNext = m_value_union.paBinary->GetAt( c ) ;
|
|
//char * chNext = chBuff + ::strlen( chBuff ) ;
|
|
//if ( chNext >= chLimit )
|
|
//{
|
|
// ::strcat( chNext, pszMaskEllipsis ) ;
|
|
// break ;
|
|
//}
|
|
//::wsprintf( chNext, pszMaskBin, cNext ) ;
|
|
//}
|
|
pszMask = pszMaskHex ;
|
|
::wsprintf( chBuff, pszMask, QueryNumber(i) ) ;
|
|
break;
|
|
|
|
default:
|
|
strResult.LoadString(IDS_INFO_TYPNAM_INVALID) ;
|
|
break ;
|
|
}
|
|
strResult += chBuff ;
|
|
}
|
|
}
|
|
END_MEM_EXCEPTION(err)
|
|
|
|
return err ;
|
|
}
|
|
|
|
LONG
|
|
CDhcpParamValue :: SetString (
|
|
const char * pszNewValue,
|
|
INT index
|
|
)
|
|
{
|
|
if ( m_data_type != DhcpStringDataOption )
|
|
{
|
|
return ERROR_INVALID_PARAMETER ;
|
|
}
|
|
|
|
ASSERT( m_value_union.paString != NULL ) ;
|
|
|
|
LONG err = 0 ;
|
|
|
|
CATCH_MEM_EXCEPTION
|
|
{
|
|
m_value_union.paString->SetAtGrow( index, pszNewValue ) ;
|
|
}
|
|
END_MEM_EXCEPTION(err)
|
|
|
|
return err ;
|
|
}
|
|
|
|
LONG
|
|
CDhcpParamValue :: SetNumber (
|
|
INT nValue,
|
|
INT index
|
|
)
|
|
{
|
|
if ( m_data_type != DhcpByteOption
|
|
&& m_data_type != DhcpWordOption
|
|
&& m_data_type != DhcpDWordOption
|
|
&& m_data_type != DhcpIpAddressOption
|
|
&& m_data_type != DhcpBinaryDataOption
|
|
)
|
|
{
|
|
return ERROR_INVALID_PARAMETER ;
|
|
}
|
|
|
|
ASSERT( m_value_union.paDword != NULL ) ;
|
|
|
|
LONG err = 0 ;
|
|
|
|
CATCH_MEM_EXCEPTION
|
|
{
|
|
if ( m_data_type != DhcpBinaryDataOption )
|
|
{
|
|
m_value_union.paDword->SetAtGrow( index, (DWORD) nValue ) ;
|
|
}
|
|
else
|
|
{
|
|
m_value_union.paBinary->SetAtGrow( index, (BYTE) nValue ) ;
|
|
}
|
|
}
|
|
END_MEM_EXCEPTION(err)
|
|
|
|
return err ;
|
|
}
|
|
|
|
LONG
|
|
CDhcpParamValue :: QueryNumber (
|
|
INT index
|
|
) const
|
|
{
|
|
if ( m_data_type != DhcpByteOption
|
|
&& m_data_type != DhcpWordOption
|
|
&& m_data_type != DhcpDWordOption
|
|
&& m_data_type != DhcpIpAddressOption
|
|
&& m_data_type != DhcpBinaryDataOption
|
|
)
|
|
{
|
|
return -1 ;
|
|
}
|
|
|
|
LONG cResult ;
|
|
|
|
if ( m_data_type == DhcpBinaryDataOption )
|
|
{
|
|
ASSERT( m_value_union.paBinary != NULL ) ;
|
|
cResult = index < m_value_union.paBinary->GetSize()
|
|
? m_value_union.paBinary->GetAt( index )
|
|
: -1 ;
|
|
}
|
|
else
|
|
{
|
|
ASSERT( m_value_union.paDword != NULL ) ;
|
|
cResult = index < m_value_union.paDword->GetSize()
|
|
? m_value_union.paDword->GetAt( index )
|
|
: -1 ;
|
|
}
|
|
|
|
return cResult ;
|
|
}
|
|
|
|
const CHAR *
|
|
CDhcpParamValue :: QueryString (
|
|
INT index
|
|
) const
|
|
{
|
|
if ( m_data_type != DhcpStringDataOption )
|
|
{
|
|
return NULL ;
|
|
}
|
|
|
|
const CString & str = m_value_union.paString->ElementAt( index ) ;
|
|
|
|
return (const char *) str ;
|
|
}
|
|
|
|
DHCP_IP_ADDRESS
|
|
CDhcpParamValue :: QueryIpAddr (
|
|
INT index
|
|
) const
|
|
{
|
|
return (DHCP_IP_ADDRESS) QueryNumber( index ) ;
|
|
}
|
|
|
|
LONG
|
|
CDhcpParamValue :: SetIpAddr (
|
|
DHCP_IP_ADDRESS dhcIpAddr,
|
|
INT index
|
|
)
|
|
{
|
|
return SetNumber( (INT) dhcIpAddr, index ) ;
|
|
}
|
|
|
|
INT
|
|
CDhcpParamType :: MaxSizeOfType (
|
|
DHCP_OPTION_DATA_TYPE dhcType
|
|
)
|
|
{
|
|
INT nResult = -1 ;
|
|
|
|
switch ( dhcType )
|
|
{
|
|
case DhcpByteOption:
|
|
nResult = sizeof(CHAR) ;
|
|
break ;
|
|
|
|
case DhcpWordOption:
|
|
nResult = sizeof(WORD) ;
|
|
break ;
|
|
|
|
case DhcpDWordOption:
|
|
nResult = sizeof(DWORD) ;
|
|
break ;
|
|
|
|
case DhcpIpAddressOption:
|
|
nResult = sizeof(DHCP_IP_ADDRESS) ;
|
|
break ;
|
|
|
|
case DhcpDWordDWordOption:
|
|
nResult = sizeof(DWORD_DWORD);
|
|
break ;
|
|
|
|
case DhcpBinaryDataOption:
|
|
case DhcpEncapsulatedDataOption:
|
|
case DhcpStringDataOption:
|
|
nResult = DHC_STRING_MAX ;
|
|
break ;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return nResult ;
|
|
}
|
|
|
|
INT
|
|
CDhcpParamType :: OrderById (
|
|
const CObjectPlus * pDhcpType
|
|
) const
|
|
{
|
|
const CDhcpParamType * pType = (const CDhcpParamType *) pDhcpType ;
|
|
|
|
return m_id < pType->m_id
|
|
? -1
|
|
: m_id > pType->m_id ;
|
|
}
|
|
|
|
//
|
|
// Normal constructor: just wrapper the data given
|
|
//
|
|
CDhcpParamType :: CDhcpParamType (
|
|
const DHCP_OPTION & dhpOption
|
|
)
|
|
: m_value( dhpOption ),
|
|
m_id( dhpOption.OptionID ),
|
|
m_opt_type( dhpOption.OptionType )
|
|
{
|
|
LONG err = 0 ;
|
|
if ( ! m_value )
|
|
{
|
|
err = m_value.QueryError() ;
|
|
}
|
|
else
|
|
{
|
|
CATCH_MEM_EXCEPTION
|
|
{
|
|
if ( ! ( SetName( dhpOption.OptionName )
|
|
&& SetComment( dhpOption.OptionComment ) ) )
|
|
{
|
|
err = ERROR_NOT_ENOUGH_MEMORY ;
|
|
}
|
|
}
|
|
END_MEM_EXCEPTION(err)
|
|
}
|
|
if ( err )
|
|
{
|
|
ReportError( err ) ;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Constructor taking just a value structure. We must query
|
|
// the scope for the name, etc.
|
|
//
|
|
CDhcpParamType :: CDhcpParamType (
|
|
const CDhcpScope & cScope,
|
|
const DHCP_OPTION_VALUE & dhcpOptionValue
|
|
)
|
|
: m_value( dhcpOptionValue ),
|
|
m_id( dhcpOptionValue.OptionID )
|
|
{
|
|
LONG err = 0 ;
|
|
|
|
//
|
|
// Get current type information (name and comment).
|
|
//
|
|
if ( err = cScope.QueryType( this, TRUE, FALSE ) )
|
|
{
|
|
ReportError( err ) ;
|
|
}
|
|
SetDirty( FALSE ) ;
|
|
}
|
|
|
|
//
|
|
// Copy constructor
|
|
//
|
|
CDhcpParamType ::CDhcpParamType (
|
|
const CDhcpParamType & dhpType
|
|
)
|
|
: m_id( dhpType.m_id ),
|
|
m_opt_type( dhpType.m_opt_type ),
|
|
m_name( dhpType.m_name ),
|
|
m_comment( dhpType.m_comment ),
|
|
m_value( dhpType.QueryDataType() )
|
|
{
|
|
CDhcpOptionValue dhcOptionValue( & dhpType.m_value ) ;
|
|
LONG err = dhcOptionValue.QueryError() ;
|
|
|
|
if ( err == 0 )
|
|
{
|
|
m_value = dhcOptionValue ;
|
|
}
|
|
|
|
if ( err )
|
|
{
|
|
ReportError( err ) ;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Constructor using a base type and an overriding value.
|
|
//
|
|
CDhcpParamType :: CDhcpParamType (
|
|
const CDhcpParamType & dhpType,
|
|
const DHCP_OPTION_VALUE & dhcOptionValue
|
|
)
|
|
: m_id( dhpType.m_id ),
|
|
m_opt_type( dhpType.QueryOptType() ),
|
|
m_name( dhpType.m_name ),
|
|
m_comment( dhpType.m_comment ),
|
|
m_value( dhcOptionValue )
|
|
{
|
|
}
|
|
|
|
//
|
|
// Constructor for dynamic instances
|
|
//
|
|
CDhcpParamType :: CDhcpParamType (
|
|
DHCP_OPTION_ID nId,
|
|
DHCP_OPTION_DATA_TYPE dhcType,
|
|
const char * pszOptionName,
|
|
const char * pszComment,
|
|
DHCP_OPTION_TYPE dhcOptType
|
|
)
|
|
: m_id( nId ),
|
|
m_opt_type( dhcOptType ),
|
|
m_value( dhcType, TRUE ),
|
|
m_name( pszOptionName ),
|
|
m_comment( pszComment )
|
|
{
|
|
}
|
|
|
|
|
|
CDhcpParamType :: ~ CDhcpParamType ()
|
|
{
|
|
}
|
|
|
|
void
|
|
CDhcpParamType :: SetOptType (
|
|
DHCP_OPTION_TYPE dhcOptType
|
|
)
|
|
{
|
|
m_opt_type = dhcOptType ;
|
|
}
|
|
|
|
LONG
|
|
CDhcpParamType :: Update (
|
|
const CDhcpOptionValue & dhpOption
|
|
)
|
|
{
|
|
m_value = dhpOption ;
|
|
|
|
return 0 ;
|
|
}
|
|
|
|
BOOL
|
|
CDhcpParamType :: SetName (
|
|
const char * pszName
|
|
)
|
|
{
|
|
m_name = pszName ;
|
|
SetDirty() ;
|
|
return TRUE ;
|
|
}
|
|
|
|
BOOL
|
|
CDhcpParamType :: SetName (
|
|
const WCHAR * pwcszName
|
|
)
|
|
{
|
|
BOOL bResult = ::UtilSetWchar( m_name, pwcszName ) ;
|
|
SetDirty() ;
|
|
return bResult ;
|
|
}
|
|
|
|
BOOL
|
|
CDhcpParamType :: SetComment (
|
|
const char * pszComment
|
|
)
|
|
{
|
|
m_comment = pszComment ;
|
|
SetDirty() ;
|
|
return TRUE ;
|
|
}
|
|
|
|
BOOL
|
|
CDhcpParamType :: SetComment (
|
|
const WCHAR * pwcszComment
|
|
)
|
|
{
|
|
BOOL bResult = ::UtilSetWchar( m_comment, pwcszComment ) ;
|
|
SetDirty() ;
|
|
return bResult ;
|
|
}
|
|
|
|
void
|
|
CDhcpParamType :: QueryDisplayName (
|
|
CString & cStr
|
|
) const
|
|
{
|
|
char szBuff [ DHC_STRING_MAX ] ;
|
|
|
|
::wsprintf( szBuff, "%3.3d %s", (int) QueryId(), (const char *) m_name ) ;
|
|
cStr = szBuff ;
|
|
}
|
|
|
|
//
|
|
// Construct a list from the data types known to a specific scope
|
|
//
|
|
CObListParamTypes :: CObListParamTypes (
|
|
const CDhcpScope & cScope
|
|
)
|
|
: m_en_category( DhcpDefaultOptions ),
|
|
m_ip_reservation( 0 )
|
|
{
|
|
APIERR err = FillFromScope( cScope ) ;
|
|
if ( err )
|
|
{
|
|
ReportError( err ) ;
|
|
}
|
|
}
|
|
|
|
CObListParamTypes :: ~ CObListParamTypes ()
|
|
{
|
|
}
|
|
|
|
//
|
|
// Copy constructor. Deep-copy duplication of an entire list.
|
|
//
|
|
CObListParamTypes :: CObListParamTypes (
|
|
const CObListParamTypes & oblTypes
|
|
)
|
|
: m_en_category( DhcpDefaultOptions ),
|
|
m_ip_reservation( oblTypes.m_ip_reservation )
|
|
{
|
|
RemoveAll() ;
|
|
CObListIter obli( oblTypes ) ;
|
|
CDhcpParamType * pobType ;
|
|
|
|
//
|
|
// N.B.: This constructor deliberately does not handle exceptions.
|
|
//
|
|
while ( pobType = (CDhcpParamType *) obli.Next() )
|
|
{
|
|
AddTail( new CDhcpParamType( *pobType ) ) ;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Construct an empty list.
|
|
//
|
|
CObListParamTypes :: CObListParamTypes ()
|
|
: m_en_category( DhcpDefaultOptions )
|
|
{
|
|
}
|
|
|
|
LONG
|
|
CObListParamTypes ::SortById ()
|
|
{
|
|
if ( GetCount() < 2 )
|
|
{
|
|
return 0 ;
|
|
}
|
|
|
|
CObListIter obli( *this ) ;
|
|
int cId = -1 ;
|
|
CDhcpParamType * pdhpType = NULL ;
|
|
|
|
//
|
|
// First, check if the list is already in sequence.
|
|
//
|
|
while ( pdhpType = (CDhcpParamType *) obli.Next() )
|
|
{
|
|
if ( (int)pdhpType->QueryId() < cId )
|
|
{
|
|
break ;
|
|
}
|
|
|
|
cId = pdhpType->QueryId() ;
|
|
}
|
|
|
|
//
|
|
// If the list is already in sequence, return now.
|
|
//
|
|
if ( pdhpType == NULL )
|
|
{
|
|
return 0 ;
|
|
}
|
|
|
|
return CObOwnedList::Sort( (CObjectPlus::PCOBJPLUS_ORDER_FUNC) & CDhcpParamType::OrderById ) ;
|
|
}
|
|
|
|
//
|
|
// Find a particular element by its option identifier.
|
|
//
|
|
CDhcpParamType *
|
|
CObListParamTypes :: Find (
|
|
DHCP_OPTION_ID nId
|
|
) const
|
|
{
|
|
CObListIter obli( *this ) ;
|
|
CDhcpParamType * pdhpType = NULL ;
|
|
|
|
while ( pdhpType = (CDhcpParamType *) obli.Next() )
|
|
{
|
|
if ( pdhpType->QueryId() == nId )
|
|
{
|
|
break ;
|
|
}
|
|
}
|
|
|
|
return pdhpType ;
|
|
}
|
|
|
|
//
|
|
// Update the list if necessary
|
|
//
|
|
LONG
|
|
CObListParamTypes :: Save (
|
|
CDhcpScope & cScope
|
|
)
|
|
{
|
|
return ERROR_NOT_SUPPORTED ;
|
|
}
|
|
|
|
//
|
|
// (Re)-Fill the list of parameter (option) types from
|
|
// the given scope.
|
|
//
|
|
// Construct a particularized parameter type list. This means enumerate
|
|
// the parameters for the given scope, and create each object using
|
|
// the given type.
|
|
//
|
|
CObListParamTypes :: CObListParamTypes (
|
|
const CDhcpScope & cScope,
|
|
const CObListParamTypes & colTypes,
|
|
DHCP_OPTION_SCOPE_TYPE enCategory,
|
|
DHCP_IP_ADDRESS dhipaReservation
|
|
)
|
|
: m_en_category( enCategory ),
|
|
m_ip_reservation( dhipaReservation )
|
|
{
|
|
FillParams( cScope, colTypes ) ;
|
|
}
|
|
|
|
#if 0
|
|
//
|
|
// Match the elements of this value/type list to a master list and
|
|
// remove the elements which no longer match. This is done, for example,
|
|
// when the parameter/option value editing dialog has called the type
|
|
// editor, which reports that the basic types have been changed. Values
|
|
// associated with now-defunct types must be discarded.
|
|
//
|
|
// CODEWORK no one seems to call this
|
|
//
|
|
LONG
|
|
CObListParamTypes :: Prune (
|
|
const CObListParamTypes & colTypes
|
|
)
|
|
{
|
|
//
|
|
// Temporary list of defunct types.
|
|
//
|
|
CObListParamTypes colDefunct ;
|
|
CDhcpParamType * pdhcType ;
|
|
CObListIter obli( *this ) ;
|
|
|
|
//
|
|
// Note that we can't delete while iterating. That's the reason for
|
|
// the two loops.
|
|
//
|
|
while ( pdhcType = (CDhcpParamType *) obli.Next() )
|
|
{
|
|
//
|
|
// If we don't find it in the type reference list, it's history
|
|
//
|
|
if ( ! Find( pdhcType->QueryId() ) )
|
|
{
|
|
//
|
|
// Add it to the defunct type/value list
|
|
//
|
|
// CODEWORK I don't think this would work, it should be
|
|
// adding copies of pdhcType
|
|
//
|
|
colDefunct.AddHead( pdhcType ) ;
|
|
}
|
|
}
|
|
|
|
//
|
|
// At this point, the defunct objects are on both lists. Iterate the
|
|
// defunct list and delete them from "this".
|
|
//
|
|
CObListIter obliDefunct( colDefunct ) ;
|
|
while ( pdhcType = (CDhcpParamType *) obliDefunct.Next() )
|
|
{
|
|
Remove( pdhcType ) ;
|
|
}
|
|
|
|
//
|
|
// Since the defunct list is an "owned list", falling out of this routine
|
|
// suffices to destroy the old type/value objects.
|
|
//
|
|
return 0 ;
|
|
}
|
|
#endif
|
|
|
|
|
|
CObListOfTypesOnHost :: CObListOfTypesOnHost (
|
|
const CDhcpScope & cScope
|
|
)
|
|
: m_p_list_types( NULL )
|
|
{
|
|
APIERR err = UpdateList( cScope );
|
|
if ( err )
|
|
{
|
|
ReportError( err ) ;
|
|
}
|
|
}
|
|
|
|
LONG
|
|
CObListOfTypesOnHost :: UpdateList (
|
|
const CDhcpScope & cScope
|
|
)
|
|
{
|
|
APIERR err = 0 ;
|
|
CATCH_MEM_EXCEPTION
|
|
{
|
|
if ( m_p_list_types )
|
|
{
|
|
delete m_p_list_types ;
|
|
}
|
|
m_host_name = cScope.QueryScopeId() ;
|
|
m_p_list_types = new CObListParamTypes( cScope ) ;
|
|
err = m_p_list_types->QueryError() ;
|
|
}
|
|
END_MEM_EXCEPTION(err)
|
|
|
|
return err ;
|
|
}
|
|
|
|
CObListOfTypesOnHost :: ~ CObListOfTypesOnHost ()
|
|
{
|
|
delete m_p_list_types ;
|
|
}
|
|
|
|
//
|
|
// General utility functions
|
|
//
|
|
void
|
|
ClearToZeroes (
|
|
void * vptr,
|
|
int lgt
|
|
)
|
|
{
|
|
::memset( vptr, 0, lgt ) ;
|
|
}
|
|
|
|
|
|
void
|
|
SafeStrCopy (
|
|
char * pchDest,
|
|
int cchDest,
|
|
const char * pszSource
|
|
)
|
|
{
|
|
while ( --cchDest && *pszSource )
|
|
{
|
|
*pchDest++ = *pszSource++ ;
|
|
}
|
|
|
|
*pchDest = 0 ;
|
|
}
|
|
|
|
|
|
// Same as IDS_INFO_HEX_TABLE
|
|
char rgchHex[] = "00112233445566778899aAbBcCdDeEfF";
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// FGetCtrlDWordValue()
|
|
//
|
|
// Return a 32-bit unsigned integer from an edit control
|
|
//
|
|
// This function is like GetDlgItemInt() except it accepts hexadecimal values,
|
|
// has range checking and/or overflow checking.
|
|
// If value is out of range, function will display a friendly message and will
|
|
// set the focus to control.
|
|
// Range: dwMin to dwMax inclusive
|
|
// - If both dwMin and dwMax are zero, no range checking is performed
|
|
// - Return TRUE if successful, otherwise FALSE
|
|
// - On error, pdwValue remains unchanged.
|
|
//
|
|
BOOL FGetCtrlDWordValue(HWND hwndEdit, DWORD * pdwValue, DWORD dwMin, DWORD dwMax)
|
|
{
|
|
char szT[256];
|
|
|
|
DWORD dwResult;
|
|
|
|
ASSERT(IsWindow(hwndEdit));
|
|
ASSERT(pdwValue);
|
|
ASSERT(dwMin <= dwMax);
|
|
|
|
::GetWindowText(hwndEdit, szT, sizeof(szT)-1);
|
|
if (!FCvtAsciiToInteger(szT, OUT &dwResult))
|
|
{
|
|
// Syntax Error and/or integer overflow
|
|
goto Error;
|
|
}
|
|
if ((dwMin == 0) && (dwMax == 0))
|
|
goto Success;
|
|
if ((dwResult < dwMin) || (dwResult > dwMax))
|
|
Error:
|
|
{
|
|
char szBuffer[256];
|
|
|
|
::LoadString(theApp.m_hInstance, IDS_ERR_INVALID_INTEGER, szBuffer, sizeof(szBuffer)-1);
|
|
::wsprintf (szT, szBuffer, (int)dwMin, (int)dwMax);
|
|
ASSERT(strlen(szT)<sizeof(szT));
|
|
::SetFocus(hwndEdit);
|
|
::AfxMessageBox(szT);
|
|
::SetFocus(hwndEdit);
|
|
return FALSE;
|
|
}
|
|
Success:
|
|
*pdwValue = dwResult;
|
|
return TRUE;
|
|
} // FGetCtrlDWordValue
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Convert a string to a binary integer
|
|
// - String is allowed to be decimal or hexadecimal
|
|
// - Minus sign is not allowed
|
|
// If successful, set *pdwValue to the integer and return TRUE.
|
|
// If not successful (overflow or illegal integer) return FALSE.
|
|
//
|
|
BOOL FCvtAsciiToInteger(
|
|
IN const char * pszNum,
|
|
OUT DWORD * pdwValue)
|
|
{
|
|
DWORD dwResult = 0;
|
|
DWORD dwResultPrev = 0;
|
|
int iBase = 10; // Assume a decimal base
|
|
|
|
ASSERT(pszNum != NULL);
|
|
ASSERT(pdwValue != NULL);
|
|
while (*pszNum == ' ' || *pszNum == '0') // Skip leading blanks and/or zeroes
|
|
pszNum++;
|
|
if (*pszNum == 'x' || *pszNum == 'X') // Check if we are using hexadecimal base
|
|
{
|
|
iBase = 16;
|
|
pszNum++;
|
|
}
|
|
while (*pszNum)
|
|
{
|
|
int iDigit;
|
|
// Search the character in the hexadecimal string
|
|
char const * const pchDigit = strchr(rgchHex, *pszNum);
|
|
|
|
if (!pchDigit)
|
|
{
|
|
// Character is not found
|
|
return(FALSE);
|
|
}
|
|
iDigit = (pchDigit - rgchHex) >> 1;
|
|
if (iDigit >= iBase)
|
|
{
|
|
// Hexadecimal character in a decimal integer
|
|
return(FALSE);
|
|
}
|
|
dwResultPrev = dwResult;
|
|
dwResult *= iBase;
|
|
dwResult += iDigit;
|
|
if (dwResult < dwResultPrev)
|
|
{
|
|
// Integer Overflow
|
|
return(FALSE);
|
|
}
|
|
pszNum++; // Parse the next character
|
|
} // while
|
|
// Convertion has been successful
|
|
*pdwValue = dwResult;
|
|
return(TRUE);
|
|
} // FCvtAsciiToInteger
|
|
|
|
//
|
|
// Convert a string of hex digits to a byte array
|
|
//
|
|
BOOL
|
|
CvtHexString (
|
|
const char * pszNum,
|
|
CByteArray & cByte
|
|
)
|
|
{
|
|
int i = 0,
|
|
iDig,
|
|
iByte,
|
|
cDig ;
|
|
int iBase = 16 ;
|
|
BOOL bByteBoundary ;
|
|
|
|
//
|
|
// Skip leading blanks
|
|
//
|
|
for ( ; *pszNum == ' ' ; pszNum++ ) ;
|
|
|
|
//
|
|
// Skip a leading zero
|
|
//
|
|
if ( *pszNum == '0' )
|
|
{
|
|
pszNum++ ;
|
|
}
|
|
|
|
//
|
|
// Look for hexadecimal marker
|
|
//
|
|
if ( *pszNum == 'x' || *pszNum == 'X' )
|
|
{
|
|
pszNum++ ;
|
|
}
|
|
|
|
bByteBoundary = ::strlen( pszNum ) % 2 ;
|
|
|
|
for ( iByte = cDig = 0 ; *pszNum ; )
|
|
{
|
|
const char * pszDig = ::strchr( rgchHex, *pszNum++ ) ;
|
|
if ( pszDig == NULL )
|
|
{
|
|
break;
|
|
// return FALSE;
|
|
}
|
|
|
|
iDig = (pszDig - rgchHex) / 2 ;
|
|
if ( iDig >= iBase )
|
|
{
|
|
break ;
|
|
// return FALSE;
|
|
}
|
|
|
|
iByte = (iByte * 16) + iDig ;
|
|
|
|
if ( bByteBoundary )
|
|
{
|
|
cByte.SetAtGrow( cDig++, iByte ) ;
|
|
iByte = 0 ;
|
|
}
|
|
bByteBoundary = ! bByteBoundary ;
|
|
}
|
|
|
|
cByte.SetSize( cDig ) ;
|
|
|
|
//
|
|
// Return TRUE if we reached the end of the string.
|
|
//
|
|
return *pszNum == 0 ;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CvtByteArrayToString (
|
|
const CByteArray & abAddr,
|
|
CString & str
|
|
)
|
|
{
|
|
int i ;
|
|
APIERR err = 0 ;
|
|
|
|
CATCH_MEM_EXCEPTION
|
|
{
|
|
str.Empty() ;
|
|
|
|
//
|
|
// The hex conversion string has two characters per nibble,
|
|
// to allow for upper case.
|
|
//
|
|
for ( i = 0 ; i < abAddr.GetSize() ; i++ )
|
|
{
|
|
int i1 = ((abAddr.GetAt(i) & 0xF0) >> 4) * 2 ,
|
|
i2 = (abAddr.GetAt(i) & 0x0F) * 2 ;
|
|
str += rgchHex[ i1 ] ;
|
|
str += rgchHex[ i2 ] ;
|
|
}
|
|
}
|
|
END_MEM_EXCEPTION(err)
|
|
|
|
if ( err )
|
|
{
|
|
str.Empty() ;
|
|
}
|
|
|
|
return err == 0 ;
|
|
}
|
|
|
|
|
|
CLBOption::CLBOption(
|
|
BOOL fGlobal, // Scope or global
|
|
DHCP_OPTION_ID idOption, // Id value
|
|
const CString& strName,
|
|
const CString& strValue
|
|
)
|
|
: m_fGlobal(fGlobal),
|
|
m_idOption(idOption),
|
|
m_strName(strName),
|
|
m_strValue(strValue)
|
|
{
|
|
}
|
|
|
|
//
|
|
// Scope constructor
|
|
//
|
|
CLBScope::CLBScope(
|
|
BOOL fLast, // Last scope belonging to host
|
|
BOOL fEnabled, // Scope is enabled
|
|
CDhcpScope * pDhcpScope
|
|
)
|
|
: m_fScope(TRUE),
|
|
m_fLast(fLast),
|
|
m_fEnabled(fEnabled),
|
|
m_pHostName(NULL),
|
|
m_pDhcpScope(pDhcpScope),
|
|
m_poblScopes(NULL),
|
|
m_liDhcpVersion(CHostName::liBadVersion)
|
|
{
|
|
}
|
|
|
|
//
|
|
// Host constructor
|
|
//
|
|
CLBScope::CLBScope(
|
|
BOOL fOpen,
|
|
CHostName * pHostName
|
|
)
|
|
: m_fScope(FALSE),
|
|
m_fOpen(fOpen),
|
|
m_pHostName(pHostName),
|
|
m_pDhcpScope(NULL),
|
|
m_poblScopes(NULL),
|
|
m_liDhcpVersion(CHostName::liBadVersion)
|
|
{
|
|
}
|
|
|
|
const CString &
|
|
CLBScope::QueryString()
|
|
{
|
|
static CString str;
|
|
if (IsScope())
|
|
{
|
|
QueryDhcpScope()->QueryDisplayName(str);
|
|
}
|
|
else
|
|
{
|
|
if (QueryHostName()->QueryIpAddress() == 0x7f000001)
|
|
{
|
|
//
|
|
// BUGBUG: This breaks encapsulation.
|
|
//
|
|
return theApp.GetLocalString();
|
|
}
|
|
return(QueryHostName()->QueryString());
|
|
}
|
|
|
|
return str ;
|
|
}
|
|
|
|
const int COptionsListBox::nBitmaps = 2;
|
|
|
|
void
|
|
COptionsListBox::DrawItemEx(
|
|
CListBoxExDrawStruct& ds
|
|
)
|
|
{
|
|
CLBOption * p = (CLBOption *)ds.m_ItemData;
|
|
ASSERT(p != NULL);
|
|
|
|
CDC* pBmpDC = (CDC*)&ds.m_pResources->DcBitMap();
|
|
int bmh = ds.m_pResources->BitmapHeight();
|
|
int bmw = ds.m_pResources->BitmapWidth();
|
|
int cStringLength;
|
|
|
|
//
|
|
// select bitmap from resource
|
|
//
|
|
int bm_h = (ds.m_Sel)?0:bmh;
|
|
int bm_w = p->IsGlobal()?0:bmw;
|
|
ds.m_pDC->BitBlt( ds.m_Rect.left+1, ds.m_Rect.top, bmw, bmh, pBmpDC, bm_w, bm_h, SRCCOPY );
|
|
|
|
TRY
|
|
{
|
|
cStringLength = ::lstrlen((LPCSTR)p->QueryValue()) +
|
|
::lstrlen((LPCSTR)p->QueryName()) + 256;
|
|
|
|
char * szBuff = new char[cStringLength];
|
|
::wsprintf(szBuff, "%3.3d %s --- %s", // BUGBUG: App should own this as a resource string
|
|
p->QueryOption(),
|
|
(LPCSTR)p->QueryName(),
|
|
(LPCSTR)p->QueryValue()
|
|
) ;
|
|
|
|
ds.m_pDC->TextOut(ds.m_Rect.left+bmw+3, ds.m_Rect.top, szBuff);
|
|
delete szBuff;
|
|
}
|
|
CATCH_ALL(e)
|
|
{
|
|
TRACEEOLID("Exception in DrawItemEx, asking for " << cStringLength << " bytes.");
|
|
}
|
|
END_CATCH_ALL
|
|
}
|
|
|
|
const int CScopesListBox::nBitmaps = 3;
|
|
|
|
CString CScopesListBox::strOpen("-");
|
|
CString CScopesListBox::strClosed("+");
|
|
|
|
int
|
|
CScopesListBox::CompareItem(
|
|
LPCOMPAREITEMSTRUCT lpCIS
|
|
)
|
|
{
|
|
CLBScope * p1 = (CLBScope *)lpCIS->itemData1;
|
|
CLBScope * p2 = (CLBScope *)lpCIS->itemData2;
|
|
DHCP_IP_ADDRESS l1, l2;
|
|
|
|
l1 = p1->IsScope() ? p1->QueryDhcpScope()->QueryScopeId().QueryIpAddress()
|
|
: p1->QueryHostName()->QueryIpAddress();
|
|
|
|
l2 = p2->IsScope() ? p2->QueryDhcpScope()->QueryScopeId().QueryIpAddress()
|
|
: p2->QueryHostName()->QueryIpAddress();
|
|
|
|
//
|
|
// Loopback address should be at the top
|
|
//
|
|
if (l1 == 0x7f000001)
|
|
{
|
|
l1 = 1;
|
|
}
|
|
|
|
if (l2 == 0x7f000001)
|
|
{
|
|
l2 = 1;
|
|
}
|
|
|
|
return (l1 == l2 ? 0 : l1 > l2 ? +1 : -1);
|
|
}
|
|
|
|
//
|
|
// Override base class DrawItem, because we don't want the selection
|
|
// rectangle to include the hierarchical lines and the +/-
|
|
//
|
|
void
|
|
CScopesListBox::DrawItem(
|
|
LPDRAWITEMSTRUCT lpDIS
|
|
)
|
|
{
|
|
ASSERT(m_pResources); //need to attach resources before creation/adding items
|
|
|
|
CDC* pDC = CDC::FromHandle(lpDIS->hDC);
|
|
|
|
CLBScope * p = (CLBScope *)lpDIS->itemData;
|
|
//ASSERT(p != NULL);
|
|
|
|
//
|
|
// BUGBUG??? A deleted DHCP server will
|
|
// have -1 itemdata -- why?
|
|
//
|
|
if (p == NULL || p == (void *)-1)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (p->IsScope())
|
|
{
|
|
//
|
|
// Leave room for the hierarchical marks
|
|
//
|
|
lpDIS->rcItem.left += 20;
|
|
}
|
|
//
|
|
// draw focus rectangle when no items in listbox
|
|
//
|
|
if(lpDIS->itemID == (UINT)-1)
|
|
{
|
|
if(lpDIS->itemAction&ODA_FOCUS)
|
|
{
|
|
//
|
|
// rcItem.bottom seems to be 0 for variable height list boxes
|
|
//
|
|
lpDIS->rcItem.bottom = m_lfHeight;
|
|
pDC->DrawFocusRect( &lpDIS->rcItem );
|
|
}
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
int selChange = lpDIS->itemAction & ODA_SELECT;
|
|
int focusChange = lpDIS->itemAction & ODA_FOCUS;
|
|
int drawEntire = lpDIS->itemAction & ODA_DRAWENTIRE;
|
|
|
|
if(selChange || drawEntire)
|
|
{
|
|
BOOL sel = lpDIS->itemState & ODS_SELECTED;
|
|
|
|
COLORREF hlite = ((sel) ? (m_pResources->ColorHighlight())
|
|
: (m_pResources->ColorWindow()));
|
|
COLORREF textcol = ((sel) ? (m_pResources->ColorHighlightText())
|
|
: (m_pResources->ColorWindowText()));
|
|
pDC->SetBkColor(hlite);
|
|
pDC->SetTextColor(textcol);
|
|
//
|
|
// fill the rectangle with the background colour.
|
|
//
|
|
pDC->ExtTextOut( 0, 0, ETO_OPAQUE, &lpDIS->rcItem, NULL, 0, NULL );
|
|
|
|
CListBoxExDrawStruct ds( pDC,
|
|
(RECT *)&lpDIS->rcItem, sel,
|
|
(DWORD)lpDIS->itemData, lpDIS->itemID,
|
|
m_pResources );
|
|
|
|
//
|
|
// Now call the draw function of the derived class
|
|
//
|
|
DrawItemEx( ds );
|
|
}
|
|
|
|
if( focusChange || (drawEntire && (lpDIS->itemState & ODS_FOCUS)) )
|
|
{
|
|
pDC->DrawFocusRect(&lpDIS->rcItem);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
CScopesListBox::DrawItemEx(
|
|
CListBoxExDrawStruct& ds
|
|
)
|
|
{
|
|
CLBScope * p = (CLBScope *)ds.m_ItemData;
|
|
ASSERT(p != NULL);
|
|
|
|
CDC* pBmpDC = (CDC*)&ds.m_pResources->DcBitMap();
|
|
int bmh = ds.m_pResources->BitmapHeight();
|
|
int bmw = ds.m_pResources->BitmapWidth();
|
|
|
|
//
|
|
// select bitmap from resource
|
|
//
|
|
int nBitmap = 0;
|
|
|
|
if (p->IsScope())
|
|
{
|
|
int indent = 10;
|
|
|
|
//
|
|
// set line colour
|
|
//
|
|
COLORREF crOld;
|
|
COLORREF textcol = m_pResources->ColorWindowText();
|
|
crOld = ds.m_pDC->SetBkColor(textcol);
|
|
|
|
//
|
|
// it looks better having the tees and corners at half bitmap height
|
|
// than text height for large fonts.
|
|
//
|
|
int bmHeight = m_pResources->BitmapHeight();
|
|
|
|
if(p->IsLast())
|
|
{
|
|
//
|
|
// Draw the top half of the vertical
|
|
//
|
|
CRect r( indent, ds.m_Rect.top, indent+1, ds.m_Rect.top + bmHeight / 2 );
|
|
ds.m_pDC->ExtTextOut( indent, 0, ETO_OPAQUE, r, NULL, 0, NULL );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Draw full vertical
|
|
//
|
|
CRect r( indent, ds.m_Rect.top, indent+1, ds.m_Rect.bottom );
|
|
ds.m_pDC->ExtTextOut( indent, 0, ETO_OPAQUE, r, NULL, 0, NULL );
|
|
}
|
|
//
|
|
// Draw the horizontal
|
|
//
|
|
CRect r (indent, ds.m_Rect.top + bmHeight/2, 2*indent, ds.m_Rect.top + bmHeight / 2 + 1);
|
|
ds.m_pDC->ExtTextOut( indent, 0, ETO_OPAQUE, r, NULL, 0, NULL );
|
|
|
|
ds.m_pDC->SetBkColor(crOld);
|
|
|
|
//ds.m_Rect.left += 2*indent;
|
|
nBitmap = p->IsEnabled() ? 2 : 1;
|
|
}
|
|
else
|
|
{
|
|
ds.m_pDC->TextOut(ds.m_Rect.left, ds.m_Rect.top,
|
|
p->IsOpen() ? strOpen : strClosed);
|
|
ds.m_Rect.left += 6;
|
|
nBitmap = 0;
|
|
}
|
|
|
|
int bm_h = (ds.m_Sel)?0:bmh;
|
|
int bm_w = bmw*nBitmap;
|
|
ds.m_pDC->BitBlt( ds.m_Rect.left+1, ds.m_Rect.top, bmw, bmh, pBmpDC, bm_w, bm_h, SRCCOPY );
|
|
|
|
ds.m_pDC->TextOut(ds.m_Rect.left+bmw+3, ds.m_Rect.top, p->QueryString());
|
|
}
|
|
|
|
const int CLeasesListBox::nBitmaps = 5;
|
|
|
|
void
|
|
CLeasesListBox::AttachResources(
|
|
const CListBoxExResources* pRes
|
|
)
|
|
{
|
|
m_str_client_mask.LoadString( IDS_INFO_FORMAT_CLIENT_IP ) ;
|
|
m_str_resv_mask.LoadString( IDS_INFO_FORMAT_RESV_IP ) ;
|
|
m_str_resv_in_use_mask.LoadString( IDS_INFO_FORMAT_RESV_IN_USE ) ;
|
|
|
|
CListBoxEx::AttachResources(pRes);
|
|
}
|
|
|
|
void
|
|
CLeasesListBox::DrawItemEx(
|
|
CListBoxExDrawStruct& ds
|
|
)
|
|
{
|
|
char szIp [ DHC_STRING_MAX ] ;
|
|
|
|
BOOL bUnused ;
|
|
|
|
CDhcpClient * pClient = (CDhcpClient *)ds.m_ItemData;
|
|
ASSERT(pClient != NULL);
|
|
|
|
const DATE_TIME & dt = pClient->QueryExpiryDateTime() ;
|
|
|
|
//
|
|
// Convert the IP address to displayable form
|
|
//
|
|
::UtilCvtIpAddrToString( pClient->QueryIpAddress(), szIp, sizeof szIp ) ;
|
|
|
|
CString strUID;
|
|
|
|
//
|
|
// See if the reservation is in use (date/time will be zero if unused)
|
|
//
|
|
bUnused = dt.dwLowDateTime == DHCP_DATE_TIME_ZERO_LOW
|
|
&& dt.dwHighDateTime == DHCP_DATE_TIME_ZERO_HIGH ;
|
|
|
|
CDC* pBmpDC = (CDC*)&ds.m_pResources->DcBitMap();
|
|
int bmh = ds.m_pResources->BitmapHeight();
|
|
int bmw = ds.m_pResources->BitmapWidth();
|
|
|
|
int nBitmap;
|
|
BOOL fZombie = FALSE;
|
|
|
|
//
|
|
// Check to see if we have a zombie entry.
|
|
//
|
|
DATE_TIME dateTime = pClient->QueryExpiryDateTime();
|
|
SYSTEMTIME sysTime ;
|
|
|
|
if ( (dateTime.dwLowDateTime == DHCP_DATE_TIME_INFINIT_LOW
|
|
&& dateTime.dwHighDateTime == DHCP_DATE_TIME_INFINIT_HIGH
|
|
)
|
|
|| (dateTime.dwHighDateTime == DHCP_DATE_TIME_ZERO_HIGH
|
|
&& dateTime.dwLowDateTime == DHCP_DATE_TIME_ZERO_LOW
|
|
)
|
|
)
|
|
{
|
|
fZombie = FALSE; // infinite lease.
|
|
}
|
|
else if ( ! ::FileTimeToSystemTime( (FILETIME *) & dateTime, & sysTime ) )
|
|
{
|
|
TRACEEOLID("CDhcpLeaseDlg:: FileTimeToSystemTime() failed. error = "
|
|
<< ::GetLastError() ) ;
|
|
fZombie = FALSE; // can't assume
|
|
}
|
|
else
|
|
{
|
|
SYSTEMTIME sysNow;
|
|
::GetSystemTime(&sysNow);
|
|
CTime tmLease(sysTime);
|
|
CTime tmNow(sysNow);
|
|
if (tmNow >= tmLease)
|
|
{
|
|
fZombie = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Select the appropriate bitmap to
|
|
// display here.
|
|
//
|
|
if (fZombie)
|
|
{
|
|
nBitmap = BMP_ZOMBIE;
|
|
}
|
|
//
|
|
// RAS Mapping?
|
|
//
|
|
else if (pClient->QueryHardwareAddress().GetSize() >= 3
|
|
&& pClient->QueryHardwareAddress()[0] == 'R'
|
|
&& pClient->QueryHardwareAddress()[1] == 'A'
|
|
&& pClient->QueryHardwareAddress()[2] == 'S')
|
|
{
|
|
nBitmap = BMP_RAS;
|
|
}
|
|
else
|
|
{
|
|
nBitmap = pClient->IsReservation() ? (bUnused ? BMP_RESV : BMP_RESVINUSE) : BMP_NORMAL;
|
|
}
|
|
//
|
|
// select bitmap from resource
|
|
//
|
|
int bm_h = (ds.m_Sel)?0:bmh;
|
|
int bm_w = nBitmap * bmw;
|
|
ds.m_pDC->BitBlt( ds.m_Rect.left+1, ds.m_Rect.top, bmw, bmh, pBmpDC, bm_w, bm_h, SRCCOPY );
|
|
|
|
ds.m_pDC->TextOut(ds.m_Rect.left+bmw+3, ds.m_Rect.top, szIp);
|
|
ds.m_pDC->TextOut(ds.m_Rect.left+bmw+95, ds.m_Rect.top, (LPCSTR)pClient->QueryName());
|
|
ds.m_pDC->TextOut(ds.m_Rect.left+bmw+200, ds.m_Rect.top,
|
|
pClient->IsReservation() ? (bUnused ? m_str_resv_mask : m_str_resv_in_use_mask)
|
|
: m_str_client_mask);
|
|
}
|
|
|
|
int
|
|
CLeasesListBox::CompareItem(
|
|
LPCOMPAREITEMSTRUCT lpCIS
|
|
)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
// End of DHCPGEN.CPP
|