#include "precomp.h"
DEBUG_FILEZONE(ZONE_T120_GCCNC);
/*
 *	netaddr.cpp
 *
 *	Copyright (c) 1995 by DataBeam Corporation, Lexington, KY
 *
 *	Abstract:
 *		This is the implementation file for the CNetAddrListContainer Class.  This
 *		class manages the data associated with a network address.  Network
 *		addresses can be one of three types: aggregated channel, transport
 *		connection, or non-standard.  A variety of structures, objects, and
 *		Rogue Wave containers are used to buffer the network address data
 *		internally.
 *
 *	Protected Instance Variables:
 *		m_NetAddrItemList
 *			List of structures used to hold the network address data internally.
 *		m_pSetOfNetAddrPDU
 *			Storage for the "PDU" form of the network address list.
 *		m_cbDataSize
 *			Variable holding the size of the memory which will be required to
 *			hold any data referenced by the "API" network address structures.
 *		m_fValidNetAddrPDU
 *			Flag indicating that memory has been allocated to hold the internal
 *			"PDU" network address list.
 *
 *	Private Member Functions:
 *		StoreNetworkAddressList
 *			This routine is used to store the network address data passed in as
 *			"API" data in the internal structures.
 *		ConvertPDUDataToInternal	
 *			This routine is used to store the network address data passed in as
 *			"PDU" data in the internal structures.
 * 		ConvertNetworkAddressInfoToPDU
 *			This routine is used to convert the network address info structures
 *			maintained internally into the "PDU" form which is a 
 *			SetOfNetworkAddresses.
 *		ConvertTransferModesToInternal
 *			This routine is used to convert the PDU network address transfer 
 *			modes structure into the internal form where the structure is saved
 *			as a GCCTranferModes structure.
 *		ConvertHighLayerCompatibilityToInternal
 *			This routine is used to convert the PDU network address high layer
 *			compatibility structure into the internal form where the structure
 *			is saved as a GCCHighLayerCompatibility structure.
 *		ConvertTransferModesToPDU
 *			This routine is used to convert the API network address transfer
 *			modes structure into the PDU form which is a TranferModes structure.
 *		ConvertHighLayerCompatibilityToPDU
 *			This routine is used to convert the API network address high layer
 *			compatibility structure into the PDU form which is a 
 *			HighLayerCompatibility structure.
 *		IsDialingStringValid
 *			This routine is used to ensure that the values held within a
 *			dialing string do not violate the imposed ASN.1 constraints.
 *		IsCharacterStringValid
 *			This routine is used to ensure that the values held within a
 *			character string do not violate the imposed ASN.1 constraints.
 *		IsExtraDialingStringValid
 *			This routine is used to ensure that the values held within an
 *			extra dialing string do not violate the imposed ASN.1 constraints.
 *
 *	Caveats:
 *		This container stores much of the network address information internally
 *		using an "API" GCCNetworkAddress structure.  Any data referenced by
 *		pointers in this structure is stored in some other container.
 *		Therefore, the pointers held within the internal "API" structure are
 *		not valid and must not be accessed.
 *
 *	Author:
 *		blp/jbo
 */
#include <stdio.h>

#include "ms_util.h"
#include "netaddr.h"

/*
 * These macros are used to define the size constraints of an "nsap" address.
 */
#define		MINIMUM_NSAP_ADDRESS_SIZE		1
#define		MAXIMUM_NSAP_ADDRESS_SIZE		20

/*
 * These macros are used to verify that a network address has a valid number
 * of network address entities.
 */
#define		MINIMUM_NUMBER_OF_ADDRESSES		1
#define		MAXIMUM_NUMBER_OF_ADDRESSES		64

/*
 * These macros are used to define the size constraints of an extra dialing
 * string.
 */
#define		MINIMUM_EXTRA_DIALING_STRING_SIZE		1
#define		MAXIMUM_EXTRA_DIALING_STRING_SIZE		255



NET_ADDR::NET_ADDR(void)
:
    pszSubAddress(NULL),
    pwszExtraDialing(NULL),
    high_layer_compatibility(NULL),
    poszTransportSelector(NULL),
    poszNonStandardParam(NULL),
	object_key(NULL)
{
}


NET_ADDR::~NET_ADDR(void)
{
    switch (network_address.network_address_type)
    {
    case GCC_AGGREGATED_CHANNEL_ADDRESS:
		delete pszSubAddress;
		delete pwszExtraDialing;
		delete high_layer_compatibility;
        break;
    case GCC_TRANSPORT_CONNECTION_ADDRESS:
		delete poszTransportSelector;
        break;
    case GCC_NONSTANDARD_NETWORK_ADDRESS:
		delete poszNonStandardParam;
		if (NULL != object_key)
        {
            object_key->Release();
        }
        break;
    default:
        ERROR_OUT(("NET_ADDR::~NET_ADDR: unknown addr type=%u", (UINT) network_address.network_address_type));
        break;
	}
}


/*
 *	CNetAddrListContainer()
 *
 *	Public Function Description:
 * 		This constructor is used when creating a CNetAddrListContainer object with
 *		the "API" form of network address, GCCNetworkAddress.
 */
CNetAddrListContainer::
CNetAddrListContainer(UINT                 number_of_network_addresses,
                      PGCCNetworkAddress    *network_address_list,
                      PGCCError             return_value )  
:
    CRefCount(MAKE_STAMP_ID('N','t','A','L')),
    m_pSetOfNetAddrPDU(NULL),
    m_fValidNetAddrPDU(FALSE),
    m_cbDataSize(0)
{
	/*
	 * Initialize the instance variables.  The m_NetAddrItemList which
	 * will hold the network address data internally will be filled in by the
	 * call to StoreNetworkAddressList.
	 */

	/*
	 * Check to make sure a valid number of network addresses exist.
	 */
	if ((number_of_network_addresses < MINIMUM_NUMBER_OF_ADDRESSES)
			|| (number_of_network_addresses > MAXIMUM_NUMBER_OF_ADDRESSES))
	{
		ERROR_OUT(("CNetAddrListContainer::CNetAddrListContainer: ERROR Invalid number of network addresses, %u", (UINT) number_of_network_addresses));
		*return_value = GCC_BAD_NETWORK_ADDRESS;
	}
	/*
	 * Check to make sure that the list pointer is valid.
	 */
	else if (network_address_list == NULL)
	{
		ERROR_OUT(("CNetAddrListContainer::CNetAddrListContainer: ERROR NULL address list"));
		*return_value = GCC_BAD_NETWORK_ADDRESS;
	}
	/*
	 * Save the network address(es) in the internal structures.
	 */
	else
	{
		*return_value = StoreNetworkAddressList(number_of_network_addresses,
												network_address_list);
	}
}

/*
 *	CNetAddrListContainer()
 *
 *	Public Function Description:
 * 		This constructor is used when creating a CNetAddrListContainer object with
 *		the "PDU" form of network address, SetOfNetworkAddresses.
 */
CNetAddrListContainer::
CNetAddrListContainer(PSetOfNetworkAddresses    network_address_list, 
                      PGCCError                 return_value )
:
    CRefCount(MAKE_STAMP_ID('N','t','A','L')),
    m_pSetOfNetAddrPDU(NULL),
    m_fValidNetAddrPDU(FALSE),
    m_cbDataSize(0)
{
	PSetOfNetworkAddresses		network_address_ptr;

	/*
	 * Initialize the instance variables.  The m_NetAddrItemList which
	 * will hold the network address data internally will be filled in by the
	 * calls to ConvertPDUDataToInternal.
	 */

	*return_value = GCC_NO_ERROR;
	network_address_ptr = network_address_list;

	/*
	 * Loop through the set of network addresses, saving each in an internal
	 * NET_ADDR structure and saving those structures in the internal
	 * list.
	 */
	if (network_address_list != NULL)
	{
		while (1)
		{
			/*
			 * Convert each "PDU" network address into the internal form.  Note
			 * that object ID validation is not performed on data received as
			 * a PDU.  If a bad object ID comes in on the wire, this will be
			 * flagged as an allocation failure.
			 */
			if (ConvertPDUDataToInternal (network_address_ptr) != GCC_NO_ERROR)
			{
				ERROR_OUT(("CNetAddrListContainer::CNetAddrListContainer: Error converting PDU data to internal"));
				*return_value = GCC_ALLOCATION_FAILURE;
				break;
			}
			else
            {
				network_address_ptr = network_address_ptr->next;
            }

			if (network_address_ptr == NULL)
				break;
		}
	}
}

/*
 *	CNetAddrListContainer()
 *
 *	Public Function Description:
 *		This is the copy constructor used to create a new CNetAddrListContainer
 *		object from an existing CNetAddrListContainer object. 
 */
CNetAddrListContainer::
CNetAddrListContainer(CNetAddrListContainer *address_list,
                      PGCCError		        pRetCode)
