You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4544 lines
127 KiB
4544 lines
127 KiB
#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
|
|
{
|
|
if(old_set_of_capabilities != NULL)
|
|
{
|
|
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:
|
|
|
|
if(rc != GCC_NO_ERROR)
|
|
{
|
|
FreeSetOfNonCollapsingCapabilitiesPDU(*pSetOfCaps);
|
|
*pSetOfCaps = NULL;
|
|
}
|
|
|
|
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 = NULL;
|
|
CAppRecordList2 *record_list=NULL;
|
|
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;
|
|
}
|
|
|
|
if(!m_NodeRecordList2.Append(sender_id, node_record))
|
|
{
|
|
goto MyExit;
|
|
}
|
|
|
|
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:
|
|
|
|
if(rc ==GCC_ALLOCATION_FAILURE)
|
|
{
|
|
if(node_record)
|
|
{
|
|
delete node_record;
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
|
|
if(!m_NodeRecordList2.Append(sender_id, node_record))
|
|
{
|
|
delete node_record;
|
|
return GCC_ALLOCATION_FAILURE;
|
|
}
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
if( !non_collapsed_caps_list->Append(pAppCapItem) )
|
|
{
|
|
rc = GCC_ALLOCATION_FAILURE;
|
|
goto MyExit;
|
|
}
|
|
} // for
|
|
|
|
ASSERT(GCC_NO_ERROR == rc);
|
|
|
|
MyExit:
|
|
|
|
if (GCC_NO_ERROR != rc)
|
|
{
|
|
if( NULL != pAppCapItem )
|
|
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 = NULL;
|
|
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
|
|
if( !pAppCapItemList->Append(pAppCapItem) )
|
|
{
|
|
rc = GCC_ALLOCATION_FAILURE;
|
|
goto MyExit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rc = GCC_ALLOCATION_FAILURE;
|
|
goto MyExit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rc = GCC_ALLOCATION_FAILURE;
|
|
goto MyExit;
|
|
}
|
|
}
|
|
|
|
MyExit:
|
|
|
|
if (GCC_NO_ERROR != rc)
|
|
{
|
|
if(pAppCapItem != NULL)
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
|
|
|