windows-nt/Source/XPSP1/NT/termsrv/remdsk/rds/t120/mst120/crost.cpp
2020-09-26 16:20:57 +08:00

3143 lines
83 KiB
C++
Raw Permalink Blame History

This file contains invisible Unicode characters

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

#include "precomp.h"
#include "fsdiag.h"
DEBUG_FILEZONE(ZONE_T120_CONF_ROSTER);
/*
* crost.cpp
*
* Copyright (c) 1995 by DataBeam Corporation, Lexington, KY
*
* Abstract:
* This is the implementation file for the Conference Roster Class.
* Instances of this class represent a single Conference Roster's
* information base. It encapsulates all the functionality required to
* maintain the information base which includes the ability to add new
* roster records, delete records and update records. It has the ability
* to convert its internal information base into a list of conference
* records that can be used in a GCC_ROSTER_UPDATE_INDICATION callback.
* It is also responsible for converting its internal information base
* into Conference Roster Update PDUs. Basically, this class is
* responsible for all operations that require direct access to the
* records contained in a Conference Roster.
*
* The Conference Roster class incorporates Rogue Wave list to hold the
* roster record information. Using iterators throughout the class makes
* it easy to quickly convert the information contained in the list into
* either a PDU or into a list of record pointers (for roster update
* indications back to the node controller).
*
* A Conference Roster object has the ability to serialize its roster data
* into a single contiguous memory block when it is required to send a
* message to the application interface. This serialization process is
* managed externally by the CConfRosterMsg class through calls
* to LockConferenceRoster(), UnLockConferenceRoster() and
* GetConfRoster(). When a conference roster is to be serialized, a
* call is made to LockConferenceRoster() which causes the CConfRoster
* object to increment an internal lock count and returns the number of
* bytes required to hold the complete roster update. The Conference
* Roster is then serialized into memory through a call to
* GetConfRoster(). The CConfRoster is then unlocked to allow
* it to be deleted when the free flag gets set through the
* FreeConferenceRoster() function. In the current implementation of GCC,
* FreeConferenceRoster() is not used since the CConfRosterMsg
* maintains the data used to deliver the message.
*
* Private Instance Variables:
* m_RecordList2
* This is the rogue wave list used to hold the pointers to all of the
* rogue wave records.
* m_nInstanceNumber
* This instance variable maintains an up to date instance #
* corresponding to the current conference roster.
* m_fNodesAdded
* Flag indicating if any node records have been added to the
* conference roster since the last reset.
* m_fNodesRemoved
* Flag indicating if any node records have been removed from the
* conference roster since the last reset.
* m_fRosterChanged
* Flag indicating if the roster has changed since the last reset.
* m_uidTopProvider
* The node id of the top provider in the conference.
* m_uidSuperiorNode
* This is the node id of this nodes superior node. For the top
* provider this is zero.
* m_cbDataMemorySize
* This is the number of bytes required to hold the data associated
* with a roster update message. This is calculated on a lock.
* m_NodeInformation
* Structure used to hold the roster update indication node information
* data in "PDU" form.
* 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_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_fPduFlushed
* Flag indicating if the PDU that currently exists has been flushed.
* m_pNodeRecordUpdateSet
* Pointer to internal PDU data.
*
* Caveats:
* None.
*
* Author:
* blp/jbo
*/
#include "ms_util.h"
#include "crost.h"
#define MAXIMUM_NODE_NAME_LENGTH 255
#define MAXIMUM_PARTICIPANT_NAME_LENGTH 255
#define MAXIMUM_SITE_INFORMATION_LENGTH 255
#define ALTERNATIVE_NODE_ID_LENGTH 2
/*
* CConfRoster ()
*
* Public Function Description:
* This is a constructor for the CConfRoster class. It initializes
* instance variables.
*
*/
CConfRoster::CConfRoster(UserID uidTopProvider, UserID uidSuperiorNode, UserID uidMyself,
BOOL is_top_provider, BOOL is_local_roster, BOOL maintain_pdu_buffer)
:
CRefCount(MAKE_STAMP_ID('C','R','s','t')),
m_fNodesAdded(FALSE),
m_fNodesRemoved(FALSE),
m_fRosterChanged(FALSE),
m_fTopProvider(is_top_provider),
m_fLocalRoster(is_local_roster),
m_fMaintainPduBuffer(maintain_pdu_buffer),
m_fPduFlushed(FALSE),
m_uidTopProvider(uidTopProvider),
m_uidSuperiorNode(uidSuperiorNode),
m_uidMyNodeID(uidMyself),
m_nInstanceNumber(0),
m_cbDataMemorySize(0),
m_RecordList2(DESIRED_MAX_NODE_RECORDS),
m_pNodeRecordUpdateSet(NULL)
{
m_NodeInformation.node_record_list.choice = NODE_NO_CHANGE_CHOSEN;
}
/*
* ~CConfRoster ()
*
* Public Function Description:
* This is the destructor for the CConfRoster. It performs any
* necessary cleanup.
*/
CConfRoster::~CConfRoster(void)
{
// Free up any left over PDU data.
if (m_fMaintainPduBuffer)
FreeRosterUpdateIndicationPDU ();
// Cleanup the Rogue Wave list of node records.
ClearRecordList();
}
/*
* Utilities that operate on roster update PDU structures.
*/
/*
* void FlushRosterUpdateIndicationPDU ()
*
* Public Function Description:
* This routine is used to retrieve a "RosterUpdateIndication" in the "PDU"
* form which is suitable for passing to the ASN.1 encoder. The "PDU"
* structure is built from a previous request to the conference roster.
*/
void CConfRoster::FlushRosterUpdateIndicationPDU(
PNodeInformation node_information)
{
/*
** 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 no change will be passed back in the node
** information.
*/
if (m_fPduFlushed)
{
FreeRosterUpdateIndicationPDU ();
m_fPduFlushed = FALSE;
}
// First we copy all of the node record list information.
*node_information = m_NodeInformation;
/*
** Next we copy the relevent instance variables. Note that we must do
** this after we copy the node information so that these variables
** will not be copied over with garbage.
*/
node_information->roster_instance_number = (ASN1uint16_t)m_nInstanceNumber;
node_information->nodes_are_added = (ASN1bool_t)m_fNodesAdded;
node_information->nodes_are_removed = (ASN1bool_t)m_fNodesRemoved;
/*
** 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.
*/
if (m_NodeInformation.node_record_list.choice != NODE_NO_CHANGE_CHOSEN)
m_fPduFlushed = TRUE;
}
/*
* GCCError BuildFullRefreshPDU ()
*
* Public Function Description
*
*/
GCCError CConfRoster::BuildFullRefreshPDU(void)
{
GCCError rc;
/*
** 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_fPduFlushed)
{
FreeRosterUpdateIndicationPDU ();
m_fPduFlushed = FALSE;
}
rc = BuildRosterUpdateIndicationPDU (FULL_REFRESH, 0);
return (rc);
}
/*
* GCCError BuildRosterUpdateIndicationPDU ()
*
* Public Function Description:
* This routine is used to build a "RosterUpdateIndication" in the "PDU"
* form which is suitable for passing to the ASN.1 encoder. The "PDU"
* structure is built from the data maintained internally.
*/
GCCError CConfRoster::BuildRosterUpdateIndicationPDU(
CONF_ROSTER_UPDATE_TYPE update_type,
UserID node_id)
{
GCCError rc = GCC_NO_ERROR;
if (m_fMaintainPduBuffer)
{
/*
** If "PDU" data has already been allocated then we free it up and
** rebuild the PDU structure. This ensures that the most up-to-date
** PDU is returned.
*/
if ((update_type == FULL_REFRESH) || m_fTopProvider)
{
if (m_NodeInformation.node_record_list.choice ==
NODE_RECORD_REFRESH_CHOSEN)
{
// Here we free the old set of refreshes.
FreeSetOfRefreshesPDU();
}
else if (m_NodeInformation.node_record_list.choice ==
NODE_RECORD_UPDATE_CHOSEN)
{
ERROR_OUT(("CConfRoster::BuildRosterUpdateIndicationPDU:"
"ASSERTION: building refresh when update exists"));
rc = GCC_INVALID_PARAMETER;
}
if (rc == GCC_NO_ERROR)
{
rc = BuildSetOfRefreshesPDU();
if (rc == GCC_NO_ERROR)
{
m_NodeInformation.node_record_list.choice =
NODE_RECORD_REFRESH_CHOSEN;
}
}
}
else
{
if (m_NodeInformation.node_record_list.choice ==
NODE_RECORD_REFRESH_CHOSEN)
{
ERROR_OUT(("CConfRoster::BuildRosterUpdateIndicationPDU:"
"ASSERTION: building update when refresh exists"));
rc = GCC_INVALID_PARAMETER;
}
if (rc == GCC_NO_ERROR)
{
rc = BuildSetOfUpdatesPDU(node_id, update_type);
if (rc == GCC_NO_ERROR)
{
//
// LONCHANC: Commented out the following check because
// we can overrun the update, namely, two updates coming
// in side by side. It happens when shutting down a
// conference, we got two ConferenceAnnouncePresenceRequest.
// It is quite stupid in the node controller to call it
// twice unncessarily. The node controller should not call
// it at all when we know we are about to ending a conference.
//
// When two updates come in side by side, m_pNodeRecordUpdateSet
// will keep all the update information intact. New information
// can then be appended to the list.
//
// if (m_NodeInformation.node_record_list.choice ==
// NODE_NO_CHANGE_CHOSEN)
{
m_NodeInformation.node_record_list.u.node_record_update =
m_pNodeRecordUpdateSet;
m_NodeInformation.node_record_list.choice =
NODE_RECORD_UPDATE_CHOSEN;
}
}
}
}
}
return (rc);
}
/*
* GCCError BuildSetOfRefreshesPDU ()
*
* Private Function Description:
* This routine is used to retrieve the "SetOfRefreshes" portion of a
* "RosterUpdateIndication" in the "PDU" form. The internally maintained
* data is converted into the "PDU" form.
*
* Formal Parameters:
* None.
*
* Return Value
* GCC_NO_ERROR - No error occured.
* GCC_ALLOCATION_FAILURE - A resource error occured.
*
* Side Effects
* None.
*
* Caveats
* None.
*/
GCCError CConfRoster::BuildSetOfRefreshesPDU(void)
{
GCCError rc = GCC_NO_ERROR;
PSetOfNodeRecordRefreshes new_record_refresh;
PSetOfNodeRecordRefreshes old_record_refresh;
PNodeRecord node_record;
CONF_RECORD *lpRec;
UserID uid;
m_NodeInformation.node_record_list.u.node_record_refresh = NULL;
old_record_refresh = NULL; // This eliminates a compiler warning
m_RecordList2.Reset();
while (NULL != (lpRec = m_RecordList2.Iterate(&uid)))
{
DBG_SAVE_FILE_LINE
new_record_refresh = new SetOfNodeRecordRefreshes;
if (new_record_refresh == NULL)
{
ERROR_OUT(("CConfRoster::BuildSetOfRefreshesPDU: can't create set ofnode record refreshes"));
rc = GCC_ALLOCATION_FAILURE;
goto MyExit;
}
//
// Ensure everything here is clean.
// We may fail in the middle of building this node record.
//
::ZeroMemory(new_record_refresh, sizeof(SetOfNodeRecordRefreshes));
//
// Hook to the linked list.
//
if (m_NodeInformation.node_record_list.u.node_record_refresh == NULL)
{
m_NodeInformation.node_record_list.u.node_record_refresh = new_record_refresh;
}
else
{
old_record_refresh->next = new_record_refresh;
}
old_record_refresh = new_record_refresh;
/*
* Initialize the refresh "next" pointer to NULL and set the
* refresh value node ID equal to the internal node ID.
*/
new_record_refresh->next = NULL;
new_record_refresh->value.node_id = uid;
/*
* Fill in the "PDU" node record structure from the internal
* record structure.
*/
node_record = &(new_record_refresh->value.node_record);
node_record->bit_mask = 0;
/*
* Check to see if the superior node ID is present. If the value
* is zero, then the record is for the top provider node and the
* superior node ID does not need to be filled in.
*/
if (lpRec->superior_node != 0)
{
node_record->bit_mask |= SUPERIOR_NODE_PRESENT;
node_record->superior_node = lpRec->superior_node;
}
/*
* Fill in the node type and node properties which are always
* present.
*/
node_record->node_type = lpRec->node_type;
node_record->node_properties = lpRec->node_properties;
/*
** This roster object must not go out of scope while this
** update record is still in use!
*/
/*
* Fill in the node name if it is present.
*/
if (lpRec->pwszNodeName != NULL)
{
node_record->bit_mask |= NODE_NAME_PRESENT;
node_record->node_name.value = lpRec->pwszNodeName;
node_record->node_name.length = ::lstrlenW(lpRec->pwszNodeName);
}
/*
* Fill in the participants list if it is present.
*/
if (lpRec->participant_name_list != NULL)
{
node_record->bit_mask |= PARTICIPANTS_LIST_PRESENT;
rc = BuildParticipantsListPDU(uid, &(node_record->participants_list));
if (GCC_NO_ERROR != rc)
{
ERROR_OUT(("CConfRoster::BuildSetOfRefreshesPDU: can't build participant list, rc=%d", rc));
goto MyExit;
}
}
/*
* Fill in the site information if it is present.
*/
if (lpRec->pwszSiteInfo != NULL)
{
node_record->bit_mask |= SITE_INFORMATION_PRESENT;
node_record->site_information.value = lpRec->pwszSiteInfo;
node_record->site_information.length = ::lstrlenW(lpRec->pwszSiteInfo);
}
/*
* Fill in the network address if it is present.
*/
if ((lpRec->network_address_list != NULL) && (rc == GCC_NO_ERROR))
{
node_record->bit_mask |= RECORD_NET_ADDRESS_PRESENT;
rc = lpRec->network_address_list->GetNetworkAddressListPDU (
&(node_record->record_net_address));
if (GCC_NO_ERROR != rc)
{
ERROR_OUT(("CConfRoster::BuildSetOfRefreshesPDU: can't get network address list, rc=%d", rc));
goto MyExit;
}
}
/*
* Fill in the alternative node ID if it is present.
*/
if (lpRec->poszAltNodeID != NULL)
{
node_record->bit_mask |= ALTERNATIVE_NODE_ID_PRESENT;
node_record->alternative_node_id.choice = H243_NODE_ID_CHOSEN;
node_record->alternative_node_id.u.h243_node_id.length = lpRec->poszAltNodeID->length;
::CopyMemory(node_record->alternative_node_id.u.h243_node_id.value,
lpRec->poszAltNodeID->value,
node_record->alternative_node_id.u.h243_node_id.length);
}
/*
* Fill in the user data list if it is present.
*/
if ((lpRec->user_data_list != NULL) && (rc == GCC_NO_ERROR))
{
node_record->bit_mask |= RECORD_USER_DATA_PRESENT;
rc = lpRec->user_data_list->GetUserDataPDU (&(node_record->record_user_data));
}
}
MyExit:
if (rc != GCC_NO_ERROR)
{
ERROR_OUT(("CConfRoster::BuildSetOfRefreshesPDU: ASSERTION: Error occured: rc=%d", rc));
}
return (rc);
}
/*
* GCCError BuildSetOfUpdatesPDU ()
*
* Private Function Description
* This routine is used to retrieve the "SetOfUpdates" portion of a
* "RosterUpdateIndication" in the "PDU" form. The internally maintained
* data is converted into the "PDU" form.
*
* Formal Parameters:
* node_id - (i) Node ID of node record to be included in
* the update.
* update_type - (i) The type of update PDU to build (Add,
* Delete, Replace).
*
* Return Value
* GCC_NO_ERROR - No error occured.
* GCC_ALLOCATION_FAILURE - A resource error occured.
*
* Side Effects
* None.
*
* Caveats
* None.
*/
GCCError CConfRoster::BuildSetOfUpdatesPDU(
UserID node_id,
CONF_ROSTER_UPDATE_TYPE update_type)
{
GCCError rc = GCC_NO_ERROR;
PNodeRecord node_record = NULL;
CONF_RECORD *lpRec;
PSetOfNodeRecordUpdates pRecordUpdate, p;
BOOL fReplaceExistingOne = FALSE;
if (NULL != (lpRec = m_RecordList2.Find(node_id)))
{
//
// LONCHANC: Check to see if a update record already exists
// for this particular node ID. If so, we should replace
// the record.
//
for (p = m_pNodeRecordUpdateSet; NULL != p; p = p->next)
{
if (node_id == p->value.node_id)
{
pRecordUpdate = p;
fReplaceExistingOne = TRUE;
CleanUpdateRecordPDU(pRecordUpdate); // do not free the record itself
//
// Remember who is the next to restore because
// we will zero out the entire structure later.
//
p = pRecordUpdate->next;
break;
}
}
if (! fReplaceExistingOne)
{
DBG_SAVE_FILE_LINE
pRecordUpdate = new SetOfNodeRecordUpdates;
if (NULL == pRecordUpdate)
{
ERROR_OUT(("CConfRoster::BuildSetOfUpdatesPDU: can't create set of node record updates, rc=%d", rc));
rc = GCC_ALLOCATION_FAILURE;
goto MyExit;
}
}
//
// Ensure everything here is clean.
// We may fail in the middle of building this node record.
//
::ZeroMemory(pRecordUpdate, sizeof(SetOfNodeRecordUpdates));
if (! fReplaceExistingOne)
{
//
// Hook to the linked list.
//
if (m_pNodeRecordUpdateSet == NULL)
{
m_pNodeRecordUpdateSet = pRecordUpdate;
}
else
{
// append to the list
for (p = m_pNodeRecordUpdateSet; NULL != p->next; p = p->next)
;
p->next = pRecordUpdate;
}
}
else
{
ASSERT(NULL == pRecordUpdate->next); // just zero out
// p could not NULL if the one being replaced is
// the last one in the list.
pRecordUpdate->next = p; // restore
}
/*
* Initialize the update "next" pointer to NULL and set the
* update value node ID equal to the node ID passed in.
*/
// pRecordUpdate->next = NULL; // struct already zeroed out
pRecordUpdate->value.node_id = node_id;
if (update_type == ADD_RECORD)
{
pRecordUpdate->value.node_update.choice = NODE_ADD_RECORD_CHOSEN;
node_record = &pRecordUpdate->value.node_update.u.node_add_record;
}
else if (update_type == REPLACE_RECORD)
{
pRecordUpdate->value.node_update.choice = NODE_REPLACE_RECORD_CHOSEN;
node_record = &pRecordUpdate->value.node_update.u.node_replace_record;
}
else
{
pRecordUpdate->value.node_update.choice = NODE_REMOVE_RECORD_CHOSEN;
}
if (node_record != NULL)
{
// node_record->bit_mask = 0; // struct already zeroed out
/*
* Check to see if the superior node ID is present. If the
* value is zero, then the record is for the top provider node
* and the superior node ID does not need to be filled in.
*/
if (lpRec->superior_node != 0)
{
node_record->bit_mask |= SUPERIOR_NODE_PRESENT;
node_record->superior_node = lpRec->superior_node;
}
/*
* Fill in the node type and node properties which are always
* present.
*/
node_record->node_type = lpRec->node_type;
node_record->node_properties = lpRec->node_properties;
/*
** This roster object must not go out of scope while this
** update record is still in use!
*/
/*
* Fill in the node name if it is present.
*/
if (lpRec->pwszNodeName != NULL)
{
node_record->bit_mask |= NODE_NAME_PRESENT;
node_record->node_name.value = lpRec->pwszNodeName;
node_record->node_name.length = ::lstrlenW(lpRec->pwszNodeName);
}
/*
* Fill in the participants list if it is present.
*/
if (lpRec->participant_name_list != NULL)
{
node_record->bit_mask |= PARTICIPANTS_LIST_PRESENT;
rc = BuildParticipantsListPDU (node_id,
&(node_record->participants_list));
if (GCC_NO_ERROR != rc)
{
ERROR_OUT(("CConfRoster::BuildSetOfUpdatesPDU: can't build participant list, rc=%d", rc));
goto MyExit;
}
}
/*
* Fill in the site information if it is present.
*/
if (lpRec->pwszSiteInfo != NULL)
{
node_record->bit_mask |= SITE_INFORMATION_PRESENT;
node_record->site_information.value = lpRec->pwszSiteInfo;
node_record->site_information.length = ::lstrlenW(lpRec->pwszSiteInfo);
}
/*
* Fill in the network address if it is present.
*/
if ((lpRec->network_address_list != NULL) && (rc == GCC_NO_ERROR))
{
node_record->bit_mask |= RECORD_NET_ADDRESS_PRESENT;
rc = lpRec->network_address_list->GetNetworkAddressListPDU (
&(node_record->record_net_address));
if (GCC_NO_ERROR != rc)
{
ERROR_OUT(("CConfRoster::BuildSetOfUpdatesPDU: can't get network address list, rc=%d", rc));
goto MyExit;
}
}
/*
* Fill in the alternative node ID if it is present.
*/
if (lpRec->poszAltNodeID != NULL)
{
node_record->bit_mask |= ALTERNATIVE_NODE_ID_PRESENT;
node_record->alternative_node_id.choice = H243_NODE_ID_CHOSEN;
node_record->alternative_node_id.u.h243_node_id.length = lpRec->poszAltNodeID->length;
::CopyMemory(node_record->alternative_node_id.u.h243_node_id.value,
lpRec->poszAltNodeID->value,
node_record->alternative_node_id.u.h243_node_id.length);
}
/*
* Fill in the user data list if it is present.
*/
if (lpRec->user_data_list != NULL)
{
node_record->bit_mask |= RECORD_USER_DATA_PRESENT;
rc = lpRec->user_data_list->GetUserDataPDU (&(node_record->record_user_data));
}
}
}
else
{
ERROR_OUT(("CConfRoster::BuildSetOfUpdatesPDU: invalid param"));
rc = GCC_INVALID_PARAMETER;
}
MyExit:
return (rc);
}
/*
* GCCError BuildParticipantsListPDU ()
*
* Public Function Description
* This routine is used to retrieve the "ParticipantList" portion of a
* "RosterUpdateIndication" in the "PDU" form. The internally maintained
* data is converted into the "PDU" form.
*
* Formal Parameters:
* node_id - (i) Node ID of node record to get the
* participant list from.
* participants_list - (o) This is a pointer to the set of participant
* list PDU structures to be filled in by this
* routine.
*
* Return Value
* GCC_NO_ERROR - No error occured.
* GCC_ALLOCATION_FAILURE - A resource error occured.
*
* Side Effects
* None.
*
* Caveats
* None.
*/
GCCError CConfRoster::BuildParticipantsListPDU(
UserID node_id,
PParticipantsList * participants_list)
{
GCCError rc = GCC_NO_ERROR;
PParticipantsList new_participants_list;
PParticipantsList old_participants_list;
CONF_RECORD *lpRec;
if (NULL != (lpRec = m_RecordList2.Find(node_id)))
{
LPWSTR PUstring;
*participants_list = NULL;
old_participants_list = NULL;
lpRec->participant_name_list->Reset();
while (NULL != (PUstring = lpRec->participant_name_list->Iterate()))
{
DBG_SAVE_FILE_LINE
new_participants_list = new ParticipantsList;
if (new_participants_list == NULL)
{
rc = GCC_ALLOCATION_FAILURE;
FreeParticipantsListPDU (*participants_list);
break;
}
if (*participants_list == NULL)
*participants_list = new_participants_list;
else
old_participants_list->next = new_participants_list;
/*
* Save this pointer so that it's "next" pointer can be filled in
* by the line above on the next pass through.
*/
old_participants_list = new_participants_list;
/*
* Initialize the current "next" pointer to NULL in case this is
* the last time through the loop.
*/
new_participants_list->next = NULL;
/*
* Finally, put the participant list info. in the structure.
*/
new_participants_list->value.value = PUstring;
new_participants_list->value.length = ::lstrlenW(PUstring);
}
}
else
rc = GCC_INVALID_PARAMETER;
return (rc);
}
/*
* These routines are used to free up a roster update indication PDU.
*/
/*
* void FreeRosterUpdateIndicationPDU ()
*
* Private Function Description
* This routine is responsible for freeing up all the data associated
* with the PDU. This routine should be called each time a PDU is
* obtained through the GetRosterUpdateIndicationPDU () routine.
*
* Formal Parameters:
* None.
*
* Return Value
* None.
*
* Side Effects
* None.
*
* Caveats
* None.
*/
void CConfRoster::FreeRosterUpdateIndicationPDU(void)
{
if (m_NodeInformation.node_record_list.choice == NODE_RECORD_REFRESH_CHOSEN)
{
FreeSetOfRefreshesPDU ();
}
else if (m_NodeInformation.node_record_list.choice == NODE_RECORD_UPDATE_CHOSEN)
{
FreeSetOfUpdatesPDU ();
}
m_NodeInformation.node_record_list.choice = NODE_NO_CHANGE_CHOSEN;
m_pNodeRecordUpdateSet = NULL;
}
/*
* void FreeSetOfRefreshesPDU ()
*
* Private Function Description:
* This routine is used to free up any data allocated to construct the
* "PDU" form of the "SetOfRefreshes" portion of the RosterUpdateIndication
* "PDU" structure.
*
* Formal Parameters:
* None.
*
* Return Value
* None.
*
* Side Effects
* None.
*
* Caveats
* None.
*/
void CConfRoster::FreeSetOfRefreshesPDU(void)
{
PSetOfNodeRecordRefreshes pCurr, pNext;
for (pCurr = m_NodeInformation.node_record_list.u.node_record_refresh;
NULL != pCurr;
pCurr = pNext)
{
pNext = pCurr->next;
if (pCurr->value.node_record.bit_mask & PARTICIPANTS_LIST_PRESENT)
{
FreeParticipantsListPDU(pCurr->value.node_record.participants_list);
}
delete pCurr;
}
m_NodeInformation.node_record_list.u.node_record_refresh = NULL;
m_RecordList2.CleanList();
}
/*
* void FreeSetOfUpdatesPDU ()
*
* Private Function Description:
* This routine is used to free up any data allocated to construct the
* "PDU" form of the "SetOfUpdates" portion of the RosterUpdateIndication
* "PDU" structure.
*
* Formal Parameters:
* None.
*
* Return Value
* None.
*
* Side Effects
* None.
*
* Caveats
* None.
*/
void CConfRoster::
CleanUpdateRecordPDU ( PSetOfNodeRecordUpdates pCurr)
{
/*
* Check to see if the update is an "Add" or a "Replace".
*/
if (pCurr->value.node_update.choice == NODE_ADD_RECORD_CHOSEN)
{
/*
* Free the participants list memory if any exists.
*/
if (pCurr->value.node_update.u.node_add_record.bit_mask & PARTICIPANTS_LIST_PRESENT)
{
FreeParticipantsListPDU(pCurr->value.node_update.u.node_add_record.participants_list);
}
}
else if (pCurr->value.node_update.choice == NODE_REPLACE_RECORD_CHOSEN)
{
/*
* Free the participants list memory if any exists.
*/
if (pCurr->value.node_update.u.node_replace_record.bit_mask & PARTICIPANTS_LIST_PRESENT)
{
FreeParticipantsListPDU(pCurr->value.node_update.u.node_replace_record.participants_list);
}
}
}
void CConfRoster::FreeSetOfUpdatesPDU(void)
{
PSetOfNodeRecordUpdates pCurr, pNext;
//PSetOfNodeRecordUpdates current_record_update;
for (pCurr = m_NodeInformation.node_record_list.u.node_record_update;
NULL != pCurr;
pCurr = pNext)
{
pNext = pCurr->next;
CleanUpdateRecordPDU(pCurr);
delete pCurr;
}
m_NodeInformation.node_record_list.u.node_record_update = NULL;
m_RecordList2.CleanList();
}
void CConfRecordList2::CleanList(void)
{
CONF_RECORD *lpRec;
/*
* Iterate through the internal list of Record structures telling each
* CUserDataListContainer object in the Record to free up it's PDU data.
*/
Reset();
while (NULL != (lpRec = Iterate()))
{
if (lpRec->user_data_list != NULL)
{
lpRec->user_data_list->FreeUserDataListPDU();
}
if (lpRec->network_address_list != NULL)
{
lpRec->network_address_list->FreeNetworkAddressListPDU();
}
}
}
/*
* void FreeParticipantsListPDU ()
*
* Private Function Description
* This routine is used to free up any data allocated to construct the
* "PDU" form of the "ParticipantList" portion of the
* RosterUpdateIndication "PDU" structure.
*
* Formal Parameters:
* participants_list - (i/o) This is the participant list PDU
* to free up.
*
* Return Value
* None.
*
* Side Effects
* None.
*
* Caveats
* None.
*/
void CConfRoster::FreeParticipantsListPDU(
PParticipantsList participants_list)
{
PParticipantsList pCurr, pNext;
for (pCurr = participants_list; NULL != pCurr; pCurr = pNext)
{
pNext = pCurr->next;
delete pCurr;
}
}
/*
* These routines process roster update indication PDUs.
*/
/*
* GCCError ProcessRosterUpdateIndicationPDU ()
*
* Public Function Description:
* This routine is used process a RosterUpdateIndication PDU by saving the
* data in the internal format.
*/
GCCError CConfRoster::ProcessRosterUpdateIndicationPDU(
PNodeInformation node_information,
UserID sender_id)
{
GCCError rc = GCC_NO_ERROR;
CUidList node_delete_list;
/*
** 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_fPduFlushed)
{
FreeRosterUpdateIndicationPDU ();
m_fPduFlushed = FALSE;
}
/*
** If this is a conference roster update and refresh is chosen we must
** clear out the entire list and rebuild it.
*/
if (node_information->node_record_list.choice == NODE_RECORD_REFRESH_CHOSEN)
{
m_fRosterChanged = TRUE;
/*
** If this refresh came from the top provider we must clear out the
** entire roster to prepare for the new roster list. If it was NOT
** sent by the Top Provider, we must determine which sub tree is
** affected and clear out this particular sub tree.
*/
if (sender_id == m_uidTopProvider)
{
ClearRecordList();
}
else
{
rc = GetNodeSubTree(sender_id, &node_delete_list);
if (rc == GCC_NO_ERROR)
{
UserID uid;
// Clear out the affected nodes
node_delete_list.Reset();
while (GCC_INVALID_UID != (uid = node_delete_list.Iterate()))
{
DeleteRecord(uid);
}
}
}
/*
** Increment the instance number if this node is the top provider or
** a local roster otherwise get the instance number from the PDU.
*/
if (rc == GCC_NO_ERROR)
{
if ((m_fTopProvider) || (m_fLocalRoster))
{
m_nInstanceNumber++;
}
else
{
m_nInstanceNumber = node_information->roster_instance_number;
}
if (m_fNodesAdded == FALSE)
{
m_fNodesAdded = node_information->nodes_are_added;
}
if (m_fNodesRemoved == FALSE)
{
m_fNodesRemoved = node_information->nodes_are_removed;
}
rc = ProcessSetOfRefreshesPDU(node_information->node_record_list.u.node_record_refresh);
}
}
else if (node_information->node_record_list.choice == NODE_RECORD_UPDATE_CHOSEN)
{
m_fRosterChanged = TRUE;
/*
** Increment the instance number if this node is the top provider or
** a local roster otherwise get the instance number from the PDU.
*/
if ((m_fTopProvider) || (m_fLocalRoster))
{
m_nInstanceNumber++;
}
else
{
m_nInstanceNumber = node_information->roster_instance_number;
}
if (m_fNodesAdded == FALSE)
{
m_fNodesAdded = node_information->nodes_are_added;
}
if (m_fNodesRemoved == FALSE)
{
m_fNodesRemoved = node_information->nodes_are_removed;
}
rc = ProcessSetOfUpdatesPDU(node_information->node_record_list.u.node_record_update);
}
return (rc);
}
/*
* GCCError ProcessSetOfRefreshesPDU ()
*
* Private Function Description:
* This routine is used process the SetOfRefreshes portion of a
* RosterUpdateIndication PDU by saving the data in the internal format.
*
* Formal Parameters:
* record_refresh - (i) Refresh PDU data to process.
*
* Return Value
* GCC_NO_ERROR - No error occured.
* GCC_ALLOCATION_FAILURE - A resource error occured.
*
* Side Effects
* None.
*
* Caveats
* None.
*/
GCCError CConfRoster::ProcessSetOfRefreshesPDU(
PSetOfNodeRecordRefreshes record_refresh)
{
GCCError rc = GCC_NO_ERROR;
PSetOfNodeRecordRefreshes current_record_refresh;
UserID node_id;
CONF_RECORD *internal_record = NULL;
if (record_refresh != NULL)
{
current_record_refresh = record_refresh;
while ((current_record_refresh != NULL) &&
(rc == GCC_NO_ERROR))
{
node_id = (UserID)current_record_refresh->value.node_id;
/*
* Create and fill in the new internal conference record.
*/
DBG_SAVE_FILE_LINE
internal_record = new CONF_RECORD;
if (internal_record == NULL)
{
ERROR_OUT(("CConfRoster::ProcessSetOfRefreshesPDU: Error "
"creating new Record"));
rc = GCC_ALLOCATION_FAILURE;
break;
}
/*
* Fill in the superior node ID if it is present.
*/
if (current_record_refresh->value.node_record.bit_mask &
SUPERIOR_NODE_PRESENT)
{
internal_record->superior_node = current_record_refresh->
value.node_record.superior_node;
}
else
{
ASSERT(0 == internal_record->superior_node);
}
/*
* Fill in the node type and node properties which are always
* present.
*/
internal_record->node_type = current_record_refresh->
value.node_record.node_type;
internal_record->node_properties = current_record_refresh->
value.node_record.node_properties;
/*
* Fill in the node name if it is present.
*/
if (current_record_refresh->value.node_record.bit_mask & NODE_NAME_PRESENT)
{
if (NULL == (internal_record->pwszNodeName = ::My_strdupW2(
current_record_refresh->value.node_record.node_name.length,
current_record_refresh->value.node_record.node_name.value)))
{
rc = GCC_ALLOCATION_FAILURE;
}
}
else
{
ASSERT(NULL == internal_record->pwszNodeName);
}
/*
* Fill in the participants name list if it is present.
*/
if ((rc == GCC_NO_ERROR) &&
(current_record_refresh->value.node_record.bit_mask &
PARTICIPANTS_LIST_PRESENT))
{
rc = ProcessParticipantsListPDU (
current_record_refresh->
value.node_record.participants_list,
internal_record);
}
else
{
ASSERT(NULL == internal_record->participant_name_list);
}
/*
* Fill in the site information if it is present.
*/
if ((rc == GCC_NO_ERROR) &&
(current_record_refresh->value.node_record.bit_mask & SITE_INFORMATION_PRESENT))
{
if (NULL == (internal_record->pwszSiteInfo = ::My_strdupW2(
current_record_refresh->value.node_record.site_information.length,
current_record_refresh->value.node_record.site_information.value)))
{
rc = GCC_ALLOCATION_FAILURE;
}
}
else
{
ASSERT(NULL == internal_record->pwszSiteInfo);
}
/*
* Fill in the network address if it is present. The network
* address is maintained internally as a CNetAddrListContainer object
* which is constructed here from the PDU "SetOfNetworkAddresses"
* structure. If an error occurs in constructing the object, set
* the Record's network address list pointer to NULL.
*/
if ((rc == GCC_NO_ERROR) &&
(current_record_refresh->value.node_record.bit_mask &
RECORD_NET_ADDRESS_PRESENT))
{
DBG_SAVE_FILE_LINE
internal_record->network_address_list = new CNetAddrListContainer(
current_record_refresh->value.node_record.record_net_address,
&rc);
if ((internal_record->network_address_list == NULL) ||
(rc != GCC_NO_ERROR))
{
rc = GCC_ALLOCATION_FAILURE;
}
}
else
{
ASSERT(NULL == internal_record->network_address_list);
}
/*
* Fill in the alternative node ID if it is present.
*/
if ((rc == GCC_NO_ERROR) &&
(current_record_refresh->value.node_record.bit_mask &
ALTERNATIVE_NODE_ID_PRESENT))
{
if (NULL == (internal_record->poszAltNodeID = ::My_strdupO2(
current_record_refresh->value.node_record.
alternative_node_id.u.h243_node_id.value,
current_record_refresh->value.node_record.
alternative_node_id.u.h243_node_id.length)))
{
rc = GCC_ALLOCATION_FAILURE;
}
}
else
{
ASSERT(NULL == internal_record->poszAltNodeID);
}
/*
* Fill in the user data if it is present. The user data is
* maintained internally as a CUserDataListContainer object which is
* constructed here from the PDU "SetOfUserData" structure. If an
* error occurs in constructing the object, set the Record's user
* data pointer to NULL.
*/
if ((rc == GCC_NO_ERROR) &&
(current_record_refresh->value.node_record.bit_mask &
RECORD_USER_DATA_PRESENT))
{
DBG_SAVE_FILE_LINE
internal_record->user_data_list = new CUserDataListContainer(
current_record_refresh->value.node_record.record_user_data,
&rc);
if ((internal_record->user_data_list == NULL) ||
(rc != GCC_NO_ERROR))
{
rc = GCC_ALLOCATION_FAILURE;
}
}
else
{
ASSERT(NULL == internal_record->user_data_list);
}
/*
* If the Record was successfully filled in, add it to the internal
* Rogue Wave list.
*/
if (rc == GCC_NO_ERROR)
{
m_RecordList2.Append(node_id, internal_record);
current_record_refresh = current_record_refresh->next;
}
}
}
/*
** Build a full refresh PDU here if no errors occured while processing
** the refresh PDU.
*/
if (rc == GCC_NO_ERROR)
{
rc = BuildRosterUpdateIndicationPDU(FULL_REFRESH, 0);
}
else
{
delete internal_record;
}
return (rc);
}
/*
* GCCError ProcessSetOfUpdatesPDU ()
*
* Private Function Description:
* This routine is used process the SetOfUpdates portion of a
* RosterUpdateIndication PDU by saving the data in the internal format.
*
* Formal Parameters:
* record_update - (i) Update PDU data to process.
*
* Return Value
* GCC_NO_ERROR - No error occured.
* GCC_ALLOCATION_FAILURE - A resource error occured.
*
* Side Effects
* None.
*
* Caveats
* None.
*/
GCCError CConfRoster::ProcessSetOfUpdatesPDU(
PSetOfNodeRecordUpdates record_update)
{
GCCError rc = GCC_NO_ERROR;
PSetOfNodeRecordUpdates current_record_update;
UserID node_id;
PNodeRecord node_record;
CONF_RECORD *internal_record;
CONF_ROSTER_UPDATE_TYPE update_type;
if (record_update != NULL)
{
current_record_update = record_update;
while ((current_record_update != NULL) &&
(rc == GCC_NO_ERROR))
{
internal_record = NULL;
node_id = (UserID)current_record_update->value.node_id;
// Create and fill in the new conference record.
if (current_record_update->value.node_update.choice ==
NODE_ADD_RECORD_CHOSEN)
{
// Add the record.
if (! m_RecordList2.Find(node_id))
{
node_record = &current_record_update->value.node_update.u.node_add_record;
update_type = ADD_RECORD;
}
else
{
node_record = NULL;
ERROR_OUT(("CConfRoster: ProcessSetOfUpdatesPDU: can't add record"));
}
}
else if (current_record_update->value.node_update.choice ==
NODE_REPLACE_RECORD_CHOSEN)
{
// Replace the record.
if (m_RecordList2.Find(node_id))
{
DeleteRecord (node_id);
node_record = &current_record_update->
value.node_update.u.node_replace_record;
update_type = REPLACE_RECORD;
}
else
{
node_record = NULL;
WARNING_OUT(("CConfRoster: ProcessSetOfUpdatesPDU: "
"ASSERTION: Replace record failed"));
}
}
else
{
// Remove the record.
if (m_RecordList2.Find(node_id))
{
DeleteRecord (node_id);
update_type = DELETE_RECORD;
}
else
{
ERROR_OUT(("CConfRoster: ProcessSetOfUpdatesPDU: can't delete record"));
}
node_record = NULL;
}
/*
** Process the conference record if one exists. Create a new
** node record to be filled in and added to the internal record
** list.
*/
if (node_record != NULL)
{
DBG_SAVE_FILE_LINE
internal_record = new CONF_RECORD;
if (internal_record == NULL)
{
ERROR_OUT(("CConfRoster::ProcessSetOfUpdatesPDU: can't create new record"));
rc = GCC_ALLOCATION_FAILURE;
break;
}
// Fill in the superior node ID if it is present.
if (node_record->bit_mask & SUPERIOR_NODE_PRESENT)
{
internal_record->superior_node = node_record->superior_node;
}
else
{
ASSERT(0 == internal_record->superior_node);
}
/*
** Fill in the node type and node properties which are always
** present.
*/
internal_record->node_type = node_record->node_type;
internal_record->node_properties = node_record->node_properties;
// Fill in the node name if it is present.
if (node_record->bit_mask & NODE_NAME_PRESENT)
{
if (NULL == (internal_record->pwszNodeName = ::My_strdupW2(
node_record->node_name.length,
node_record->node_name.value)))
{
rc = GCC_ALLOCATION_FAILURE;
}
}
else
{
ASSERT(NULL == internal_record->pwszNodeName);
}
// Fill in the participants list if it is present.
if ((rc == GCC_NO_ERROR) &&
(node_record->bit_mask & PARTICIPANTS_LIST_PRESENT))
{
rc = ProcessParticipantsListPDU(node_record->participants_list,
internal_record);
}
else
{
ASSERT(NULL == internal_record->participant_name_list);
}
// Fill in the site information if it is present.
if ((rc == GCC_NO_ERROR) &&
(node_record->bit_mask & SITE_INFORMATION_PRESENT))
{
if (NULL == (internal_record->pwszSiteInfo = ::My_strdupW2(
node_record->site_information.length,
node_record->site_information.value)))
{
rc = GCC_ALLOCATION_FAILURE;
}
}
else
{
ASSERT(NULL == internal_record->pwszSiteInfo);
}
/*
** Fill in the network address if it is present. The network
** address is maintained internally as a CNetAddrListContainer
** object which is constructed here from the PDU
** "SetOfNetworkAddresses" structure. If an error occurs
** in constructing the object, set the Record's network address
** list pointer to NULL.
*/
if ((rc == GCC_NO_ERROR) &&
(node_record->bit_mask & RECORD_NET_ADDRESS_PRESENT))
{
DBG_SAVE_FILE_LINE
internal_record->network_address_list =
new CNetAddrListContainer(node_record->record_net_address, &rc);
if ((internal_record->network_address_list == NULL) ||
(rc != GCC_NO_ERROR))
{
rc = GCC_ALLOCATION_FAILURE;
}
}
else
{
ASSERT(NULL == internal_record->network_address_list);
}
/*
* Fill in the alternative node ID if it is present.
*/
if ((rc == GCC_NO_ERROR) &&
(node_record->bit_mask & ALTERNATIVE_NODE_ID_PRESENT))
{
if (NULL == (internal_record->poszAltNodeID = ::My_strdupO2(
node_record->alternative_node_id.u.h243_node_id.value,
node_record->alternative_node_id.u.h243_node_id.length)))
{
rc = GCC_ALLOCATION_FAILURE;
}
}
else
{
ASSERT(NULL == internal_record->poszAltNodeID);
}
/*
* Fill in the user data if it is present. The user data is
* maintained internally as a CUserDataListContainer object which is
* constructed here from the PDU "SetOfUserData" structure. If
* an error occurs in constructing the object, set the Record's
* user data pointer to NULL.
*/
if ((rc == GCC_NO_ERROR) &&
(node_record->bit_mask & RECORD_USER_DATA_PRESENT))
{
DBG_SAVE_FILE_LINE
internal_record->user_data_list = new CUserDataListContainer(
node_record->record_user_data,
&rc);
if ((internal_record->user_data_list == NULL) ||
(rc != GCC_NO_ERROR))
{
rc = GCC_ALLOCATION_FAILURE;
}
}
else
{
ASSERT(NULL == internal_record->user_data_list);
}
}
/*
** Here we add this update to our PDU and jump to the next update
** in the PDU currently being processed.
*/
if (rc == GCC_NO_ERROR)
{
/*
** If the Record was successfully filled in, add it to the
** internal Rogue Wave list.
*/
if (internal_record != NULL)
{
m_RecordList2.Append(node_id, internal_record);
}
// Build the PDU from the above update.
rc = BuildRosterUpdateIndicationPDU(update_type, node_id);
if (rc == GCC_NO_ERROR)
{
current_record_update = current_record_update->next;
}
}
else
{
delete internal_record;
}
}
}
return (rc);
}
/*
* GCCError ProcessParticipantsListPDU ()
*
* Private Function Description:
* This routine is used process the ParticipantsList portion of an
* incoming RosterUpdateIndication PDU by saving the data in the internal
* format.
*
* Formal Parameters:
* participants_list - (i) Participant List PDU data to process.
*
* Return Value
* GCC_NO_ERROR - No error occured.
* GCC_ALLOCATION_FAILURE - A resource error occured.
*
* Side Effects
* None.
*
* Caveats
* None.
*/
GCCError CConfRoster::ProcessParticipantsListPDU (
PParticipantsList participants_list,
CONF_RECORD *node_record)
{
GCCError rc = GCC_NO_ERROR;
PParticipantsList pCurr;
LPWSTR pwszParticipantName;
/*
* Clear the current list.
*/
DBG_SAVE_FILE_LINE
node_record->participant_name_list = new CParticipantNameList;
if (node_record->participant_name_list == NULL)
return (GCC_ALLOCATION_FAILURE);
for (pCurr = participants_list; NULL != pCurr; pCurr = pCurr->next)
{
if (NULL != (pwszParticipantName = ::My_strdupW2(pCurr->value.length, pCurr->value.value)))
{
(node_record->participant_name_list)->Append(pwszParticipantName);
}
else
{
rc = GCC_ALLOCATION_FAILURE;
break;
}
}
return (rc);
}
/*
* Utilities that operate on conference records.
*/
/*
* UINT LockConferenceRoster ()
*
* Public Function Description:
* This routine is used "lock" the CConfRoster data in the "API"
* form. The "API" version of the CConfRoster is built from the
* internally maintained data.
*/
UINT CConfRoster::LockConferenceRoster(void)
{
CONF_RECORD *internal_node_record;
if (Lock() == 1)
{
//CONF_RECORD *lpRec;
/*
* Set aside memory to hold the conference roster, the pointers to the
* GCCNodeRecord structures and the GCCNodeRecord structures themselves.
* The "sizeof" the structure must be rounded to an even four-byte
* boundary.
*/
m_cbDataMemorySize = ROUNDTOBOUNDARY (sizeof (GCCConferenceRoster));
m_cbDataMemorySize += m_RecordList2.GetCount() *
(sizeof(PGCCNodeRecord) + ROUNDTOBOUNDARY (sizeof(GCCNodeRecord)) );
m_RecordList2.Reset();
while (NULL != (internal_node_record = m_RecordList2.Iterate()))
{
/*
* Add the size of the node name Unicode String, if it exists.
* Space must be allowed for the NULL terminator of the string.
*/
if (internal_node_record->pwszNodeName != NULL)
{
m_cbDataMemorySize += ROUNDTOBOUNDARY(
(::lstrlenW(internal_node_record->pwszNodeName) + 1) * sizeof(WCHAR));
}
/*
* Add the amount of memory needed to hold the pointers to the
* list of participants, if it exists. Also add the total amount
* of memory needed to hold the participant list data.
*/
if (internal_node_record->participant_name_list != NULL)
{
LPWSTR lpUstring;
m_cbDataMemorySize += internal_node_record->participant_name_list->GetCount() * sizeof(LPWSTR);
/*
* Set up an iterator for the participant name list in order to
* add the amount of memory necessary to hold each Unicode
* String. Space must be allowed for the strings' NULL
* terminators.
*/
internal_node_record->participant_name_list->Reset();
while (NULL != (lpUstring = internal_node_record->participant_name_list->Iterate()))
{
m_cbDataMemorySize += ROUNDTOBOUNDARY(
(::lstrlenW(lpUstring) + 1) * sizeof(WCHAR));
}
}
/*
* Add the size of the site information Unicode String, if it
* exists. Space must be allowed for the NULL terminator of
* the string.
*/
if (internal_node_record->pwszSiteInfo != NULL)
{
m_cbDataMemorySize += ROUNDTOBOUNDARY(
(::lstrlenW(internal_node_record->pwszSiteInfo) + 1) * sizeof(WCHAR));
}
/*
* If a network address list is present, lock the internal network
* address list object in order to find the amount of memory
* required by the list.
*/
if (internal_node_record->network_address_list != NULL)
{
m_cbDataMemorySize += internal_node_record->
network_address_list->LockNetworkAddressList ();
}
/*
* Add the space necessary to hold the alternative node ID octet
* string structure as well as the string data, if it exists.
*/
if (internal_node_record->poszAltNodeID != NULL)
{
m_cbDataMemorySize += ROUNDTOBOUNDARY(sizeof(OSTR));
m_cbDataMemorySize += ROUNDTOBOUNDARY(internal_node_record->poszAltNodeID->length);
}
/*
* If a user data list is present, lock the internal user data
* list object in order to find the amount of memory required by
* the list.
*/
if (internal_node_record->user_data_list != NULL)
{
m_cbDataMemorySize += internal_node_record->user_data_list->LockUserDataList ();
}
}
}
return m_cbDataMemorySize;
}
/*
* void UnLockConferenceRoster ()
*
* Public Function Description:
* This routine is used to "unlock" the CConfRoster "API" data. The
* lock count is decremented each time the routine is called and the "API"
* data will actually be freed when the lock count reaches zero.
*/
void CConfRoster::UnLockConferenceRoster(void)
{
if (Unlock(FALSE) == 0)
{
CONF_RECORD *lpRec;
/*
** Set up an iterator in order to unlock any internal data
** containers
** which have been locked.
*/
m_RecordList2.Reset();
while (NULL != (lpRec = m_RecordList2.Iterate()))
{
/*
* Unlock the network address list if it exists.
*/
if (lpRec->network_address_list != NULL)
{
lpRec->network_address_list->UnLockNetworkAddressList ();
}
/*
* Unlock the user data list if it exists.
*/
if (lpRec->user_data_list != NULL)
{
lpRec->user_data_list->UnLockUserDataList ();
}
}
}
// we have to call Release() because we used Unlock(FALSE)
Release();
}
/*
* UINT GetConfRoster ()
*
* Public Function Description:
* This routine is called in order to retrieve the CConfRoster data
* in "API" form. The CConfRoster data must first be "locked" before
* this routine may be called.
*/
UINT CConfRoster::GetConfRoster(
PGCCConferenceRoster * conference_roster,
LPBYTE memory)
{
UINT rc;
/*
* If the user data has been locked, fill in the output parameters and
* the data referenced by the pointers. Otherwise, report that the object
* has yet to be locked into the "API" form.
*/
if (GetLockCount() > 0)
{
UINT total_data_length = 0;
UINT data_length = 0;
UINT node_record_counter = 0;
PGCCNodeRecord node_record;
PGCCConferenceRoster roster;
CONF_RECORD *internal_record;
UserID node_id;
USHORT i;
/*
* Fill in the output length parameter which indicates how much data
* referenced outside the structure will be written.
*/
rc = m_cbDataMemorySize;
/*
* Set the conference roster pointer equal to the memory pointer passed
* in. This is where the conference roster structure will be built.
* Save the conference roster pointer for convienence.
*/
*conference_roster = (PGCCConferenceRoster)memory;
roster = *conference_roster;
/*
* Fill in all of the elements of the conference roster except for
* the node record list.
*/
roster->instance_number = (USHORT)m_nInstanceNumber;
roster->nodes_were_added = m_fNodesAdded;
roster->nodes_were_removed = m_fNodesRemoved;
roster->number_of_records = (USHORT) m_RecordList2.GetCount();
/*
* The "total_data_length" will hold the total amount of data written
* into memory. Save the amount of memory needed to hold the
* conference roster. Add the amount of memory necessary to hold the
* node record pointers and structures.
*/
data_length = ROUNDTOBOUNDARY(sizeof(GCCConferenceRoster));
total_data_length = data_length + m_RecordList2.GetCount() *
(ROUNDTOBOUNDARY(sizeof(GCCNodeRecord)) + sizeof(PGCCNodeRecord));
/*
* Move the memory pointer past the conference roster structure. This
* is where the node record pointer list will be written.
*/
memory += data_length;
/*
* Set the roster's node record list pointer.
*/
roster->node_record_list = (PGCCNodeRecord *)memory;
/*
* Move the memory pointer past the list of node record pointers.
*/
memory += (m_RecordList2.GetCount() * sizeof(PGCCNodeRecord));
/*
* Iterate through the internal list of record structures, building
* "API" GCCNodeRecord structures in memory.
*/
m_RecordList2.Reset();
while (NULL != (internal_record = m_RecordList2.Iterate(&node_id)))
{
/*
* Save the pointer to the node record structure in the list
* of pointers. Get the internal node record from the list.
*/
node_record = (PGCCNodeRecord)memory;
roster->node_record_list[node_record_counter++] = node_record;
/*
* Fill in the node ID and the superior node ID.
*/
node_record->node_id = node_id;
node_record->superior_node_id = internal_record->superior_node;
/*
* Fill in the node type and the node properties.
*/
GetNodeTypeAndProperties (
internal_record->node_type,
internal_record->node_properties,
&node_record->node_type,
&node_record->node_properties);
/*
* Move the memory pointer past the node record structure. This is
* where the node name unicode string will be written, if it exists.
*/
memory += ROUNDTOBOUNDARY(sizeof(GCCNodeRecord));
if (internal_record->pwszNodeName != NULL)
{
/*
* Set the record's node name pointer and copy the node name
* data into memory from the internal unicode string. Be sure
* to copy the strings NULL terminating character. Move the
* memory pointer past the node name string data.
*/
node_record->node_name = (LPWSTR) memory;
UINT cbStrSize = (::lstrlenW(internal_record->pwszNodeName) + 1) * sizeof(WCHAR);
::CopyMemory(memory, internal_record->pwszNodeName, cbStrSize);
total_data_length += ROUNDTOBOUNDARY(cbStrSize);
memory += (Int) ROUNDTOBOUNDARY(cbStrSize);
}
else
{
/*
* The node name string does not exist, so set the node record
* pointer to NULL.
*/
node_record->node_name = NULL;
}
if (internal_record->participant_name_list != NULL)
{
LPWSTR lpUstring;
/*
* Fill in the node record's participant name list. Use an
* iterator to access each participant name for this node
* record, copying each string into the appropriate location
* in memory.
*/
node_record->participant_name_list = (LPWSTR *)memory;
node_record->number_of_participants = (USHORT)
internal_record->participant_name_list->GetCount();
/*
* Move the memory pointer past the list of participant name
* pointers. This is where the first participant name string
* will be written. There is no need to round this value off
* to an even multiple of four bytes since a LPWSTR
* is actually a pointer.
*/
memory += internal_record->participant_name_list->GetCount() * sizeof(LPWSTR);
total_data_length += internal_record->participant_name_list->GetCount() * sizeof(LPWSTR);
/*
* Initialize the loop counter to zero and fill in the
* participants name list.
*/
i = 0;
internal_record->participant_name_list->Reset();
while (NULL != (lpUstring = internal_record->participant_name_list->Iterate()))
{
node_record->participant_name_list[i++] = (LPWSTR)memory;
UINT cbStrSize = (::lstrlenW(lpUstring) + 1) * sizeof(WCHAR);
::CopyMemory(memory, lpUstring, cbStrSize);
memory += ROUNDTOBOUNDARY(cbStrSize);
total_data_length += ROUNDTOBOUNDARY(cbStrSize);
}
}
else
{
/*
* The participant name list does not exist, so set the node
* record pointer to NULL and the number of participants to
* zero.
*/
node_record->participant_name_list = NULL;
node_record->number_of_participants = 0;
}
if (internal_record->pwszSiteInfo != NULL)
{
/*
* Set the record's site information pointer and copy the site
* information data into memory from the internal unicode
* string. Be sure to copy the strings NULL terminating
* character. Move the memory pointer past the site information
* string data.
*/
node_record->site_information = (LPWSTR)memory;
UINT cbStrSize = (::lstrlenW(internal_record->pwszSiteInfo) + 1) * sizeof(WCHAR);
::CopyMemory(memory, internal_record->pwszSiteInfo, cbStrSize);
total_data_length += ROUNDTOBOUNDARY(cbStrSize);
memory += ROUNDTOBOUNDARY(cbStrSize);
}
else
{
/*
* The site information string does not exist, so set the
* node record pointer to NULL.
*/
node_record->site_information = NULL;
}
if (internal_record->network_address_list != NULL)
{
/*
* Fill in the network address list by using the internal
* CNetAddrListContainer object. The "Get" call will fill in the
* node record's network address list pointer and number of
* addresses, write the network address data into memory, and
* return the amount of data written into memory.
*/
data_length = internal_record->network_address_list->GetNetworkAddressListAPI (
&node_record->number_of_network_addresses,
&node_record->network_address_list,
memory);
/*
* Move the memory pointer past the network address list data.
* This is where the user data list data will be written.
*/
memory += data_length;
total_data_length += data_length;
}
else
{
/*
* The network address list does not exist, so set the node
* record pointer to NULL and the number of addresses to zero.
*/
node_record->network_address_list = NULL;
node_record->number_of_network_addresses = 0;
}
if (internal_record->poszAltNodeID != NULL)
{
/*
* Set the node record's alternative node ID pointer to the
* location in memory where the OSTR will be built.
* Note that the node record contains a pointer to a
* OSTR structure in memory, not just a pointer to
* string data.
*/
node_record->alternative_node_id = (LPOSTR) memory;
/*
* Move the memory pointer past the octet string structure.
* This is where the actual string data will be written.
*/
memory += ROUNDTOBOUNDARY(sizeof(OSTR));
total_data_length += ROUNDTOBOUNDARY(sizeof(OSTR));
node_record->alternative_node_id->length =
internal_record->poszAltNodeID->length;
/*
* Set the pointer for the alternative node ID octet string
* equal to the location in memory where it will be copied.
*/
node_record->alternative_node_id->value =(LPBYTE)memory;
/*
* Now copy the octet string data from the internal Rogue Wave
* string into the object key structure held in memory.
*/
::CopyMemory(memory, internal_record->poszAltNodeID->value,
node_record->alternative_node_id->length);
/*
* Move the memory pointer past the alternative node ID string
* data written into memory.
*/
memory += ROUNDTOBOUNDARY(node_record->alternative_node_id->length);
total_data_length += ROUNDTOBOUNDARY(node_record->alternative_node_id->length);
}
else
{
/*
* The alternative node ID string does not exist, so set the
* node record pointer to NULL.
*/
node_record->alternative_node_id = NULL;
}
if (internal_record->user_data_list != NULL)
{
/*
* Fill in the user data list by using the internal CUserDataListContainer
* object. The "Get" call will fill in the node record's user
* data list pointer and number of user data members, write the
* user data into memory, and return the amount of data written
* into memory.
*/
data_length = internal_record->user_data_list->GetUserDataList (
&node_record->number_of_user_data_members,
&node_record->user_data_list,
memory);
/*
* Move the memory pointer past the user data list data.
*/
memory += data_length;
total_data_length += data_length;
}
else
{
/*
* The user data list does not exist, so set the node record
* pointer to NULL and the number of data members to zero.
*/
node_record->user_data_list = NULL;
node_record->number_of_user_data_members = 0;
}
}
}
else
{
ERROR_OUT(("CConfRoster::GetConfRoster: Error Data Not Locked"));
*conference_roster = NULL;
rc = 0;
}
return rc;
}
/*
* GCCError AddRecord ()
*
* Public Function Description:
* This routine is used to add a new Node Record to this conference
* roster object.
*/
GCCError CConfRoster::AddRecord( PGCCNodeRecord node_record,
UserID node_id)
{
GCCError rc = GCC_NO_ERROR;
USHORT i;
LPWSTR pwszParticipantName;
CONF_RECORD *internal_record;
/*
** 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_fPduFlushed)
{
FreeRosterUpdateIndicationPDU ();
m_fPduFlushed = FALSE;
}
if (! m_RecordList2.Find(node_id))
{
DBG_SAVE_FILE_LINE
internal_record = new CONF_RECORD;
if (internal_record != NULL)
{
/*
** Convert the passed in conference record to the form that it
** is going to be stored in the internal roster database.
*/
/*
** Save the node type and properties internally. These will
** always exist.
*/
GetPDUNodeTypeAndProperties (
node_record->node_type,
node_record->node_properties,
&internal_record->node_type,
&internal_record->node_properties);
internal_record->superior_node = m_uidSuperiorNode;
// Save the node name internally if it exists.
if (node_record->node_name != NULL)
{
if (::lstrlenW(node_record->node_name) > MAXIMUM_NODE_NAME_LENGTH)
{
rc = GCC_INVALID_NODE_NAME;
}
else
if (NULL == (internal_record->pwszNodeName = ::My_strdupW(node_record->node_name)))
{
rc = GCC_ALLOCATION_FAILURE;
}
}
else
{
ASSERT(NULL == internal_record->pwszNodeName);
}
// Save the list of participants internally if it exists.
if ((node_record->number_of_participants != 0) &&
(rc == GCC_NO_ERROR))
{
if (node_record->participant_name_list != NULL)
{
DBG_SAVE_FILE_LINE
internal_record->participant_name_list = new CParticipantNameList;
if (internal_record->participant_name_list == NULL)
rc = GCC_ALLOCATION_FAILURE;
}
else
{
ASSERT(NULL == internal_record->participant_name_list);
rc = GCC_INVALID_PARAMETER;
}
if (rc == GCC_NO_ERROR)
{
/*
** Convert each participant name that is LPWSTR
** to a UnicodeString when storing it into a record.
*/
for (i = 0; i < node_record->number_of_participants; i++)
{
if (node_record->participant_name_list[i] != NULL)
{
if (::lstrlenW(node_record->participant_name_list[i]) >
MAXIMUM_PARTICIPANT_NAME_LENGTH)
{
rc = GCC_INVALID_PARTICIPANT_NAME;
//
// LONCHANC: Why no "break"?
//
}
else
if (NULL == (pwszParticipantName = ::My_strdupW(
node_record->participant_name_list[i])))
{
rc = GCC_ALLOCATION_FAILURE;
break;
}
else
{
// Add the participant to the list
internal_record->participant_name_list->Append(pwszParticipantName);
}
}
else
{
rc = GCC_INVALID_PARAMETER;
break;
}
}
}
}
else
{
ASSERT(NULL == internal_record->participant_name_list);
}
// Save site information internally if it exists.
if (node_record->site_information != NULL)
{
if (::lstrlenW(node_record->site_information) > MAXIMUM_SITE_INFORMATION_LENGTH)
{
rc = GCC_INVALID_SITE_INFORMATION;
}
else
if (NULL == (internal_record->pwszSiteInfo =
::My_strdupW(node_record->site_information)))
{
rc = GCC_ALLOCATION_FAILURE;
}
}
else
{
ASSERT(NULL == internal_record->pwszSiteInfo);
}
/*
** Fill in the network address list if it exists. The network
** address list is maintained internally in a CNetAddrListContainer
** object which is constructed here using the GCCNetworkAddress
** portion of the "API" node record passed in.
*/
if ((node_record->number_of_network_addresses != 0) &&
(node_record->network_address_list != NULL) &&
(rc == GCC_NO_ERROR))
{
DBG_SAVE_FILE_LINE
internal_record->network_address_list = new CNetAddrListContainer(
node_record->number_of_network_addresses,
node_record->network_address_list,
&rc);
if ((internal_record->network_address_list == NULL) ||
(rc != GCC_NO_ERROR))
{
rc = GCC_ALLOCATION_FAILURE;
}
}
else
{
ASSERT(NULL == internal_record->network_address_list);
}
// Save the alternative node ID internally if it exists.
if ((node_record->alternative_node_id != NULL) &&
(rc == GCC_NO_ERROR))
{
if (NULL == (internal_record->poszAltNodeID = ::My_strdupO2(
node_record->alternative_node_id->value,
node_record->alternative_node_id->length)))
{
rc = GCC_ALLOCATION_FAILURE;
}
else if (internal_record->poszAltNodeID->length != ALTERNATIVE_NODE_ID_LENGTH)
{
ERROR_OUT(("not equal to alt node id length"));
rc = GCC_INVALID_ALTERNATIVE_NODE_ID;
}
}
else
{
ASSERT(NULL == internal_record->poszAltNodeID);
}
/*
** Fill in the user data if it exists. The user data is
** maintained internally in a CUserDataListContainer object which is
** constructed here using the GCCUserData portion of the "API"
** node record passed in.
*/
if ((node_record->number_of_user_data_members != 0) &&
(node_record->user_data_list != NULL) &&
(rc == GCC_NO_ERROR))
{
DBG_SAVE_FILE_LINE
internal_record->user_data_list = new CUserDataListContainer(
node_record->number_of_user_data_members,
node_record->user_data_list,
&rc);
if ((internal_record->user_data_list == NULL) ||
(rc != GCC_NO_ERROR))
{
rc = GCC_ALLOCATION_FAILURE;
}
}
else
{
ASSERT(NULL == internal_record->user_data_list);
}
/*
** If the new Record was successfully filled in, add it to the
** internal Rogue Wave list of Records.
*/
if (rc == GCC_NO_ERROR)
{
// Increment the instance number.
m_nInstanceNumber++;
m_fNodesAdded = TRUE;
m_fRosterChanged = TRUE;
// Add the new record to the list of internal records.
m_RecordList2.Append(node_id, internal_record);
// Add an update to the PDU.
rc = BuildRosterUpdateIndicationPDU(ADD_RECORD, node_id);
}
else
{
delete internal_record;
}
}
else
{
rc = GCC_ALLOCATION_FAILURE;
}
}
else
{
rc = GCC_INVALID_PARAMETER;
}
return (rc);
}
/*
* GCCError RemoveUserReference ()
*
* Public Function Description:
* This routine is used to remove a node record from the list of node
* records.
*/
GCCError CConfRoster::RemoveUserReference(UserID detached_node_id)
{
GCCError rc = GCC_NO_ERROR;
CONF_RECORD *node_record;
CUidList node_delete_list;
/*
** 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_fPduFlushed)
{
FreeRosterUpdateIndicationPDU ();
m_fPduFlushed = FALSE;
}
/*
** Here we must determine if the node that is detaching is directly
** connected to this node. If so, we will delete the node and any other
** nodes found in the roster list that are subordinate to this. We
** determine all of this by using the superior node id stored in each
** conference record.
*/
if (NULL != (node_record = m_RecordList2.Find(detached_node_id)))
{
// Is this node directly connected to me?
if (node_record->superior_node == m_uidMyNodeID)
{
/*
** Use NULL for the pointer since were not concerned about
** the pointer here.
*/
rc = GetNodeSubTree(detached_node_id, &node_delete_list);
if (rc == GCC_NO_ERROR)
{
UserID uid;
node_delete_list.Reset();
while ((GCC_INVALID_UID != (uid = node_delete_list.Iterate())) &&
(rc == GCC_NO_ERROR))
{
rc = DeleteRecord(uid);
}
if (rc == GCC_NO_ERROR)
{
// Increment the instance number.
m_nInstanceNumber++;
m_fNodesRemoved = TRUE;
m_fRosterChanged = TRUE;
// Add an update to the PDU.
rc = BuildRosterUpdateIndicationPDU (FULL_REFRESH, 0 );
}
}
}
else
{
rc = GCC_INVALID_PARAMETER;
}
}
else
{
rc = GCC_INVALID_PARAMETER;
}
return (rc);
}
/*
* GCCError ReplaceRecord ()
*
* Public Function Description:
* This routine is used to replace one of the records in the list of
* node records.
*/
GCCError CConfRoster::ReplaceRecord(
PGCCNodeRecord node_record,
UserID node_id)
{
GCCError rc = GCC_NO_ERROR;
USHORT i;
LPWSTR pwszParticipantName;
CONF_RECORD *pCRD = NULL;
/*
** 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_fPduFlushed)
{
FreeRosterUpdateIndicationPDU ();
m_fPduFlushed = FALSE;
}
//
// LONCHANC: Do we really need to check this? Why can't we simply
// add the new one if the old one does not exist?
//
if (NULL == m_RecordList2.Find(node_id))
{
rc = GCC_INVALID_PARAMETER;
goto MyExit;
}
DBG_SAVE_FILE_LINE
if (NULL == (pCRD = new CONF_RECORD))
{
rc = GCC_ALLOCATION_FAILURE;
goto MyExit;
}
/*
** First we build all the internal data and check for validity
** before we replace the old record. We want to make sure that
** everything will build before we do the replace. This prevents
** us from corrupting the current record if there is a problem
** with the new record data.
*/
// Save the node name internally if it exists.
if (node_record->node_name != NULL)
{
if (::lstrlenW(node_record->node_name) > MAXIMUM_NODE_NAME_LENGTH)
{
rc = GCC_INVALID_NODE_NAME;
}
else
if (NULL == (pCRD->pwszNodeName = ::My_strdupW(node_record->node_name)))
{
rc = GCC_ALLOCATION_FAILURE;
}
}
// Save the list of participants internally if it exists.
if ((node_record->number_of_participants != 0) &&
(rc == GCC_NO_ERROR))
{
if (node_record->participant_name_list != NULL)
{
DBG_SAVE_FILE_LINE
if (NULL == (pCRD->participant_name_list = new CParticipantNameList))
{
rc = GCC_ALLOCATION_FAILURE;
}
}
else
rc = GCC_INVALID_PARAMETER;
if (rc == GCC_NO_ERROR)
{
/*
** Convert each participant name that is LPWSTR
** to a UnicodeString when storing it into a record.
*/
for (i = 0; i < node_record->number_of_participants; i++)
{
if (node_record->participant_name_list[i] != NULL)
{
if (::lstrlenW(node_record->participant_name_list[i]) >
MAXIMUM_PARTICIPANT_NAME_LENGTH)
{
rc = GCC_INVALID_PARTICIPANT_NAME;
//
// LONCHANC: Why no "break"?
//
}
else
if (NULL == (pwszParticipantName = ::My_strdupW(
node_record->participant_name_list[i])))
{
rc = GCC_ALLOCATION_FAILURE;
break;
}
else
{
// Add the participant to the list
pCRD->participant_name_list->Append(pwszParticipantName);
}
}
else
{
rc = GCC_INVALID_PARAMETER;
break;
}
}
}
}
// Save site information internally if it exists.
if (node_record->site_information != NULL)
{
if (::lstrlenW(node_record->site_information) > MAXIMUM_SITE_INFORMATION_LENGTH)
{
rc = GCC_INVALID_SITE_INFORMATION;
}
else
if (NULL == (pCRD->pwszSiteInfo = ::My_strdupW(node_record->site_information)))
{
rc = GCC_ALLOCATION_FAILURE;
}
}
/*
** Fill in the network address list if it exists. The network
** address list is maintained internally in a CNetAddrListContainer
** object which is constructed here using the GCCNetworkAddress
** portion of the "API" node record passed in.
*/
if ((node_record->number_of_network_addresses != 0) &&
(node_record->network_address_list != NULL) &&
(rc == GCC_NO_ERROR))
{
DBG_SAVE_FILE_LINE
pCRD->network_address_list = new CNetAddrListContainer(
node_record->number_of_network_addresses,
node_record->network_address_list,
&rc);
if ((pCRD->network_address_list == NULL) ||
(rc != GCC_NO_ERROR))
{
rc = GCC_ALLOCATION_FAILURE;
}
}
// Save the alternative node ID internally if it exists.
if ((node_record->alternative_node_id != NULL) &&
(rc == GCC_NO_ERROR))
{
if (NULL == (pCRD->poszAltNodeID = ::My_strdupO2(
node_record->alternative_node_id->value,
node_record->alternative_node_id->length)))
{
rc = GCC_ALLOCATION_FAILURE;
}
else if (pCRD->poszAltNodeID->length !=ALTERNATIVE_NODE_ID_LENGTH)
{
ERROR_OUT(("not equal to alt node id length"));
rc = GCC_INVALID_ALTERNATIVE_NODE_ID;
}
}
/*
** Fill in the user data if it exists. The user data is
** maintained internally in a CUserDataListContainer object which is
** constructed here using the GCCUserData portion of the "API"
** node record passed in.
*/
if ((node_record->number_of_user_data_members != 0) &&
(node_record->user_data_list != NULL) &&
(rc == GCC_NO_ERROR))
{
DBG_SAVE_FILE_LINE
pCRD->user_data_list = new CUserDataListContainer(
node_record->number_of_user_data_members,
node_record->user_data_list,
&rc);
if ((pCRD->user_data_list == NULL) || (rc != GCC_NO_ERROR))
{
rc = GCC_ALLOCATION_FAILURE;
}
}
/*
** Now if no errors occured we replace the old record with the new
** record information created above.
*/
if (rc == GCC_NO_ERROR)
{
/*
** Save the node type and properties internally. These will
** always exist.
*/
GetPDUNodeTypeAndProperties (
node_record->node_type,
node_record->node_properties,
&pCRD->node_type,
&pCRD->node_properties);
pCRD->superior_node = m_uidSuperiorNode;
// replace the old record with the new one
DeleteRecord(node_id);
m_RecordList2.Append(node_id, pCRD);
// Increment the instance number.
m_nInstanceNumber++;
m_fRosterChanged = TRUE;
}
MyExit:
if (GCC_NO_ERROR == rc)
{
// Add an update to the PDU.
rc = BuildRosterUpdateIndicationPDU(REPLACE_RECORD, node_id);
}
else
{
delete pCRD;
}
return (rc);
}
/*
* GCCError DeleteRecord ()
*
* Private Function Description:
* This routine is used to delete one of the records from the list of
* node records. It only operates on the conference roster list. It
* does not deal with any of the flags associated with a roster PDU or
* message such as: m_fNodesAdded and m_fNodesRemoved.
*
* Formal Parameters:
* node_id - (i) Node ID of node record to delete.
*
* Return Value
* GCC_NO_ERROR - No error occured.
* GCC_INVALID_PARAMETER - Bad node id passed in.
*
* Side Effects
* None.
*
* Caveats
* None.
*/
CONF_RECORD::CONF_RECORD(void)
:
pwszNodeName(NULL),
participant_name_list(NULL),
pwszSiteInfo(NULL),
network_address_list(NULL),
poszAltNodeID(NULL),
user_data_list(NULL),
superior_node(0)
{
}
CONF_RECORD::~CONF_RECORD(void)
{
/*
* If a node name exists, delete it from the Record.
*/
delete pwszNodeName;
/*
* If a participants list exists, clear the list and then delete it
* from the Record.
*/
if (participant_name_list != NULL)
{
participant_name_list->DeleteList();
delete participant_name_list;
}
/*
* If site information exists, delete it from the Record.
*/
delete pwszSiteInfo;
/*
* If a network address list exists, delete it from the Record.
*/
if (NULL != network_address_list)
{
network_address_list->Release();
}
/*
* If a user data list exists, delete it from the Record.
*/
if (NULL != user_data_list)
{
user_data_list->Release();
}
}
GCCError CConfRoster::DeleteRecord(UserID node_id)
{
GCCError rc;
CONF_RECORD *lpRec;
if (NULL != (lpRec = m_RecordList2.Remove(node_id)))
{
delete lpRec;
rc = GCC_NO_ERROR;
}
else
{
rc = GCC_INVALID_PARAMETER;
}
return (rc);
}
/*
* void ClearRecordList ()
*
* Private Function Description:
* This routine is used to clear out the internal list of records which
* hold the conference roster information. This routine is called upon
* destruction of this object or when a refresh occurs causing the entire
* record list to be rebuilt.
*
* Formal Parameters:
* None.
*
* Return Value
* None.
*
* Side Effects
* None.
*
* Caveats
* None.
*/
void CConfRoster::ClearRecordList(void)
{
CONF_RECORD *pRec;
while (NULL != (pRec = m_RecordList2.Get()))
{
delete pRec;
}
}
/*
* NodeType GetNodeTypeAndProperties ()
*
* Private Function Description:
* This routine is used to translate the node type and node properties
* from the "PDU" form into the "API" form.
*
* Formal Parameters:
* pdu_node_type - (i) This is the node type defined for the PDU.
* pdu_node_properties - (i) This is the node properties defined for
* the PDU.
* node_type - (o) This is a pointer to the GCCNodeType to
* be filled in by this routine.
* node_properties - (o) This is a pointer to the GCCNodeProperties
* to be filled in by this routine.
*
* Return Value
* None.
*
* Side Effects
* None.
*
* Caveats
* None.
*/
void CConfRoster::GetNodeTypeAndProperties (
NodeType pdu_node_type,
NodeProperties pdu_node_properties,
PGCCNodeType node_type,
PGCCNodeProperties node_properties)
{
/*
* First translate the node type.
*/
if (pdu_node_type == TERMINAL)
*node_type = GCC_TERMINAL;
else if (pdu_node_type == MCU)
*node_type = GCC_MCU;
else
*node_type = GCC_MULTIPORT_TERMINAL;
/*
* Next translate the node properties.
*/
if ((pdu_node_properties.device_is_peripheral) &&
(pdu_node_properties.device_is_manager == FALSE))
{
*node_properties = GCC_PERIPHERAL_DEVICE;
}
else if ((pdu_node_properties.device_is_peripheral == FALSE) &&
(pdu_node_properties.device_is_manager))
{
*node_properties = GCC_MANAGEMENT_DEVICE;
}
else if ((pdu_node_properties.device_is_peripheral) &&
(pdu_node_properties.device_is_manager))
{
*node_properties = GCC_PERIPHERAL_AND_MANAGEMENT_DEVICE;
}
else
*node_properties = GCC_NEITHER_PERIPHERAL_NOR_MANAGEMENT;
}
/*
* void GetPDUNodeTypeAndProperties ()
*
* Private Function Description:
* This routine is used to translate the node type and node properties
* from the "API" form into the "PDU" form.
*
* Formal Parameters:
* node_type - (i) This is the GCC (or API) node type.
* node_properties - (i) This is the GCC (or API) node properties
* pdu_node_type - (o) This is a pointer to the PDU node type to
* be filled in by this routine.
* pdu_node_properties - (o) This is a pointer to the PDU node properties
* to be filled in by this routine.
*
* Return Value
* None.
*
* Side Effects
* None.
*
* Caveats
* None.
*/
void CConfRoster::GetPDUNodeTypeAndProperties (
GCCNodeType node_type,
GCCNodeProperties node_properties,
PNodeType pdu_node_type,
PNodeProperties pdu_node_properties)
{
/*
* First translate node types.
*/
if (node_type == GCC_TERMINAL)
*pdu_node_type = TERMINAL;
else if (node_type == GCC_MCU)
*pdu_node_type = MCU;
else
*pdu_node_type = MULTIPORT_TERMINAL;
/*
* Next translate node properties.
*/
if (node_properties == GCC_PERIPHERAL_DEVICE)
{
pdu_node_properties->device_is_manager = FALSE;
pdu_node_properties->device_is_peripheral = TRUE;
}
else if (node_properties == GCC_MANAGEMENT_DEVICE)
{
pdu_node_properties->device_is_manager = TRUE;
pdu_node_properties->device_is_peripheral = FALSE;
}
else if (node_properties == GCC_PERIPHERAL_AND_MANAGEMENT_DEVICE)
{
pdu_node_properties->device_is_manager = TRUE;
pdu_node_properties->device_is_peripheral = TRUE;
}
else
{
pdu_node_properties->device_is_manager = FALSE;
pdu_node_properties->device_is_peripheral = FALSE;
}
}
/*
* BOOL Contains ()
*
* Public Function Description:
* This routine is used to determine whether or not a record exists within
* the internal list corresponding to the given user ID.
*/
/*
* UINT GetNumberOfApplicationRecords ()
*
* Public Function Description:
* This routine is used to get the number of node records currently being
* maintained within this object's internal list.
*/
/*
* void ResetConferenceRoster ()
*
* Public Function Description:
*/
void CConfRoster::ResetConferenceRoster(void)
{
m_fRosterChanged = FALSE;
m_fNodesAdded = FALSE;
m_fNodesRemoved = FALSE;
}
/*
* BOOL HasRosterChanged ()
*
* Public Function Description:
*/
/*
* GCCError GetNodeSubTree ()
*
* Public Function Description:
* This routine traverses the entire tree level-by-level starting at the
* root node and then progressively going down the tree.
*/
GCCError CConfRoster::GetNodeSubTree (
UserID uidRootNode,
CUidList *node_list)
{
GCCError rc = GCC_NO_ERROR;
CUidList high_level_list;
UserID uidSuperiorNode;
CONF_RECORD *lpRec;
UserID uid;
if (m_RecordList2.Find(uidRootNode))
{
/*
** First add the root node to the high level list to get every thing
** going.
*/
high_level_list.Append(uidRootNode);
while (! high_level_list.IsEmpty())
{
uidSuperiorNode = high_level_list.Get();
// Append the high level node id to the node list passed in.
node_list->Append(uidSuperiorNode);
/*
** Iterate through the entire roster looking for the next
** level of dependent nodes.
*/
m_RecordList2.Reset();
while (NULL != (lpRec = m_RecordList2.Iterate(&uid)))
{
if (lpRec->superior_node == uidSuperiorNode)
{
high_level_list.Append(uid);
}
}
}
}
else
{
rc = GCC_INVALID_PARAMETER;
}
return (rc);
}
void CParticipantNameList::DeleteList(void)
{
LPWSTR pwszParticipantName;
while (NULL != (pwszParticipantName = Get()))
{
delete pwszParticipantName;
}
}