:
    CRefCount(MAKE_STAMP_ID('N','t','A','L')),
    m_pSetOfNetAddrPDU(NULL),
    m_fValidNetAddrPDU(FALSE),
    m_cbDataSize(0)
{
	NET_ADDR    				    *network_address_info;
	NET_ADDR	    			    *lpNetAddrInfo;
	GCCNetworkAddressType			network_address_type;
	GCCError						rc;

	/*
	 * Set up an iterator for the internal list of network addresses.
	 */
	address_list->m_NetAddrItemList.Reset();

    /*
	 * Copy each NET_ADDR structure contained in the 
	 * CNetAddrListContainer object to	be copied.
	 */
	while (NULL != (lpNetAddrInfo = address_list->m_NetAddrItemList.Iterate()))
	{
		/*
		 * Create a new NET_ADDR structure to hold each element of the
		 * new CNetAddrListContainer object.  Report an error if creation of this 
		 * structure fails.
		 */
		DBG_SAVE_FILE_LINE
		if (NULL == (network_address_info = new NET_ADDR))
		{
			ERROR_OUT(("CNetAddrListContainer::CNetAddrListContainer: can't create NET_ADDR"));
			rc = GCC_ALLOCATION_FAILURE;
			goto MyExit;
		}

        /*
		 * First copy the GCCNetworkAddress structure contained in the
		 * internal NET_ADDR structure.  This copies all data
		 * except that referenced by pointers in the structure.
		 */
		network_address_info->network_address = lpNetAddrInfo->network_address;

		/*
		 * Next copy any data embedded in the network address that would 
		 * not have been copied in the above operation (typically pointers 
		 * to strings).
		 */

		/*
		 * This variable is used for abbreviation.
		 */
		network_address_type = lpNetAddrInfo->network_address.network_address_type;

		/*
		 * The network address is the "Aggregated" type.
		 */
        switch (network_address_type)
        {
        case GCC_AGGREGATED_CHANNEL_ADDRESS:
			/*
			 * If a sub-address string exists, store it in a Rogue Wave
			 * container.  Set the  structure pointer to NULL if one does 
			 * not exist.
			 */
			if (lpNetAddrInfo->pszSubAddress != NULL)
			{
				if (NULL == (network_address_info->pszSubAddress =
									::My_strdupA(lpNetAddrInfo->pszSubAddress)))
				{
					ERROR_OUT(("CNetAddrListContainer::CNetAddrListContainer: can't create sub address"));
					rc = GCC_ALLOCATION_FAILURE;
					goto MyExit;
				}
			}
			else
            {
				network_address_info->pszSubAddress = NULL;
            }
					
			/*
			 * If an extra dialing string exists, store it in a Unicode
			 * String object.  Set the  structure pointer to NULL if one 
			 * does not exist.
			 */
			if (lpNetAddrInfo->pwszExtraDialing != NULL)
			{
				if (NULL == (network_address_info->pwszExtraDialing =
									::My_strdupW(lpNetAddrInfo->pwszExtraDialing)))
				{
					ERROR_OUT(("CNetAddrListContainer::CNetAddrListContainer: can't creating extra dialing string"));
					rc = GCC_ALLOCATION_FAILURE;
					goto MyExit;
				}
			}
			else
            {
				network_address_info->pwszExtraDialing = NULL;
            }

			/*
			 * If a higher layer compatibility structure exists, store it 
			 * in a GCCHighLayerCompatibility structure.  Set the structure
			 * pointer to NULL if one does not exist.
			 */
			if (lpNetAddrInfo->high_layer_compatibility != NULL)
			{
				DBG_SAVE_FILE_LINE
				network_address_info->high_layer_compatibility = new GCCHighLayerCompatibility;
				if (network_address_info->high_layer_compatibility != NULL)
				{
					/*
					 * Copy the high layer compatibility data to the
					 * new structure.
					 */
					*network_address_info->high_layer_compatibility =  
							*(lpNetAddrInfo->high_layer_compatibility);
				}
				else
				{
					ERROR_OUT(("CNetAddrListContainer::CNetAddrListContainer: Error creating new GCCHighLayerCompat"));
					rc = GCC_ALLOCATION_FAILURE;
					goto MyExit;
				}
			}
			else
            {
				network_address_info->high_layer_compatibility = NULL;
            }
            break;

		/*
		 * The network address is the "Transport Connection" type.
		 */
        case GCC_TRANSPORT_CONNECTION_ADDRESS:
			/*
			 * If a transport selector exists, store it in a Rogue Wave 
			 * container.  Otherwise, set the structure pointer to NULL.
			 */
			if (lpNetAddrInfo->poszTransportSelector != NULL)
			{
				if (NULL == (network_address_info->poszTransportSelector =
									::My_strdupO(lpNetAddrInfo->poszTransportSelector)))
				{
					ERROR_OUT(("CNetAddrListContainer::CNetAddrListContainer: can't create transport selector"));
					rc = GCC_ALLOCATION_FAILURE;
					goto MyExit;
				}
			}
			else
            {
				network_address_info->poszTransportSelector = NULL;
            }
            break;

		/*
		 * The network address is the "Non-Standard" type.
		 */
        case GCC_NONSTANDARD_NETWORK_ADDRESS:
			/*
			 * First store the non-standard parameter data in a Rogue Wave
			 * container.
			 */
			if (NULL == (network_address_info->poszNonStandardParam =
								::My_strdupO(lpNetAddrInfo->poszNonStandardParam)))
			{
				ERROR_OUT(("CNetAddrListContainer::CNetAddrListContainer: can't create non-standard param"));
				rc = GCC_ALLOCATION_FAILURE;
				goto MyExit;
			}

			/*
			 * Next store the object key internally in an CObjectKeyContainer
			 * object.  Note that there is no need to report the error
			 * "BAD_NETWORK_ADDRESS" here since the object key data 
			 * would have been validated when the original network address
			 * was created.
			 */
			DBG_SAVE_FILE_LINE
			network_address_info->object_key = new CObjectKeyContainer(lpNetAddrInfo->object_key, &rc);
			if ((network_address_info->object_key == NULL) || (rc != GCC_NO_ERROR))
			{
				ERROR_OUT(("CNetAddrListContainer::CNetAddrListContainer: Error creating new CObjectKeyContainer"));
				rc = GCC_ALLOCATION_FAILURE;
				goto MyExit;
			}
            break;

		/*
		 * The network address is of unknown type.  This should never be
		 * encountered so flag it as an allocation failure.
		 */
        default:
			ERROR_OUT(("CNetAddrListContainer::CNetAddrListContainer: Invalid type received as PDU"));
			rc = GCC_ALLOCATION_FAILURE;
			goto MyExit;
		}

		/*
		 * Go ahead and insert the pointer to the NET_ADDR
		 * structure into the internal Rogue Wave list.
		 */
		m_NetAddrItemList.Append(network_address_info);
	}

    rc = GCC_NO_ERROR;

MyExit:

    if (GCC_NO_ERROR != rc)
    {
        delete network_address_info;
    }

    *pRetCode = rc;
}


/*
 *	~CNetAddrListContainer()
 *
 *	Public Function Description:
 *		The destructor is used to free up any memory allocated during the life
 * 		of the object.
 */
CNetAddrListContainer::
~CNetAddrListContainer(void)
{
	
	/*
	 * Free any data allocated to hold "PDU" information.
	 */
	if (m_fValidNetAddrPDU)
    {
		FreeNetworkAddressListPDU();
    }

	/*
	 * Free any data allocated for the internal list of "info" structures.
	 */
	NET_ADDR *pNetAddrInfo;
	m_NetAddrItemList.Reset();
	while (NULL != (pNetAddrInfo = m_NetAddrItemList.Iterate()))
	{
		delete pNetAddrInfo;
	}
}


/*
 *	LockNetworkAddressList ()
 *
 *	Public Function Description:
 *		This routine is called to "Lock" the network address data in "API" form.
 *		The amount of memory required to hold the "API" data which is referenced
 *		by, but not included in the GCCNetworkAddress structure, will be
 *		returned. 
 *
 */
UINT CNetAddrListContainer::
LockNetworkAddressList(void)
{  
	/*
	 * If this is the first time this routine is called, determine the size of 
	 * the memory required to hold the data.  Otherwise, just increment the 
	 * lock count.
	 */
	if (Lock() == 1)
	{
    	PGCCNetworkAddress		network_address;
	    NET_ADDR    		    *lpNetAddrInfo;

		/*
		 * Set aside memory to hold the pointers to the GCCNetworkAddress
		 * structures as well as the structures themselves.  The "sizeof" the 
		 * structure must be rounded to an even four-byte boundary.
		 */
		m_cbDataSize = m_NetAddrItemList.GetCount() * 
				( sizeof(PGCCNetworkAddress) + ROUNDTOBOUNDARY(sizeof(GCCNetworkAddress)) );

		/*
		 * Loop through the list of network addresses, adding up the space
		 * requirements of each address.
		 */
		m_NetAddrItemList.Reset();
	 	while (NULL != (lpNetAddrInfo = m_NetAddrItemList.Iterate()))
		{
			/*
			 * Use a local variable to keep from having to access the Rogue Wave
			 * iterator repeatedly.
			 */
			network_address = &lpNetAddrInfo->network_address;

			/*
			 * Check to see what type of network address exists.
			 */
			switch (network_address->network_address_type)
            {
            case GCC_AGGREGATED_CHANNEL_ADDRESS:
				/*
				 * Add the length of the sub address string if it exists.
				 */
				if (lpNetAddrInfo->pszSubAddress != NULL)
				{
					m_cbDataSize += ROUNDTOBOUNDARY(::lstrlenA(lpNetAddrInfo->pszSubAddress) + 1);
				}

				/*
				 * Add the size of the GCCExtraDialingString structure as well
				 * as the length of the extra dialing string if it exists.
				 */
				if (lpNetAddrInfo->pwszExtraDialing != NULL)
				{
					m_cbDataSize += ROUNDTOBOUNDARY(sizeof(GCCExtraDialingString)) +
                                    ROUNDTOBOUNDARY((::lstrlenW(lpNetAddrInfo->pwszExtraDialing) + 1) * sizeof(WCHAR));
				}

				/*
				 * Add the size of the high layer compatibility structure if
				 * it exists.
				 */
				if (lpNetAddrInfo->high_layer_compatibility != NULL)
				{
					m_cbDataSize += ROUNDTOBOUNDARY(sizeof(GCCHighLayerCompatibility));
				}
                break;

            case GCC_TRANSPORT_CONNECTION_ADDRESS:
				/*
				 * Add the size of the OSTR structure as well as the
				 * length of the octet string if it exists.
				 */
				if (lpNetAddrInfo->poszTransportSelector != NULL)
				{
					m_cbDataSize += ROUNDTOBOUNDARY(sizeof(OSTR)) +
					                ROUNDTOBOUNDARY(lpNetAddrInfo->poszTransportSelector->length); 
				}
                break;

            case GCC_NONSTANDARD_NETWORK_ADDRESS:
				/*
				 * Lock the object key in the non-standard parameter in order to
				 * determine the amount of memory needed to hold its data.
				 */
				m_cbDataSize += lpNetAddrInfo->object_key->LockObjectKeyData ();

				/*
				 * Add the space needed to hold the octet string data for the 
				 * non-standard parameter.
				 */
				m_cbDataSize += ROUNDTOBOUNDARY(lpNetAddrInfo->poszNonStandardParam->length);
                break;
			}
		}
	}

	return m_cbDataSize;
} 


