windows-nt/Source/XPSP1/NT/enduser/netmeeting/t120/mst120/arost.cpp
2020-09-26 16:20:57 +08:00

4513 lines
122 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "precomp.h"
DEBUG_FILEZONE(ZONE_T120_APP_ROSTER);
/*
* arost.cpp
*
* Copyright (c) 1995 by DataBeam Corporation, Lexington, KY
*
* Abstract:
* This is the implementation file for the Application Roster Class. This
* class maintains the application roster, builds roster update and
* refresh PDUs and manages the capabilities list which is part of the
* application roster.
*
* This class makes use of a number of Rogue Wave lists to maintain the
* roster entries and the capabilities list. The lists are organized in
* such a way that the heirarchy of the conference can be maintained. This
* is important to perform the necessary operations required by the T.124
* specification. In general, there is a main "Roster_Record_List" that
* maintains a list of "AppRosterRecords". The list is indexed by the
* GCC user ID where each record in the list holds a list of application
* records (or entities) at that node, a list of capabilities for each
* "entity" and a list of sub-nodes (the GCC user IDs of all the nodes
* below this one in the connection hierarchy). The Roster_Record_List
* only holds entries for immediately connected nodes.
*
* SEE INTERFACE FILE FOR A MORE DETAILED ABSTRACT
*
* Private Instance Variables:
* m_pAppRosterMgr
* Pointer to the object that will receive all owner callbacks.
* m_cbDataMemory
* This is the number of bytes required to hold the data associated
* with a roster update message. This is calculated on a lock.
* m_fTopProvider
* Flag indicating if the node where this roster lives is the top
* provider.
* m_fLocalRoster
* Flag indicating if the roster data is associated with a local
* roster (maintaining intermediate node data) or global roster (
* (maintaining roster data for the whole conference).
* m_pSessionKey
* Pointer to a session key object that holds the session key
* associated with this roster.
* m_nInstance
* The current instance of the roster. This number will change
* whenever the roster is updated.
* m_fRosterHasChanged
* Flag indicating if the roster has changed since the last reset.
* m_fPeerEntitiesAdded
* Flag indicating if any APE records have been added to the
* application roster since the last reset.
* m_fPeerEntitiesRemoved
* Flag indicating if any APE records have been deleted from the
* application roster since the last reset.
* m_fCapabilitiesHaveChanged
* Flag indicating if the capabilities has changed since the last
* reset.
* m_NodeRecordList2
* List which contains all the application roster's node records.
* m_CollapsedCapListForAllNodes
* List which contains all the application roster's collapsed
* capabilities.
* m_fMaintainPduBuffer
* Flag indicating if it is necessary for this roster object to
* maintain internal PDU data. Won't be necessary for global rosters
* at subordinate nodes.
* m_fPduIsFlushed
* Flag indicating if the PDU that currently exists has been flushed.
* m_SetOfAppInfo
* Pointer to internal PDU data.
* m_pSetOfAppRecordUpdates
* This instance variable keeps up with the current record update so
* that it will not be necessary to search the entire list updates
* each a new update is added to the internal PDU.
*
* Caveats:
* None.
*
* Author:
* blp
*/
#include "arost.h"
#include "arostmgr.h"
#include "clists.h"
/*
** The maximum length the application data for a non-collapsed capablity
** can be.
*/
#define MAXIMUM_APPLICATION_DATA_LENGTH 255
/*
* AppRosterRecord ()
*
* Public Function Description
* Constructor definition to instantiate the hash list dictionaries that
* are used in an AppRosterRecord. This constructor is needed to allow
* the AppRosterRecord structure to be directly instantiated with hash
* list.
*/
APP_NODE_RECORD::APP_NODE_RECORD(void) :
AppRecordList(DESIRED_MAX_APP_RECORDS),
ListOfAppCapItemList2(DESIRED_MAX_CAP_LISTS),
SubNodeList2(DESIRED_MAX_NODES)
{}
/*
* CAppRoster ()
*
* Public Function Description
* When pGccSessKey is not NULL
* This constructor is used to create an empty application roster. Note
* that the session key for the roster must be passed in to the
* constructor.
*
* When pSessKey is not NULL
* This constructor builds a roster based on an indication pdu.
* Application Roster objects may exist at nodes which do not have
* applications to perform the necessary operations required by T.124
*/
CAppRoster::CAppRoster (
PGCCSessionKey pGccSessKey,// create an empty app roster
PSessionKey pPduSessKey,// build an app roster based on an indication pdu
CAppRosterMgr *pAppRosterMgr,
BOOL fTopProvider,
BOOL fLocalRoster,
BOOL fMaintainPduBuffer,
PGCCError pRetCode)
:
CRefCount(MAKE_STAMP_ID('A','R','s','t')),
m_nInstance(0),
m_pAppRosterMgr(pAppRosterMgr),
m_cbDataMemory(0),
m_fTopProvider(fTopProvider),
m_fLocalRoster(fLocalRoster),
m_pSessionKey(NULL),
m_fRosterHasChanged(FALSE),
m_fPeerEntitiesAdded(FALSE),
m_fPeerEntitiesRemoved(FALSE),
m_fCapabilitiesHaveChanged(FALSE),
m_NodeRecordList2(DESIRED_MAX_NODES),
m_fMaintainPduBuffer(fMaintainPduBuffer),
m_fPduIsFlushed(FALSE),
m_pSetOfAppRecordUpdates(NULL)
{
DebugEntry(CAppRoster::CAppRoster);
GCCError rc = GCC_NO_ERROR;
ZeroMemory(&m_SetOfAppInfo, sizeof(m_SetOfAppInfo));
/*
** Here we store the session key of the roster.
*/
if (NULL != pGccSessKey)
{
ASSERT(NULL == pPduSessKey);
DBG_SAVE_FILE_LINE
m_pSessionKey = new CSessKeyContainer(pGccSessKey, &rc);
}
else
if (NULL != pPduSessKey)
{
DBG_SAVE_FILE_LINE
m_pSessionKey = new CSessKeyContainer(pPduSessKey, &rc);
}
else
{
ERROR_OUT(("CAppRoster::CAppRoster: invalid session key"));
rc = GCC_BAD_SESSION_KEY;
goto MyExit;
}
if (NULL == m_pSessionKey || GCC_NO_ERROR != rc)
{
ERROR_OUT(("CAppRoster::CAppRoster: can't create session key"));
rc = GCC_ALLOCATION_FAILURE;
// we do the cleanup in the destructor
goto MyExit;
}
// Initialize the PDU structure to be no change.
m_SetOfAppInfo.value.application_record_list.choice = APPLICATION_NO_CHANGE_CHOSEN;
m_SetOfAppInfo.value.application_capabilities_list.choice = CAPABILITY_NO_CHANGE_CHOSEN;
/*
** Here we go ahead and set up the session key portion of the
** PDU so we don't have to worry about it later.
*/
if (m_fMaintainPduBuffer)
{
rc = m_pSessionKey->GetSessionKeyDataPDU(&m_SetOfAppInfo.value.session_key);
}
ASSERT(GCC_NO_ERROR == rc);
MyExit:
DebugExitINT(CAppRoster:;CAppRoster, rc);
*pRetCode = rc;
}
/*
* ~CAppRoster ()
*
* Public Function Description:
* The destructor for the CAppRoster class is used to clean up
* any memory allocated during the life of the object.
*/
CAppRoster::~CAppRoster(void)
{
/*
* Free up all memory associated with the roster record list.
*/
ClearNodeRecordList();
// Clear the Collapsed Capabilities List.
m_CollapsedCapListForAllNodes.DeleteList();
/*
* Free up any outstanding PDU data.
*/
if (m_fMaintainPduBuffer)
{
FreeRosterUpdateIndicationPDU();
}
/*
* Free any memory associated with the session key..
*/
if (NULL != m_pSessionKey)
{
m_pSessionKey->Release();
}
}
/*
* Utilities that operate on roster update PDU strucutures.
*/
/*
* GCCError FlushRosterUpdateIndicationPDU ()
*
* Public Function Description
* This routine is used to access any PDU data that might currently be
* queued inside the application roster. PDU data is queued whenever
* a request is made to the application roster that affects its
* internal information base.
*/
void CAppRoster::FlushRosterUpdateIndicationPDU(PSetOfApplicationInformation *pSetOfAppInfo)
{
DebugEntry(CAppRoster::FlushRosterUpdateIndicationPDU);
/*
** If this roster has already been flushed we will NOT allow the same
** PDU to be flushed again. Instead we delete the previously flushed
** PDU and set the flag back to unflushed. If another flush comes in
** before a PDU is built NULL will be returned in the application
** information pointer.
*/
if (m_fPduIsFlushed)
{
FreeRosterUpdateIndicationPDU();
m_fPduIsFlushed = FALSE;
}
if ((m_SetOfAppInfo.value.application_record_list.choice != APPLICATION_NO_CHANGE_CHOSEN) ||
(m_SetOfAppInfo.value.application_capabilities_list.choice != CAPABILITY_NO_CHANGE_CHOSEN))
{
if (m_SetOfAppInfo.value.application_record_list.choice == APPLICATION_NO_CHANGE_CHOSEN)
{
TRACE_OUT(("CAppRoster::FlushRosterUpdateIndicationPDU:"
"Sending APPLICATION_NO_CHANGE_CHOSEN PDU"));
}
/*
** This section of the code sets up all the variables that don't
** pertain to the record list or the caps list. Note that the
** session key PDU data was set up in the constructor. Also note that
** the record list data and capabilities list data should be set up
** before this routine is called if there is any PDU traffic to issue.
*/
m_SetOfAppInfo.next = NULL;
m_SetOfAppInfo.value.roster_instance_number = (USHORT) m_nInstance;
m_SetOfAppInfo.value.peer_entities_are_added = (ASN1bool_t)m_fPeerEntitiesAdded;
m_SetOfAppInfo.value.peer_entities_are_removed = (ASN1bool_t)m_fPeerEntitiesRemoved;
/*
** Here we set up the pointer to the whole PDU structure associated
** with this application roster.
*/
*pSetOfAppInfo = &m_SetOfAppInfo;
/*
** Setting this to true will cause the PDU data to be freed up the
** next time the roster object is entered insuring that new PDU
** data will be created.
*/
m_fPduIsFlushed = TRUE;
}
else
{
*pSetOfAppInfo = NULL;
}
}
/*
* GCCError BuildFullRefreshPDU ()
*
* Public Function Description
* This routine is responsible for generating a full application roster
* refresh PDU.
*/
GCCError CAppRoster::BuildFullRefreshPDU(void)
{
GCCError rc;
DebugEntry(CAppRoster::BuildFullRefreshPDU);
/*
** Free up the old PDU data here if it is being maintained and the
** PDU has been flushed. Note that we also set the PDU is flushed boolean
** back to FALSE so that the new PDU will be maintained until it is
** flushed.
*/
if (m_fPduIsFlushed)
{
FreeRosterUpdateIndicationPDU ();
m_fPduIsFlushed = FALSE;
}
rc = BuildApplicationRecordListPDU (APP_FULL_REFRESH, 0, 0);
if (rc == GCC_NO_ERROR)
{
BuildSetOfCapabilityRefreshesPDU ();
}
return rc;
}
/*
* GCCError BuildApplicationRecordListPDU ()
*
* Private Function Description
* This routine creates an application roster update indication
* PDU based on the passed in parameters. Memory used after this
* routine is called is still owned by this object and will be
* freed the next time this objects internal information base is
* modified.
*
* Formal Parameters:
* update_type - What type of update are we building.
* user_id - node id of record to update.
* entity_id - entity id of record to update.
*
* Return Value
* GCC_NO_ERROR - No error occured.
* GCC_INVALID_PARAMETER - Parameter passed in is invalid.
* GCC_ALLOCATION_FAILURE - A resource error occured.
*
* Side Effects
* None.
*
* Caveats
* None.
*/
GCCError CAppRoster::BuildApplicationRecordListPDU (
APP_ROSTER_UPDATE_TYPE update_type,
UserID user_id,
EntityID entity_id)
{
GCCError rc = GCC_NO_ERROR;
DebugEntry(CAppRoster::BuildApplicationRecordListPDU);
if (m_fMaintainPduBuffer)
{
/*
** Note here that the top provider node always sends a full refresh
** PDU so there is no need to pay any attention to update type in
** this case.
*/
if ((update_type == APP_FULL_REFRESH) || m_fTopProvider)
{
/*
** First check to see if a refresh was already processed since the
** last PDU was flushed. If so we must free up the last refresh in
** preperation for the new one built here. Otherwise, if we have
** already started building an update this is not currently
** supported and is considered an error here.
*/
if (m_SetOfAppInfo.value.application_record_list.choice == APPLICATION_RECORD_REFRESH_CHOSEN)
{
FreeSetOfRefreshesPDU();
}
else
if (m_SetOfAppInfo.value.application_record_list.choice == APPLICATION_RECORD_UPDATE_CHOSEN)
{
ERROR_OUT(("CAppRoster::BuildApplicationRecordListPDU:"
"ASSERTION: building refresh when update exists"));
return GCC_INVALID_PARAMETER;
}
// This routine fills in the complete record list at this node.
rc = BuildSetOfRefreshesPDU();
if (rc == GCC_NO_ERROR)
{
m_SetOfAppInfo.value.application_record_list.choice = APPLICATION_RECORD_REFRESH_CHOSEN;
}
}
else
if (update_type != APP_NO_CHANGE)
{
/*
** Here if there has already been a refresh PDU built we flag this
** as an error since we do not support both types of application
** information at the same time.
*/
if (m_SetOfAppInfo.value.application_record_list.choice == APPLICATION_RECORD_REFRESH_CHOSEN)
{
ERROR_OUT(("CAppRoster::BuildApplicationRecordListPDU:"
"ASSERTION: building update when refresh exists"));
return GCC_INVALID_PARAMETER;
}
// This routine fills in the specified update.
rc = BuildSetOfUpdatesPDU(update_type, user_id, entity_id);
if (rc == GCC_NO_ERROR)
{
/*
** If the first set of updates has not been used yet we
** initialize it here with the first update.
*/
if (m_SetOfAppInfo.value.application_record_list.choice == APPLICATION_NO_CHANGE_CHOSEN)
{
ASSERT(NULL != m_pSetOfAppRecordUpdates);
m_SetOfAppInfo.value.application_record_list.u.application_record_update =
m_pSetOfAppRecordUpdates;
m_SetOfAppInfo.value.application_record_list.choice = APPLICATION_RECORD_UPDATE_CHOSEN;
}
}
}
}
return rc;
}
/*
* GCCError BuildSetOfRefreshesPDU ()
*
* Private Function Description
* This member function fills in the PDU with the entire set of roster
* entries at this node. This is typically called when the Top Provider is
* broadcasting a full refresh of the application roster.
*
* Formal Parameters
* none
*
* Return Value
* GCC_NO_ERROR - On Success
* GCC_ALLOCATION_FAILURE - On resource failure
*
* Side Effects
* none
*
* Caveats
* none
*/
GCCError CAppRoster::BuildSetOfRefreshesPDU(void)
{
GCCError rc = GCC_ALLOCATION_FAILURE;
PSetOfApplicationRecordRefreshes pNewAppRecordRefreshes;
PSetOfApplicationRecordRefreshes pOldAppRecordRefreshes = NULL;
APP_NODE_RECORD *lpAppNodeRecord;
APP_RECORD *lpAppRecData;
CAppRecordList2 *lpAppRecDataList;
UserID uid, uid2;
EntityID eid;
DebugEntry(CAppRoster::BuildSetOfRefreshesPDU);
m_SetOfAppInfo.value.application_record_list.u.application_record_refresh = NULL;
m_NodeRecordList2.Reset();
while (NULL != (lpAppNodeRecord = m_NodeRecordList2.Iterate(&uid)))
{
/*
** First we iterate through this nodes application record list. This
** encodes all the records local to this node. After this, all the
** sub nodes within this roster record will be encoded.
*/
lpAppNodeRecord->AppRecordList.Reset();
while (NULL != (lpAppRecData = lpAppNodeRecord->AppRecordList.Iterate(&eid)))
{
DBG_SAVE_FILE_LINE
pNewAppRecordRefreshes = new SetOfApplicationRecordRefreshes;
if (NULL == pNewAppRecordRefreshes)
{
goto MyExit;
}
if (m_SetOfAppInfo.value.application_record_list.u.application_record_refresh == NULL)
{
m_SetOfAppInfo.value.application_record_list.u.application_record_refresh = pNewAppRecordRefreshes;
}
else
{
pOldAppRecordRefreshes->next = pNewAppRecordRefreshes;
}
(pOldAppRecordRefreshes = pNewAppRecordRefreshes)->next = NULL;
pNewAppRecordRefreshes->value.node_id = uid;
pNewAppRecordRefreshes->value.entity_id = eid;
// Fill in the application record.
rc = BuildApplicationRecordPDU(lpAppRecData,
&pNewAppRecordRefreshes->value.application_record);
if (GCC_NO_ERROR != rc)
{
goto MyExit;
}
}
// This section of the code copies the sub node records.
lpAppNodeRecord->SubNodeList2.Reset();
while (NULL != (lpAppRecDataList = lpAppNodeRecord->SubNodeList2.Iterate(&uid2)))
{
lpAppRecDataList->Reset();
while (NULL != (lpAppRecData = lpAppRecDataList->Iterate(&eid)))
{
DBG_SAVE_FILE_LINE
pNewAppRecordRefreshes = new SetOfApplicationRecordRefreshes;
if (NULL == pNewAppRecordRefreshes)
{
goto MyExit;
}
/*
** We must again check for null because it is possible
** to have an application roster with sub node records
** but no application records.
*/
if (m_SetOfAppInfo.value.application_record_list.u.application_record_refresh == NULL)
{
m_SetOfAppInfo.value.application_record_list.u.application_record_refresh = pNewAppRecordRefreshes;
}
else
{
pOldAppRecordRefreshes->next = pNewAppRecordRefreshes;
}
(pOldAppRecordRefreshes = pNewAppRecordRefreshes)->next = NULL;
pNewAppRecordRefreshes->value.node_id = uid2;
pNewAppRecordRefreshes->value.entity_id = eid;
// Fill in the application record.
rc = BuildApplicationRecordPDU (lpAppRecData,
&pNewAppRecordRefreshes->value.application_record);
if (GCC_NO_ERROR != rc)
{
goto MyExit;
}
}
}
}
rc = GCC_NO_ERROR;
MyExit:
return rc;
}
/*
* GCCError BuildSetOfUpdatesPDU ()
*
* Private Function Description
* This routine builds a single update based on the update type specified
* in the passed in parameter.
*
* Formal Parameters
* update_type - (i) Either APP_REPLACE_RECORD, APP_DELETE_RECORD, or
* APP_ADD_RECORD.
* node_id - (i) The node id of the update PDU record to build.
* entity_id (i) The entity id of the update PDU record to build.
*
* Return Value
* GCC_NO_ERROR - On Success
* GCC_ALLOCATION_FAILURE - On resource failure
* GCC_NO_SUCH_APPLICATION - If the specified record doesn't exist
*
* Side Effects
* none
*
* Caveats
* none
*/
GCCError CAppRoster::BuildSetOfUpdatesPDU(
APP_ROSTER_UPDATE_TYPE update_type,
UserID node_id,
EntityID entity_id)
{
GCCError rc = GCC_NO_ERROR;
CAppRecordList2 *pAppRecordList;
APP_RECORD *pAppRecord = NULL;
APP_NODE_RECORD *node_record;
DebugEntry(CAppRoster::BuildSetOfUpdatesPDU);
/*
** We must first determine the pointer to the application record
** specified by the passed in user id and entity_id. We only do
** this search if the update type is not APP_DELETE_RECORD.
*/
if (update_type != APP_DELETE_RECORD)
{
if (NULL != (node_record = m_NodeRecordList2.Find(node_id)))
{
// Get a pointer to the application record from the entity id.
pAppRecord = node_record->AppRecordList.Find(entity_id);
}
else
{
// Here we iterate through the sub-node list looking for the record
m_NodeRecordList2.Reset();
while(NULL != (node_record = m_NodeRecordList2.Iterate()))
{
if (NULL != (pAppRecordList = node_record->SubNodeList2.Find(node_id)))
{
pAppRecord = pAppRecordList->Find(entity_id);
break;
}
}
}
}
/*
** Now if the application record was found or the update type is delete
** record we go ahead and encode the PDU here.
*/
if ((pAppRecord != NULL) || (update_type == APP_DELETE_RECORD))
{
/*
** Here the record update will be NULL if it is the first record
** update being encoded. Otherwise we must bump the record to the
** next set of updates.
*/
DBG_SAVE_FILE_LINE
PSetOfApplicationRecordUpdates pUpdates = new SetOfApplicationRecordUpdates;
if (NULL == pUpdates)
{
return GCC_ALLOCATION_FAILURE;
}
pUpdates->next = NULL;
if (m_pSetOfAppRecordUpdates == NULL)
{
m_pSetOfAppRecordUpdates = pUpdates;
}
else
{
//
// LONCHANC: right now, append the new one.
// but, can we prepend the new one???
//
PSetOfApplicationRecordUpdates p;
for (p = m_pSetOfAppRecordUpdates; NULL != p->next; p = p->next)
;
p->next = pUpdates;
}
/*
* This routine only returns one record.
*/
pUpdates->value.node_id = node_id;
pUpdates->value.entity_id = entity_id;
switch (update_type)
{
case APP_ADD_RECORD:
pUpdates->value.application_update.choice = APPLICATION_ADD_RECORD_CHOSEN;
BuildApplicationRecordPDU(pAppRecord,
&(pUpdates->value.application_update.u.application_add_record));
break;
case APP_REPLACE_RECORD:
pUpdates->value.application_update.choice = APPLICATION_REPLACE_RECORD_CHOSEN;
rc = BuildApplicationRecordPDU(pAppRecord,
&(pUpdates->value.application_update.u.application_replace_record));
break;
default:
/*
* The record does not have to be filled in for this case.
*/
pUpdates->value.application_update.choice = APPLICATION_REMOVE_RECORD_CHOSEN;
break;
}
}
else
{
WARNING_OUT(("CAppRoster::BuildSetOfUpdatesPDU: Assertion:"
"No applicaton record found for PDU"));
rc = GCC_NO_SUCH_APPLICATION;
}
return rc;
}
/*
* GCCError BuildApplicationRecordPDU ()
*
* Private Function Description
* This routine build a single application record for a PDU. A pointer to
* the record is passed in to the routine.
*
* Formal Parameters
* application_record - (i) Record to be encoded.
* application_record_pdu - (i) PDU to fill in.
*
* Return Value
* GCC_NO_ERROR - On Success
* GCC_ALLOCATION_FAILURE - A resource error occured.
*
* Side Effects
* none
*
* Caveats
* none
*/
GCCError CAppRoster::BuildApplicationRecordPDU(
APP_RECORD *pAppRecord,
PApplicationRecord pAppRecordPdu)
{
GCCError rc = GCC_NO_ERROR;
DebugEntry(CAppRoster::BuildApplicationRecordPDU);
pAppRecordPdu->bit_mask = 0;
if (! pAppRecord->non_collapsed_caps_list.IsEmpty())
{
pAppRecordPdu->bit_mask |= NON_COLLAPSING_CAPABILITIES_PRESENT;
rc = BuildSetOfNonCollapsingCapabilitiesPDU(
&pAppRecordPdu->non_collapsing_capabilities,
&pAppRecord->non_collapsed_caps_list);
if (GCC_NO_ERROR != rc)
{
goto MyExit;
}
}
// Fill in the startup channel type if it is specified
if (pAppRecord->startup_channel_type != MCS_NO_CHANNEL_TYPE_SPECIFIED)
{
pAppRecordPdu->bit_mask |= RECORD_STARTUP_CHANNEL_PRESENT;
pAppRecordPdu->record_startup_channel = (ChannelType) pAppRecord->startup_channel_type;
}
// Fill in the application user id if one is specified
if (pAppRecord->application_user_id != 0)
{
pAppRecordPdu->bit_mask |= APPLICATION_USER_ID_PRESENT;
pAppRecordPdu->application_user_id = pAppRecord->application_user_id;
}
// Fill in the required fields
pAppRecordPdu->application_is_active = (ASN1bool_t)pAppRecord->is_enrolled_actively;
pAppRecordPdu->is_conducting_capable = (ASN1bool_t)pAppRecord->is_conducting_capable;
ASSERT(GCC_NO_ERROR == rc);
MyExit:
return rc;
}
/*
* GCCError BuildSetOfCapabilityRefreshesPDU ()
*
* Private Function Description
* This routine builds a PDU structure with the complete set of
* capabilities maintained at this node.
*
* Formal Parameters
* None
*
* Return Value
* GCC_NO_ERROR - On Success
* GCC_ALLOCATIONFAILURE - On resource failure
*
* Side Effects
* None
*
* Caveats
* The standard allows us to send a zero length set of capabilities when
* an application leaves that previously had capabilites.
*/
GCCError CAppRoster::BuildSetOfCapabilityRefreshesPDU(void)
{
GCCError rc = GCC_ALLOCATION_FAILURE;
PSetOfApplicationCapabilityRefreshes pNew;
PSetOfApplicationCapabilityRefreshes pOld = NULL;
DebugEntry(CAppRoster::BuildSetOfCapabilityRefreshesPDU);
if (m_fMaintainPduBuffer)
{
APP_CAP_ITEM *lpAppCapData;
/*
** We must first free up any previously built PDU data associated
** with a capability refresh.
*/
if (m_SetOfAppInfo.value.application_capabilities_list.choice == APPLICATION_CAPABILITY_REFRESH_CHOSEN)
{
FreeSetOfCapabilityRefreshesPDU ();
}
m_SetOfAppInfo.value.application_capabilities_list.choice = APPLICATION_CAPABILITY_REFRESH_CHOSEN;
m_SetOfAppInfo.value.application_capabilities_list.u.application_capability_refresh = NULL;
// Iterate through the complete list of capabilities.
m_CollapsedCapListForAllNodes.Reset();
while (NULL != (lpAppCapData = m_CollapsedCapListForAllNodes.Iterate()))
{
DBG_SAVE_FILE_LINE
pNew = new SetOfApplicationCapabilityRefreshes;
if (NULL == pNew)
{
goto MyExit;
}
/*
** If the set of capability refreshes pointer is equal to NULL
** we are at the first capability. Here we need to save the
** pointer to the first capability.
*/
if (m_SetOfAppInfo.value.application_capabilities_list.u.
application_capability_refresh == NULL)
{
m_SetOfAppInfo.value.application_capabilities_list.u.
application_capability_refresh = pNew;
}
else
{
pOld->next = pNew;
}
/*
** This is used to set the next pointer if another record
** exists after this one.
*/
/*
* This will get filled in later if there is another record.
*/
(pOld = pNew)->next = NULL;
// Fill in the capability identifier
rc = lpAppCapData->pCapID->GetCapabilityIdentifierDataPDU(
&pNew->value.capability_id);
if (GCC_NO_ERROR != rc)
{
goto MyExit;
}
// Fill in the capability choice from the GCC capability class.
pNew->value.capability_class.choice = (USHORT) lpAppCapData->eCapType;
// Note that nothing is filled in for a logical capability.
if (lpAppCapData->eCapType == GCC_UNSIGNED_MINIMUM_CAPABILITY)
{
pNew->value.capability_class.u.unsigned_minimum =
lpAppCapData->nUnsignedMinimum;
}
else if (lpAppCapData->eCapType == GCC_UNSIGNED_MAXIMUM_CAPABILITY)
{
pNew->value.capability_class.u.unsigned_maximum =
lpAppCapData->nUnsignedMaximum;
}
// Fill in number of entities regardless of capability type.
pNew->value.number_of_entities = lpAppCapData->cEntries;
}
}
rc = GCC_NO_ERROR;
MyExit:
return rc;
}
/*
* ApplicationRosterError BuildSetOfNonCollapsingCapabilitiesPDU ()
*
* Private Function Description
* This routine builds a PDU structure for the non collapsing capabilities
* list associated passed in.
*
* Formal Parameters
* pSetOfCaps - (o) PDU structure to fill in
* capabilities_list - (i) Source non-collapsing capabilities.
*
* Return Value
* GCC_NO_ERROR - On Success
* GCC_ALLOCATIONFAILURE - On resource failure
*
* Side Effects
* None
*
* Caveats
* None
*/
GCCError CAppRoster::BuildSetOfNonCollapsingCapabilitiesPDU(
PSetOfNonCollapsingCapabilities *pSetOfCaps,
CAppCapItemList *pAppCapItemList)
{
GCCError rc = GCC_ALLOCATION_FAILURE;
PSetOfNonCollapsingCapabilities new_set_of_capabilities;
PSetOfNonCollapsingCapabilities old_set_of_capabilities;
APP_CAP_ITEM *lpAppCapData;
DebugEntry(CAppRoster::BuildSetOfNonCollapsingCapabilitiesPDU);
*pSetOfCaps = NULL;
old_set_of_capabilities = NULL; // Setting this to NULL removes warning
/*
* Iterate through the complete list of capabilities.
*/
pAppCapItemList->Reset();
while (NULL != (lpAppCapData = pAppCapItemList->Iterate()))
{
DBG_SAVE_FILE_LINE
new_set_of_capabilities = new SetOfNonCollapsingCapabilities;
if (NULL == new_set_of_capabilities)
{
goto MyExit;
}
/*
** If the passed in pointer is equal to NULL we are at the first
** capability. Here we need to save the pointer to the first
** capability in the passed in pointer.
*/
if (*pSetOfCaps == NULL)
{
*pSetOfCaps = new_set_of_capabilities;
}
else
{
old_set_of_capabilities->next = new_set_of_capabilities;
}
/*
** This is used to set the next pointer if another record exists
** after this one.
*/
old_set_of_capabilities = new_set_of_capabilities;
/*
* This will get filled in later if there is another record.
*/
new_set_of_capabilities->next = NULL;
new_set_of_capabilities->value.bit_mask = 0;
// Fill in the capability identifier
rc = lpAppCapData->pCapID->GetCapabilityIdentifierDataPDU(
&new_set_of_capabilities->value.capability_id);
if (GCC_NO_ERROR != rc)
{
goto MyExit;
}
if ((lpAppCapData->poszAppData != NULL) && (rc == GCC_NO_ERROR))
{
new_set_of_capabilities->value.bit_mask |= APPLICATION_DATA_PRESENT;
new_set_of_capabilities->value.application_data.length =
lpAppCapData->poszAppData->length;
new_set_of_capabilities->value.application_data.value =
lpAppCapData->poszAppData->value;
}
}
rc = GCC_NO_ERROR;
MyExit:
return rc;
}
/*
* These routines are used to free up a roster update indication PDU.
*/
/*
* void FreeRosterUpdateIndicationPDU ()
*
* Private Function Description
* This routine frees up all the internal data allocated to hold the roster
* update PDU.
*
* Formal Parameters
* None
*
* Return Value
* None
*
* Side Effects
* None
*
* Caveats
* Note that the session key PDU data is not freed. Since this data will
* not change through out the life of this application roster object
* we just use the same session id PDU data for every roster update
* indication.
*/
void CAppRoster::FreeRosterUpdateIndicationPDU(void)
{
DebugEntry(CAppRoster::FreeRosterUpdateIndicationPDU);
switch (m_SetOfAppInfo.value.application_record_list.choice)
{
case APPLICATION_RECORD_REFRESH_CHOSEN:
FreeSetOfRefreshesPDU ();
break;
case APPLICATION_RECORD_UPDATE_CHOSEN:
FreeSetOfUpdatesPDU ();
break;
}
// Free the PDU data associated with the capability list if one exists.
if (m_SetOfAppInfo.value.application_capabilities_list.choice == APPLICATION_CAPABILITY_REFRESH_CHOSEN)
{
FreeSetOfCapabilityRefreshesPDU ();
}
m_SetOfAppInfo.value.application_record_list.choice = APPLICATION_NO_CHANGE_CHOSEN;
m_SetOfAppInfo.value.application_capabilities_list.choice = CAPABILITY_NO_CHANGE_CHOSEN;
m_pSetOfAppRecordUpdates = NULL;
}
/*
* void FreeSetOfRefreshesPDU ()
*
* Private Function Description
* This routine Frees all the memory associated with a set
* of application record refreshes.
*
* Formal Parameters
* none
*
* Return Value
* none
*
* Side Effects
* none
*
* Caveats
* none
*/
void CAppRoster::FreeSetOfRefreshesPDU(void)
{
PSetOfApplicationRecordRefreshes pCurr, pNext;
DebugEntry(CAppRoster::FreeSetOfRefreshesPDU);
for (pCurr = m_SetOfAppInfo.value.application_record_list.u.application_record_refresh;
NULL != pCurr;
pCurr = pNext)
{
pNext = pCurr->next;
// Free up any non-collapsing capabilities data
if (pCurr->value.application_record.bit_mask & NON_COLLAPSING_CAPABILITIES_PRESENT)
{
FreeSetOfNonCollapsingCapabilitiesPDU(pCurr->value.application_record.non_collapsing_capabilities);
}
// Delete the actual record refresh
delete pCurr;
}
m_SetOfAppInfo.value.application_record_list.u.application_record_refresh = NULL;
}
/*
* void FreeSetOfUpdatesPDU ()
*
* Private Function Description
* This routine frees the memory associated with a complete set
* application roster updates.
*
* Formal Parameters
* none
*
* Return Value
* none
*
* Side Effects
* none
*
* Caveats
* none
*/
void CAppRoster::FreeSetOfUpdatesPDU(void)
{
PSetOfApplicationRecordUpdates pCurr, pNext;
PApplicationRecord application_record;
DebugEntry(CAppRoster::FreeSetOfUpdatesPDU);
for (pCurr = m_SetOfAppInfo.value.application_record_list.u.application_record_update;
NULL != pCurr;
pCurr = pNext)
{
// remember the next one because we will free the current one
pNext = pCurr->next;
// Free up any non-collapsing capabilities data
switch(pCurr->value.application_update.choice)
{
case APPLICATION_ADD_RECORD_CHOSEN:
application_record = &pCurr->value.application_update.u.application_add_record;
break;
case APPLICATION_REPLACE_RECORD_CHOSEN:
application_record = &pCurr->value.application_update.u.application_replace_record;
break;
default:
application_record = NULL;
break;
}
if (application_record != NULL)
{
if (application_record->bit_mask & NON_COLLAPSING_CAPABILITIES_PRESENT)
{
FreeSetOfNonCollapsingCapabilitiesPDU(application_record->non_collapsing_capabilities);
}
}
// Delete the actual update structure
delete pCurr;
}
m_SetOfAppInfo.value.application_record_list.u.application_record_update = NULL;
}
/*
* void FreeSetOfCapabilityRefreshesPDU ()
*
* Private Function Description
* This routine frees all the memory associated with the capability PDU.
*
* Formal Parameters
* capability_refresh - (i) Capabilities to be freed.
*
* Return Value
* none
*
* Side Effects
* none
*
* Caveats
* Note that the capability id PDU data is not freed here. Since this
* data should not change through out the life of this object we don't
* bother freeing and regenerating it.
*/
void CAppRoster::FreeSetOfCapabilityRefreshesPDU(void)
{
PSetOfApplicationCapabilityRefreshes pCurr, pNext;
for (pCurr = m_SetOfAppInfo.value.application_capabilities_list.u.application_capability_refresh;
NULL != pCurr;
pCurr = pNext)
{
pNext = pCurr->next;
delete pCurr;
}
}
/*
* void FreeSetOfNonCollapsingCapabilitiesPDU ()
*
* Private Function Description
* This routine frees all the memory associated with the
* non-collapsed capability PDU.
*
* Formal Parameters
* capability_refresh - (i) Non-Collapsed Capabilities to be freed.
*
* Return Value
* none
*
* Side Effects
* none
*
* Caveats
* Note that the capability id PDU data is not freed here. Since this
* data should not change through out the life of this object we don't
* bother freeing and regenerating it.
*/
void CAppRoster::FreeSetOfNonCollapsingCapabilitiesPDU (
PSetOfNonCollapsingCapabilities capability_refresh)
{
PSetOfNonCollapsingCapabilities pCurr, pNext;
for (pCurr = capability_refresh; NULL != pCurr; pCurr = pNext)
{
pNext = pCurr->next;
delete pCurr;
}
}
/*
* These routines process roster update indication PDUs.
*/
/*
* ApplicationRosterError ProcessRosterUpdateIndicationPDU ()
*
* Public Function Description
* This routine is responsible for processing the decoded PDU data.
* It essentially changes the application roster object's internal database
* based on the information in the structure.
*/
GCCError CAppRoster::ProcessRosterUpdateIndicationPDU (
PSetOfApplicationInformation application_information,
UserID sender_id)
{
GCCError rc = GCC_NO_ERROR;
DebugEntry(CAppRoster::ProcessRosterUpdateIndicationPDU);
/*
** Free up the old PDU data here if it is being maintained and the
** PDU has been flushed. Note that we also set the PDU is flushed boolean
** back to FALSE so that the new PDU will be maintained until it is
** flushed.
*/
if (m_fPduIsFlushed)
{
FreeRosterUpdateIndicationPDU ();
m_fPduIsFlushed = FALSE;
}
/*
** Now check the application key to make sure we have a match. If
** not, return with no change.
*/
if (! m_pSessionKey->IsThisYourSessionKeyPDU(&application_information->value.session_key))
{
WARNING_OUT(("CAppRoster::ProcessRosterUpdateIndicationPDU:GCC_BAD_SESSION_KEY"));
rc = GCC_BAD_SESSION_KEY;
goto MyExit;
}
/*
** If this is a roster update and refresh is chosen we must
** clear out the entire list and rebuild it.
*/
if (application_information->value.application_record_list.choice != APPLICATION_NO_CHANGE_CHOSEN)
{
// The roster is about to change
m_fRosterHasChanged = TRUE;
/*
** If this node is the top provider or this roster is local and
** only used to propogate PDUs up toward the top provider,
** we increment the instance number. If it is not we get the
** instance number out of the PDU.
*/
if (m_fTopProvider || m_fLocalRoster)
{
m_nInstance++;
}
else
{
m_nInstance = application_information->value.roster_instance_number;
}
/*
** Here if either of these booleans is already TRUE we do not
** want to write over them with this PDU data. Therefore, we
** check for FALSE before we do anything with them.
*/
if (! m_fPeerEntitiesAdded)
{
m_fPeerEntitiesAdded = application_information->value.peer_entities_are_added;
}
if (! m_fPeerEntitiesRemoved)
{
m_fPeerEntitiesRemoved = application_information->value.peer_entities_are_removed;
}
if (application_information->value.application_record_list.choice == APPLICATION_RECORD_REFRESH_CHOSEN)
{
TRACE_OUT(("CAppRoster::ProcessRosterUpdateIndicationPDU:ProcessSetOfRefreshesPDU"));
rc = ProcessSetOfRefreshesPDU(
application_information->value.application_record_list.u.application_record_refresh,
sender_id);
}
else
{
TRACE_OUT(("CAppRoster::ProcessRosterUpdateIndicationPDU:ProcessSetOfUpdatesPDU"));
rc = ProcessSetOfUpdatesPDU(
application_information->value.application_record_list.u.application_record_update,
sender_id);
}
if (GCC_NO_ERROR != rc)
{
goto MyExit;
}
}
else
{
ERROR_OUT(("AppRoster::ProcessRosterUpdateIndicationPDU:ASSERTION: NO Change PDU received"));
}
// Process the capabilities list portion of the PDU.
if (application_information->value.application_capabilities_list.choice == APPLICATION_CAPABILITY_REFRESH_CHOSEN)
{
// Set flag to show that change has occured.
m_fCapabilitiesHaveChanged = TRUE;
/*
** We will store the new capabilities in the roster record
** associated with the sender id. Note that it is possible for
** this roster record to contain an empty application record list
** if the sending node has no enrolled applications.
*/
rc = ProcessSetOfCapabilityRefreshesPDU(
application_information->value.application_capabilities_list.u.application_capability_refresh,
sender_id);
}
else
{
ASSERT(GCC_NO_ERROR == rc);
}
MyExit:
return rc;
}
/*
* GCCError ProcessSetOfRefreshesPDU ()
*
* Private Function Description
* This routine processes a set of record refreshes. It is responsible
* for managing the creation (or update) of all affected application
* records. The roster list built from a refresh PDU does not maintain the
* hierarchy of the conference since it is not important at this point.
* Refreshes are issued as broacast from the Top Provider down to the
* sub-ordinate nodes.
*
* Formal Parameters
* record_refresh - (i) Set of record refresh PDUs to be processed.
* sender_id - (i) Node id of node that sent the update.
*
* Return Value
* GCC_NO_ERROR - On Success
* GCC_ALLOCATION_FAILURE - On resource failure
*
* Side Effects
* none
*
* Caveate
* none
*/
GCCError CAppRoster::ProcessSetOfRefreshesPDU(
PSetOfApplicationRecordRefreshes record_refresh,
UserID sender_id)
{
GCCError rc = GCC_ALLOCATION_FAILURE;
PSetOfApplicationRecordRefreshes pCurr;
APP_RECORD *app_record;
APP_NODE_RECORD *node_record;
CAppRecordList2 *record_list;
UserID node_id;
EntityID entity_id;
DebugEntry(CAppRoster::ProcessSetOfRefreshesPDU);
if (record_refresh != NULL)
{
// Clear out the node record for the sender id
ClearNodeRecordFromList (sender_id);
/*
** Create the node record for the sender id passed into this routine.
** Note that if the sender of this refresh is the Top Provider
** all nodes below the top provider are contained in the sub node
** list of the Top Provider's node record.
*/
DBG_SAVE_FILE_LINE
node_record = new APP_NODE_RECORD;
if (NULL == node_record)
{
goto MyExit;
}
m_NodeRecordList2.Append(sender_id, node_record);
for (pCurr = record_refresh; NULL != pCurr; pCurr = pCurr->next)
{
node_id = pCurr->value.node_id;
entity_id = pCurr->value.entity_id;
if (sender_id != node_id)
{
// Get or create the sub node record list
if (NULL == (record_list = node_record->SubNodeList2.Find(node_id)))
{
DBG_SAVE_FILE_LINE
record_list = new CAppRecordList2(DESIRED_MAX_APP_RECORDS);
if (NULL == record_list)
{
goto MyExit;
}
node_record->SubNodeList2.Append(node_id, record_list);
}
}
else
{
/*
** Here we set up the pointer to the record list. This
** list is the node records application list which
** means that this list contains the application records
** associated with the sender's node.
*/
record_list = &node_record->AppRecordList;
}
// Now create and fill in the new application record.
DBG_SAVE_FILE_LINE
app_record = new APP_RECORD;
if (NULL == app_record)
{
goto MyExit;
}
rc = ProcessApplicationRecordPDU(app_record, &pCurr->value.application_record);
if (GCC_NO_ERROR != rc)
{
goto MyExit;
}
record_list->Append(entity_id, app_record);
} // for
}
else
{
// This roster no longer contains any entries so clear the list!!!
ClearNodeRecordList ();
}
/*
** Build a full refresh PDU here if no errors occured while processing
** the refresh PDU.
*/
rc = BuildApplicationRecordListPDU (APP_FULL_REFRESH, 0, 0);
MyExit:
return rc;
}
/*
* GCCError ProcessSetOfUpdatesPDU ()
*
* Private Function Description
* This routine processes a set of roster updates. It iterates through
* the complete list of updates making all necessary changes to the
* internal information base and building the appropriate PDU.
*
* Formal Parameters
* record_update - (i) set of updates PDU to be processed
* sender_id - (i) gcc user id of node that sent the update
*
* Return Value
* APP_ROSTER_NO_ERROR - On Success
* APP_ROSTER_RESOURCE_ERROR - On resource failure
*
* Side Effects
* none
*
* Caveate
* none
*/
GCCError CAppRoster::ProcessSetOfUpdatesPDU(
PSetOfApplicationRecordUpdates record_update,
UserID sender_id)
{
GCCError rc = GCC_ALLOCATION_FAILURE;
PSetOfApplicationRecordUpdates pCurr;
UserID node_id;
EntityID entity_id;
PApplicationRecord pdu_record;
APP_RECORD *application_record = NULL;
APP_NODE_RECORD *node_record;
CAppRecordList2 *record_list;
APP_ROSTER_UPDATE_TYPE update_type;
DebugEntry(CAppRoster::ProcessSetOfUpdatesPDU);
if (record_update != NULL)
{
for (pCurr = record_update; NULL != pCurr; pCurr = pCurr->next)
{
node_id = pCurr->value.node_id;
entity_id = pCurr->value.entity_id;
switch(pCurr->value.application_update.choice)
{
case APPLICATION_ADD_RECORD_CHOSEN:
pdu_record = &(pCurr->value.application_update.u.application_add_record);
update_type = APP_ADD_RECORD;
break;
case APPLICATION_REPLACE_RECORD_CHOSEN:
DeleteRecord (node_id, entity_id, FALSE);
pdu_record = &(pCurr->value.application_update.u.application_replace_record);
update_type = APP_REPLACE_RECORD;
break;
default: // Remove record
/*
** Inform the owner that a record was delete while processing
** this PDU so that it can perform any necessary cleanup.
*/
m_pAppRosterMgr->DeleteRosterRecord(node_id, entity_id);
DeleteRecord (node_id, entity_id, TRUE);
pdu_record = NULL;
update_type = APP_DELETE_RECORD;
break;
}
/*
** First get the roster record and if one does not exist for this
** app record create it. After that we will create the application
** record and put it into the correct slot in the application
** roster record.
*/
if (pdu_record != NULL)
{
/*
** First find the correct node record and if it does not
** exist create it.
*/
if (NULL == (node_record = m_NodeRecordList2.Find(sender_id)))
{
DBG_SAVE_FILE_LINE
node_record = new APP_NODE_RECORD;
if (NULL == node_record)
{
goto MyExit;
}
m_NodeRecordList2.Append(sender_id, node_record);
}
/*
** If the user and sender id is the same then the record
** will be contained in the app_record_list. Otherwise, it
** will be maintained in the sub-node list.
*/
/*
** If the sender_id equals the node id being processed
** use the application record list instead of the sub
** node list.
*/
if (sender_id != node_id)
{
/*
** Find the correct node list and create it if it does
** not exists. This list holds lists of all the
** application peer entities at a node.
*/
if (NULL == (record_list = node_record->SubNodeList2.Find(node_id)))
{
DBG_SAVE_FILE_LINE
record_list = new CAppRecordList2(DESIRED_MAX_APP_RECORDS);
if (NULL == record_list)
{
goto MyExit;
}
node_record->SubNodeList2.Append(node_id, record_list);
}
}
else
{
record_list = &node_record->AppRecordList;
}
// Now fill in the application record
DBG_SAVE_FILE_LINE
application_record = new APP_RECORD;
if (NULL == application_record)
{
goto MyExit;
}
record_list->Append(entity_id, application_record);
rc = ProcessApplicationRecordPDU(application_record, pdu_record);
if (GCC_NO_ERROR != rc)
{
goto MyExit;
}
} // if
/*
** Here we add this update to our PDU and jump to the next update
** in the PDU currently being processed.
*/
rc = BuildApplicationRecordListPDU ( update_type,
node_id,
entity_id);
if (rc != GCC_NO_ERROR)
{
goto MyExit;
}
/*
** If the capabilities changed during the above processing
** we must create a new collapsed capabilities list and
** build a new capability refresh PDU.
*/
if (m_fCapabilitiesHaveChanged)
{
MakeCollapsedCapabilitiesList();
rc = BuildSetOfCapabilityRefreshesPDU ();
if (rc != GCC_NO_ERROR)
{
goto MyExit;
}
}
} // for
} // if
rc = GCC_NO_ERROR;
MyExit:
return rc;
}
/*
* GCCError ProcessApplicationRecordPDU ()
*
* Private Function Description
* This routine is responsible for decoding the Application Record
* portion of the roster update pdu.
*
* Formal Parameters
* application_record - This is the internal destination app record.
* pdu_record - Source PDU data
*
* Return Value
* GCC_NO_ERROR - On Success
* GCC_ALLOCATION_FAILURE - On resource failure
*
* Side Effects
* none
*
* Caveats
* none
*/
GCCError CAppRoster::ProcessApplicationRecordPDU (
APP_RECORD *application_record,
PApplicationRecord pdu_record)
{
GCCError rc = GCC_NO_ERROR;
DebugEntry(CAppRoster::ProcessApplicationRecordPDU);
application_record->is_enrolled_actively = pdu_record->application_is_active;
application_record->is_conducting_capable = pdu_record->is_conducting_capable;
if (pdu_record->bit_mask & RECORD_STARTUP_CHANNEL_PRESENT)
{
application_record->startup_channel_type =
(MCSChannelType)pdu_record->record_startup_channel;
}
else
application_record->startup_channel_type= MCS_NO_CHANNEL_TYPE_SPECIFIED;
if (pdu_record->bit_mask & APPLICATION_USER_ID_PRESENT)
{
application_record->application_user_id =
pdu_record->application_user_id;
}
else
application_record->application_user_id = 0;
if (pdu_record->bit_mask & NON_COLLAPSING_CAPABILITIES_PRESENT)
{
rc = ProcessNonCollapsingCapabilitiesPDU (
&application_record->non_collapsed_caps_list,
pdu_record->non_collapsing_capabilities);
}
return rc;
}
/*
* GCCError ProcessSetOfCapabilityRefreshesPDU ()
*
* Private Function Description
* This routine is responsible for decoding the capabilities portion
* of an roster update PDU.
*
* Formal Parameters
* capability_refresh - (i) set of capabilities PDU to be processed
* sender_id - (i) gcc user id of node that sent the update
*
* Return Value
* GCC_NO_ERROR - On Success
* GCC_ALLOCATION_FAILURE - On resource failure
*
* Side Effects
* none
*
* Caveats
* This routine does handle NULL for the capability refresh which means
* that the capabilities delivered no longer exists.
*/
GCCError CAppRoster::ProcessSetOfCapabilityRefreshesPDU(
PSetOfApplicationCapabilityRefreshes capability_refresh,
UserID sender_id)
{
GCCError rc = GCC_NO_ERROR;
PSetOfApplicationCapabilityRefreshes pCurr;
CAppCapItemList *pAppCapList;
APP_CAP_ITEM *pAppCapItem;
APP_NODE_RECORD *node_record;
DebugEntry(CAppRoster::ProcessSetOfCapabilityRefreshesPDU);
if (NULL == (node_record = m_NodeRecordList2.Find(sender_id)))
{
DBG_SAVE_FILE_LINE
node_record = new APP_NODE_RECORD;
if (NULL == node_record)
{
return GCC_ALLOCATION_FAILURE;
}
m_NodeRecordList2.Append(sender_id, node_record);
}
// get collapsed cap list ptr
pAppCapList = &node_record->CollapsedCapList;
// Clear out all the old capabilities from this list.
pAppCapList->DeleteList();
// Begin processing the PDU.
for (pCurr = capability_refresh; NULL != pCurr; pCurr = pCurr->next)
{
ASSERT(GCC_NO_ERROR == rc);
// Create and fill in the new capability.
DBG_SAVE_FILE_LINE
pAppCapItem = new APP_CAP_ITEM((GCCCapabilityType) pCurr->value.capability_class.choice);
if (NULL == pAppCapItem)
{
return GCC_ALLOCATION_FAILURE;
}
// Create the capability ID
DBG_SAVE_FILE_LINE
pAppCapItem->pCapID = new CCapIDContainer(&pCurr->value.capability_id, &rc);
if (NULL == pAppCapItem->pCapID)
{
rc = GCC_ALLOCATION_FAILURE;
}
if (GCC_NO_ERROR != rc)
{
delete pAppCapItem;
return rc;
}
// append this cap to the collapsed cap list
pAppCapList->Append(pAppCapItem);
/*
** Note that a logical type's value is maintained as
** number of entities.
*/
if (pCurr->value.capability_class.choice == UNSIGNED_MINIMUM_CHOSEN)
{
pAppCapItem->nUnsignedMinimum = pCurr->value.capability_class.u.unsigned_minimum;
}
else
if (pCurr->value.capability_class.choice == UNSIGNED_MAXIMUM_CHOSEN)
{
pAppCapItem->nUnsignedMaximum = pCurr->value.capability_class.u.unsigned_maximum;
}
pAppCapItem->cEntries = pCurr->value.number_of_entities;
} // for
// This forces a new capabilities list to be calculated.
MakeCollapsedCapabilitiesList();
/*
** Here we build the new PDU data associated with this refresh of the
** capability list.
*/
return BuildSetOfCapabilityRefreshesPDU();
}
/*
* GCCError ProcessNonCollapsingCapabilitiesPDU ()
*
* Private Function Description
* This routine is responsible for decoding the non-collapsing capabilities
* portion of a roster record PDU.
*
* Formal Parameters
* non_collapsed_caps_list - (o) Pointer to list to fill in with new
* non-collapsed caps.
* pSetOfCaps - (i) non-collapsed PDU data
*
* Return Value
* GCC_NO_ERROR - On Success
* GCC_ALLOCATION_FAILURE - On resource failure
*
* Side Effects
* none
*
* Caveats
* none
*/
GCCError CAppRoster::ProcessNonCollapsingCapabilitiesPDU (
CAppCapItemList *non_collapsed_caps_list,
PSetOfNonCollapsingCapabilities pSetOfCaps)
{
GCCError rc = GCC_NO_ERROR;
PSetOfNonCollapsingCapabilities pCurr;
APP_CAP_ITEM *pAppCapItem;
DebugEntry(CAppRoster::ProcessNonCollapsingCapsPDU);
for (pCurr = pSetOfCaps; NULL != pCurr; pCurr = pCurr->next)
{
//
// LONCHANC: The following cap data does not have a type???
// for now, set it to zero.
//
DBG_SAVE_FILE_LINE
pAppCapItem = new APP_CAP_ITEM((GCCCapabilityType)0);
if (NULL == pAppCapItem)
{
rc = GCC_ALLOCATION_FAILURE;
goto MyExit;
}
DBG_SAVE_FILE_LINE
pAppCapItem->pCapID = new CCapIDContainer(&pCurr->value.capability_id, &rc);
if (NULL == pAppCapItem->pCapID)
{
rc = GCC_ALLOCATION_FAILURE;
}
if (rc != GCC_NO_ERROR)
{
goto MyExit;
}
if (pCurr->value.bit_mask & APPLICATION_DATA_PRESENT)
{
if (NULL == (pAppCapItem->poszAppData = ::My_strdupO2(
pCurr->value.application_data.value,
pCurr->value.application_data.length)))
{
rc = GCC_ALLOCATION_FAILURE;
goto MyExit;
}
}
non_collapsed_caps_list->Append(pAppCapItem);
} // for
ASSERT(GCC_NO_ERROR == rc);
MyExit:
if (GCC_NO_ERROR != rc)
{
delete pAppCapItem;
}
return rc;
}
/*
* Utilities that operate on conference records.
*/
/*
* UINT LockApplicationRoster ()
*
* Public Function Description
* This routine is used to lock a GCCApplicationRoster and to determine the
* amount of memory necessary to hold the data referenced by the "API"
* application roster structure. The GCCApplicationRoster is used in
* indications to applications at the local node.
*/
UINT CAppRoster::LockApplicationRoster(void)
{
UINT number_of_records = 0;
UINT number_of_capabilities = 0;
APP_NODE_RECORD *lpAppNodeRecord;
APP_RECORD *lpAppRecData;
APP_CAP_ITEM *lpAppCapData;
CAppRecordList2 *lpAppRecDataList;
DebugEntry(CAppRoster::LockApplicationRoster);
/*
* If this is the first time this routine is called, determine the size of
* the memory required to hold the data referenced by the application
* roster structure. Otherwise, just increment the lock count.
*/
if (Lock() == 1)
{
/*
* Lock the data for the session key held within the roster. This lock
* call returns the size of the memory required to hold the session key
* data, rounded to an even multiple of four-bytes.
*/
m_cbDataMemory = m_pSessionKey->LockSessionKeyData();
/*
* First calculate the total number of records. This count is used to
* determine the space necessary to hold the records. Note that we must
* count both the application record list and the sub-node list.
*/
m_NodeRecordList2.Reset();
while (NULL != (lpAppNodeRecord = m_NodeRecordList2.Iterate()))
{
/*
* Add the application records at this node to the count.
*/
number_of_records += lpAppNodeRecord->AppRecordList.GetCount();
/*
* Next count the sub node records.
*/
if (! lpAppNodeRecord->SubNodeList2.IsEmpty())
{
lpAppNodeRecord->SubNodeList2.Reset();
while (NULL != (lpAppRecDataList = lpAppNodeRecord->SubNodeList2.Iterate()))
{
number_of_records += lpAppRecDataList->GetCount();
}
}
}
/*
* Now determine the amount of memory necessary to hold all of the
* pointers to the application records as well as the actual
* GCCApplicationRecord structures.
*/
m_cbDataMemory += number_of_records *
(sizeof(PGCCApplicationRecord) +
ROUNDTOBOUNDARY( sizeof(GCCApplicationRecord)) );
m_NodeRecordList2.Reset();
while (NULL != (lpAppNodeRecord = m_NodeRecordList2.Iterate()))
{
/*
* Iterate through this node's record list, determining the amount
* of memory necessary to hold the pointers to the non-collapsing
* capabilities as well as the capability ID data and octet string
* data associated with each non-collapsing capability.
*/
lpAppNodeRecord->AppRecordList.Reset();
while (NULL != (lpAppRecData = lpAppNodeRecord->AppRecordList.Iterate()))
{
/*
* Set up an iterator for the list of non-collapsing
* capabilities held within each application roster.
*/
lpAppRecData->non_collapsed_caps_list.Reset();
number_of_capabilities += lpAppRecData->non_collapsed_caps_list.GetCount();
while (NULL != (lpAppCapData = lpAppRecData->non_collapsed_caps_list.Iterate()))
{
/*
* Lock the data for each capability ID. The lock call
* returns the length of the data referenced by each
* capability ID rounded to occupy an even multiple of
* four-bytes.
*/
m_cbDataMemory += lpAppCapData->pCapID->LockCapabilityIdentifierData();
/*
* Add up the space required to hold the application data
* octet strings if they are present. Make sure there is
* enough space for each octet string to occupy an even
* multiple of four bytes. Add room to hold the actual
* octet string structure also since the capability
* structure only contains a pointer to a OSTR.
*/
if (lpAppCapData->poszAppData != NULL)
{
m_cbDataMemory += ROUNDTOBOUNDARY(sizeof(OSTR));
m_cbDataMemory += ROUNDTOBOUNDARY(lpAppCapData->poszAppData->length);
}
}
}
/*
* Iterate through this node's sub-node record list, determining the
* amount of memory necessary to hold the pointers to the
* non-collapsing capabilities as well as the capability ID data and
* octet string data associated with each non-collapsing capability.
*/
lpAppNodeRecord->SubNodeList2.Reset();
while (NULL != (lpAppRecDataList = lpAppNodeRecord->SubNodeList2.Iterate()))
{
lpAppRecDataList->Reset();
while (NULL != (lpAppRecData = lpAppRecDataList->Iterate()))
{
/*
* Set up an iterator for the list of non-collapsing
* capabilities held within each application roster.
*/
number_of_capabilities += lpAppRecData->non_collapsed_caps_list.GetCount();
lpAppRecData->non_collapsed_caps_list.Reset();
while (NULL != (lpAppCapData = lpAppRecData->non_collapsed_caps_list.Iterate()))
{
/*
* Lock the data for each capability ID. The lock call
* returns the length of the data referenced by each
* capability ID fixed up to occupy an even multiple of
* four-bytes.
*/
m_cbDataMemory += lpAppCapData->pCapID->LockCapabilityIdentifierData();
/*
* Add up the space required to hold the application
* data octet strings if they are present. Make sure
* there is enough space for each octet string to occupy
* an even multiple of four bytes. Add room to hold the
* actual octet string structure also since the
* capability structure only contains a pointer to a OSTR
*/
if (lpAppCapData->poszAppData != NULL)
{
m_cbDataMemory += ROUNDTOBOUNDARY(sizeof(OSTR));
m_cbDataMemory += ROUNDTOBOUNDARY(lpAppCapData->poszAppData->length);
}
}
}
}
}
/*
* Determine the amount of memory necessary to hold all of the pointers
* to the non-collapsing capabilities as well as the actual
* GCCNonCollapsingCapability structures.
*/
m_cbDataMemory += number_of_capabilities *
(sizeof (PGCCNonCollapsingCapability) +
ROUNDTOBOUNDARY( sizeof(GCCNonCollapsingCapability)) );
/*
* Add the amount of memory necessary to hold the string data associated
* with each capability ID.
*/
m_CollapsedCapListForAllNodes.Reset();
while (NULL != (lpAppCapData = m_CollapsedCapListForAllNodes.Iterate()))
{
m_cbDataMemory += lpAppCapData->pCapID->LockCapabilityIdentifierData();
}
/*
* Add the memory to hold the application capability pointers
* and structures.
*/
number_of_capabilities = m_CollapsedCapListForAllNodes.GetCount();
m_cbDataMemory += number_of_capabilities *
(sizeof (PGCCApplicationCapability) +
ROUNDTOBOUNDARY( sizeof(GCCApplicationCapability)) );
}
return m_cbDataMemory;
}
/*
* UINT GetAppRoster()
*
* Public Function Description
* This routine is used to obtain a pointer to the GCCApplicatonRoster.
* This routine should not be called before LockApplicationRoster is
* called. LockApplicationRoster will create the GCCApplicationRoster in
* the memory provided. The GCCApplicationRoster is what is delivered to
* the end user Application SAP.
*/
UINT CAppRoster::GetAppRoster(
PGCCApplicationRoster pGccAppRoster,
LPBYTE pData)
{
UINT rc;
DebugEntry(CAppRoster::GetAppRoster);
if (GetLockCount() > 0)
{
UINT data_length;
/*
* Fill in the output length parameter which indicates how much data
* referenced outside the structure will be written.
*/
rc = m_cbDataMemory;
/*
* Get the data associated with the roster's session key and save
* the length of the data written into memory.
*/
data_length = m_pSessionKey->GetGCCSessionKeyData(&pGccAppRoster->session_key, pData);
/*
* Move the memory pointer past the data associated with the
* session key.
*/
pData += data_length;
/*
* Fill in other roster structure elements.
*/
pGccAppRoster->application_roster_was_changed = m_fRosterHasChanged;
pGccAppRoster->instance_number = (USHORT) m_nInstance;
pGccAppRoster->nodes_were_added = m_fPeerEntitiesAdded;
pGccAppRoster->nodes_were_removed = m_fPeerEntitiesRemoved;
pGccAppRoster->capabilities_were_changed = m_fCapabilitiesHaveChanged;
/*
* Fill in the full set of application roster records.
*/
data_length = GetApplicationRecords(pGccAppRoster, pData);
/*
* Move the memory pointer past the application records and their
* associated data. Get the full set of application capabilities.
*/
pData += data_length;
data_length = GetCapabilitiesList(pGccAppRoster, pData);
}
else
{
ERROR_OUT(("CAppRoster::GetAppRoster: Error data not locked"));
rc = 0;
}
return rc;
}
/*
* void UnLockApplicationRoster ()
*
* Public Function Description
* This member function is responsible for unlocking the data locked for
* the "API" application roster after the lock count goes to zero.
*/
void CAppRoster::UnLockApplicationRoster()
{
DebugEntry(CAppRoster::UnLockApplicationRoster);
if (Unlock(FALSE) == 0)
{
// reset the size
m_cbDataMemory = 0;
// free up all the memory locked for "API" data.
APP_NODE_RECORD *lpAppNodeRecord;
APP_RECORD *lpAppRecData;
APP_CAP_ITEM *lpAppCapData;
CAppRecordList2 *lpAppRecDataList;
// unlock session key data
m_pSessionKey->UnLockSessionKeyData();
// iterate through all the node records
m_NodeRecordList2.Reset();
while (NULL != (lpAppNodeRecord = m_NodeRecordList2.Iterate()))
{
// iterate through this node's record list
lpAppNodeRecord->AppRecordList.Reset();
while (NULL != (lpAppRecData = lpAppNodeRecord->AppRecordList.Iterate()))
{
// set up an iterator for the list of non-collapsing
// capabilities held within each application roster.
lpAppRecData->non_collapsed_caps_list.Reset();
while (NULL != (lpAppCapData = lpAppRecData->non_collapsed_caps_list.Iterate()))
{
lpAppCapData->pCapID->UnLockCapabilityIdentifierData();
}
}
// iterate through this node's sub-node record list
lpAppNodeRecord->SubNodeList2.Reset();
while (NULL != (lpAppRecDataList = lpAppNodeRecord->SubNodeList2.Iterate()))
{
lpAppRecDataList->Reset();
while (NULL != (lpAppRecData = lpAppRecDataList->Iterate()))
{
// set up an iterator for the list of non-collapsing
// capabilities held within each application roster.
lpAppRecData->non_collapsed_caps_list.Reset();
while (NULL != (lpAppCapData = lpAppRecData->non_collapsed_caps_list.Iterate()))
{
lpAppCapData->pCapID->UnLockCapabilityIdentifierData();
}
}
}
}
// iterate through collapsed caps
m_CollapsedCapListForAllNodes.Reset();
while (NULL != (lpAppCapData = m_CollapsedCapListForAllNodes.Iterate()))
{
lpAppCapData->pCapID->UnLockCapabilityIdentifierData();
}
}
// we have to call Release() because we used Unlock(FALSE)
Release();
}
/*
* UINT GetApplicationRecords ()
*
* Private Function Description
* This routine inserts the complete set of application roster records
* into the passed in application roster structure.
*
* Formal Parameters
* gcc_roster - (o) GCCApplicationRoster to be filled in.
* memory - (o) Location in memory to begin writing records.
*
* Return Value
* The total amount of data written into memory.
*
* Side Effects
* The memory pointer passed in will be advanced by the amount of memory
* necessary to hold the application records and their data.
*
* Caveats
* none
*/
UINT CAppRoster::GetApplicationRecords(
PGCCApplicationRoster gcc_roster,
LPBYTE memory)
{
UINT data_length = 0;
UINT record_count = 0;
PGCCApplicationRecord gcc_record;
UINT capability_data_length;
APP_NODE_RECORD *lpAppNodeRec;
CAppRecordList2 *lpAppRecDataList;
APP_RECORD *lpAppRecData;
UserID uid, uid2;
EntityID eid;
DebugEntry(CAppRoster::GetApplicationRecords);
/*
* Initialize the number of records in the roster to zero.
*/
gcc_roster->number_of_records = 0;
/*
* First calculate the total number of records. This count is used to
* allocate the space necessary to hold the record pointers. Note that we
* must count both the application record list and the sub-node list.
*/
m_NodeRecordList2.Reset();
while (NULL != (lpAppNodeRec = m_NodeRecordList2.Iterate()))
{
/*
* Add the number of application records at this node to the count.
*/
gcc_roster->number_of_records += (USHORT) (lpAppNodeRec->AppRecordList.GetCount());
/*
* Next add the number of sub node entries.
*/
if (! lpAppNodeRec->SubNodeList2.IsEmpty())
{
lpAppNodeRec->SubNodeList2.Reset();
while (NULL != (lpAppRecDataList = lpAppNodeRec->SubNodeList2.Iterate()))
{
gcc_roster->number_of_records += (USHORT) (lpAppRecDataList->GetCount());
}
}
}
if (gcc_roster->number_of_records != 0)
{
/*
* Fill in the roster's pointer to the list of application record
* pointers. The pointer list will begin at the memory location passed
* into this routine.
*/
gcc_roster->application_record_list = (PGCCApplicationRecord *)memory;
/*
* Move the memory pointer past the list of record pointers. This is
* where the first application record will be written.
*/
memory += gcc_roster->number_of_records * sizeof(PGCCApplicationRecord);
/*
* Add to the data length the amount of memory necessary to hold the
* application record pointers. Go ahead and add the amount of memory
* necessary to hold all of the GCCApplicationRecord structures.
*/
data_length += gcc_roster->number_of_records *
(sizeof(PGCCApplicationRecord) +
ROUNDTOBOUNDARY(sizeof(GCCApplicationRecord)));
record_count = 0;
m_NodeRecordList2.Reset();
while (NULL != (lpAppNodeRec = m_NodeRecordList2.Iterate(&uid)))
{
/*
* Iterate through this node's record list, building an "API"
* application record for each record in the list.
*/
lpAppNodeRec->AppRecordList.Reset();
while (NULL != (lpAppRecData = lpAppNodeRec->AppRecordList.Iterate(&eid)))
{
/*
* Set the application record pointer equal to the location in
* memory where it will be written.
*/
gcc_record = (PGCCApplicationRecord)memory;
/*
* Save the pointer to the application record in the roster's
* list of record pointers.
*/
gcc_roster->application_record_list[record_count] = gcc_record;
/*
* Get the GCC node ID from the node iterator.
*/
gcc_record->node_id = uid;
/*
* Get the Entity ID from the record iterator.
*/
gcc_record->entity_id = eid;
/*
* Fill in other application record elements.
*/
gcc_record->is_enrolled_actively = lpAppRecData->is_enrolled_actively;
gcc_record->is_conducting_capable = lpAppRecData->is_conducting_capable;
gcc_record->startup_channel_type = lpAppRecData->startup_channel_type;
gcc_record->application_user_id = lpAppRecData->application_user_id;
/*
* Advance the memory pointer past the application record
* structure. This is where the list of non-collapsing
* capabilities pointers will begin. Round the memory location
* off to fall on an even four-byte boundary.
*/
memory += ROUNDTOBOUNDARY(sizeof(GCCApplicationRecord));
/*
* Fill in the non-collapsing capabilities for this application
* record.
*/
capability_data_length = GetNonCollapsedCapabilitiesList(
gcc_record,
&lpAppRecData->non_collapsed_caps_list,
memory);
/*
* Add the amount of memory necessary to hold the list of
* capabilities and associated data to the overall length and
* move the memory pointer past the capabilities data.
*/
memory += capability_data_length;
data_length += capability_data_length;
/*
* Increment the record list array counter.
*/
record_count++;
}
/*
* Iterate through this node's sub-node record list, building an
* "API" application record for each record in the list.
*/
lpAppNodeRec->SubNodeList2.Reset();
while (NULL != (lpAppRecDataList = lpAppNodeRec->SubNodeList2.Iterate(&uid2)))
{
/*
* Iterate through this node's record list.
*/
lpAppRecDataList->Reset();
while (NULL != (lpAppRecData = lpAppRecDataList->Iterate(&eid)))
{
/*
* Set the application record pointer equal to the location
* in memory where it will be written.
*/
gcc_record = (PGCCApplicationRecord)memory;
/*
* Save the pointer to the application record in the
* roster's list of record pointers.
*/
gcc_roster->application_record_list[record_count] = gcc_record;
/*
* Get the node ID from the sub_node_iterator.
*/
gcc_record->node_id = uid2;
/*
* Get the entity ID from the record_iterator.
*/
gcc_record->entity_id = eid;
/*
* Fill in other application record elements.
*/
gcc_record->is_enrolled_actively = lpAppRecData->is_enrolled_actively;
gcc_record->is_conducting_capable = lpAppRecData->is_conducting_capable;
gcc_record->startup_channel_type = lpAppRecData->startup_channel_type;
gcc_record->application_user_id = lpAppRecData->application_user_id;
/*
* Advance the memory pointer past the application record
* structure. This is where the list of non-collapsing
* capabilities pointers will begin. Round the memory
* location off to fall on an even four-byte boundary.
*/
memory += ROUNDTOBOUNDARY(sizeof(GCCApplicationRecord));
/*
* Fill in the non-collapsing capabilities for this
* application record. The memory pointer will be advanced
* past the capabilities list and data.
*/
capability_data_length = GetNonCollapsedCapabilitiesList(
gcc_record,
&lpAppRecData->non_collapsed_caps_list,
memory);
/*
* Add the amount of memory necessary to hold the list of
* capabilities and associated data to the overall length.
*/
memory += capability_data_length;
data_length += capability_data_length;
/*
* Increment the record list array counter.
*/
record_count++;
}
}
}
}
else
{
/*
* There were no application records so set the pointer to the list
* of records to NULL and the data_length return value to zero.
*/
gcc_roster->application_record_list = NULL;
data_length = 0;
}
return (data_length);
}
/*
* UINT GetCapabilitiesList ()
*
* Private Function Description
* This routine fills in the capabilities portion of the
* GCCAppicationRoster structure.
*
* Formal Parameters
* gcc_roster - (o) GCCApplicationRoster to be filled in
* memory - (o) Location in memory to begin writing records.
*
* Return Value
* The total amount of data written into memory.
*
* Side Effects
* none
*
* Caveats
* none
*/
UINT CAppRoster::GetCapabilitiesList(
PGCCApplicationRoster gcc_roster,
LPBYTE memory)
{
UINT data_length = 0;
UINT capability_id_data_length = 0;
UINT capability_count;
PGCCApplicationCapability gcc_capability;
APP_CAP_ITEM *lpAppCapData;
DebugEntry(CAppRoster::GetCapabilitiesList);
/*
* Retrieve the number of capabilities for this roster and fill in any that
* are present.
*/
gcc_roster->number_of_capabilities = (USHORT) m_CollapsedCapListForAllNodes.GetCount();
if (gcc_roster->number_of_capabilities != 0)
{
/*
* Fill in the roster's pointer to the list of application capability
* pointers. The pointer list will begin at the memory location passed
* into this routine.
*/
gcc_roster->capabilities_list = (PGCCApplicationCapability *)memory;
/*
* Move the memory pointer past the list of capability pointers. This
* is where the first application capability structure will be written.
*/
memory += (Int)(gcc_roster->number_of_capabilities *
sizeof(PGCCApplicationCapability));
/*
* Add to the data length the amount of memory necessary to hold the
* application capability pointers. Go ahead and add the amount of
* memory necessary to hold all of the GCCApplicationCapability
* structures.
*/
data_length += gcc_roster->number_of_capabilities *
(sizeof(PGCCApplicationCapability) +
ROUNDTOBOUNDARY ( sizeof(GCCApplicationCapability)) );
capability_count = 0;
m_CollapsedCapListForAllNodes.Reset();
while (NULL != (lpAppCapData = m_CollapsedCapListForAllNodes.Iterate()))
{
/*
* Set the application capability pointer equal to the
* location in memory where it will be written.
*/
gcc_capability = (PGCCApplicationCapability)memory;
/*
* Save the pointer to the application capability in the roster's
* list of application capability pointers.
*/
gcc_roster->capabilities_list[capability_count] =
gcc_capability;
/*
* Advance the memory pointer past the application capability
* structure. This is where the string data for the capability ID
* will be written. Ensure that the memory pointer falls on an
* even four-byte boundary.
*/
memory += (Int)(ROUNDTOBOUNDARY(sizeof(GCCApplicationCapability)));
/*
* Retrieve the capability ID information from the internal
* CapabilityIDData object. The length returned by this call will
* have already been rounded to an even multiple of four bytes.
*/
capability_id_data_length = lpAppCapData->pCapID->GetGCCCapabilityIDData(
&gcc_capability->capability_id,
memory);
/*
* Advance the memory pointer past the string data written into
* memory by the capability ID object. Add the length of the string
* data to the overall capability length.
*/
memory += (Int)capability_id_data_length;
data_length += capability_id_data_length;
/*
* Now fill in the rest of the capability.
*/
gcc_capability->capability_class.eType =lpAppCapData->eCapType;
if (gcc_capability->capability_class.eType ==
GCC_UNSIGNED_MINIMUM_CAPABILITY)
{
gcc_capability->capability_class.nMinOrMax = lpAppCapData->nUnsignedMinimum;
}
else if (gcc_capability->capability_class.eType == GCC_UNSIGNED_MAXIMUM_CAPABILITY)
{
gcc_capability->capability_class.nMinOrMax = lpAppCapData->nUnsignedMaximum;
}
gcc_capability->number_of_entities = lpAppCapData->cEntries;
/*
* Increment the capability ID array counter.
*/
capability_count++;
}
}
else
{
gcc_roster->capabilities_list = NULL;
}
return (data_length);
}
/*
* UINT GetNonCollapsedCapabilitiesList ()
*
* Private Function Description:
* This routine is used to fill in the "API" non-collapsing capabilities
* portion of a GCCApplicationRoster from the data which is stored
* internally by this class.
*
* Formal Parameters
* gcc_record - (o) The application record to be filled in.
* pAppCapItemList (i) The internal capabilities data.
* memory (i/o) The memory location to begin writing data.
*
* Return Value
* The total amount of data written into memory.
*
* Side Effects
* The memory pointer passed in will be advanced by the amount of memory
* necessary to hold the capabilities and their data.
*
* Caveats
* none
*/
UINT CAppRoster::GetNonCollapsedCapabilitiesList(
PGCCApplicationRecord gcc_record,
CAppCapItemList *pAppCapItemList,
LPBYTE memory)
{
UINT capability_count;
PGCCNonCollapsingCapability gcc_capability;
APP_CAP_ITEM *lpAppCapData;
UINT capability_id_length = 0;
UINT capability_data_length = 0;
DebugEntry(CAppRoster::GetNonCollapsedCapabilitiesList);
/*
* Get the number of non-collapsed capabilities.
*/
gcc_record->number_of_non_collapsed_caps = (USHORT) pAppCapItemList->GetCount();
if (gcc_record->number_of_non_collapsed_caps != 0)
{
/*
* Fill in the record's pointer to the list of non-collapsing
* capabilities pointers. The pointer list will begin at the memory
* location passed into this routine.
*/
gcc_record->non_collapsed_caps_list = (PGCCNonCollapsingCapability *)memory;
/*
* Move the memory pointer past the list of capability pointers. This
* is where the first capability structure will be written.
*/
memory += (Int)(gcc_record->number_of_non_collapsed_caps *
sizeof(PGCCNonCollapsingCapability));
/*
* Add to the data length the amount of memory necessary to hold the
* capability pointers. Go ahead and add the amount of memory necessary
* to hold all of the GCCNonCollapsingCapability structures.
*/
capability_data_length = gcc_record->number_of_non_collapsed_caps *
(sizeof(PGCCNonCollapsingCapability) +
ROUNDTOBOUNDARY(sizeof (GCCNonCollapsingCapability)));
/*
* Iterate through this record's capabilities list, building an "API"
* non-collapsing capability for each capability in the list.
*/
capability_count = 0;
pAppCapItemList->Reset();
while (NULL != (lpAppCapData = pAppCapItemList->Iterate()))
{
/*
* Set the capability pointer equal to the location in memory where
* it will be written.
*/
gcc_capability = (PGCCNonCollapsingCapability)memory;
/*
* Save the pointer to the capability in the record's list of
* capability pointers.
*/
gcc_record->non_collapsed_caps_list[capability_count] = gcc_capability;
/*
* Move the memory pointer past the capability ID structure. This
* is where the data associated with the structure will be written.
* Retrieve the capability ID data from the internal object, saving
* it in the "API" capability ID structure.
*/
memory += (Int)ROUNDTOBOUNDARY(sizeof(GCCNonCollapsingCapability));
capability_id_length = lpAppCapData->pCapID->GetGCCCapabilityIDData(
&gcc_capability->capability_id, memory);
/*
* Add to the data length the amount of memory necessary to hold the
* capability ID data.
*/
capability_data_length += capability_id_length;
/*
* Move the memory pointer past the data filled in for the
* capability ID. This is where the application data OSTR
* contained in the non-collapsing capability will be written, if
* one exists. Note that the capability contains a pointer to a
* OSTR and therefore the OSTR structure as well
* as the string data must be written into memory.
*/
memory += capability_id_length;
if (lpAppCapData->poszAppData != NULL)
{
/*
* Set the application data structure pointer equal to the
* location in memory where it will be written.
*/
gcc_capability->application_data = (LPOSTR) memory;
gcc_capability->application_data->length = lpAppCapData->poszAppData->length;
/*
* Move the memory pointer past the OSTR structure
* and round it off to an even four-byte boundary. This is
* where the actual string data will be written so set the
* structure string pointer equal to that location.
*/
memory += ROUNDTOBOUNDARY(sizeof(OSTR));
gcc_capability->application_data->value =(LPBYTE)memory;
/*
* Copy the actual application string data into memory.
*/
::CopyMemory(gcc_capability->application_data->value,
lpAppCapData->poszAppData->value,
lpAppCapData->poszAppData->length);
/*
* Add to the data length the amount of memory necessary to
* hold the application data structure and string. The lengths
* will need to be aligned on a four-byte boundary before
* adding them to the total length.
*/
capability_data_length += ROUNDTOBOUNDARY(sizeof(OSTR));
capability_data_length += ROUNDTOBOUNDARY(gcc_capability->application_data->length);
/*
* Move the memory pointer past the application string data.
* The memory pointer is then fixed up to ensure that it falls
* on an even four-byte boundary.
*/
memory += ROUNDTOBOUNDARY(lpAppCapData->poszAppData->length);
}
else
{
gcc_capability->application_data = NULL;
}
/*
* Increment the capability array counter.
*/
capability_count++;
}
}
else
{
gcc_record->non_collapsed_caps_list = NULL;
capability_data_length = 0;
}
return (capability_data_length);
}
/*
* void FreeApplicationRosterData ()
*
* Private Function Description:
* This routine is used to free up any data which was locked for an "API"
* application roster.
*
* Formal Parameters
* none
*
* Return Value
* none
*
* Side Effects
* none
*
* Caveats
* none
*/
void CAppRoster::FreeApplicationRosterData(void)
{
APP_NODE_RECORD *lpAppNodeRec;
APP_RECORD *lpAppRecData;
APP_CAP_ITEM *lpAppCapData;
CAppRecordList2 *lpAppRecDataList;
DebugEntry(CAppRoster::FreeApplicationRosterData);
m_pSessionKey->UnLockSessionKeyData();
/*
* Unlock the data associated with each non-collapsed capability by
* iterating through the list of application records at each node as well as
* the list of sub-node records at each node, calling "UnLock" for each
* CapabilityIDData associated with each cabability.
*/
m_NodeRecordList2.Reset();
while (NULL != (lpAppNodeRec = m_NodeRecordList2.Iterate()))
{
lpAppNodeRec->AppRecordList.Reset();
while (NULL != (lpAppRecData = lpAppNodeRec->AppRecordList.Iterate()))
{
lpAppRecData->non_collapsed_caps_list.Reset();
while (NULL != (lpAppCapData = lpAppRecData->non_collapsed_caps_list.Iterate()))
{
lpAppCapData->pCapID->UnLockCapabilityIdentifierData ();
}
}
lpAppNodeRec->SubNodeList2.Reset();
while (NULL != (lpAppRecDataList = lpAppNodeRec->SubNodeList2.Iterate()))
{
lpAppRecDataList->Reset();
while (NULL != (lpAppRecData = lpAppRecDataList->Iterate()))
{
lpAppRecData->non_collapsed_caps_list.Reset();
while (NULL != (lpAppCapData = lpAppRecData->non_collapsed_caps_list.Iterate()))
{
lpAppCapData->pCapID->UnLockCapabilityIdentifierData();
}
}
}
}
/*
* Iterate through the list of collapsed capabilities, unlocking the data
* for each CapabilityIDData object associated with each capability.
*/
m_CollapsedCapListForAllNodes.Reset();
while (NULL != (lpAppCapData = m_CollapsedCapListForAllNodes.Iterate()))
{
lpAppCapData->pCapID->UnLockCapabilityIdentifierData();
}
}
/*
* GCCError AddRecord ()
*
* Public Function Description
* This member function is responsible for inserting a new application
* record into the Roster. This routine will return a failure if the
* application record already exist.
*
* Caveats
* Note that it is possible for a roster record (not application record)
* to already exist at this node if this is the second application
* entity to enroll at this node.
*/
GCCError CAppRoster::
AddRecord(GCCEnrollRequest *pReq, GCCNodeID nid, GCCEntityID eid)
{
GCCError rc = GCC_NO_ERROR;
APP_NODE_RECORD *node_record;
APP_RECORD *pAppRecord;
CAppCapItemList *pAppCapItemList;
DebugEntry(CAppRoster::AddRecord);
if (m_fPduIsFlushed)
{
FreeRosterUpdateIndicationPDU ();
m_fPduIsFlushed = FALSE;
}
/*
* First create a roster entry for this user ID if one does not exists.
*/
if (NULL == (node_record = m_NodeRecordList2.Find(nid)))
{
DBG_SAVE_FILE_LINE
node_record = new APP_NODE_RECORD;
if (node_record != NULL)
{
m_NodeRecordList2.Append(nid, node_record);
}
else
{
ERROR_OUT(("CAppRoster: AddRecord: Resource Error Occured"));
rc = GCC_ALLOCATION_FAILURE;
goto MyExit;
}
}
else
{
WARNING_OUT(("CAppRoster: AddRecord: Node Record is found"));
}
/*
* Check to make sure that the application record does not already exist..
*/
if ((NULL != node_record->AppRecordList.Find(eid)) ||
(NULL != node_record->ListOfAppCapItemList2.Find(eid)))
{
WARNING_OUT(("AppRoster: AddRecord: Record already exists"));
rc = GCC_INVALID_PARAMETER;
goto MyExit;
}
// Next create a record entry in the roster's app_record_list.
DBG_SAVE_FILE_LINE
pAppRecord = new APP_RECORD;
if (NULL == pAppRecord)
{
ERROR_OUT(("CAppRoster: AddRecord: can't create APP_RECORD"));
rc = GCC_ALLOCATION_FAILURE;
goto MyExit;
}
/*
** Here we must determine if an entry already exists at this
** node. If so, only one entry can be conducting capable at a
** node. Therefore, we set this variable based on this. We use
** the "was_conducting_capable" variable to keep up with the
** original state incase the conducting capable node leaves the
** conference.
*/
pAppRecord->is_conducting_capable = pReq->fConductingCapable;
APP_RECORD *p;
node_record->AppRecordList.Reset();
while (NULL != (p = node_record->AppRecordList.Iterate()))
{
if (p->is_conducting_capable)
{
pAppRecord->is_conducting_capable = FALSE;
break;
}
}
pAppRecord->was_conducting_capable = pReq->fConductingCapable;
pAppRecord->is_enrolled_actively = pReq->fEnrollActively;
pAppRecord->startup_channel_type = pReq->nStartupChannelType;
pAppRecord->application_user_id = pReq->nUserID;
if (pReq->cNonCollapsedCaps != 0)
{
rc = AddNonCollapsedCapabilities (
&pAppRecord->non_collapsed_caps_list,
pReq->cNonCollapsedCaps,
pReq->apNonCollapsedCaps);
if (GCC_NO_ERROR != rc)
{
ERROR_OUT(("CAppRoster::AddRecord: can't add non collapsed caps, rc=%u", (UINT) rc));
delete pAppRecord;
goto MyExit;
}
}
// Add the new record to the list of records at this node
node_record->AppRecordList.Append(eid, pAppRecord);
// from now on, we cannot free pAppRecord in case of error,
// because it is now in the app record list.
// Increment the instance number.
m_nInstance++;
m_fPeerEntitiesAdded = TRUE;
m_fRosterHasChanged = TRUE;
// Add an update to the PDU.
rc = BuildApplicationRecordListPDU(APP_ADD_RECORD, nid, eid);
if (GCC_NO_ERROR != rc)
{
ERROR_OUT(("CAppRoster::AddRecord: can't build app record list, rc=%u", (UINT) rc));
goto MyExit;
}
if (pReq->cCollapsedCaps != 0)
{
/*
** Create a new capabilities list and insert it into the roster
** record list of capabilities.
*/
DBG_SAVE_FILE_LINE
pAppCapItemList = new CAppCapItemList;
if (NULL == pAppCapItemList)
{
ERROR_OUT(("CAppRoster::AddRecord: can't create CAppCapItemList"));
rc = GCC_ALLOCATION_FAILURE;
goto MyExit;
}
rc = AddCollapsableCapabilities(pAppCapItemList,
pReq->cCollapsedCaps,
pReq->apCollapsedCaps);
if (GCC_NO_ERROR != rc)
{
ERROR_OUT(("CAppRoster::AddRecord: can't add collapsable caps, rc=%u", (UINT) rc));
delete pAppCapItemList;
goto MyExit;
}
// Add list of capabilities to list at this node
node_record->ListOfAppCapItemList2.Append(eid, pAppCapItemList);
m_fCapabilitiesHaveChanged = TRUE;
// from now on, we cannot free pAppCapItemList in case of error,
// because it is now in the app cap item list
// Rebuild the collapsed capabilities list.
MakeCollapsedCapabilitiesList();
// Build the capabilities refresh portion of the PDU.
rc = BuildSetOfCapabilityRefreshesPDU();
if (GCC_NO_ERROR != rc)
{
ERROR_OUT(("CAppRoster::AddRecord: can't build set of cap refresh, rc=%u", (UINT) rc));
goto MyExit;
}
}
MyExit:
DebugExitINT(CAppRoster::AddRecord, rc);
return rc;
}
/*
* GCCError AddCollapsableCapabilities ()
*
* Private Function Description
* This routine takes API collapsed capabilities list data passed in
* through a local request and converts it to internal collapsed
* capabillities.
*
* Formal Parameters
* pAppCapItemList - (o) Pointer to internal capabilites list
* to fill in.
* number_of_capabilities - (i) Number of capabilities in the source
* list.
* capabilities_list - (i) Pointer to source capabilities list.
*
* Return Value
* GCC_NO_ERROR - No error occured.
* GCC_ALLOCATION_FAILURE - A resource error occured.
*
* Side Effects
* The collapsed capabilities will be recalculated at this node after
* all the new caps are added.
*
* Caveats
* none
*/
GCCError CAppRoster::AddCollapsableCapabilities (
CAppCapItemList *pAppCapItemList,
UINT number_of_capabilities,
PGCCApplicationCapability *capabilities_list)
{
GCCError rc = GCC_NO_ERROR;
APP_CAP_ITEM *pAppCapItem;
UINT i;
BOOL capability_already_exists;
DebugEntry(CAppRoster::AddCollapsableCapabilities);
for (i = 0; i < number_of_capabilities; i++)
{
DBG_SAVE_FILE_LINE
pAppCapItem = new APP_CAP_ITEM((GCCCapabilityType)
capabilities_list[i]->capability_class.eType);
if (pAppCapItem != NULL)
{
DBG_SAVE_FILE_LINE
pAppCapItem->pCapID = new CCapIDContainer(&capabilities_list[i]->capability_id, &rc);
if ((pAppCapItem->pCapID != NULL) && (rc == GCC_NO_ERROR))
{
APP_CAP_ITEM *lpAppCapData;
/*
** Here we check to make sure that this capability id does
** not alreay exists in the list.
*/
capability_already_exists = FALSE;
pAppCapItemList->Reset();
while (NULL != (lpAppCapData = pAppCapItemList->Iterate()))
{
if (*lpAppCapData->pCapID == *pAppCapItem->pCapID)
{
capability_already_exists = TRUE;
delete pAppCapItem;
break;
}
}
if (capability_already_exists == FALSE)
{
if (capabilities_list[i]->capability_class.eType ==
GCC_UNSIGNED_MINIMUM_CAPABILITY)
{
pAppCapItem->nUnsignedMinimum =
capabilities_list[i]->capability_class.nMinOrMax;
}
else if (capabilities_list[i]->capability_class.eType
== GCC_UNSIGNED_MAXIMUM_CAPABILITY)
{
pAppCapItem->nUnsignedMaximum = capabilities_list[i]->capability_class.nMinOrMax;
}
// Since we have yet to collapse the capabilities set to 1
pAppCapItem->cEntries = 1;
// Add this capability to the list
pAppCapItemList->Append(pAppCapItem);
}
}
else if (pAppCapItem->pCapID == NULL)
{
rc = GCC_ALLOCATION_FAILURE;
goto MyExit;
}
else
{
goto MyExit;
}
}
else
{
rc = GCC_ALLOCATION_FAILURE;
goto MyExit;
}
}
MyExit:
if (GCC_NO_ERROR != rc)
{
delete pAppCapItem;
}
return rc;
}
/*
* GCCError AddNonCollapsedCapabilities ()
*
* Private Function Description
* This routine takes API non-collapsed capabilities list data passed in
* through a local request and converts it to internal non-collapsed
* capabillities.
*
* Formal Parameters
* pAppCapItemList - (o) Pointer to internal non-collapsed
* capabilites list to fill in.
* number_of_capabilities - (i) Number of non-collapsed capabilities in
* the source list.
* capabilities_list - (i) Pointer to source non-collapsed
* capabilities list.
*
* Return Value
* GCC_NO_ERROR - No error occured.
* GCC_INVALID_NON_COLLAPSED_CAP - Invalid non-collapsed capability.
* GCC_ALLOCATION_FAILURE - A resource error occured.
*
* Side Effects
* none
*
* Caveats
* none
*/
GCCError CAppRoster::AddNonCollapsedCapabilities (
CAppCapItemList *pAppCapItemList,
UINT number_of_capabilities,
PGCCNonCollapsingCapability *capabilities_list)
{
GCCError rc = GCC_NO_ERROR;
APP_CAP_ITEM *pAppCapItem;
UINT i;
DebugEntry(CAppRoster::AddNonCollapsedCapabilities);
for (i = 0; i < number_of_capabilities; i++)
{
//
// LONCHANC: Cap type is not set here.
// for now, it is zero.
//
DBG_SAVE_FILE_LINE
pAppCapItem = new APP_CAP_ITEM((GCCCapabilityType) 0);
if (pAppCapItem != NULL)
{
DBG_SAVE_FILE_LINE
pAppCapItem->pCapID = new CCapIDContainer(&capabilities_list[i]->capability_id, &rc);
if (pAppCapItem->pCapID != NULL)
{
if (capabilities_list[i]->application_data != NULL)
{
if (NULL == (pAppCapItem->poszAppData = ::My_strdupO2(
capabilities_list[i]->application_data->value,
capabilities_list[i]->application_data->length)))
{
rc = GCC_ALLOCATION_FAILURE;
goto MyExit;
}
else if (pAppCapItem->poszAppData->length > MAXIMUM_APPLICATION_DATA_LENGTH)
{
rc = GCC_INVALID_NON_COLLAPSED_CAP;
goto MyExit;
}
}
// Add this capability to the list if no errors
pAppCapItemList->Append(pAppCapItem);
}
else if (pAppCapItem->pCapID == NULL)
{
rc = GCC_ALLOCATION_FAILURE;
goto MyExit;
}
else
{
goto MyExit;
}
}
else
{
rc = GCC_ALLOCATION_FAILURE;
goto MyExit;
}
}
MyExit:
if (GCC_NO_ERROR != rc)
{
delete pAppCapItem;
}
return rc;
}
/*
* GCCError RemoveRecord ()
*
* Public Function Description
* This member function completely removes the specified record from the
* application roster. This includes any capabilities associated with
* this record. It also takes care of keeping the Instance number and
* added and removed flags up to date.
*/
GCCError CAppRoster::RemoveRecord(GCCNodeID nid, GCCEntityID eid)
{
GCCError rc;
APP_RECORD *pAppRecord;
APP_NODE_RECORD *node_record;
DebugEntry(CAppRoster::RemoveRecord);
if (m_fPduIsFlushed)
{
FreeRosterUpdateIndicationPDU ();
m_fPduIsFlushed = FALSE;
}
// First see if the record is contained in the Roster_Record_List.
if (NULL == (node_record = m_NodeRecordList2.Find(nid)))
{
TRACE_OUT(("CAppRoster::RemoveRecord: can't find node record, nid=%u", (UINT) nid));
rc = GCC_INVALID_PARAMETER;
goto MyExit;
}
if (NULL == (pAppRecord = node_record->AppRecordList.Find(eid)))
{
TRACE_OUT(("CAppRoster::RemoveRecord: can't find app record, eid=%u", (UINT) eid));
rc = GCC_INVALID_PARAMETER;
goto MyExit;
}
/*
** Here we must determine if any of the remaining APEs at this
** node should become conducting capable based on their role
** at the time they enrolled. We only do this if the record
** that is being deleted was conducting capabile.
*/
if (pAppRecord->is_conducting_capable)
{
APP_RECORD *p;
EntityID eid2;
node_record->AppRecordList.Reset();
while (NULL != (p = node_record->AppRecordList.Iterate(&eid2)))
{
/*
** Here we only deal with record entries other than the
** one being removed.
*/
if (eid2 != eid)
{
if (p->was_conducting_capable)
{
p->is_conducting_capable = TRUE;
/*
** Set up the update PDU for this conducting
** capable change.
*/
rc = BuildApplicationRecordListPDU(APP_REPLACE_RECORD, nid, eid2);
if (GCC_NO_ERROR != rc)
{
ERROR_OUT(("CAppRoster::RemoveRecord: can't build app record list, rc=%u", (UINT) rc));
goto MyExit;
}
break;
}
}
}
}
// Now delete the record
rc = DeleteRecord(nid, eid, TRUE);
if (GCC_NO_ERROR != rc)
{
WARNING_OUT(("CAppRoster::RemoveRecord: can't delete record, rc=%u", (UINT) rc));
goto MyExit;
}
// Increment the instance number.
m_nInstance++;
m_fPeerEntitiesRemoved = TRUE;
m_fRosterHasChanged = TRUE;
// Add an update to the PDU.
rc = BuildApplicationRecordListPDU(APP_DELETE_RECORD, nid, eid);
if (GCC_NO_ERROR != rc)
{
ERROR_OUT(("CAppRoster::RemoveRecord: can't build app record list, rc=%u", (UINT) rc));
goto MyExit;
}
/*
** If the capabilities changed during the above processing
** we must create a new collapsed capabilities list and
** build a new capability refresh PDU.
*/
if (m_fCapabilitiesHaveChanged)
{
MakeCollapsedCapabilitiesList();
rc = BuildSetOfCapabilityRefreshesPDU();
if (GCC_NO_ERROR != rc)
{
ERROR_OUT(("CAppRoster::RemoveRecord: can't build set of cap refreshes, rc=%u", (UINT) rc));
goto MyExit;
}
}
MyExit:
DebugExitINT(CAppRoster::RemoveRecord, rc);
return rc;
}
/*
* GCCError ReplaceRecord ()
*
* Public Function Description
* This routine completely replaces the specified record's parameters
* with the new parameters passed in. This includes the capabilities.
*/
GCCError CAppRoster::
ReplaceRecord(GCCEnrollRequest *pReq, GCCNodeID nid, GCCEntityID eid)
{
GCCError rc = GCC_NO_ERROR;
BOOL capable_node_found;
APP_NODE_RECORD *node_record;
APP_RECORD *pAppRecord, *p;
APP_CAP_ITEM *lpAppCapData;
CAppCapItemList NonCollCapsList;
DebugEntry(CAppRoster::ReplaceRecord);
if (m_fPduIsFlushed)
{
FreeRosterUpdateIndicationPDU ();
m_fPduIsFlushed = FALSE;
}
/*
** First determine if the node record does actually already exists. If not
** we return an error here.
*/
if (NULL == (node_record = m_NodeRecordList2.Find(nid)))
{
ERROR_OUT(("CAppRoster::ReplaceRecord: can't find the node record for nid=%u", (UINT) nid));
rc = GCC_INVALID_PARAMETER;
goto MyExit;
}
// make sure the app record exists. if not, return an error
if (NULL == (pAppRecord = node_record->AppRecordList.Find(eid)))
{
ERROR_OUT(("CAppRoster::ReplaceRecord: can't find the app record for eid=%u", (UINT) eid));
rc = GCC_INVALID_PARAMETER;
goto MyExit;
}
/*
** First check to make sure that we can build the new record before
** replacing the old record. The only entry we need to wory about
** here are the non-collapsing capabilities.
*/
if (pReq->cNonCollapsedCaps != 0)
{
rc = AddNonCollapsedCapabilities(&NonCollCapsList,
pReq->cNonCollapsedCaps,
pReq->apNonCollapsedCaps);
if (GCC_NO_ERROR != rc)
{
ERROR_OUT(("CAppRoster::ReplaceRecord: can't add non collapsed caps, rc=%u", (UINT) rc));
goto MyExit;
}
}
// Now replace the record entries.
pAppRecord->is_enrolled_actively = pReq->fEnrollActively;
pAppRecord->was_conducting_capable = pReq->fConductingCapable;
pAppRecord->startup_channel_type = pReq->nStartupChannelType;
pAppRecord->application_user_id = pReq->nUserID;
/*
** If the is conducting capable flag that was passed in was set
** to FALSE we can go ahead and set the internal is conducting
** capable flag to FALSE regardless of what the previous
** setting was. If it was passed in TRUE we leave the previous
** setting alone.
*/
if (pAppRecord->was_conducting_capable == FALSE)
{
pAppRecord->is_conducting_capable = FALSE;
}
/*
** Here we delete the old non-collapsed capabilites and then
** add the new ones.
*/
if (! pAppRecord->non_collapsed_caps_list.IsEmpty())
{
pAppRecord->non_collapsed_caps_list.DeleteList();
pAppRecord->non_collapsed_caps_list.Clear();
}
// Copy the new non collapsed capabilities if any exists.
if (pReq->cNonCollapsedCaps != 0)
{
while (NULL != (lpAppCapData = NonCollCapsList.Get()))
{
pAppRecord->non_collapsed_caps_list.Append(lpAppCapData);
}
}
//
// handling collapsing cap list
//
m_nInstance++;
m_fRosterHasChanged = TRUE;
rc = BuildApplicationRecordListPDU(APP_REPLACE_RECORD, nid, eid);
if (rc != GCC_NO_ERROR)
{
ERROR_OUT(("CAppRoster::ReplaceRecord: can't build app record list, rc=%u", (UINT) rc));
goto MyExit;
}
/*
** Here we must make sure that at least one of the APEs is
** Conducting Capable. We do this by first scanning the
** list to see if anyone is it. If one is not found, the
** same list is scanned for an APE that "was" previously
** capable. The first one found that was previously
** capable is now it. If none are found then no one is
** capable.
*/
capable_node_found = FALSE;
node_record->AppRecordList.Reset();
while (NULL != (p = node_record->AppRecordList.Iterate()))
{
if (p->is_conducting_capable)
{
capable_node_found = TRUE;
break;
}
}
if (! capable_node_found)
{
GCCEntityID eid2;
node_record->AppRecordList.Reset();
while (NULL != (p = node_record->AppRecordList.Iterate(&eid2)))
{
if (p->was_conducting_capable)
{
p->is_conducting_capable = TRUE;
/*
** Set up the update PDU for this conducting
** capable change.
*/
rc = BuildApplicationRecordListPDU(APP_REPLACE_RECORD, nid, eid2);
if (GCC_NO_ERROR != rc)
{
ERROR_OUT(("CAppRoster::ReplaceRecord: can't build app record list, rc=%u", (UINT) rc));
goto MyExit;
}
break;
}
}
}
/*
** This section of code deals with the collapsable capabilities.
** First we determine if the capabilities passed in are different
** from the previously existing capabilities. If so, we must
** delete the old set of caps and add back in the new ones.
*/
TRACE_OUT(("ApplicatonRoster:ReplaceRecord: Check to see if caps match"));
if (! DoCapabilitiesListMatch(nid, eid, pReq->cCollapsedCaps, pReq->apCollapsedCaps))
{
CAppCapItemList *pCollCapsList, *q;
TRACE_OUT(("ApplicatonRoster:ReplaceRecord: Capabilities match"));
m_fCapabilitiesHaveChanged = TRUE;
/*
** Delete the old capabilities list since it does not match the
** new capabilities list.
*/
if (NULL != (q = node_record->ListOfAppCapItemList2.Find(eid)))
{
q->DeleteList();
delete q;
node_record->ListOfAppCapItemList2.Remove(eid);
}
/*
** Here we add back in the new capabilities. Create a new
** capabilities list and insert it into the roster record list of
** capabilities.
*/
if (pReq->cCollapsedCaps != 0)
{
DBG_SAVE_FILE_LINE
pCollCapsList = new CAppCapItemList;
if (NULL == pCollCapsList)
{
ERROR_OUT(("CAppRoster::ReplaceRecord: can't create CAppCapItemList"));
rc = GCC_ALLOCATION_FAILURE;
goto MyExit;
}
rc = AddCollapsableCapabilities(pCollCapsList,
pReq->cCollapsedCaps,
pReq->apCollapsedCaps);
if (rc != GCC_NO_ERROR)
{
ERROR_OUT(("CAppRoster::ReplaceRecord: can't add collapsed caps, rc=%u", (UINT) rc));
delete pCollCapsList;
goto MyExit;
}
// Add list of capabilities to list at this node
node_record->ListOfAppCapItemList2.Append(eid, pCollCapsList);
}
// Rebuild the collapsed capabilities list.
MakeCollapsedCapabilitiesList();
// Build the capabilities refresh portion of the PDU.
rc = BuildSetOfCapabilityRefreshesPDU();
if (GCC_NO_ERROR != rc)
{
ERROR_OUT(("CAppRoster::ReplaceRecord: can't build set of cap refreshes, rc=%u", (UINT) rc));
goto MyExit;
}
}
else
{
TRACE_OUT(("CAppRoster:ReplaceRecord:Capabilities match with previous record"));
}
MyExit:
DebugExitINT(CAppRoster::ReplaceRecord, rc);
return rc;
}
/*
* GCCError DeleteRecord ()
*
* Private Function Description
* This member function completely removes the specified record from the
* application roster. This includes any capabilities associated with
* this record.
*
* Formal Parameters
* node_id - (i) Node ID of record to delete.
* entity_id - (i) Entity ID of record to delete.
* clear_empty_records - (i) This flag indicates whether or not to
* clear out the node record if it no-longer
* holds data. When replacing a record we
* do NOT want to do this so that we don't
* lose any "unchanged" capabilities.
*
* Return Value
* GCC_NO_ERROR - No error occured.
* GCC_INVALID_PARAMETER - Record specified to delete does not exists.
*
* Side Effects
* none
*
* Caveats
* none
*/
GCCError CAppRoster::DeleteRecord(UserID node_id,
EntityID entity_id,
BOOL clear_empty_records)
{
GCCError rc = GCC_NO_ERROR;
APP_RECORD *application_record;
CAppCapItemList *pAppCapItemList;
CAppRecordList2 *pAppRecordList;
UserID node_to_check;
APP_NODE_RECORD *node_record;
//APP_CAP_ITEM *lpAppCapData;
APP_NODE_RECORD *lpAppNodeRec;
DebugEntry(CAppRoster::DeleteRecord);
// First see if the record is contained in the Roster_Record_List.
if (NULL != (node_record = m_NodeRecordList2.Find(node_id)))
{
// Set up node id to check at bottom for empty record
node_to_check = node_id;
// Delete the application record.
if (NULL != (application_record = node_record->AppRecordList.Find(entity_id)))
{
TRACE_OUT(("AppRoster: DeleteRecord: Delete AppRecord"));
// Delete the data associated with the application record
DeleteApplicationRecordData (application_record);
// Remove record from application record list
node_record->AppRecordList.Remove(entity_id);
/*
** Delete the associated capabilities list. Note that this list
** only exists for records of local nodes. The collapsed
** capabilities list at the root node record take create of
** subordniate nodes and is deleted some where else.
*/
if (NULL != (pAppCapItemList = node_record->ListOfAppCapItemList2.Find(entity_id)))
{
m_fCapabilitiesHaveChanged = TRUE;
pAppCapItemList->DeleteList();
TRACE_OUT(("AppRoster: DeleteRecord: Delete Capabilities"));
delete pAppCapItemList;
node_record->ListOfAppCapItemList2.Remove(entity_id);
}
}
else
{
WARNING_OUT(("AppRoster: DeleteRecord: can't find this eid=%u", (UINT) entity_id));
rc = GCC_INVALID_PARAMETER;
}
}
else
{
UserID uid2;
/*
** Here we search through all the sub node list trying to find the
** record. Set return value to record does not exist here and
** after the record is found set it back to no error.
*/
rc = GCC_INVALID_PARAMETER;
m_NodeRecordList2.Reset();
while (NULL != (lpAppNodeRec = m_NodeRecordList2.Iterate(&uid2)))
{
// Delete the sub_node list if it exists
if (NULL != (pAppRecordList = lpAppNodeRec->SubNodeList2.Find(node_id)))
{
// Delete the app_record_list entry.
if (NULL != (application_record = pAppRecordList->Find(entity_id)))
{
// Delete the data associated with the application record
DeleteApplicationRecordData (application_record);
pAppRecordList->Remove(entity_id);
if (pAppRecordList->IsEmpty())
{
TRACE_OUT(("AppRoster: DeleteRecord: Deleting Sub-Node"));
delete pAppRecordList;
lpAppNodeRec->SubNodeList2.Remove(node_id);
}
// Set up node id to check at bottom for empty record
node_to_check = uid2;
rc = GCC_NO_ERROR;
}
break;
}
}
}
/*
** If the record list is empty and the sub node list is empty
** we can remove this entire record from the application roster.
** If the record list is empty but the sub node list is not we
** must keep the roster record around to maintain the sub node list.
*/
if ((rc == GCC_NO_ERROR) && clear_empty_records)
{
if (NULL != (node_record = m_NodeRecordList2.Find(node_to_check)) &&
node_record->AppRecordList.IsEmpty() &&
node_record->SubNodeList2.IsEmpty())
{
if (! node_record->CollapsedCapList.IsEmpty())
{
m_fCapabilitiesHaveChanged = TRUE;
// Delete the collapsed capabilities list.
node_record->CollapsedCapList.DeleteList();
}
delete node_record;
m_NodeRecordList2.Remove(node_to_check);
}
}
return rc;
}
/*
* GCCError RemoveUserReference ()
*
* Public Function Description
* This routine will only remove the application record and its sub nodes
* if the node being removed is directly connected to this node.
* Otherwise, we wait to receive the update from either the sub node or
* the Top Provider.
*/
GCCError CAppRoster::RemoveUserReference(UserID detached_node)
{
GCCError rc = GCC_NO_ERROR;
DebugEntry(CAppRoster::RemoveUserReference);
// Clear out any previously allocated PDUs
if (m_fPduIsFlushed)
{
FreeRosterUpdateIndicationPDU ();
m_fPduIsFlushed = FALSE;
}
/*
** First Try to remove the node record if one exist. If it does not
** exist we return immediately. If it does exists we will build the
** appropriate PDU and update the instance variables.
*/
rc = ClearNodeRecordFromList (detached_node);
if (rc == GCC_NO_ERROR)
{
// Increment the instance number.
m_nInstance++;
m_fPeerEntitiesRemoved = TRUE;
m_fRosterHasChanged = TRUE;
/*
** Go ahead and do the full refresh here since we do not know the
** specifics about who was deleted.
*/
rc = BuildApplicationRecordListPDU(APP_FULL_REFRESH, 0, 0);
if (m_fCapabilitiesHaveChanged && (rc == GCC_NO_ERROR))
{
// Create a new collapsed capabilities list.
MakeCollapsedCapabilitiesList();
// Build the capabilities refresh portion of the PDU.
rc = BuildSetOfCapabilityRefreshesPDU ();
}
}
return rc;
}
/*
* void DeleteApplicationRecordData ()
*
* Private Function Description
* This routine internal application record data.
*
* Formal Parameters
* application_record - Pointer to the application record data to
* delete.
*
* Return Value
* none
*
* Side Effects
* none
*
* Caveats
* none
*/
void CAppRoster::DeleteApplicationRecordData(APP_RECORD *pAppRec)
{
pAppRec->non_collapsed_caps_list.DeleteList();
delete pAppRec;
}
/*
* USHORT GetNumberOfApplicationRecords ()
*
* Public Function Description
* This routine returns the total number of application records that exist
* in this application roster.
*
* Formal Parameters
* none
*
* Return Value
* Number of application roster records
*
* Side Effects
* none
*
* Caveats
* none
*/
UINT CAppRoster::GetNumberOfApplicationRecords(void)
{
UINT cRecords = 0;
APP_NODE_RECORD *lpAppNodeRec;
CAppRecordList2 *lpAppRecDataList;
DebugEntry(CAppRoster::GetNumberOfApplicationRecords);
/*
** First calculate the total number of records. This count is used to
** allocate the space necessary to hold the records. Note that we must
** count both the application record list and the sub-node list.
*/
m_NodeRecordList2.Reset();
while (NULL != (lpAppNodeRec = m_NodeRecordList2.Iterate()))
{
// Add the application records at this node to the count.
cRecords += lpAppNodeRec->AppRecordList.GetCount();
// Next count the sub node entries.
if (! lpAppNodeRec->SubNodeList2.IsEmpty())
{
lpAppNodeRec->SubNodeList2.Reset();
while (NULL != (lpAppRecDataList = lpAppNodeRec->SubNodeList2.Iterate()))
{
cRecords += lpAppRecDataList->GetCount();
}
}
}
return cRecords;
}
/*
* PGCCSessionKey GetSessionKey ()
*
* Public Function Description
* This routine returns the session key associated with this
* application roster.
*
* Formal Parameters
* none
*
* Return Value
* PGCCSessionKey - the application key associated with this roster
*
* Side Effects
* none
*
* Caveats
* none
*/
/*
* void ResetApplicationRoster ()
*
* Public Function Description
* This routine takes care of resetting all the internal flags that are
* used to convey the current state of the application roster. Should be
* called after the roster is flushed and any roster update messages have
* been delivered (after a change to the roster occurs).
*/
void CAppRoster::ResetApplicationRoster(void)
{
m_fCapabilitiesHaveChanged = FALSE;
m_fRosterHasChanged = FALSE;
m_fPeerEntitiesRemoved = FALSE;
m_fPeerEntitiesAdded = FALSE;
}
/*
* BOOL DoesRecordExist ()
*
* Public Function Description
* This routine informs the caller if the specified application record
* exists or not.
*/
BOOL CAppRoster::DoesRecordExist(UserID node_id, EntityID entity_id)
{
BOOL rc = FALSE;
APP_NODE_RECORD *node_record;
CAppRecordList2 *record_list;
DebugEntry(CAppRoster::DoesRecordExist);
if (NULL != (node_record = m_NodeRecordList2.Find(node_id)))
{
if (node_record->AppRecordList.Find(entity_id))
rc = TRUE;
}
else
{
m_NodeRecordList2.Reset();
while (NULL != (node_record = m_NodeRecordList2.Iterate()))
{
if (NULL != (record_list = node_record->SubNodeList2.Find(node_id)))
{
if (record_list->Find(entity_id))
rc = TRUE;
}
}
}
return rc;
}
/*
* BOOL HasRosterChanged ()
*
* Public Function Description
* This routine informs the caller if the roster has changed since the
* last time it was reset.
*/
/*
* GCCError ClearNodeRecordFromList ()
*
* Private Function Description
* This routine clears out all the application records that exists at
* the specified node or below it in the connection hierarchy.
*
* Formal Parameters
* node_id - Node ID of node to clear from Node Record list
*
* Return Value
* GCC_NO_ERROR - No error occured
* GCC_INVALID_PARAMETER - The specified node ID is not associated
* with any records.
*
* Side Effects
* none
*
* Caveats
* none
*/
GCCError CAppRoster::ClearNodeRecordFromList( UserID node_id)
{
GCCError rc = GCC_NO_ERROR;
APP_NODE_RECORD *node_record;
APP_RECORD *lpAppRecData;
//APP_CAP_ITEM *lpAppCapData;
CAppRecordList2 *lpAppRecDataList;
DebugEntry(CAppRoster::ClearNodeRecordFromList);
if (NULL != (node_record = m_NodeRecordList2.Find(node_id)))
{
// Delete all the app_record_list entries.
node_record->AppRecordList.Reset();
while (NULL != (lpAppRecData = node_record->AppRecordList.Iterate()))
{
DeleteApplicationRecordData (lpAppRecData);
}
/*
** Delete the ListOfAppCapItemList2 entries. Note that this
** list should not exists for detached nodes if the local applications
** cleanly unenroll with GCC. This list should only exists for
** locally enrolled APEs. We still check here just to make sure.
*/
if (! node_record->ListOfAppCapItemList2.IsEmpty())
{
//CAppCapItemList *lpAppCapDataList;
m_fCapabilitiesHaveChanged = TRUE;
node_record->ListOfAppCapItemList2.DeleteList();
}
// Delete the sub_node list.
node_record->SubNodeList2.Reset();
while (NULL != (lpAppRecDataList = node_record->SubNodeList2.Iterate()))
{
// Delete all the app_record_list entries.
lpAppRecDataList->Reset();
while (NULL != (lpAppRecData = lpAppRecDataList->Iterate()))
{
DeleteApplicationRecordData (lpAppRecData);
}
delete lpAppRecDataList;
}
// Delete the collapsed capabilities list.
if (! node_record->CollapsedCapList.IsEmpty())
{
m_fCapabilitiesHaveChanged = TRUE;
node_record->CollapsedCapList.DeleteList();
}
// Delete the rogoue wave reference to this roster record.
delete node_record;
m_NodeRecordList2.Remove(node_id);
}
else
rc = GCC_INVALID_PARAMETER;
return rc;
}
/*
* ApplicationRosterError ClearNodeRecordList ()
*
* Private Function Description
* This routine complete frees all memory associated with the roster
* record list and clears the list of all its entries.
*
* Formal Parameters
* none
*
* Return Value
* none
*
* Side Effects
* none
*
* Caveats
* Currently this routine does not handle standard identifiers.
*/
void CAppRoster::ClearNodeRecordList(void)
{
APP_NODE_RECORD *lpAppNodeRec;
APP_RECORD *lpAppRecData;
CAppRecordList2 *lpAppRecDataList;
//APP_CAP_ITEM *lpAppCapData;
//CAppCapItemList *lpAppCapDataList;
DebugEntry(CAppRoster::ClearNodeRecordList);
// Delete all the records in the application roster.
m_NodeRecordList2.Reset();
while (NULL != (lpAppNodeRec = m_NodeRecordList2.Iterate()))
{
// First delete all the app records at this node.
lpAppNodeRec->AppRecordList.Reset();
while (NULL != (lpAppRecData = lpAppNodeRec->AppRecordList.Iterate()))
{
DeleteApplicationRecordData(lpAppRecData);
}
// Next delete all the sub node record list.
lpAppNodeRec->SubNodeList2.Reset();
while (NULL != (lpAppRecDataList = lpAppNodeRec->SubNodeList2.Iterate()))
{
lpAppRecDataList->Reset();
while (NULL != (lpAppRecData = lpAppRecDataList->Iterate()))
{
DeleteApplicationRecordData(lpAppRecData);
}
// Delete the rogue wave list holding the lists of sub nodes.
delete lpAppRecDataList;
}
// Delete the collapsed capabilities list.
lpAppNodeRec->CollapsedCapList.DeleteList();
// Delete the list of capabilities list.
lpAppNodeRec->ListOfAppCapItemList2.DeleteList();
// Now delete the node record
delete lpAppNodeRec;
}
m_NodeRecordList2.Clear();
}
/*
* GCCError MakeCollapsedCapabilitiesList ()
*
* Private Function Description
* This routine is responsible for applying the T.124 capabilities
* rules to create the collapsed capabilities list at this node.
* It iterates through all the capabilities at this node to create this
* collapsed list.
*
* Formal Parameters
* none
*
* Return Value
* GCC_NO_ERROR - On success
* GCC_ALLOCATION_FAILURE - On resource error
*
* Side Effects
* none
*
* Caveats
* Currently this routine does not handle standard identifiers.
*/
GCCError CAppRoster::MakeCollapsedCapabilitiesList(void)
{
GCCError rc = GCC_NO_ERROR;
APP_CAP_ITEM *lpAppCapData;
APP_NODE_RECORD *lpAppNodeRec;
CAppCapItemList *lpAppCapDataList;
DebugEntry(CAppRoster::MakeCollapsedCapabilitiesList);
// First clear out the old capabilities list.
m_CollapsedCapListForAllNodes.DeleteList();
/*
** We now iterate through the capabilities at each node to create the
** new capabilities list. Note that we have to check for the collapsed
** capabilities list at each node as well as the list of capabilities list
** that represents all the different capabilities for each entity at a
** node. Note that in this implementation it is not possible to have both
** a list of capabilities list and a collapsed capabilities list in the
** same roster record.
*/
m_NodeRecordList2.Reset();
while (NULL != (lpAppNodeRec = m_NodeRecordList2.Iterate()))
{
/*
** First check the collapsed capabilities list. If entries exists
** then we don't have to worry about the list of list.
*/
if (! lpAppNodeRec->CollapsedCapList.IsEmpty())
{
lpAppNodeRec->CollapsedCapList.Reset();
while (NULL != (lpAppCapData = lpAppNodeRec->CollapsedCapList.Iterate()))
{
rc = AddCapabilityToCollapsedList(lpAppCapData);
if (GCC_NO_ERROR != rc)
{
goto MyExit; // break;
}
}
}
else
if (! lpAppNodeRec->ListOfAppCapItemList2.IsEmpty())
{
// Here we check the list of capabilities list.
lpAppNodeRec->ListOfAppCapItemList2.Reset();
while (NULL != (lpAppCapDataList = lpAppNodeRec->ListOfAppCapItemList2.Iterate()))
{
lpAppCapDataList->Reset();
while (NULL != (lpAppCapData = lpAppCapDataList->Iterate()))
{
rc = AddCapabilityToCollapsedList(lpAppCapData);
if (GCC_NO_ERROR != rc)
{
goto MyExit;
}
}
}
}
}
ASSERT(GCC_NO_ERROR == rc);
MyExit:
return rc;
}
/*
* GCCError AddCapabilityToCollapsedList ()
*
* Private Function Description
* This is the routine that performs the rules that allow the capability
* to be collapsed into the collapsed list.
*
* Formal Parameters
* new_capability - (i) Add this capability to the collapsed list.
*
* Return Value
* GCC_NO_ERROR - On success
* GCC_ALLOCATION_FAILURE - On resource error
*
* Side Effects
* none
*
* Caveats
* none
*/
GCCError CAppRoster::AddCapabilityToCollapsedList(APP_CAP_ITEM *new_capability)
{
GCCError rc = GCC_NO_ERROR;
APP_CAP_ITEM *pAppCapItem;
DebugEntry(CAppRoster::AddCapabilityToCollapsedList);
/*
** First determine if the capability already exists in the list.
** We must iterate through the complete list to determine if there
** is a matching capability id.
*/
m_CollapsedCapListForAllNodes.Reset();
while (NULL != (pAppCapItem = m_CollapsedCapListForAllNodes.Iterate()))
{
if (*pAppCapItem->pCapID == *new_capability->pCapID)
{
pAppCapItem->cEntries += new_capability->cEntries;
break;
}
}
if (pAppCapItem == NULL)
{
DBG_SAVE_FILE_LINE
pAppCapItem = new APP_CAP_ITEM(new_capability, &rc);
if (NULL == pAppCapItem)
{
return GCC_ALLOCATION_FAILURE;
}
if (GCC_NO_ERROR != rc)
{
delete pAppCapItem;
return rc;
}
m_CollapsedCapListForAllNodes.Append(pAppCapItem);
}
/*
** If the unsigned minimum or unsigned maximum rule is used perform the
** operation here.
*/
ASSERT(GCC_NO_ERROR == rc);
if (new_capability->eCapType == GCC_UNSIGNED_MINIMUM_CAPABILITY)
{
if (new_capability->nUnsignedMinimum < pAppCapItem->nUnsignedMinimum)
{
pAppCapItem->nUnsignedMinimum = new_capability->nUnsignedMinimum;
}
}
else if (new_capability->eCapType == GCC_UNSIGNED_MAXIMUM_CAPABILITY)
{
if (new_capability->nUnsignedMaximum > pAppCapItem->nUnsignedMaximum)
{
pAppCapItem->nUnsignedMaximum = new_capability->nUnsignedMaximum;
}
}
return rc;
}
/*
* BOOL DoCapabilitiesListMatch ()
*
* Private Function Description
* This routine determines if the set of capabilities that were passed in
* match the set of internal capabilities associated with the record.
*
* Formal Parameters
* node_id - (i) Node ID of record that contains the
* capabilities to check.
* entity_id - (i) Entity ID of record that contains the
* capbilities to check.
* number_of_capabilities - (i) Number of capabilities in list to check.
* capabilities_list - (i) "API" capabillities list to check
*
* Return Value
* TRUE - If capabillities list match
* FALSE - If capabillities list do NOT match
*
* Side Effects
* none
*
* Caveats
* none
*/
BOOL CAppRoster::DoCapabilitiesListMatch (
UserID node_id,
EntityID entity_id,
UINT number_of_capabilities,
PGCCApplicationCapability * capabilities_list)
{
BOOL rc = FALSE;
CAppCapItemList *pAppCapItemList;
GCCError error_value;
APP_NODE_RECORD *node_record;
UINT i;
CCapIDContainer *capability_id;
DebugEntry(CAppRoster::DoCapabilitiesListMatch);
if (NULL == (node_record = m_NodeRecordList2.Find(node_id)))
return (FALSE);
if (NULL == (pAppCapItemList = node_record->ListOfAppCapItemList2.Find(entity_id)))
{
/*
** If the record shows no capabilities and the number of passed
** in capabilities is zero than we got a match.
*/
return ((number_of_capabilities == 0) ? TRUE : FALSE);
}
else if (pAppCapItemList->GetCount() != number_of_capabilities)
{
return (FALSE);
}
/*
** If we have gotten this far we must iterate through the entire list to
** see if all the capabilities match.
*/
for (i = 0; i < number_of_capabilities; i++)
{
/*
** First we create a temporary ID to compare to the other
** capability IDs.
*/
DBG_SAVE_FILE_LINE
capability_id = new CCapIDContainer(&capabilities_list[i]->capability_id, &error_value);
if ((capability_id != NULL) && (error_value == GCC_NO_ERROR))
{
APP_CAP_ITEM *lpAppCapData;
// Start with the return value equal to FALSE
rc = FALSE;
/*
** Now iterate through the complate internal capability
** list looking for a matching capability.
*/
pAppCapItemList->Reset();
while (NULL != (lpAppCapData = pAppCapItemList->Iterate()))
{
if (*capability_id == *lpAppCapData->pCapID)
{
if (lpAppCapData->eCapType == capabilities_list[i]->capability_class.eType)
{
if (capabilities_list[i]->capability_class.eType ==
GCC_UNSIGNED_MINIMUM_CAPABILITY)
{
if (capabilities_list[i]->capability_class.nMinOrMax ==
lpAppCapData->nUnsignedMinimum)
{
rc = TRUE;
}
}
else if (capabilities_list[i]->capability_class.eType ==
GCC_UNSIGNED_MAXIMUM_CAPABILITY)
{
if (capabilities_list[i]->capability_class.nMinOrMax ==
lpAppCapData->nUnsignedMaximum)
{
rc = TRUE;
}
}
else
rc = TRUE;
}
break;
}
}
// Delete the capability ID data
capability_id->Release();
if (rc == FALSE)
break;
}
else
{
if (NULL != capability_id)
{
capability_id->Release();
}
break;
}
}
return rc;
}
void CAppRosterList::DeleteList(void)
{
CAppRoster *pAppRoster;
while (NULL != (pAppRoster = Get()))
{
pAppRoster->Release();
}
}
void CListOfAppCapItemList2::DeleteList(void)
{
CAppCapItemList *pAppCapItemList;
while (NULL != (pAppCapItemList = Get()))
{
pAppCapItemList->DeleteList();
delete pAppCapItemList;
}
}