/*
 *	GetNetworkAddressListAPI ()
 *
 *	Public Function Description:
 *		This routine is used to retrieve the list of network addresses in "API"
 *		form.
 */
UINT CNetAddrListContainer::
GetNetworkAddressListAPI(UINT				*	number_of_network_addresses,
                         PGCCNetworkAddress	**	network_address_list,
                         LPBYTE					memory)
{
	UINT					cbDataSizeToRet = 0;
	UINT					data_length = 0;
	UINT					network_address_counter = 0;
	PGCCNetworkAddress		network_address_ptr;
	NET_ADDR    		    *address_info;
	PGCCNetworkAddress		*address_array;

	/*
	 * If the user data has been locked, fill in the output parameters and
	 * the data referenced by the pointers.  Otherwise, report that the object
	 * has yet to be locked into the "API" form.
	 */ 
	if (GetLockCount() > 0)
	{
		// NET_ADDR	*lpNetAddrInfo;

		/*
		 * Fill in the output length parameter which indicates how much data
		 * referenced outside the structure will be written.
		 */
		cbDataSizeToRet = m_cbDataSize;

		/*
		 * Fill in the number of network address entities and save a pointer to 
		 * the memory location passed in.  This is where the pointers to the 
		 * GCCNetworkAddress structures will be written.  The actual structures 
		 * will be written into memory immediately following the list of 
		 * pointers.
		 */
		*number_of_network_addresses = (UINT) m_NetAddrItemList.GetCount();

		*network_address_list = (PGCCNetworkAddress *)memory;
		address_array = *network_address_list;

		/*
		 * Save the amount of memory needed to hold the list of pointers as
		 * well as the actual network address structures.
		 */
		data_length = m_NetAddrItemList.GetCount() * sizeof(PGCCNetworkAddress);

		/*
		 * Move the memory pointer past the list of network address pointers.  
		 * This is where the first network address structure will be written.
		 */
		memory += data_length;

		/*
		 * Iterate through the internal list of NET_ADDR structures,
		 * building "API" GCCNetworkAddress structures in memory.
		 */
		m_NetAddrItemList.Reset();
		while (NULL != (address_info = m_NetAddrItemList.Iterate()))
		{
			/*
			 * Save the pointer to the network address structure in the list 
			 * of pointers.
			 */
			network_address_ptr = (PGCCNetworkAddress)memory;
			address_array[network_address_counter++] = network_address_ptr;

			/*
			 * Move the memory pointer past the network address structure.  
			 * This is where the network address data will be written.
			 */
			memory += ROUNDTOBOUNDARY(sizeof(GCCNetworkAddress));

			/*
			 * Check to see what type of network address this is and fill in 
			 * the user data structure.  Here the address is the aggregated
			 * channel type.
			 */
			switch (address_info->network_address.network_address_type)
            {
            case GCC_AGGREGATED_CHANNEL_ADDRESS:
				network_address_ptr->network_address_type =	GCC_AGGREGATED_CHANNEL_ADDRESS;

				/*
				 * Copy the transfer modes.
				 */
				network_address_ptr->u.aggregated_channel_address.transfer_modes = 
					address_info->network_address.u.aggregated_channel_address.transfer_modes;

				/*
				 * Copy the international number.
				 */
                ::lstrcpyA(network_address_ptr->u.aggregated_channel_address.international_number,
						   address_info->network_address.u.aggregated_channel_address.international_number);

				/*
				 * If the sub address string exists, set the sub address string
				 * pointer and write the data into memory.  Otherwise, set the
				 * "API" pointer to NULL.
				 */
				if (address_info->pszSubAddress != NULL)
				{
					network_address_ptr->u.aggregated_channel_address.sub_address_string = 
																(GCCCharacterString)memory;

					/*
					 * Now copy the sub-address string data from the internal 
					 * Rogue Wave string into memory.
					 */		
                    ::lstrcpyA((LPSTR) memory, address_info->pszSubAddress);

					/*
					 * Move the memory pointer past the sub-address string data.
					 * This is where the GCCExtraDialingString structure will be
					 * written.
					 */
					memory += ROUNDTOBOUNDARY(::lstrlenA(address_info->pszSubAddress) + 1);
				}
				else
				{
					/*
					 * No sub-address was present so set the pointer to NULL.
					 */
					network_address_ptr->u.aggregated_channel_address.sub_address_string = NULL;
				}

				/*
				 * If the extra dialing string exists, set the extra dialing
				 * string pointer and write the data into memory.  Otherwise,
				 * set the "API" pointer to NULL.
				 */
				if (address_info->pwszExtraDialing != NULL)
				{
					network_address_ptr->u.aggregated_channel_address.extra_dialing_string = 
							(PGCCExtraDialingString)memory;

					/*
					 * Move the memory pointer past the GCCExtraDialingString
					 * structure.  This is where the extra dialing string data 
					 * will	be written.
					 */
					memory += ROUNDTOBOUNDARY(sizeof(GCCExtraDialingString));

					UINT cchExtraDialing = ::lstrlenW(address_info->pwszExtraDialing);
					network_address_ptr->u.aggregated_channel_address.extra_dialing_string->length = 
							(USHORT) cchExtraDialing;

					network_address_ptr->u.aggregated_channel_address.extra_dialing_string->value = 
																		(LPWSTR)memory;

					/*
					 * Now copy the hex string data from the internal Unicode 
					 * String into the allocated memory.
					 */
					//
					// LONCHANC: The size does not include null terminator in the original code.
					// could this be a bug???
					//
					::CopyMemory(memory, address_info->pwszExtraDialing, cchExtraDialing * sizeof(WCHAR));

					/*
					 * Move the memory pointer past the extra dialing string 
					 * data.  This is where the high layer compatibility 
					 * structure will be written.
					 */
					memory += ROUNDTOBOUNDARY(cchExtraDialing * sizeof(WCHAR));
				}
				else
				{
					/*
					 * No extra dialing string was present so set the pointer
					 * to NULL.
					 */
					network_address_ptr->u.aggregated_channel_address.extra_dialing_string = NULL;
				}

				/*
				 * If the high layer compatibility structure exists, set the 
				 * pointer and write the data into memory.  Otherwise, set
				 * the "API" pointer to NULL.
				 */
				if (address_info->high_layer_compatibility != NULL)
				{
					network_address_ptr->u.aggregated_channel_address.high_layer_compatibility = 
							(PGCCHighLayerCompatibility)memory;

					*network_address_ptr->u.aggregated_channel_address.high_layer_compatibility =
                            *(address_info->high_layer_compatibility);

					/*
					 * Move the memory pointer past the high layer 
					 * compatibility structure.
					 */
					memory += ROUNDTOBOUNDARY(sizeof(GCCHighLayerCompatibility));
				}
				else
				{
					/*
					 * No high layer compatibility structure was present so 
					 * set the pointer to NULL.
					 */
					network_address_ptr->u.aggregated_channel_address.
							high_layer_compatibility = NULL;
				}
                break;

			/*
			 * The network address is a transport connection type.
			 */
            case GCC_TRANSPORT_CONNECTION_ADDRESS:
				network_address_ptr->network_address_type = GCC_TRANSPORT_CONNECTION_ADDRESS;

				/*
				 * Now copy the nsap address.
				 */		
                ::CopyMemory(network_address_ptr->u.transport_connection_address.nsap_address.value, 
							address_info->network_address.u.transport_connection_address.nsap_address.value, 
							address_info->network_address.u.transport_connection_address.nsap_address.length);

                network_address_ptr->u.transport_connection_address.nsap_address.length =
                            address_info->network_address.u.transport_connection_address.nsap_address.length; 

				/*
				 * If a transport selector exists, set the transport selector 
				 * pointer and write the data into memory.  Otherwise, set the
				 * "API" pointer to NULL.
				 */
				if (address_info->poszTransportSelector != NULL)
				{
					network_address_ptr->u.transport_connection_address.transport_selector = (LPOSTR) memory;

					/*
					 * Move the memory pointer past the OSTR 
					 * structure.  This is where the actual string data will 
					 * be written.
					 */
					memory += ROUNDTOBOUNDARY(sizeof(OSTR));

					network_address_ptr->u.transport_connection_address.
							transport_selector->value = (LPBYTE)memory;

					network_address_ptr->u.transport_connection_address.
							transport_selector->length =
								address_info->poszTransportSelector->length;

					/*
					 * Now copy the transport selector string data from the 
					 * internal Rogue Wave string into memory.
					 */		
					::CopyMemory(memory, address_info->poszTransportSelector->value,
								address_info->poszTransportSelector->length);

					/*
					 * Move the memory pointer past the transport selector
					 * string data.
					 */
					memory += ROUNDTOBOUNDARY(address_info->poszTransportSelector->length);
				}
				else
				{
					network_address_ptr->u.transport_connection_address.transport_selector = NULL;
				}
                break;

			/*
			 * The network address is a non-standard type.
			 */
            case GCC_NONSTANDARD_NETWORK_ADDRESS:
				network_address_ptr->network_address_type = GCC_NONSTANDARD_NETWORK_ADDRESS;

				/*
				 * Check to make sure both elements of the non-standard address
				 * exist in the internal structure.
				 */
				if ((address_info->poszNonStandardParam == NULL) ||
						(address_info->object_key == NULL))
				{
					ERROR_OUT(("CNetAddrListContainer::GetNetworkAddressListAPI: Bad internal pointer"));
					cbDataSizeToRet = 0;
				}
				else
				{
					data_length = address_info->object_key->
							GetGCCObjectKeyData( &network_address_ptr->u.
							non_standard_network_address.object_key, 
							memory);

					/*
					 * Move the memory pointer past the object key data.  This 
					 * is where the octet string data will be written.
					 */
					memory += data_length;

					network_address_ptr->u.non_standard_network_address.parameter_data.value = 
							memory;

					/*
					 * Write the octet string data into memory and set the octet 
					 * string structure pointer and length.
					 */
					network_address_ptr->u.non_standard_network_address.parameter_data.length = 
								(USHORT) address_info->poszNonStandardParam->length;

					/*
					 * Now copy the octet string data from the internal Rogue 
					 * Wave string into the object key structure held in memory.
					 */		
					::CopyMemory(memory, address_info->poszNonStandardParam->value,
								address_info->poszNonStandardParam->length);

					/*
					 * Move the memory pointer past the octet string data.
					 */
					memory += ROUNDTOBOUNDARY(address_info->poszNonStandardParam->length);
				}
                break;

            default:
                ERROR_OUT(("CNetAddrListContainer::GetNetworkAddressListAPI: Error Bad type."));
                break;
            } // switch
        } // while
	}
	else
	{
    	*network_address_list = NULL;
		*number_of_network_addresses = 0;
		ERROR_OUT(("CNetAddrListContainer::GetNetworkAddressListAPI: Error Data Not Locked"));
	}

	return cbDataSizeToRet;
}

/*
 *	UnLockNetworkAddressList ()
 *
 *	Public Function Description:
 *		This routine unlocks any memory which has been locked for the "API" 
 *		form of the network address list.  If the "Free" flag has been set then
 * 		the CNetAddrListContainer object will be destroyed.
 *
 */
void CNetAddrListContainer::
UnLockNetworkAddressList(void)
{
	/*
	 * If the lock count has reached zero, this object is "unlocked" so do
	 * some cleanup.
	 */
	if (Unlock(FALSE) == 0)
	{
		/*
		 * Unlock any memory locked for the CObjectKeyContainer objects in the
		 * internal NET_ADDR structures.
		 */
		NET_ADDR *pNetAddrInfo;
		m_NetAddrItemList.Reset();
		while (NULL != (pNetAddrInfo = m_NetAddrItemList.Iterate()))
		{
			if (pNetAddrInfo->object_key != NULL)
			{
				pNetAddrInfo->object_key->UnLockObjectKeyData();
			}
		}
	}

    // we have to call Release() because we used Unlock(FALSE)
    Release();
}
   

/*
 *	GetNetworkAddressListPDU ()
 *
 *	Public Function Description:
 *		This routine is used to retrieve the network address list in "PDU" form.
 */
GCCError CNetAddrListContainer::
GetNetworkAddressListPDU(PSetOfNetworkAddresses *set_of_network_addresses)
{
	GCCError					rc = GCC_NO_ERROR;
	PSetOfNetworkAddresses		new_pdu_network_address_ptr;
	PSetOfNetworkAddresses		old_pdu_network_address_ptr = NULL;

	/*
	 * If this is the first time that PDU data has been requested then we must
	 * fill in the internal PDU structure and copy it into the structure pointed
	 * to by the output parameter.  On subsequent calls to "GetPDU" we can just
	 * copy the internal PDU structure into the structure pointed to by the
	 * output parameter.
	 */
	if (m_fValidNetAddrPDU == FALSE)
	{
		m_fValidNetAddrPDU = TRUE;

		/*
		 * Initialize the output parameter to NULL so that the first time
		 * through it will be set equal to the first new set of network address
		 * data created in the iterator loop.
		 */
		m_pSetOfNetAddrPDU = NULL;
		
		/*
		 * Iterate through the list of NET_ADDR structures, 
		 * converting each into "PDU" form and saving the pointers in the 
		 * linked list of "SetsOfNetworkAddresses".
		 */
		NET_ADDR *pNetAddrInfo;
		m_NetAddrItemList.Reset();
		while (NULL != (pNetAddrInfo = m_NetAddrItemList.Iterate()))
		{
			/*
			 * If an allocation failure occurs, call the routine which will
			 * iterate through the list freeing any data which had been
			 * allocated.
			 */
			DBG_SAVE_FILE_LINE
			new_pdu_network_address_ptr = new SetOfNetworkAddresses;
			if (new_pdu_network_address_ptr == NULL)
			{
				ERROR_OUT(("CNetAddrListContainer::GetNetworkAddressListPDU: Allocation error, cleaning up"));
				rc = GCC_ALLOCATION_FAILURE;
				FreeNetworkAddressListPDU ();
				break;
			}

			/*
			 * The first time through, set the PDU structure pointer equal
			 * to the first SetOfNetworkAddresses created.  On subsequent loops,
			 * set the structure's "next" pointer equal to the new structure.
			 */
			if (m_pSetOfNetAddrPDU == NULL)
            {
				m_pSetOfNetAddrPDU = new_pdu_network_address_ptr;
            }
			else
            {
				old_pdu_network_address_ptr->next = new_pdu_network_address_ptr;
            }

			old_pdu_network_address_ptr = new_pdu_network_address_ptr;

			/*
			 * Initialize the new "next" pointer to NULL.
			 */
			new_pdu_network_address_ptr->next = NULL;

			/*
			 * Call the routine to actually convert the network address.
			 */
			if (ConvertNetworkAddressInfoToPDU(pNetAddrInfo, new_pdu_network_address_ptr) != GCC_NO_ERROR)
			{
				ERROR_OUT(("CNetAddrListContainer::GetNetworkAddressListPDU: can't create NET_ADDR to PDU"));
				rc = GCC_ALLOCATION_FAILURE;
				break;
			}
		}
	}

	/*
	 * Copy the internal PDU structure into the structure pointed to by the
	 * output parameter.
	 */
	*set_of_network_addresses = m_pSetOfNetAddrPDU;

	return rc;
}


/*
 *	FreeNetworkAddressListPDU ()
 *
 *	Public Function Description:
 *		This routine is used to free the memory allocated for the "PDU" form
 *		of the network address list.
 */
GCCError CNetAddrListContainer::
FreeNetworkAddressListPDU(void)
{
	GCCError						rc = GCC_NO_ERROR;
	PSetOfNetworkAddresses			pdu_network_address_set;
	PSetOfNetworkAddresses			next_pdu_network_address_set;

	if (m_fValidNetAddrPDU)
	{
		m_fValidNetAddrPDU = FALSE;

		pdu_network_address_set = m_pSetOfNetAddrPDU;

		/*
		 * Loop through the list, freeing the network address data associated 
		 * with each structure contained in the list. The only data allocated
		 * for the PDU which is not held in the internal info structure list
		 * is done by the CObjectKeyContainer object.  Those objects are told to free
		 * that data in the iterator loop below.
		 */
		while (pdu_network_address_set != NULL)
		{
			next_pdu_network_address_set = pdu_network_address_set->next;
			delete pdu_network_address_set;
			pdu_network_address_set = next_pdu_network_address_set;
		}

		/*
		 * Free any PDU memory allocated by the internal CObjectKeyContainer object.
		 */
		NET_ADDR *pNetAddrInfo;
		m_NetAddrItemList.Reset();
		while (NULL != (pNetAddrInfo = m_NetAddrItemList.Iterate()))
		{
			if (pNetAddrInfo->object_key != NULL)
            {
				pNetAddrInfo->object_key->FreeObjectKeyDataPDU();
            }
		}
	}
	else
	{
		ERROR_OUT(("NetAddressList::FreeUserDataListPDU: PDU Data not allocated"));
		rc = GCC_BAD_NETWORK_ADDRESS;
	}

	return (rc);
}

/*
 *	GCCError	StoreNetworkAddressList (	
 *						UINT					number_of_network_addresses,
 *						PGCCNetworkAddress 	*	local_network_address_list);
 *
 *	Private member function of CNetAddrListContainer.
 *
 *	Function Description:
 *		This routine is used to store the network address data passed in as
 *		"API" data in the internal structures.
 *
 *	Formal Parameters:
 *		number_of_network_addresses	(i)	Number of addresses in "API" list.
 *		local_network_address_list	(i) List of "API" addresses.
 *
 *	Return Value:
 *		GCC_NO_ERROR					-	No error.
 *		GCC_ALLOCATION_FAILURE			- 	Error creating an object using the
 *												"new" operator.
 *		GCC_BAD_NETWORK_ADDRESS			-	Invalid network address passed in.
 *		GCC_BAD_NETWORK_ADDRESS_TYPE	-	Bad "choice" field for address
 *
 *  Side Effects:
 *		None.
 *
 *	Caveats:
 *		None.
 */
GCCError CNetAddrListContainer::
StoreNetworkAddressList(UINT					number_of_network_addresses,
						PGCCNetworkAddress 	*	local_network_address_list)
{
	GCCError						rc;
	NET_ADDR				        *network_address_info;
	PGCCNetworkAddress				network_address;
	UINT							i;
	
	/*
	 * For each network address in the list, create a new "info" structure to 
	 * buffer the data internally.  Fill in the structure and save it in the
	 * Rogue Wave list.
	 */
	for (i = 0; i < number_of_network_addresses; i++)
	{
		DBG_SAVE_FILE_LINE
		if (NULL == (network_address_info = new NET_ADDR))
		{
            ERROR_OUT(("CNetAddrListContainer::StoreNetworkAddressList: can't create NET_ADDR"));
			rc = GCC_ALLOCATION_FAILURE;
            goto MyExit;
        }

		/*
		 * This variable is used for abbreviation.
		 */
		network_address = &network_address_info->network_address;
		
		/*
		 * Copy all the network address data into the network address
		 * structure that is part of the network address info structure.
		 */									
		*network_address = *local_network_address_list[i];
		
		/*
		 * This section of the code deals with any data embedded in the
		 * network address that would not have been copied in the above
		 * operation (typically pointers to strings).
		 */
		switch (network_address->network_address_type)
        {
        case GCC_AGGREGATED_CHANNEL_ADDRESS:
			/*
			 * Check to make sure the international number dialing string
			 * does not violate the imposed ASN.1 constraints.
			 */
			if (! IsDialingStringValid(local_network_address_list[i]->u.aggregated_channel_address.international_number))
			{
				ERROR_OUT(("CNetAddrListContainer::StoreNetworkAddressList: Invalid international number"));
				rc = GCC_BAD_NETWORK_ADDRESS;
				goto MyExit;
			}

			/*
			 * If a sub-address string exists, store it in a Rogue Wave
			 * container.  Set the  structure pointer to NULL if one does 
			 * not exist.
			 */
			if (local_network_address_list[i]->u.aggregated_channel_address.sub_address_string != NULL)
			{
				/*
				 * Check to make sure the sub address string does not 
				 * violate the imposed ASN.1 constraints.
				 */
				if (! IsCharacterStringValid(local_network_address_list[i]->u.aggregated_channel_address.sub_address_string))
				{
					ERROR_OUT(("CNetAddrListContainer::StoreNetworkAddressList: Invalid sub address string"));
					rc = GCC_BAD_NETWORK_ADDRESS;
					goto MyExit;
				}

				/*			
				 * Create a  string to hold the sub address.
				 */
				if (NULL == (network_address_info->pszSubAddress = ::My_strdupA(
								(LPSTR) local_network_address_list[i]->u.aggregated_channel_address.sub_address_string)))
				{
					ERROR_OUT(("CNetAddrListContainer::StoreNetworkAddressList: can't creating new sub address string"));
					rc = GCC_ALLOCATION_FAILURE;
                    goto MyExit;
				}
			}
			else
            {
				network_address_info->pszSubAddress = NULL;
            }

            /*
			 * If an extra dialing string exists, store it in a Unicode
			 * String object.  Set the  structure pointer to NULL if one 
			 * does not exist.
			 */
			if (local_network_address_list[i]->u.aggregated_channel_address.extra_dialing_string != NULL)
			{
				/*
				 * Check to make sure the extra dialing string does not 
				 * violate the imposed ASN.1 constraints.
				 */
				if (! IsExtraDialingStringValid(local_network_address_list[i]->u.aggregated_channel_address.extra_dialing_string))
				{
					ERROR_OUT(("CNetAddrListContainer::StoreNetworkAddressList: Invalid extra dialing string"));
					rc = GCC_BAD_NETWORK_ADDRESS;
					goto MyExit;
				}

				if (NULL == (network_address_info->pwszExtraDialing = ::My_strdupW2(
								local_network_address_list[i]->u.aggregated_channel_address.extra_dialing_string->length,
								local_network_address_list[i]->u.aggregated_channel_address.extra_dialing_string->value)))
				{
					ERROR_OUT(("CNetAddrListContainer::StoreNetworkAddressList: Error creating extra dialing string"));
					rc = GCC_ALLOCATION_FAILURE;
					goto MyExit;
				}
			}
			else
            {
				network_address_info->pwszExtraDialing = NULL;
            }

			/*
			 * If a higher layer compatibility structure exists, store it 
			 * in a GCCHighLayerCompatibility structure.  Set the structure
			 * pointer to NULL if one does not exist.
			 */
			if (local_network_address_list[i]->u.aggregated_channel_address.high_layer_compatibility != NULL)
			{
				DBG_SAVE_FILE_LINE
				network_address_info->high_layer_compatibility = new GCCHighLayerCompatibility;
				if (network_address_info->high_layer_compatibility != NULL)
				{
					/*
					 * Copy the high layer compatibility data to the
					 * new structure.
					 */
					*network_address_info->high_layer_compatibility =  
							*(local_network_address_list[i]->u.aggregated_channel_address.high_layer_compatibility);
				}
				else
				{
					ERROR_OUT(("CNetAddrListContainer::StoreNetworkAddressList: Error creating new GCCHighLayerCompatibility"));
					rc = GCC_ALLOCATION_FAILURE;
					goto MyExit;
				}
			}
			else
            {
				network_address_info->high_layer_compatibility = NULL;
            }
            break;

        case GCC_TRANSPORT_CONNECTION_ADDRESS:
			/*
			 * Check to make sure the length of the nsap address is within
			 * the allowable range.
			 */
			if ((local_network_address_list[i]->u.transport_connection_address.nsap_address.length < MINIMUM_NSAP_ADDRESS_SIZE)
                ||
				(local_network_address_list[i]->u.transport_connection_address.nsap_address.length > MAXIMUM_NSAP_ADDRESS_SIZE))
			{
				ERROR_OUT(("CNetAddrListContainer::StoreNetworkAddressList: Invalid nsap address"));
				rc = GCC_BAD_NETWORK_ADDRESS;
				goto MyExit;
			}

			/*
			 * If a transport selector exists, store it in a Rogue Wave 
			 * string.  Otherwise, set the structure pointer to NULL.
			 */
			if (local_network_address_list[i]->u.transport_connection_address.transport_selector != NULL)
			{
				/*			
				 * Create a Rogue Wave string to hold the transport
				 * selector string.
				 */
				if (NULL == (network_address_info->poszTransportSelector = ::My_strdupO2(
								local_network_address_list[i]->u.transport_connection_address.transport_selector->value,
						 		local_network_address_list[i]->u.transport_connection_address.transport_selector->length)))
				{
					ERROR_OUT(("CNetAddrListContainer::StoreNetworkAddressList: can't create transport selector"));
					rc = GCC_ALLOCATION_FAILURE;
                    goto MyExit;
				}
			}
			else
            {
				network_address_info->poszTransportSelector = NULL;
            }
            break;

        case GCC_NONSTANDARD_NETWORK_ADDRESS:
			/*			
			 * Create a Rogue Wave string to hold the non-standard
			 * parameter octet string.
			 */
			if (NULL == (network_address_info->poszNonStandardParam = ::My_strdupO2(
								local_network_address_list[i]->u.non_standard_network_address.parameter_data.value,
					 			local_network_address_list[i]->u.non_standard_network_address.parameter_data.length)))
			{
				ERROR_OUT(("CNetAddrListContainer::StoreNetworkAddressList: can't create non-standard param"));
				rc = GCC_ALLOCATION_FAILURE;
                goto MyExit;
			}
		
			/*
			 * Next store the object key internally in an CObjectKeyContainer
			 * object.
			 */
			DBG_SAVE_FILE_LINE
			network_address_info->object_key = new CObjectKeyContainer(
					&local_network_address_list[i]->u.non_standard_network_address.object_key,
					&rc);
			if (network_address_info->object_key == NULL || rc != GCC_NO_ERROR)
			{
				ERROR_OUT(("CNetAddrListContainer::StoreNetAddrList: Error creating new CObjectKeyContainer"));
				rc = GCC_ALLOCATION_FAILURE;
				goto MyExit;
			}
            break;

        default:
			ERROR_OUT(("CNetAddrListContainer::StoreNetAddrList: bad network address type=%u", (UINT) network_address->network_address_type));
			rc = GCC_BAD_NETWORK_ADDRESS_TYPE;
			goto MyExit;
		}

		/*
		 * If all data was properly saved, insert the "info" structure
		 * pointer into the Rogue Wave list.
		 */
		m_NetAddrItemList.Append(network_address_info);
	} // for

    rc = GCC_NO_ERROR;

MyExit:

    if (GCC_NO_ERROR != rc)
    {
        delete network_address_info;
    }

    return rc;
}

/*
 *	GCCError	ConvertPDUDataToInternal (	
 *						PSetOfNetworkAddresses			network_address_ptr)
 *
 *	Private member function of CNetAddrListContainer.
 *
 *	Function Description:
 *		This routine is used to store the network address data passed in as
 *		"PDU" data in the internal structures.
 *
 *	Formal Parameters:
 *		network_address_ptr	(i) 	"PDU" address list structure.
 *
 *	Return Value:
 *		GCC_NO_ERROR					-	No error.
 *		GCC_ALLOCATION_FAILURE			- 	Error creating an object using the
 *												"new" operator.
 *
 *  Side Effects:
 *		None.
 *
 *	Caveats:
 *		None.
 */
GCCError CNetAddrListContainer::
ConvertPDUDataToInternal(PSetOfNetworkAddresses network_address_ptr)
{
	GCCError					rc;
	GCCError					error_value;
	NET_ADDR    			    *network_address_info_ptr;
	PGCCNetworkAddress			copy_network_address;
	PNetworkAddress				pdu_network_address;

	/*
	 * Create a new info structure to hold the data internally.
	 */
	DBG_SAVE_FILE_LINE
	if (NULL == (network_address_info_ptr = new NET_ADDR))
	{
		ERROR_OUT(("CNetAddrListContainer::ConvertPDUDataToInternal: can't create NET_ADDR"));
		rc = GCC_ALLOCATION_FAILURE;
        goto MyExit;
	}

    /*
	 * Use these variables for clarity and brevity.
	 */
	copy_network_address = &network_address_info_ptr->network_address;
	pdu_network_address = &network_address_ptr->value; 

	/*
	 * Check to see what type of network address exists and save the data
	 * in the internal structures.
	 */
	switch (pdu_network_address->choice)
    {
    case AGGREGATED_CHANNEL_CHOSEN:
		copy_network_address->network_address_type = GCC_AGGREGATED_CHANNEL_ADDRESS;

		/*
		 * Save the tranfer modes structure.
		 */
		ConvertTransferModesToInternal(
				&pdu_network_address->u.aggregated_channel.transfer_modes,
				&copy_network_address->u.aggregated_channel_address.transfer_modes);
						
		/*
		 * Save the international number.
		 */
        ::lstrcpyA(copy_network_address->u.aggregated_channel_address.international_number,
					pdu_network_address->u.aggregated_channel.international_number);
						
		/*
		 * Save the sub address string (if it exists) in the Rogue Wave
		 * buffer contained in the network info structure.  Otherwise, set
		 * the structure pointer to NULL.
		 */
		if (pdu_network_address->u.aggregated_channel.bit_mask & SUB_ADDRESS_PRESENT)
		{
			/*			
			 * Create a Rogue Wave string to hold the sub address string.
			 */
			if (NULL == (network_address_info_ptr->pszSubAddress = ::My_strdupA(
								pdu_network_address->u.aggregated_channel.sub_address)))
			{
				ERROR_OUT(("CNetAddrListContainer::ConvertPDUDataToInternal: can't create sub address string"));
				rc = GCC_ALLOCATION_FAILURE;
                goto MyExit;
			}
		}
		else
		{
			/*
			 * The sub address string is not present so set the internal
			 * info structure pointer to NULL.
			 */
			network_address_info_ptr->pszSubAddress = NULL;
		}

		/*
		 * Next save the extra dialing string if one exists.
		 */
		if (pdu_network_address->u.aggregated_channel.bit_mask & EXTRA_DIALING_STRING_PRESENT)
		{
			if (NULL == (network_address_info_ptr->pwszExtraDialing = ::My_strdupW2(
							pdu_network_address->u.aggregated_channel.extra_dialing_string.length,
							pdu_network_address->u.aggregated_channel.extra_dialing_string.value)))
			{
				ERROR_OUT(("CNetAddrListContainer::ConvertPDUDataToInternal: Error creating extra dialing string"));
				rc = GCC_ALLOCATION_FAILURE;
                goto MyExit;
			}
		}
		else
		{
			/*
			 * The extra dialing string is not present so set the internal
			 * info structure pointer to NULL.
			 */
			network_address_info_ptr->pwszExtraDialing = NULL;
		}

		/*
		 * Save the high layer compatibility structure if it is present.
		 */
		if (pdu_network_address->u.aggregated_channel.bit_mask & HIGH_LAYER_COMPATIBILITY_PRESENT)
		{
			DBG_SAVE_FILE_LINE
			network_address_info_ptr->high_layer_compatibility = new GCCHighLayerCompatibility;
			if (network_address_info_ptr->high_layer_compatibility != NULL)
			{
				/*
				 * Copy the high layer compatibility data to the
				 * new structure.
				 */
				ConvertHighLayerCompatibilityToInternal(
						&pdu_network_address->u.aggregated_channel.high_layer_compatibility,
						network_address_info_ptr->high_layer_compatibility);
			}
			else
			{
				ERROR_OUT(("CNetAddrListContainer::ConvertPDUDataToInternal: Error creating new GCCHighLayerCompatibility"));
				rc = GCC_ALLOCATION_FAILURE;
                goto MyExit;
			}
		}
		else
		{
			/*
			 * The high layer compatibility structure is not present so set
			 * the internal	info structure pointer to NULL.
			 */
			network_address_info_ptr->high_layer_compatibility = NULL;
		}
        break;

    /*
     * Save the transport connection address.
     */
    case TRANSPORT_CONNECTION_CHOSEN:
	    copy_network_address->network_address_type = GCC_TRANSPORT_CONNECTION_ADDRESS;

	    /*
	     * Save the nsap address by copying the length and then the string.
	     */
	    copy_network_address->u.transport_connection_address.nsap_address.length =
                pdu_network_address->u.transport_connection.nsap_address.length;

        ::lstrcpyA((LPSTR)copy_network_address->u.transport_connection_address.nsap_address.value,
				    (LPSTR)pdu_network_address->u.transport_connection.nsap_address.value);
	    /*
	     * Save the transport selector if one exists.
	     */
	    if (pdu_network_address->u.transport_connection.bit_mask & TRANSPORT_SELECTOR_PRESENT)
	    {
		    /*			
		     * Create a Rogue Wave string to hold the transport
		     * selector string.
		     */
		    if (NULL == (network_address_info_ptr->poszTransportSelector = ::My_strdupO2(
						    pdu_network_address->u.transport_connection.transport_selector.value,
					 	    pdu_network_address->u.transport_connection.transport_selector.length)))
		    {
			    ERROR_OUT(("CNetAddrListContainer::ConvertPDUDataToInternal: can't create transport selector"));
			    rc = GCC_ALLOCATION_FAILURE;
                goto MyExit;
		    }
	    }
	    else
	    {
		    /*
		     * The transport selector is not present so set the internal
		     * info structure pointer to NULL.
		     */
		    network_address_info_ptr->poszTransportSelector = NULL;
	    }
        break;

    /*
     * Save the non standard address.
     */
    case ADDRESS_NON_STANDARD_CHOSEN:
	    copy_network_address->network_address_type = GCC_NONSTANDARD_NETWORK_ADDRESS;

	    /*			
	     * Create a Rogue Wave string to hold the non-standard
	     * parameter octet string.
	     */
	    if (NULL == (network_address_info_ptr->poszNonStandardParam = ::My_strdupO2(
						    pdu_network_address->u.address_non_standard.data.value,
				 		    pdu_network_address->u.address_non_standard.data.length)))
	    {
		    ERROR_OUT(("CNetAddrListContainer::ConvertPDUDataToInternal: can't create non-standard param"));
		    rc = GCC_ALLOCATION_FAILURE;
            goto MyExit;
	    }

	    /*
	     * Next store the object key internally in an CObjectKeyContainer
	     * object.
	     */
	    DBG_SAVE_FILE_LINE
	    network_address_info_ptr->object_key = new CObjectKeyContainer(
			    &pdu_network_address->u.address_non_standard.key,
			    &error_value);
	    if ((network_address_info_ptr->object_key == NULL) ||
			    (error_value != GCC_NO_ERROR))
	    {
		    ERROR_OUT(("CNetAddrListContainer::ConvertPDUDataToInternal: Error creating new CObjectKeyContainer"));
		    rc = GCC_ALLOCATION_FAILURE;
            goto MyExit;
	    }
        break;

    default:
        ERROR_OUT(("CNetAddrListContainer::ConvertPDUDataToInternal: Error bad network address type"));
        rc = GCC_ALLOCATION_FAILURE;
        goto MyExit;
    } // switch

    /*
	 * Go ahead and save the pointer to the info structure in the 
	 * internal Rogue Wave list.
	 */
	m_NetAddrItemList.Append(network_address_info_ptr);

    rc = GCC_NO_ERROR;

MyExit:

    if (GCC_NO_ERROR != rc)
    {
        delete network_address_info_ptr;
    }

	return rc;
}

/*
 * GCCError		ConvertNetworkAddressInfoToPDU (
 *						NET_ADDR    			    *network_address_info_ptr,
 *						PSetOfNetworkAddresses		network_address_pdu_ptr)
 *
 *	Private member function of CNetAddrListContainer.
 *
 *	Function Description:
 *		This routine is used to convert the network address info structures
 *		maintained internally into the "PDU" form which is a 
 *		SetOfNetworkAddresses.
 *
 *	Formal Parameters:
 *		network_address_info_ptr	(i) Internal network address structure.
 *		network_address_pdu_ptr		(o) PDU network address structure to fill in
 *
 *	Return Value:
 *		GCC_NO_ERROR					-	No error.
 *		GCC_ALLOCATION_FAILURE			- 	Error converting the network address
 *
 *  Side Effects:
 *		None.
 *
 *	Caveats:
 *		None.
 */
GCCError CNetAddrListContainer::
ConvertNetworkAddressInfoToPDU(NET_ADDR    			    *network_address_info_ptr,
                               PSetOfNetworkAddresses   network_address_pdu_ptr)
{
	GCCError				rc = GCC_NO_ERROR;
	PGCCNetworkAddress		api_ptr;
	PNetworkAddress			pdu_ptr;

	/*
	 * This variable will point to the "API" network address structure held in 
	 * the internal info structure.  It is used for brevity.
	 */
	api_ptr = &network_address_info_ptr->network_address;

	/*
	 * This variable will point to the "PDU" network address structure held in 
	 * the "SetOfNetworkAddresses" structure.  It is used for brevity.
	 */
	pdu_ptr = &network_address_pdu_ptr->value;

	/*
	 * Check to see what type of network address exists.  Fill in the
	 * appropriate form of the network address PDU structure.
	 */
	switch (api_ptr->network_address_type)
    {
    case GCC_AGGREGATED_CHANNEL_ADDRESS:
		/*
		 * Fill in the aggregated channel address PDU structure.
		 */
		pdu_ptr->choice = AGGREGATED_CHANNEL_CHOSEN;

		pdu_ptr->u.aggregated_channel.bit_mask = 0;

		/*
		 * Convert the structure holding the transfer modes into PDU form.
		 */
		ConvertTransferModesToPDU(&api_ptr->u.aggregated_channel_address.transfer_modes,
								  &pdu_ptr->u.aggregated_channel.transfer_modes);
		/*
		 * Copy the international number string.
		 */
        ::lstrcpyA(pdu_ptr->u.aggregated_channel.international_number,
				   api_ptr->u.aggregated_channel_address.international_number);

		/*
		 * Copy the sub-address string if it is present.  Set the bit mask in
		 * the PDU structure indicating that a sub-address string is present.
		 */
		if (network_address_info_ptr->pszSubAddress != NULL)
		{
			pdu_ptr->u.aggregated_channel.bit_mask |= SUB_ADDRESS_PRESENT;
            ::lstrcpyA((LPSTR) pdu_ptr->u.aggregated_channel.sub_address, 
					   network_address_info_ptr->pszSubAddress);
		}

		/* 
		 * Copy the extra dialing string if it is present.  Set the bit mask in
		 * the PDU structure indicating that an extra dialing string is present.
		 */
		if (network_address_info_ptr->pwszExtraDialing != NULL)
		{
			pdu_ptr->u.aggregated_channel.bit_mask |= EXTRA_DIALING_STRING_PRESENT;

			pdu_ptr->u.aggregated_channel.extra_dialing_string.value = 
					network_address_info_ptr->pwszExtraDialing;

			pdu_ptr->u.aggregated_channel.extra_dialing_string.length = 
					::lstrlenW(network_address_info_ptr->pwszExtraDialing);
		}

		/*
		 * Convert the structure holding the high layer compatibilities into 
		 * PDU form, if it is present.  Set the bit mask in	the PDU structure 
		 * indicating that a high layer compatibility structure is present.
		 */
		if (network_address_info_ptr->high_layer_compatibility != NULL)
		{
			pdu_ptr->u.aggregated_channel.bit_mask |= HIGH_LAYER_COMPATIBILITY_PRESENT;

			ConvertHighLayerCompatibilityToPDU(
					network_address_info_ptr->high_layer_compatibility,
					&pdu_ptr->u.aggregated_channel.high_layer_compatibility);
		}
        break;

    case GCC_TRANSPORT_CONNECTION_ADDRESS:
		/*
		 * Fill in the transport connection address PDU structure.
		 */
		pdu_ptr->choice = TRANSPORT_CONNECTION_CHOSEN;

		/*
		 * Copy the nsap_address.
		 */
		pdu_ptr->u.transport_connection.nsap_address.length = 
				api_ptr->u.transport_connection_address.nsap_address.length;
				
        ::lstrcpyA((LPSTR)pdu_ptr->u.transport_connection.nsap_address.value,
				   (LPSTR)api_ptr->u.transport_connection_address.nsap_address.value);
				
		/*
		 * Copy the transport selector if it is present.  Set the bit mask in
		 * the PDU structure indicating that a transport selector is present.
		 */
		if (network_address_info_ptr->poszTransportSelector != NULL)
		{
			pdu_ptr->u.transport_connection.bit_mask |= TRANSPORT_SELECTOR_PRESENT;

			pdu_ptr->u.transport_connection.transport_selector.length =
					network_address_info_ptr->poszTransportSelector->length;

			pdu_ptr->u.transport_connection.transport_selector.value = 
					(LPBYTE) network_address_info_ptr->poszTransportSelector->value;
		}
        break;

    case GCC_NONSTANDARD_NETWORK_ADDRESS:
		/*
		 * Fill in the non-standard network address PDU structure.
		 */
		pdu_ptr->choice = ADDRESS_NON_STANDARD_CHOSEN;

		/*
		 * Fill in the data portion of the non-standard parameter.
		 */
		pdu_ptr->u.address_non_standard.data.length = 
				network_address_info_ptr->poszNonStandardParam->length;

        pdu_ptr->u.address_non_standard.data.value = 
				network_address_info_ptr->poszNonStandardParam->value;

		/*
		 * Now fill in the object key portion of the non-standard parameter
		 * using the CObjectKeyContainer object stored internally in the network
		 * address info structure.
		 */
		rc = network_address_info_ptr->object_key->GetObjectKeyDataPDU(&pdu_ptr->u.address_non_standard.key);
		if (rc != GCC_NO_ERROR)
		{
			ERROR_OUT(("CNetAddrListContainer::ConvertNetworkAddressInfoToPDU: Error getting object key data PDU"));
		}
        break;

    default:
        /*
		 * The constructors will check to make sure a valid network address
		 * type exists so this should never be encountered.
		 */
		ERROR_OUT(("CNetAddrListContainer::ConvertNetworkAddressInfoToPDU: Error bad network address type"));
		rc = GCC_ALLOCATION_FAILURE;
	}

	return rc;
}

/*
 *	void		ConvertTransferModesToInternal (
 *						PTransferModes				source_transfer_modes,
 *						PGCCTransferModes			copy_transfer_modes)
 *
 *	Private member function of CNetAddrListContainer.
 *
 *	Function Description:
 *		This routine is used to convert the PDU network address transfer modes
 *		structure into the internal form where the structure is saved as a
 *		GCCTranferModes structure.
 *
 *	Formal Parameters:
 *		source_transfer_modes	(i)	Structure holding "PDU" transfer modes.
 *		copy_transfer_modes		(o) Structure to hold "API" transfer modes.
 *
 *	Return Value:
 *		None.
 *
 *  Side Effects:
 *		None.
 *
 *	Caveats:
 *		None.
 */
void CNetAddrListContainer::
ConvertTransferModesToInternal(PTransferModes       source_transfer_modes,
                               PGCCTransferModes    copy_transfer_modes)
{
	copy_transfer_modes->speech = (BOOL) source_transfer_modes->speech;
	copy_transfer_modes->voice_band = (BOOL) source_transfer_modes->voice_band;
	copy_transfer_modes->digital_56k = (BOOL) source_transfer_modes->digital_56k;
	copy_transfer_modes->digital_64k = (BOOL) source_transfer_modes->digital_64k;
	copy_transfer_modes->digital_128k = (BOOL) source_transfer_modes->digital_128k;
	copy_transfer_modes->digital_192k = (BOOL) source_transfer_modes->digital_192k;
	copy_transfer_modes->digital_256k = (BOOL) source_transfer_modes->digital_256k;
	copy_transfer_modes->digital_320k = (BOOL) source_transfer_modes->digital_320k;
	copy_transfer_modes->digital_384k = (BOOL) source_transfer_modes->digital_384k;
	copy_transfer_modes->digital_512k = (BOOL) source_transfer_modes->digital_512k;
	copy_transfer_modes->digital_768k = (BOOL) source_transfer_modes->digital_768k;
	copy_transfer_modes->digital_1152k = (BOOL) source_transfer_modes->digital_1152k;
	copy_transfer_modes->digital_1472k = (BOOL) source_transfer_modes->digital_1472k;
	copy_transfer_modes->digital_1536k = (BOOL) source_transfer_modes->digital_1536k;
	copy_transfer_modes->digital_1920k = (BOOL) source_transfer_modes->digital_1920k;
	copy_transfer_modes->packet_mode = (BOOL) source_transfer_modes->packet_mode;
	copy_transfer_modes->frame_mode = (BOOL) source_transfer_modes->frame_mode;
	copy_transfer_modes->atm = (BOOL) source_transfer_modes->atm;
}

/*
 *	void		ConvertHighLayerCompatibilityToInternal (
 *					PHighLayerCompatibility				source_structure,
 *					PGCCHighLayerCompatibility			copy_structure)
 *
 *	Private member function of CNetAddrListContainer.
 *
 *	Function Description:
 *		This routine is used to convert the PDU network address high layer
 *		compatibility structure into the internal form where the structure is 
 *		saved as a GCCHighLayerCompatibility structure.
 *
 *	Formal Parameters:
 *		source_structure		(i)	Structure holding "PDU" high layer 
 *										compatibilities.
 *		copy_structure			(o) Structure to hold "API" high layer 
 *										compatibilities.
 *
 *	Return Value:
 *		None.
 *
 *  Side Effects:
 *		None.
 *
 *	Caveats:
 *		None.
 */
void CNetAddrListContainer::
ConvertHighLayerCompatibilityToInternal(PHighLayerCompatibility     source_structure,
                                        PGCCHighLayerCompatibility  copy_structure)
{
	copy_structure->telephony3kHz = (BOOL) source_structure->telephony3kHz;
	copy_structure->telephony7kHz = (BOOL) source_structure->telephony7kHz;
	copy_structure->videotelephony = (BOOL) source_structure->videotelephony;
	copy_structure->videoconference = (BOOL) source_structure->videoconference;
	copy_structure->audiographic = (BOOL) source_structure->audiographic;
	copy_structure->audiovisual = (BOOL) source_structure->audiovisual;
	copy_structure->multimedia = (BOOL) source_structure->multimedia;
}

/*
 *	void		ConvertTransferModesToPDU (
 *					PGCCTransferModes					source_transfer_modes,
 *					PTransferModes						copy_transfer_modes)
 *
 *	Private member function of CNetAddrListContainer.
 *
 *	Function Description:
 *		This routine is used to convert the API network address transfer modes
 *		structure into the PDU form which is a TranferModes structure.
 *
 *	Formal Parameters:
 *		source_transfer_modes	(i)	Structure holding "API" transfer modes.
 *		copy_transfer_modes		(i) Structure holding "PDU" transfer modes.
 *
 *	Return Value:
 *		None.
 *
 *  Side Effects:
 *		None.
 *
 *	Caveats:
 *		None.
 */
void CNetAddrListContainer::
ConvertTransferModesToPDU(PGCCTransferModes     source_transfer_modes,
                          PTransferModes        copy_transfer_modes)
{
	copy_transfer_modes->speech = (ASN1bool_t) source_transfer_modes->speech;
	copy_transfer_modes->voice_band = (ASN1bool_t) source_transfer_modes->voice_band;
	copy_transfer_modes->digital_56k = (ASN1bool_t) source_transfer_modes->digital_56k;
	copy_transfer_modes->digital_64k = (ASN1bool_t) source_transfer_modes->digital_64k;
	copy_transfer_modes->digital_128k = (ASN1bool_t) source_transfer_modes->digital_128k;
	copy_transfer_modes->digital_192k = (ASN1bool_t) source_transfer_modes->digital_192k;
	copy_transfer_modes->digital_256k = (ASN1bool_t) source_transfer_modes->digital_256k;
	copy_transfer_modes->digital_320k = (ASN1bool_t) source_transfer_modes->digital_320k;
	copy_transfer_modes->digital_384k = (ASN1bool_t) source_transfer_modes->digital_384k;
	copy_transfer_modes->digital_512k = (ASN1bool_t) source_transfer_modes->digital_512k;
	copy_transfer_modes->digital_768k = (ASN1bool_t) source_transfer_modes->digital_768k;
	copy_transfer_modes->digital_1152k = (ASN1bool_t) source_transfer_modes->digital_1152k;
	copy_transfer_modes->digital_1472k = (ASN1bool_t) source_transfer_modes->digital_1472k;
	copy_transfer_modes->digital_1536k = (ASN1bool_t) source_transfer_modes->digital_1536k;
	copy_transfer_modes->digital_1920k = (ASN1bool_t) source_transfer_modes->digital_1920k;
	copy_transfer_modes->packet_mode = (ASN1bool_t) source_transfer_modes->packet_mode;
	copy_transfer_modes->frame_mode = (ASN1bool_t) source_transfer_modes->frame_mode;
	copy_transfer_modes->atm = (ASN1bool_t) source_transfer_modes->atm;
}

/*
 *	void		ConvertHighLayerCompatibilityToPDU (
 *					PGCCHighLayerCompatibility				source_structure,
 *					PHighLayerCompatibility					copy_structure)
 *
 *	Private member function of CNetAddrListContainer.
 *
 *	Function Description:
 *		This routine is used to convert the API network address high layer
 *		compatibility structure into the PDU form which is a 
 *		HighLayerCompatibility structure.
 *
 *	Formal Parameters:
 *		source_structure		(i)	Structure holding "API" high layer 
 *										compatibilities.
 *		copy_structure			(o) Structure to hold "PDU" high layer 
 *										compatibilities.
 *
 *	Return Value:
 *		None.
 *
 *  Side Effects:
 *		None.
 *
 *	Caveats:
 *		None.
 */
void CNetAddrListContainer::
ConvertHighLayerCompatibilityToPDU(PGCCHighLayerCompatibility   source_structure,
                                   PHighLayerCompatibility      copy_structure)
{
	copy_structure->telephony3kHz = (ASN1bool_t) source_structure->telephony3kHz;
	copy_structure->telephony7kHz = (ASN1bool_t) source_structure->telephony7kHz;
	copy_structure->videotelephony = (ASN1bool_t) source_structure->videotelephony;
	copy_structure->videoconference = (ASN1bool_t) source_structure->videoconference;
	copy_structure->audiographic = (ASN1bool_t) source_structure->audiographic;
	copy_structure->audiovisual = (ASN1bool_t) source_structure->audiovisual;
	copy_structure->multimedia = (ASN1bool_t) source_structure->multimedia;
}

/*
 *	BOOL    	IsDialingStringValid ( GCCDialingString		dialing_string)
 *
 *	Private member function of CNetAddrListContainer.
 *
 *	Function Description:
 *		This routine is used to ensure that the values held within a
 *		dialing string do not violate the imposed ASN.1 constraints.  The
 *		dialing string is constrained to be digits between 0 and 9, inclusive.
 *
 *	Formal Parameters:
 *		dialing_string		(i)	Dialing string to validate. 
 *
 *	Return Value:
 *		TRUE				- The string is valid.
 *		FALSE				- The string violates the ASN.1 constraints.
 *
 *  Side Effects:
 *		None.
 *
 *	Caveats:
 *		None.
 */
BOOL CNetAddrListContainer::
IsDialingStringValid(GCCDialingString dialing_string)
{
	BOOL fRet = TRUE;
	
	while (*dialing_string != 0)
	{
		if ((*dialing_string < '0') || (*dialing_string > '9'))
		{
			fRet = FALSE;
			break;
		}
		dialing_string++;
	}

	return fRet;
}

/*
 *	BOOL    	IsCharacterStringValid (
 *								GCCCharacterString			character_string)
 *
 *	Private member function of CNetAddrListContainer.
 *
 *	Function Description:
 *		This routine is used to ensure that the values held within a
 *		character string do not violate the imposed ASN.1 constraints.  The
 *		character string is constrained to be digits between 0 and 9, inclusive.
 *
 *	Formal Parameters:
 *		character_string		(i)	Character string to validate. 
 *
 *	Return Value:
 *		TRUE				- The string is valid.
 *		FALSE				- The string violates the ASN.1 constraints.
 *
 *  Side Effects:
 *		None.
 *
 *	Caveats:
 *		None.
 */
BOOL CNetAddrListContainer::
IsCharacterStringValid(GCCCharacterString character_string)
{
	BOOL fRet = TRUE;
	
	while (*character_string != 0)
	{
		if ((*character_string < '0') || (*character_string > '9'))
		{
			fRet = FALSE;
			break;
		}
	
		character_string++;
	}
	
	return fRet;
}

/*
 *	BOOL    	IsExtraDialingStringValid (
 *							PGCCExtraDialingString		extra_dialing_string)
 *
 *	Private member function of CNetAddrListContainer.
 *
 *	Function Description:
 *		This routine is used to ensure that the values held within an
 *		extra dialing string do not violate the imposed ASN.1 constraints.
 *
 *	Formal Parameters:
 *		extra_dialing_string		(i)	Dialing string to validate. 
 *
 *	Return Value:
 *		TRUE				- The string is valid.
 *		FALSE				- The string violates the ASN.1 constraints.
 *
 *  Side Effects:
 *		None.
 *
 *	Caveats:
 *		None.
 */
BOOL CNetAddrListContainer::
IsExtraDialingStringValid(PGCCExtraDialingString extra_dialing_string)
{
	BOOL fRet = TRUE;

	/*
	 * Check to make sure the length of the string is within the
	 * allowable range.
	 */
	if ((extra_dialing_string->length < MINIMUM_EXTRA_DIALING_STRING_SIZE) || 
		(extra_dialing_string->length > MAXIMUM_EXTRA_DIALING_STRING_SIZE))
	{
		fRet = FALSE;
	}
    else
    {
	    /*
	     * If the length is valid, check the string values.
	     */
    	LPWSTR pwsz = extra_dialing_string->value;
		for (USHORT i = 0; i < extra_dialing_string->length; i++)
		{
			if ((*pwsz != '#') && (*pwsz != '*') && (*pwsz != ','))
			{
				if ((*pwsz < '0') || (*pwsz > '9'))
				{
					fRet = FALSE;
					break;
				}
			}
		
			pwsz++;
		}
	}

	return fRet;
}