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.
5948 lines
155 KiB
5948 lines
155 KiB
#include "precomp.h"
|
|
DEBUG_FILEZONE(ZONE_T120_GCCNC);
|
|
/*
|
|
* conf2.cpp
|
|
*
|
|
* Copyright (c) 1995 by DataBeam Corporation, Lexington, KY
|
|
*
|
|
* Abstract:
|
|
* This is the second part of the imlementation file for the CConf
|
|
* Class. The conference class is the heart of GCC. It maintains all the
|
|
* information basses for a single conference including conference and
|
|
* application rosters as well as registry information. It also
|
|
* routes, encodes and decodes various PDU's and primitives supported
|
|
* by GCC.
|
|
*
|
|
* This second part of the implementation file deals mainly with the
|
|
* command target calls and any callbacks received by the Owner Callback
|
|
* function. It also contains many of the utility functions used by the
|
|
* conference object.
|
|
*
|
|
* FOR A MORE DETAILED EXPLANATION OF THIS CLASS SEE THE INTERFACE FILE.
|
|
*
|
|
*
|
|
* Private Instance Variables
|
|
*
|
|
* ALL PRIVATE INSTANCE VARIABLES ARE DEFINED IN CONF.CPP
|
|
*
|
|
* Portable:
|
|
* Yes
|
|
*
|
|
* Caveats:
|
|
* None.
|
|
*
|
|
* Author:
|
|
* blp
|
|
*/
|
|
|
|
#include "conf.h"
|
|
#include "gcontrol.h"
|
|
#include "translat.h"
|
|
#include "ogcccode.h"
|
|
#include "string.h"
|
|
#include <iappldr.h>
|
|
|
|
|
|
#define FT_VERSION_STR "MS FT Version"
|
|
#define WB_VERSION_STR "MS WB Version"
|
|
#define CHAT_VERSION_STR "MS CHAT Version"
|
|
|
|
|
|
OSTR FT_VERSION_ID = {sizeof(FT_VERSION_STR), (unsigned char*)FT_VERSION_STR};
|
|
OSTR WB_VERSION_ID = {sizeof(WB_VERSION_STR), (unsigned char*)WB_VERSION_STR};
|
|
OSTR CHAT_VERSION_ID = {sizeof(CHAT_VERSION_STR), (unsigned char*)CHAT_VERSION_STR};
|
|
|
|
|
|
#define TERMINATE_TIMER_DURATION 10000 // Duration in milliseconds
|
|
|
|
static const struct ASN1objectidentifier_s WB_ASN1_OBJ_IDEN[6] = {
|
|
{ (ASN1objectidentifier_t) &(WB_ASN1_OBJ_IDEN[1]), 0 },
|
|
{ (ASN1objectidentifier_t) &(WB_ASN1_OBJ_IDEN[2]), 0 },
|
|
{ (ASN1objectidentifier_t) &(WB_ASN1_OBJ_IDEN[3]), 20 },
|
|
{ (ASN1objectidentifier_t) &(WB_ASN1_OBJ_IDEN[4]), 126 },
|
|
{ (ASN1objectidentifier_t) &(WB_ASN1_OBJ_IDEN[5]), 0 },
|
|
{ NULL, 1 }
|
|
};
|
|
|
|
static const struct Key WB_APP_PROTO_KEY = {
|
|
1, (ASN1objectidentifier_t)&WB_ASN1_OBJ_IDEN};
|
|
|
|
|
|
static const struct ASN1objectidentifier_s FT_ASN1_OBJ_IDEN[6] = {
|
|
{ (ASN1objectidentifier_t) &(FT_ASN1_OBJ_IDEN[1]), 0 },
|
|
{ (ASN1objectidentifier_t) &(FT_ASN1_OBJ_IDEN[2]), 0 },
|
|
{ (ASN1objectidentifier_t) &(FT_ASN1_OBJ_IDEN[3]), 20 },
|
|
{ (ASN1objectidentifier_t) &(FT_ASN1_OBJ_IDEN[4]), 127 },
|
|
{ (ASN1objectidentifier_t) &(FT_ASN1_OBJ_IDEN[5]), 0 },
|
|
{ NULL, 1 }
|
|
};
|
|
|
|
static const struct Key FT_APP_PROTO_KEY = {
|
|
1, (ASN1objectidentifier_t)&FT_ASN1_OBJ_IDEN};
|
|
|
|
|
|
struct Key CHAT_APP_PROTO_KEY;
|
|
|
|
|
|
/*
|
|
* This is a global variable that has a pointer to the one GCC coder that
|
|
* is instantiated by the GCC Controller. Most objects know in advance
|
|
* whether they need to use the MCS or the GCC coder, so, they do not need
|
|
* this pointer in their constructors.
|
|
*/
|
|
extern CGCCCoder *g_GCCCoder;
|
|
|
|
extern MCSDLLInterface *g_pMCSIntf;
|
|
|
|
/*
|
|
** These are GCCCommandTarget Calls. The only command targets that
|
|
** conference is connected to are Application SAPs and the Control SAP, so
|
|
** these Public member functions are only called from above.
|
|
*/
|
|
|
|
/*
|
|
* CConf::ConfJoinReqResponse()
|
|
*
|
|
* Public Function Description
|
|
* This routine is called when a node controller responds to a join
|
|
* request that was issued by a join from a node connected to a subnode.
|
|
*/
|
|
GCCError CConf::
|
|
ConfJoinReqResponse
|
|
(
|
|
UserID receiver_id,
|
|
CPassword *password_challenge,
|
|
CUserDataListContainer *user_data_list,
|
|
GCCResult result
|
|
)
|
|
{
|
|
DebugEntry(CConf::ConfJoinReqResponse);
|
|
|
|
/*
|
|
** Since the joining node is not directly connected to this
|
|
** node we send the response back through the user channel.
|
|
** It is the user attachment objects responsibility to
|
|
** encode this PDU.
|
|
*/
|
|
if (m_pMcsUserObject != NULL)
|
|
{
|
|
m_pMcsUserObject->ConferenceJoinResponse(
|
|
receiver_id,
|
|
m_fClearPassword,
|
|
m_fConfLocked,
|
|
m_fConfListed,
|
|
m_eTerminationMethod,
|
|
password_challenge,
|
|
user_data_list,
|
|
result);
|
|
}
|
|
|
|
DebugExitINT(CConf::ConfJoinReqResponse, GCC_NO_ERROR);
|
|
return (GCC_NO_ERROR);
|
|
}
|
|
|
|
/*
|
|
* CConf::ConfInviteRequest()
|
|
*
|
|
* Public Function Description
|
|
* This routine is called from the owner object when a
|
|
* ConfInviteRequest primitive needs to be processed.
|
|
*/
|
|
GCCError CConf::
|
|
ConfInviteRequest
|
|
(
|
|
LPWSTR pwszCallerID,
|
|
TransportAddress calling_address,
|
|
TransportAddress called_address,
|
|
BOOL fSecure,
|
|
CUserDataListContainer *user_data_list,
|
|
PConnectionHandle connection_handle
|
|
)
|
|
{
|
|
GCCError rc = GCC_NO_ERROR;
|
|
PUChar encoded_pdu;
|
|
UINT encoded_pdu_length;
|
|
MCSError mcs_error;
|
|
ConnectGCCPDU connect_pdu;
|
|
INVITE_REQ_INFO *invite_request_info;
|
|
|
|
DebugEntry(CConf::ConfInviteRequest);
|
|
|
|
if (! m_fConfIsEstablished)
|
|
{
|
|
ERROR_OUT(("CConf::ConfInviteRequest: Conference not established"));
|
|
rc = GCC_CONFERENCE_NOT_ESTABLISHED;
|
|
goto MyExit;
|
|
}
|
|
|
|
/*
|
|
** If the conference is locked, we only allow invite request if there
|
|
** are outstanding adds. T.124 states that when a conference is
|
|
** locked you can only use ADD to bring in new nodes to the conference.
|
|
*/
|
|
if (m_fConfLocked && m_AddResponseList.IsEmpty())
|
|
{
|
|
WARNING_OUT(("CConf::ConfInviteRequest: Conference is locked"));
|
|
rc = GCC_INVALID_CONFERENCE;
|
|
goto MyExit;
|
|
}
|
|
|
|
// Create the ConfInviteRequest PDU here.
|
|
connect_pdu.choice = CONFERENCE_INVITE_REQUEST_CHOSEN;
|
|
|
|
connect_pdu.u.conference_invite_request.bit_mask = 0;
|
|
|
|
/*
|
|
** First get the numeric and text (if it exists) portion of the
|
|
** conference name.
|
|
*/
|
|
connect_pdu.u.conference_invite_request.conference_name.bit_mask =0;
|
|
|
|
::lstrcpyA(connect_pdu.u.conference_invite_request.conference_name.numeric,
|
|
m_pszConfNumericName);
|
|
|
|
if (m_pwszConfTextName != NULL)
|
|
{
|
|
connect_pdu.u.conference_invite_request.conference_name.bit_mask |=
|
|
CONFERENCE_NAME_TEXT_PRESENT;
|
|
connect_pdu.u.conference_invite_request.conference_name.conference_name_text.value =
|
|
m_pwszConfTextName;
|
|
connect_pdu.u.conference_invite_request.conference_name.conference_name_text.length =
|
|
::lstrlenW(m_pwszConfTextName);
|
|
}
|
|
|
|
// Now set up the privilege list PDU data
|
|
if (m_pConductorPrivilegeList != NULL)
|
|
{
|
|
rc = m_pConductorPrivilegeList->GetPrivilegeListPDU(
|
|
&connect_pdu.u.conference_invite_request.cirq_conductor_privs);
|
|
if (GCC_NO_ERROR != rc)
|
|
{
|
|
ERROR_OUT(("CConf::ConfInviteRequest: can't get conductor privilege list, rc=%d", rc));
|
|
goto MyExit;
|
|
}
|
|
|
|
connect_pdu.u.conference_invite_request.bit_mask |= CIRQ_CONDUCTOR_PRIVS_PRESENT;
|
|
}
|
|
|
|
if (m_pConductModePrivilegeList != NULL)
|
|
{
|
|
rc = m_pConductModePrivilegeList->GetPrivilegeListPDU(
|
|
&connect_pdu.u.conference_invite_request.cirq_conducted_privs);
|
|
if (GCC_NO_ERROR != rc)
|
|
{
|
|
ERROR_OUT(("CConf::ConfInviteRequest: can't get conduct mode privilege list, rc=%d", rc));
|
|
goto MyExit;
|
|
}
|
|
|
|
connect_pdu.u.conference_invite_request.bit_mask |= CIRQ_CONDUCTED_PRIVS_PRESENT;
|
|
}
|
|
|
|
|
|
if (m_pNonConductModePrivilegeList != NULL)
|
|
{
|
|
rc = m_pNonConductModePrivilegeList->GetPrivilegeListPDU(
|
|
&connect_pdu.u.conference_invite_request.cirq_non_conducted_privs);
|
|
if (GCC_NO_ERROR != rc)
|
|
{
|
|
ERROR_OUT(("CConf::ConfInviteRequest: can't get non-conduct mode privilege list, rc=%d", rc));
|
|
goto MyExit;
|
|
}
|
|
|
|
connect_pdu.u.conference_invite_request.bit_mask |= CIRQ_NON_CONDUCTED_PRIVS_PRESENT;
|
|
}
|
|
|
|
if (m_pwszConfDescription != NULL)
|
|
{
|
|
connect_pdu.u.conference_invite_request.cirq_description.value =
|
|
m_pwszConfDescription;
|
|
connect_pdu.u.conference_invite_request.cirq_description.length =
|
|
::lstrlenW(m_pwszConfDescription);
|
|
|
|
connect_pdu.u.conference_invite_request.bit_mask |= CIRQ_DESCRIPTION_PRESENT;
|
|
}
|
|
|
|
if (pwszCallerID != NULL)
|
|
{
|
|
connect_pdu.u.conference_invite_request.cirq_caller_id.value = pwszCallerID;
|
|
connect_pdu.u.conference_invite_request.cirq_caller_id.length = ::lstrlenW(pwszCallerID);
|
|
connect_pdu.u.conference_invite_request.bit_mask |= CIRQ_CALLER_ID_PRESENT;
|
|
}
|
|
|
|
if (user_data_list != NULL)
|
|
{
|
|
rc = user_data_list->GetUserDataPDU(
|
|
&connect_pdu.u.conference_invite_request.cirq_user_data);
|
|
if (GCC_NO_ERROR != rc)
|
|
{
|
|
ERROR_OUT(("CConf::ConfInviteRequest: can't get user data, rc=%d", rc));
|
|
goto MyExit;
|
|
}
|
|
|
|
connect_pdu.u.conference_invite_request.bit_mask |= CIRQ_USER_DATA_PRESENT;
|
|
}
|
|
|
|
connect_pdu.u.conference_invite_request.node_id = m_pMcsUserObject->GetMyNodeID();
|
|
connect_pdu.u.conference_invite_request.top_node_id = m_pMcsUserObject->GetTopNodeID();
|
|
connect_pdu.u.conference_invite_request.tag = GetNewUserIDTag();
|
|
connect_pdu.u.conference_invite_request.clear_password_required = (ASN1bool_t)m_fClearPassword;
|
|
connect_pdu.u.conference_invite_request.conference_is_locked = (ASN1bool_t)m_fConfLocked;
|
|
connect_pdu.u.conference_invite_request.conference_is_conductible = (ASN1bool_t)m_fConfConductible;
|
|
connect_pdu.u.conference_invite_request.conference_is_listed = (ASN1bool_t)m_fConfListed;
|
|
connect_pdu.u.conference_invite_request.termination_method = (TerminationMethod)m_eTerminationMethod;
|
|
|
|
if (! g_GCCCoder->Encode((LPVOID) &connect_pdu,
|
|
CONNECT_GCC_PDU,
|
|
PACKED_ENCODING_RULES,
|
|
&encoded_pdu,
|
|
&encoded_pdu_length))
|
|
{
|
|
ERROR_OUT(("CConf::ConfInviteRequest: can't encode"));
|
|
rc = GCC_ALLOCATION_FAILURE;
|
|
goto MyExit;
|
|
}
|
|
|
|
mcs_error = g_pMCSIntf->ConnectProviderRequest (
|
|
&m_nConfID, // calling domain selector
|
|
&m_nConfID, // called domain selector
|
|
calling_address,
|
|
called_address,
|
|
fSecure,
|
|
FALSE, // Downward connection
|
|
encoded_pdu,
|
|
encoded_pdu_length,
|
|
connection_handle,
|
|
m_pDomainParameters,
|
|
this);
|
|
|
|
g_GCCCoder->FreeEncoded(encoded_pdu);
|
|
|
|
if (MCS_NO_ERROR != mcs_error)
|
|
{
|
|
ERROR_OUT(("CConf::ConfInviteRequest: ConnectProviderRequest failed: rc=%d", mcs_error));
|
|
|
|
/*
|
|
** DataBeam's current implementation of MCS returns
|
|
** MCS_INVALID_PARAMETER when something other than
|
|
** the transport prefix is wrong with the specified
|
|
** transport address.
|
|
*/
|
|
rc = (mcs_error == MCS_INVALID_PARAMETER) ?
|
|
GCC_INVALID_TRANSPORT_ADDRESS :
|
|
g_pMCSIntf->TranslateMCSIFErrorToGCCError(mcs_error);
|
|
goto MyExit;
|
|
}
|
|
|
|
/*
|
|
** Add the user's tag number to the list of
|
|
** outstanding user ids along with its associated
|
|
** connection.
|
|
*/
|
|
m_ConnHdlTagNumberList2.Append(connect_pdu.u.conference_invite_request.tag, *connection_handle);
|
|
|
|
// Add connection handle to the list of connections
|
|
ASSERT(0 != *connection_handle);
|
|
m_ConnHandleList.Append(*connection_handle);
|
|
|
|
/*
|
|
** Add the connection handle and the Node Id tag to
|
|
** the list of outstanding invite request.
|
|
*/
|
|
DBG_SAVE_FILE_LINE
|
|
invite_request_info = new INVITE_REQ_INFO;
|
|
if (NULL == invite_request_info)
|
|
{
|
|
ERROR_OUT(("CConf::ConfInviteRequest: can't create invite request info"));
|
|
rc = GCC_ALLOCATION_FAILURE;
|
|
goto MyExit;
|
|
}
|
|
|
|
invite_request_info->connection_handle = *connection_handle;
|
|
invite_request_info->invite_tag = m_nUserIDTagNumber;
|
|
invite_request_info->user_data_list = NULL;
|
|
|
|
m_InviteRequestList.Append(invite_request_info);
|
|
|
|
// Free the privilege list packed into structures for encoding
|
|
if (connect_pdu.u.conference_invite_request.bit_mask & CIRQ_CONDUCTOR_PRIVS_PRESENT)
|
|
{
|
|
m_pConductorPrivilegeList->FreePrivilegeListPDU(
|
|
connect_pdu.u.conference_invite_request.cirq_conductor_privs);
|
|
}
|
|
|
|
if (connect_pdu.u.conference_invite_request.bit_mask & CIRQ_CONDUCTED_PRIVS_PRESENT)
|
|
{
|
|
m_pConductModePrivilegeList->FreePrivilegeListPDU(
|
|
connect_pdu.u.conference_invite_request.cirq_conducted_privs);
|
|
}
|
|
|
|
if (connect_pdu.u.conference_invite_request.bit_mask & CIRQ_NON_CONDUCTED_PRIVS_PRESENT)
|
|
{
|
|
m_pNonConductModePrivilegeList->FreePrivilegeListPDU(
|
|
connect_pdu.u.conference_invite_request.cirq_non_conducted_privs);
|
|
}
|
|
|
|
ASSERT(GCC_NO_ERROR == rc);
|
|
|
|
MyExit:
|
|
|
|
DebugExitINT(CConf::ConfInviteRequest, rc);
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
* CConf::ConfLockRequest()
|
|
*
|
|
* Public Function Description:
|
|
* This routine is called from Control Sap when a
|
|
* ConfLockRequest primitive needs to be processed.
|
|
*/
|
|
#ifdef JASPER
|
|
GCCError CConf::
|
|
ConfLockRequest ( void )
|
|
{
|
|
GCCError rc = GCC_NO_ERROR;
|
|
|
|
DebugEntry(CConf::ConfLockRequest);
|
|
|
|
if (m_fConfIsEstablished)
|
|
{
|
|
if (m_fConfLocked == CONFERENCE_IS_NOT_LOCKED)
|
|
{
|
|
if (IsConfTopProvider())
|
|
{
|
|
ProcessConferenceLockRequest((UserID)m_pMcsUserObject->GetMyNodeID());
|
|
}
|
|
else
|
|
{
|
|
rc = m_pMcsUserObject->SendConferenceLockRequest();
|
|
}
|
|
}
|
|
else // the conference is already locked
|
|
{
|
|
#ifdef JASPER
|
|
g_pControlSap->ConfLockConfirm(GCC_RESULT_CONFERENCE_ALREADY_LOCKED, m_nConfID);
|
|
#endif // JASPER
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERROR_OUT(("CConf::ConfLockRequest: conference not established"));
|
|
rc = GCC_CONFERENCE_NOT_ESTABLISHED;
|
|
}
|
|
|
|
DebugExitINT(CConf::ConfLockRequest, rc);
|
|
return rc;
|
|
}
|
|
#endif // JASPER
|
|
|
|
|
|
/*
|
|
* CConf::ConfLockResponse()
|
|
*
|
|
* Public Function Description:
|
|
* This routine is called from Control Sap when a
|
|
* ConfLockResponse primitive needs to be processed.
|
|
*/
|
|
GCCError CConf::
|
|
ConfLockResponse
|
|
(
|
|
UserID requesting_node,
|
|
GCCResult result
|
|
)
|
|
{
|
|
GCCError rc = GCC_NO_ERROR;
|
|
|
|
DebugEntry(CConf::ConfLockResponse);
|
|
|
|
if (m_fConfIsEstablished)
|
|
{
|
|
if (requesting_node == m_pMcsUserObject->GetTopNodeID())
|
|
{
|
|
#ifdef JASPER
|
|
g_pControlSap->ConfLockConfirm(result, m_nConfID);
|
|
#endif // JASPER
|
|
}
|
|
else
|
|
{
|
|
rc = m_pMcsUserObject->SendConferenceLockResponse(requesting_node, result);
|
|
}
|
|
|
|
if (rc == GCC_NO_ERROR && result == GCC_RESULT_SUCCESSFUL)
|
|
{
|
|
m_fConfLocked = CONFERENCE_IS_LOCKED;
|
|
rc = m_pMcsUserObject->SendConferenceLockIndication(
|
|
TRUE, //indicates uniform send
|
|
0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERROR_OUT(("CConf::ConfLockResponse: conference not established"));
|
|
rc = GCC_CONFERENCE_NOT_ESTABLISHED;
|
|
}
|
|
|
|
DebugExitINT(CConf::ConfLockResponse, rc);
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*
|
|
* CConf::ConfUnlockRequest()
|
|
*
|
|
* Public Function Description:
|
|
* This routine is called from Control Sap when a
|
|
* ConferenceUnlockRequest primitive needs to be processed.
|
|
*/
|
|
#ifdef JASPER
|
|
GCCError CConf::
|
|
ConfUnlockRequest ( void )
|
|
{
|
|
GCCError rc = GCC_NO_ERROR;
|
|
|
|
DebugEntry(CConf::ConfUnlockRequest);
|
|
|
|
if (m_fConfIsEstablished)
|
|
{
|
|
if (m_fConfLocked == CONFERENCE_IS_LOCKED)
|
|
{
|
|
if (IsConfTopProvider())
|
|
{
|
|
ProcessConferenceUnlockRequest((UserID)m_pMcsUserObject->GetMyNodeID());
|
|
}
|
|
else
|
|
{
|
|
rc = m_pMcsUserObject->SendConferenceUnlockRequest();
|
|
}
|
|
}
|
|
else // the conference is already unlocked
|
|
{
|
|
#ifdef JASPER
|
|
g_pControlSap->ConfUnlockConfirm(GCC_RESULT_CONFERENCE_ALREADY_UNLOCKED, m_nConfID);
|
|
#endif // JASPER
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERROR_OUT(("CConf::ConfUnlockRequest: conference not established"));
|
|
rc = GCC_CONFERENCE_NOT_ESTABLISHED;
|
|
}
|
|
|
|
DebugExitINT(CConf::ConfUnlockRequest, rc);
|
|
return rc;
|
|
}
|
|
#endif // JASPER
|
|
|
|
|
|
/*
|
|
* CConf::ConfUnlockResponse()
|
|
*
|
|
* Public Function Description:
|
|
* This routine is called from Control Sap when a
|
|
* ConfUnlockResponse primitive needs to be processed.
|
|
*/
|
|
#ifdef JASPER
|
|
GCCError CConf::
|
|
ConfUnlockResponse
|
|
(
|
|
UserID requesting_node,
|
|
GCCResult result
|
|
)
|
|
{
|
|
GCCError rc = GCC_NO_ERROR;
|
|
|
|
DebugEntry(CConf::ConfUnlockResponse);
|
|
|
|
if (m_fConfIsEstablished)
|
|
{
|
|
if (requesting_node == m_pMcsUserObject->GetTopNodeID())
|
|
{
|
|
#ifdef JASPER
|
|
g_pControlSap->ConfUnlockConfirm(result, m_nConfID);
|
|
#endif // JASPER
|
|
}
|
|
else
|
|
{
|
|
rc = m_pMcsUserObject->SendConferenceUnlockResponse(requesting_node, result);
|
|
}
|
|
|
|
if (rc == GCC_NO_ERROR && result == GCC_RESULT_SUCCESSFUL)
|
|
{
|
|
m_fConfLocked = CONFERENCE_IS_NOT_LOCKED;
|
|
rc = m_pMcsUserObject->SendConferenceUnlockIndication(
|
|
TRUE, //indicates uniform send
|
|
0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERROR_OUT(("CConf::ConfUnlockResponse: conference not established"));
|
|
rc = GCC_CONFERENCE_NOT_ESTABLISHED;
|
|
}
|
|
|
|
DebugExitINT(CConf::ConfUnlockResponse, rc);
|
|
return rc;
|
|
}
|
|
#endif // JASPER
|
|
|
|
/*
|
|
* CConf::ConfEjectUserRequest ()
|
|
*
|
|
* Private Function Description
|
|
* This function initiates an eject user for the specified node id.
|
|
*/
|
|
GCCError CConf::
|
|
ConfEjectUserRequest
|
|
(
|
|
UserID ejected_node_id,
|
|
GCCReason reason
|
|
)
|
|
{
|
|
GCCError rc = GCC_NO_ERROR;
|
|
|
|
DebugEntry(CConf::ConfEjectUserRequest);
|
|
|
|
if (m_fConfIsEstablished)
|
|
{
|
|
if (IsConfTopProvider())
|
|
{
|
|
if (IsThisNodeParticipant(ejected_node_id))
|
|
{
|
|
ConnectionHandle nConnHdl;
|
|
BOOL fChildNode = FALSE;
|
|
|
|
// First check to see if it is a child node that is being ejected.
|
|
m_ConnHandleList.Reset();
|
|
while (0 != (nConnHdl = m_ConnHandleList.Iterate()))
|
|
{
|
|
if (m_pMcsUserObject->GetUserIDFromConnection(nConnHdl) == ejected_node_id)
|
|
{
|
|
fChildNode = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (fChildNode ||
|
|
DoesRequesterHavePrivilege(m_pMcsUserObject->GetMyNodeID(), EJECT_USER_PRIVILEGE))
|
|
{
|
|
// Add this ejected node to the list of Ejected Nodes
|
|
m_EjectedNodeConfirmList.Append(ejected_node_id);
|
|
|
|
/*
|
|
** The user attachment object decides where the ejct should
|
|
** be sent (either to the Top Provider or conference wide as
|
|
** an indication.
|
|
*/
|
|
m_pMcsUserObject->EjectNodeFromConference(ejected_node_id, reason);
|
|
}
|
|
else
|
|
{
|
|
#ifdef JASPER
|
|
/*
|
|
** The top provider does not have the privilege to eject
|
|
** a node from the conference. Send the appropriate
|
|
** confirm.
|
|
*/
|
|
g_pControlSap->ConfEjectUserConfirm(
|
|
m_nConfID,
|
|
ejected_node_id,
|
|
GCC_RESULT_INVALID_REQUESTER);
|
|
#endif // JASPER
|
|
rc = fChildNode ? GCC_INSUFFICIENT_PRIVILEGE : GCC_INVALID_MCS_USER_ID;
|
|
WARNING_OUT(("CConf::ConfEjectUserRequest: failed, rc=%d", rc));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rc = GCC_INVALID_MCS_USER_ID;
|
|
WARNING_OUT(("CConf::ConfEjectUserRequest: failed, rc=%d", rc));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Add this ejected node to the list of Ejected Nodes
|
|
m_EjectedNodeConfirmList.Append(ejected_node_id);
|
|
|
|
/*
|
|
** The user attachment object decides where the ejct should
|
|
** be sent (either to the Top Provider or conference wide as
|
|
** an indication.
|
|
*/
|
|
m_pMcsUserObject->EjectNodeFromConference(ejected_node_id, reason);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERROR_OUT(("CConf::ConfEjectUserRequest: conf not established"));
|
|
rc = GCC_CONFERENCE_NOT_ESTABLISHED;
|
|
}
|
|
|
|
DebugExitINT(CConf::ConfEjectUserRequest, rc);
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
* CConf::ConfAnnouncePresenceRequest ()
|
|
*
|
|
* Private Function Description
|
|
* This function forces a roster update indication and a confirm to be
|
|
* sent.
|
|
*/
|
|
GCCError CConf::
|
|
ConfAnnouncePresenceRequest ( PGCCNodeRecord node_record )
|
|
{
|
|
GCCError rc;
|
|
|
|
DebugEntry(CConf::ConfAnnouncePresenceRequest);
|
|
|
|
// If the conference is not established send back a negative confirm
|
|
if (! m_fConfIsEstablished)
|
|
{
|
|
WARNING_OUT(("CConf::ConfAnnouncePresenceRequest: conf not established"));
|
|
rc = GCC_CONFERENCE_NOT_ESTABLISHED;
|
|
goto MyExit;
|
|
}
|
|
|
|
/*
|
|
** This takes care of setting up the nodes record in the
|
|
** appropriate conference roster.
|
|
*/
|
|
rc = m_pConfRosterMgr->AddNodeRecord(node_record);
|
|
if (GCC_NO_ERROR != rc)
|
|
{
|
|
TRACE_OUT(("CConf::ConfAnnouncePresenceRequest: updating previous record"));
|
|
rc = m_pConfRosterMgr->UpdateNodeRecord(node_record);
|
|
if (GCC_NO_ERROR != rc)
|
|
{
|
|
ERROR_OUT(("CConf::ConfAnnouncePresenceRequest: can't update node record, rc=%d", rc));
|
|
goto MyExit;
|
|
}
|
|
}
|
|
|
|
// Only flush the roster data here if there is no startup alarm.
|
|
rc = AsynchFlushRosterData();
|
|
if (GCC_NO_ERROR != rc)
|
|
{
|
|
ERROR_OUT(("CConf::ConfAnnouncePresenceRequest: can't flush roster data, rc=%d", rc));
|
|
goto MyExit;
|
|
}
|
|
|
|
g_pControlSap->ConfAnnouncePresenceConfirm(m_nConfID, GCC_RESULT_SUCCESSFUL);
|
|
|
|
ASSERT(GCC_NO_ERROR == rc);
|
|
|
|
MyExit:
|
|
|
|
DebugExitINT(CConf::ConfAnnouncePresenceRequest, rc);
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*
|
|
* GCCError ConfDisconnectRequest ()
|
|
*
|
|
* Public Function Description
|
|
* This function initiates a disconnect of this node from the conference.
|
|
* This involves ejecting all subordinate nodes before actually
|
|
* disconnecting the parent connection.
|
|
*/
|
|
GCCError CConf::
|
|
ConfDisconnectRequest ( void )
|
|
{
|
|
GCCError rc = GCC_NO_ERROR;
|
|
UserID child_node_id;
|
|
ConnectionHandle nConnHdl;
|
|
|
|
DebugEntry(CConf::ConfDisconnectRequest);
|
|
|
|
/*
|
|
** Before we start the disconnect process we must remove all the
|
|
** outstanding invite request from our list and send back associated
|
|
** confirms. Here we go ahead disconnect all connection associated with
|
|
** the invites.
|
|
*/
|
|
DeleteOutstandingInviteRequests();
|
|
|
|
/*
|
|
** We set conference established to FALSE since the conference is
|
|
** no longer established (this also prevents a terminate indication
|
|
** from being sent).
|
|
*/
|
|
m_fConfIsEstablished = FALSE;
|
|
|
|
/*
|
|
** Iterate through the list of connection handles and eject each
|
|
** of the child nodes that is associated with it.
|
|
*/
|
|
m_ConnHandleList.Reset();
|
|
while (0 != (nConnHdl = m_ConnHandleList.Iterate()))
|
|
{
|
|
child_node_id = m_pMcsUserObject->GetUserIDFromConnection(nConnHdl);
|
|
|
|
rc = m_pMcsUserObject->EjectNodeFromConference (child_node_id,
|
|
GCC_REASON_HIGHER_NODE_DISCONNECTED);
|
|
if (rc != GCC_NO_ERROR)
|
|
{
|
|
ERROR_OUT(("CConf::ConfDisconnectRequest: can't eject node from conference"));
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If there is an error we go ahead and do a hard disconnect
|
|
if (m_ConnHandleList.IsEmpty() || rc != GCC_NO_ERROR)
|
|
{
|
|
/*
|
|
** First inform the control SAP that this node has successfuly
|
|
** disconnected.
|
|
*/
|
|
rc = g_pControlSap->ConfDisconnectConfirm(m_nConfID, GCC_RESULT_SUCCESSFUL);
|
|
|
|
// Tell the owner object to terminate this conference
|
|
InitiateTermination(GCC_REASON_NORMAL_TERMINATION, 0);
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
** Wait for all the ejects to complete before the conference is
|
|
** terminated.
|
|
*/
|
|
m_fConfDisconnectPending = TRUE;
|
|
}
|
|
|
|
DebugExitINT(CConf::ConfDisconnectRequest, rc);
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*
|
|
* GCCError ConfTerminateRequest ()
|
|
*
|
|
* Public Function Description
|
|
* This routine initiates a terminate sequence which starts with a request
|
|
* to the Top Provider if this node is not already the Top Provider.
|
|
*/
|
|
#ifdef JASPER
|
|
GCCError CConf::
|
|
ConfTerminateRequest ( GCCReason reason )
|
|
{
|
|
GCCError rc;
|
|
|
|
DebugEntry(CConf::ConfTerminateRequest);
|
|
|
|
if (m_fConfIsEstablished)
|
|
{
|
|
/*
|
|
** Before we start the termination process we must remove all the
|
|
** outstanding invite request from our list and send back associated
|
|
** confirms. Here we go ahead disconnect all connections associated
|
|
** with these invites.
|
|
*/
|
|
DeleteOutstandingInviteRequests();
|
|
|
|
if (IsConfTopProvider())
|
|
{
|
|
if (DoesRequesterHavePrivilege( m_pMcsUserObject->GetMyNodeID(),
|
|
TERMINATE_PRIVILEGE))
|
|
{
|
|
TRACE_OUT(("CConf::ConfTerminateRequest: Node has permission to terminate"));
|
|
/*
|
|
** Since the terminate was successful, we go ahead and
|
|
** set the m_fConfIsEstablished instance variable to
|
|
** FALSE. This prevents any other messages from flowing
|
|
** to the SAPs other than terminate messages.
|
|
*/
|
|
m_fConfIsEstablished = FALSE;
|
|
|
|
// Send the terminate confirm.
|
|
g_pControlSap->ConfTerminateConfirm(m_nConfID, GCC_RESULT_SUCCESSFUL);
|
|
|
|
// This call takes care of both the local and remote terminate
|
|
m_pMcsUserObject->ConferenceTerminateIndication(reason);
|
|
}
|
|
else
|
|
{
|
|
WARNING_OUT(("CConf::ConfTerminateRequest: Node does NOT have permission to terminate"));
|
|
g_pControlSap->ConfTerminateConfirm(m_nConfID, GCC_RESULT_INVALID_REQUESTER);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_pMcsUserObject->ConferenceTerminateRequest(reason);
|
|
}
|
|
rc = GCC_NO_ERROR;
|
|
}
|
|
else
|
|
{
|
|
ERROR_OUT(("CConf::ConfTerminateRequest: conference not established"));
|
|
rc = GCC_CONFERENCE_NOT_ESTABLISHED;
|
|
}
|
|
|
|
DebugExitINT(CConf::ConfTerminateRequest, rc);
|
|
return rc;
|
|
}
|
|
#endif // JASPER
|
|
|
|
|
|
/********************* Registry Calls ***********************************/
|
|
|
|
|
|
/*
|
|
* GCCError RegistryRegisterChannelRequest ()
|
|
*
|
|
* Public Function Description
|
|
* This initiates a registry request sequence. Note that the registry
|
|
* response is handled by the registry class.
|
|
*/
|
|
GCCError CConf::
|
|
RegistryRegisterChannelRequest
|
|
(
|
|
PGCCRegistryKey registry_key,
|
|
ChannelID nChnlID,
|
|
CAppSap *pAppSap
|
|
)
|
|
{
|
|
GCCError rc;
|
|
EntityID eid;
|
|
|
|
DebugEntry(CConf::RegistryRegisterChannelRequest);
|
|
|
|
rc = GetEntityIDFromAPEList(pAppSap, ®istry_key->session_key, &eid);
|
|
if (rc == GCC_NO_ERROR)
|
|
{
|
|
rc = m_pAppRegistry->RegisterChannel(registry_key, nChnlID, eid);
|
|
}
|
|
|
|
DebugExitINT(CConf::RegistryRegisterChannelRequest, rc);
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*
|
|
* GCCError RegistryAssignTokenRequest ()
|
|
*
|
|
* Public Function Description
|
|
* This initiates a registry request sequence. Note that the registry
|
|
* response is handled by the registry class.
|
|
*/
|
|
GCCError CConf::
|
|
RegistryAssignTokenRequest
|
|
(
|
|
PGCCRegistryKey registry_key,
|
|
CAppSap *pAppSap
|
|
)
|
|
{
|
|
GCCError rc;
|
|
GCCEntityID eid;
|
|
|
|
DebugEntry(CConf::RegistryAssignTokenRequest);
|
|
|
|
rc = GetEntityIDFromAPEList(pAppSap, ®istry_key->session_key, &eid);
|
|
if (rc == GCC_NO_ERROR)
|
|
{
|
|
rc = m_pAppRegistry->AssignToken(registry_key, eid);
|
|
}
|
|
|
|
DebugExitINT(CConf::RegistryAssignTokenRequest, rc);
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*
|
|
* GCCError RegistrySetParameterRequest ()
|
|
*
|
|
* Public Function Description
|
|
* This initiates a registry request sequence. Note that the registry
|
|
* response is handled by the registry class.
|
|
*/
|
|
GCCError CConf::
|
|
RegistrySetParameterRequest
|
|
(
|
|
PGCCRegistryKey registry_key,
|
|
LPOSTR parameter_value,
|
|
GCCModificationRights modification_rights,
|
|
CAppSap *pAppSap
|
|
)
|
|
{
|
|
GCCError rc;
|
|
GCCEntityID eid;
|
|
|
|
DebugEntry(CConf::RegistrySetParameterRequest);
|
|
|
|
rc = GetEntityIDFromAPEList(pAppSap, ®istry_key->session_key, &eid);
|
|
if (rc == GCC_NO_ERROR)
|
|
{
|
|
rc = m_pAppRegistry->SetParameter(registry_key,
|
|
parameter_value,
|
|
modification_rights,
|
|
eid);
|
|
}
|
|
|
|
DebugExitINT(CConf::RegistrySetParameterRequest, rc);
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*
|
|
* GCCError RegistryRetrieveEntryRequest ()
|
|
*
|
|
* Public Function Description
|
|
* This initiates a registry request sequence. Note that the registry
|
|
* response is handled by the registry class.
|
|
*/
|
|
GCCError CConf::
|
|
RegistryRetrieveEntryRequest
|
|
(
|
|
PGCCRegistryKey registry_key,
|
|
CAppSap *pAppSap
|
|
)
|
|
{
|
|
GCCError rc;
|
|
GCCEntityID eid;
|
|
|
|
DebugEntry(CConf::RegistryRetrieveEntryRequest);
|
|
|
|
rc = GetEntityIDFromAPEList(pAppSap, ®istry_key->session_key, &eid);
|
|
if (rc == GCC_NO_ERROR)
|
|
{
|
|
rc = m_pAppRegistry->RetrieveEntry(registry_key, eid);
|
|
}
|
|
|
|
DebugExitINT(CConf::RegistryRetrieveEntryRequest, rc);
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*
|
|
* GCCError RegistryDeleteEntryRequest ()
|
|
*
|
|
* Public Function Description
|
|
* This initiates a registry request sequence. Note that the registry
|
|
* response is handled by the registry class.
|
|
*/
|
|
GCCError CConf::
|
|
RegistryDeleteEntryRequest
|
|
(
|
|
PGCCRegistryKey registry_key,
|
|
CAppSap *pAppSap
|
|
)
|
|
{
|
|
GCCError rc;
|
|
EntityID eid;
|
|
|
|
DebugEntry(CConf::RegistryDeleteEntryRequest);
|
|
|
|
rc = GetEntityIDFromAPEList(pAppSap, ®istry_key->session_key, &eid);
|
|
if (rc == GCC_NO_ERROR)
|
|
{
|
|
rc = m_pAppRegistry->DeleteEntry(registry_key, eid);
|
|
}
|
|
|
|
DebugExitINT(CConf::RegistryDeleteEntryRequest, rc);
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*
|
|
* GCCError RegistryMonitorRequest ()
|
|
*
|
|
* Public Function Description
|
|
* This initiates a registry request sequence. Note that the registry
|
|
* response is handled by the registry class.
|
|
*/
|
|
GCCError CConf::
|
|
RegistryMonitorRequest
|
|
(
|
|
BOOL fEnableDelivery,
|
|
PGCCRegistryKey registry_key,
|
|
CAppSap *pAppSap)
|
|
{
|
|
GCCError rc;
|
|
GCCEntityID eid;
|
|
|
|
DebugEntry(CConf::RegistryMonitorRequest);
|
|
|
|
rc = GetEntityIDFromAPEList(pAppSap, ®istry_key->session_key, &eid);
|
|
if (rc == GCC_NO_ERROR)
|
|
{
|
|
rc = m_pAppRegistry->MonitorRequest(registry_key, fEnableDelivery, eid);
|
|
}
|
|
|
|
DebugExitINT(CConf:RegistryMonitorRequest, rc);
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*
|
|
* GCCError RegistryAllocateHandleRequest ()
|
|
*
|
|
* Public Function Description
|
|
* This initiates a registry request sequence. Note that the registry
|
|
* response is handled by the registry class. This registry call is
|
|
* a bit different from the other registry calls. Notice that there is
|
|
* no registry key associated with this call so there is no way to
|
|
* explicitly determine the entity ID. Luckily, the entity ID is not
|
|
* passed back in the allocate confirm so we just pick an entity id
|
|
* that is associated with this SAP. It makes no difference which one
|
|
* we pick because they all accomplish the same thing.
|
|
*/
|
|
GCCError CConf::
|
|
RegistryAllocateHandleRequest
|
|
(
|
|
UINT cHandles,
|
|
CAppSap *pAppSap
|
|
)
|
|
{
|
|
GCCError rc;
|
|
ENROLLED_APE_INFO *lpEnrAPEInfo;
|
|
GCCEntityID eid;
|
|
|
|
DebugEntry(CConf::RegistryAllocateHandleRequest);
|
|
|
|
// First we must find a single entity id that is associated with this SAP.
|
|
if (NULL != (lpEnrAPEInfo = GetEnrolledAPEbySap(pAppSap, &eid)))
|
|
{
|
|
ASSERT(GCC_INVALID_EID != eid);
|
|
rc = m_pAppRegistry->AllocateHandleRequest(cHandles, eid);
|
|
}
|
|
else
|
|
{
|
|
WARNING_OUT(("CConf::RegistryAllocateHandleRequest: Application not enrolled"));
|
|
rc = GCC_APP_NOT_ENROLLED;
|
|
}
|
|
|
|
DebugExitINT(CConf::RegistryAllocateHandleRequest, rc);
|
|
return rc;
|
|
}
|
|
|
|
|
|
/********************* Conductorship Calls ***********************************/
|
|
|
|
|
|
/*
|
|
* GCCError ConductorAssignRequest ()
|
|
*
|
|
* Public Function Description
|
|
* This initiates a Conductor assign request sequence. Here the node is
|
|
* requesting to become the conductor.
|
|
*/
|
|
#ifdef JASPER
|
|
GCCError CConf::
|
|
ConductorAssignRequest ( void )
|
|
{
|
|
GCCError rc = GCC_NO_ERROR;
|
|
GCCResult eResult = INVALID_GCC_RESULT;
|
|
|
|
DebugEntry(CConf::ConductorAssignRequest);
|
|
|
|
// Return an error if the conference is not established.
|
|
if (m_fConfIsEstablished)
|
|
{
|
|
if (m_fConfConductible)
|
|
{
|
|
if (m_nConductorNodeID != m_pMcsUserObject->GetMyNodeID())
|
|
{
|
|
if ((m_nPendingConductorNodeID == 0) && ! m_fConductorGiveResponsePending)
|
|
{
|
|
m_fConductorAssignRequestPending = TRUE;
|
|
rc = m_pMcsUserObject->ConductorTokenGrab();
|
|
}
|
|
else
|
|
{
|
|
TRACE_OUT(("CConf::ConductorAssignConfirm:Give Pending"));
|
|
eResult = GCC_RESULT_CONDUCTOR_GIVE_IS_PENDING;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERROR_OUT(("CConf::ConductorAssignRequest: Already Conductor"));
|
|
/*
|
|
** Since we are already the conductor send back a successful
|
|
** result
|
|
*/
|
|
//
|
|
// LONCHANC: Why not GCC_RESULT_ALREADY_CONDUCTOR?
|
|
//
|
|
eResult = GCC_RESULT_SUCCESSFUL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERROR_OUT(("CConf::ConductorAssignRequest: not conductible"));
|
|
eResult = GCC_RESULT_NOT_CONDUCTIBLE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERROR_OUT(("CConf::ConductorAssignRequest: conference not established"));
|
|
rc = GCC_CONFERENCE_NOT_ESTABLISHED;
|
|
}
|
|
|
|
#ifdef JASPER
|
|
if (INVALID_GCC_RESULT != eResult)
|
|
{
|
|
g_pControlSap->ConductorAssignConfirm(eResult, m_nConfID);
|
|
}
|
|
#endif // JASPER
|
|
|
|
DebugExitINT(CConf::ConductorAssignRequest, rc);
|
|
return rc;
|
|
}
|
|
#endif // JASPER
|
|
|
|
|
|
/*
|
|
* GCCError ConductorReleaseRequest ()
|
|
*
|
|
* Public Function Description
|
|
* Here the node is attempting to give up conductorship.
|
|
*/
|
|
#ifdef JASPER
|
|
GCCError CConf::
|
|
ConductorReleaseRequest ( void )
|
|
{
|
|
GCCError rc = GCC_NO_ERROR;
|
|
GCCResult eResult = INVALID_GCC_RESULT;
|
|
|
|
DebugEntry(CConf::ConductorReleaseRequest);
|
|
|
|
if (m_fConfConductible)
|
|
{
|
|
if (m_nConductorNodeID == m_pMcsUserObject->GetMyNodeID())
|
|
{
|
|
if (m_nPendingConductorNodeID == 0)
|
|
{
|
|
/*
|
|
** This does not seem right, but this is the way that T.124
|
|
** defines it should work.
|
|
*/
|
|
m_nConductorNodeID = 0; // Set back to non-conducted mode
|
|
|
|
m_fConductorGrantedPermission = FALSE;
|
|
|
|
rc = m_pMcsUserObject->SendConductorReleaseIndication();
|
|
if (rc == GCC_NO_ERROR)
|
|
{
|
|
rc = m_pMcsUserObject->ConductorTokenRelease();
|
|
|
|
/*
|
|
** Inform the control SAP and all the enrolled application
|
|
** SAPs that the conductor was released. We do this here
|
|
** because we will not process the release indication
|
|
** when it comes back in.
|
|
*/
|
|
if (rc == GCC_NO_ERROR)
|
|
{
|
|
g_pControlSap->ConductorReleaseIndication(m_nConfID);
|
|
|
|
/*
|
|
** We iterate on a temporary list to avoid any problems
|
|
** if the application sap leaves during the callback.
|
|
*/
|
|
CAppSap *pAppSap;
|
|
CAppSapList TempList(m_RegisteredAppSapList);
|
|
TempList.Reset();
|
|
while (NULL != (pAppSap = TempList.Iterate()))
|
|
{
|
|
if (DoesSAPHaveEnrolledAPE(pAppSap))
|
|
{
|
|
pAppSap->ConductorReleaseIndication(m_nConfID);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TRACE_OUT(("CConf: ConductorReleaseRequest: Give Pending"));
|
|
eResult = GCC_RESULT_CONDUCTOR_GIVE_IS_PENDING;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERROR_OUT(("CConf::ConductorReleaseRequest: Not the Conductor"));
|
|
eResult = GCC_RESULT_NOT_THE_CONDUCTOR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERROR_OUT(("CConf::ConductorReleaseRequest: not conductible"));
|
|
eResult = GCC_RESULT_NOT_CONDUCTIBLE;
|
|
}
|
|
|
|
#ifdef JASPER
|
|
if (INVALID_GCC_RESULT != eResult)
|
|
{
|
|
g_pControlSap->ConductorReleaseConfirm(eResult, m_nConfID);
|
|
}
|
|
#endif // JASPER
|
|
|
|
DebugExitINT(CConf::ConductorReleaseRequest, rc);
|
|
return rc;
|
|
}
|
|
#endif // JASPER
|
|
|
|
|
|
/*
|
|
* GCCError ConductorPleaseRequest ()
|
|
*
|
|
* Public Function Description
|
|
* Here the node is asking to be given conductorship.
|
|
*/
|
|
#ifdef JASPER
|
|
GCCError CConf::
|
|
ConductorPleaseRequest ( void )
|
|
{
|
|
GCCError rc = GCC_NO_ERROR;
|
|
GCCResult eResult = INVALID_GCC_RESULT;
|
|
|
|
DebugEntry(CConf::ConductorPleaseRequest);
|
|
|
|
if (m_fConfConductible)
|
|
{
|
|
// Return an error if the conference is not established
|
|
if (m_nConductorNodeID != 0)
|
|
{
|
|
if (m_nConductorNodeID != m_pMcsUserObject->GetMyNodeID())
|
|
{
|
|
rc = m_pMcsUserObject->ConductorTokenPlease();
|
|
if (rc == GCC_NO_ERROR)
|
|
{
|
|
// Send back positive confirm if successful
|
|
eResult = GCC_RESULT_SUCCESSFUL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING_OUT(("CConf::ConductorPleaseRequest: already conductor"));
|
|
eResult = GCC_RESULT_ALREADY_CONDUCTOR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERROR_OUT(("CConf::ConductorPleaseRequest: not in conducted mode"));
|
|
eResult = GCC_RESULT_NOT_IN_CONDUCTED_MODE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERROR_OUT(("CConf::ConductorPleaseRequest: not conductible"));
|
|
eResult = GCC_RESULT_NOT_CONDUCTIBLE;
|
|
}
|
|
|
|
#ifdef JASPER
|
|
if (INVALID_GCC_RESULT != eResult)
|
|
{
|
|
g_pControlSap->ConductorPleaseConfirm(eResult, m_nConfID);
|
|
}
|
|
#endif // JASPER
|
|
|
|
DebugExitINT(CConf::ConductorPleaseRequest, rc);
|
|
return rc;
|
|
}
|
|
#endif // JASPER
|
|
|
|
|
|
/*
|
|
* GCCError ConductorGiveRequest ()
|
|
*
|
|
* Public Function Description
|
|
* The function is called when the conductor wants to pass off
|
|
* conductorship to a different node.
|
|
*/
|
|
#ifdef JASPER
|
|
GCCError CConf::
|
|
ConductorGiveRequest ( UserID recipient_node_id )
|
|
{
|
|
GCCError rc = GCC_NO_ERROR;
|
|
GCCResult eResult = INVALID_GCC_RESULT;
|
|
|
|
DebugEntry(CConf::ConductorGiveRequest);
|
|
|
|
if (m_fConfConductible)
|
|
{
|
|
// Am I in conducted mode?
|
|
if (m_nConductorNodeID != 0)
|
|
{
|
|
// Am I the conductor?
|
|
if (m_nConductorNodeID == m_pMcsUserObject->GetMyNodeID())
|
|
{
|
|
if (recipient_node_id != m_pMcsUserObject->GetMyNodeID())
|
|
{
|
|
if (m_nPendingConductorNodeID == 0)
|
|
{
|
|
/*
|
|
** We don't assume that the recipient node is the new
|
|
** conductor until we get a confirm or an
|
|
** AssignIndication. The m_nPendingConductorNodeID is
|
|
** used to buffer the recipient until the give confirm
|
|
** is received.
|
|
*/
|
|
m_nPendingConductorNodeID = recipient_node_id;
|
|
rc = m_pMcsUserObject->ConductorTokenGive(recipient_node_id);
|
|
}
|
|
else
|
|
{
|
|
TRACE_OUT(("CConf::ConductorGiveRequest: conductor give is pending"));
|
|
eResult = GCC_RESULT_CONDUCTOR_GIVE_IS_PENDING;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING_OUT(("CConf::ConductorGiveRequest: already conductor"));
|
|
eResult = GCC_RESULT_ALREADY_CONDUCTOR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERROR_OUT(("CConf::ConductorGiveRequest: not the conductor"));
|
|
eResult = GCC_RESULT_NOT_THE_CONDUCTOR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERROR_OUT(("CConf::ConductorGiveRequest: not in conduct mode"));
|
|
eResult = GCC_RESULT_NOT_IN_CONDUCTED_MODE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERROR_OUT(("CConf::ConductorGiveRequest: not conductible"));
|
|
eResult = GCC_RESULT_NOT_CONDUCTIBLE;
|
|
}
|
|
|
|
#ifdef JASPER
|
|
if (INVALID_GCC_RESULT != eResult)
|
|
{
|
|
g_pControlSap->ConductorGiveConfirm(eResult, m_nConfID, recipient_node_id);
|
|
}
|
|
#endif // JASPER
|
|
|
|
DebugExitINT(CConf::ConductorGiveRequest, rc);
|
|
return rc;
|
|
}
|
|
#endif // JASPER
|
|
|
|
|
|
/*
|
|
* GCCError ConductorGiveResponse ()
|
|
*
|
|
* Public Function Description
|
|
* This function gets called in response to a Conductor Give Indication.
|
|
* If result is success then this node is the new conductor.
|
|
*/
|
|
GCCError CConf::
|
|
ConductorGiveResponse ( GCCResult eResult )
|
|
{
|
|
GCCError rc = GCC_NO_ERROR;
|
|
|
|
DebugEntry(CConf::ConductorGiveResponse);
|
|
|
|
if (! m_fConductorGiveResponsePending)
|
|
{
|
|
ERROR_OUT(("CConf::ConductorGiveResponse: no give response pending"));
|
|
rc = GCC_NO_GIVE_RESPONSE_PENDING;
|
|
goto MyExit;
|
|
}
|
|
|
|
m_fConductorGiveResponsePending = FALSE;
|
|
|
|
if (eResult == GCC_RESULT_SUCCESSFUL)
|
|
{
|
|
// Set the conductor id to my user id if the response is success.
|
|
m_nConductorNodeID = m_pMcsUserObject->GetMyNodeID();
|
|
|
|
// The new conductor always has permission.
|
|
m_fConductorGrantedPermission = TRUE;
|
|
|
|
/*
|
|
** We must perform the give response before sending the dummy to
|
|
** the top provider so that MCS knows that the conductor token
|
|
** belongs to this node.
|
|
*/
|
|
rc = m_pMcsUserObject->ConductorTokenGiveResponse(RESULT_SUCCESSFUL);
|
|
if (GCC_NO_ERROR != rc)
|
|
{
|
|
ERROR_OUT(("CConf::ConductorGiveResponse: ConductorTokenGiveResponse failed, rc=%d", rc));
|
|
goto MyExit;
|
|
}
|
|
|
|
/*
|
|
** If this node is not the Top Provider, we must try to Give the
|
|
** Conductor token to the Top Provider. The Top Provider is used
|
|
** to issue the Assign Indication whenever the conductor changes
|
|
** hands.
|
|
*/
|
|
if (m_pMcsUserObject->GetMyNodeID() != m_pMcsUserObject->GetTopNodeID())
|
|
{
|
|
rc = m_pMcsUserObject->ConductorTokenGive(m_pMcsUserObject->GetTopNodeID());
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
** Here we go ahead and send the assign indication because we
|
|
** are already at the Top Provider.
|
|
*/
|
|
rc = m_pMcsUserObject->SendConductorAssignIndication(m_nConductorNodeID);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Inform that giver that we are not interested
|
|
rc = m_pMcsUserObject->ConductorTokenGiveResponse(RESULT_USER_REJECTED);
|
|
}
|
|
|
|
MyExit:
|
|
|
|
DebugExitINT(CConf::ConductorGiveResponse, rc);
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*
|
|
* GCCError ConductorPermitAskRequest ()
|
|
*
|
|
* Public Function Description
|
|
* This call is made when a node wants to request permission from the
|
|
* conductor.
|
|
*/
|
|
#ifdef JASPER
|
|
GCCError CConf::
|
|
ConductorPermitAskRequest ( BOOL grant_permission )
|
|
{
|
|
GCCError rc = GCC_NO_ERROR;
|
|
GCCResult eResult = INVALID_GCC_RESULT;
|
|
|
|
DebugEntry(CConf::ConductorPermitAskRequest);
|
|
|
|
if (m_fConfConductible)
|
|
{
|
|
// Am I in conducted mode?
|
|
if (m_nConductorNodeID != 0)
|
|
{
|
|
if (m_nConductorNodeID != m_pMcsUserObject->GetMyNodeID())
|
|
{
|
|
rc = m_pMcsUserObject->SendConductorPermitAsk(grant_permission);
|
|
if (rc == GCC_NO_ERROR)
|
|
{
|
|
eResult = GCC_RESULT_SUCCESSFUL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING_OUT(("CConf::ConductorPermitAskRequest: already conductor"));
|
|
eResult = GCC_RESULT_ALREADY_CONDUCTOR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERROR_OUT(("CConf::ConductorPermitAskRequest: not in conducted mode"));
|
|
eResult = GCC_RESULT_NOT_IN_CONDUCTED_MODE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERROR_OUT(("CConf::ConductorPermitAskRequest: not conductible"));
|
|
eResult = GCC_RESULT_NOT_CONDUCTIBLE;
|
|
}
|
|
|
|
#ifdef JASPER
|
|
if (INVALID_GCC_RESULT != eResult)
|
|
{
|
|
g_pControlSap->ConductorPermitAskConfirm(eResult, grant_permission, m_nConfID);
|
|
}
|
|
#endif // JASPER
|
|
|
|
DebugExitINT(CConf::ConductorPermitAskRequest, rc);
|
|
return rc;
|
|
}
|
|
#endif // JASPER
|
|
|
|
|
|
/*
|
|
* GCCError ConductorPermitGrantRequest ()
|
|
*
|
|
* Public Function Description
|
|
* This function is called when a conductor wishes to grant permission
|
|
* to a specific node or to a list of nodes.
|
|
*/
|
|
#ifdef JASPER
|
|
GCCError CConf::
|
|
ConductorPermitGrantRequest
|
|
(
|
|
UINT number_granted,
|
|
PUserID granted_node_list,
|
|
UINT number_waiting,
|
|
PUserID waiting_node_list
|
|
)
|
|
{
|
|
GCCError rc = GCC_NO_ERROR;
|
|
GCCResult eResult = INVALID_GCC_RESULT;
|
|
|
|
DebugEntry(CConf::ConductorPermitGrantRequest);
|
|
|
|
if (m_fConfConductible)
|
|
{
|
|
// Am I in conducted mode?
|
|
if (m_nConductorNodeID != 0)
|
|
{
|
|
// Am I the conductor?
|
|
if (m_nConductorNodeID == m_pMcsUserObject->GetMyNodeID())
|
|
{
|
|
TRACE_OUT(("CConf: ConductorPermitGrantRequest: SEND: number_granted = %d", number_granted));
|
|
|
|
rc = m_pMcsUserObject->SendConductorPermitGrant(
|
|
number_granted,
|
|
granted_node_list,
|
|
number_waiting,
|
|
waiting_node_list);
|
|
if (rc == GCC_NO_ERROR)
|
|
{
|
|
eResult = GCC_RESULT_SUCCESSFUL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERROR_OUT(("CConf::ConductorPermitGrantRequest: not the conductor"));
|
|
eResult = GCC_RESULT_NOT_THE_CONDUCTOR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERROR_OUT(("CConf::ConductorPermitGrantRequest: not in conducted mode"));
|
|
eResult = GCC_RESULT_NOT_IN_CONDUCTED_MODE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERROR_OUT(("CConf::ConductorPermitGrantRequest: not conductible"));
|
|
eResult = GCC_RESULT_NOT_CONDUCTIBLE;
|
|
}
|
|
|
|
#ifdef JASPER
|
|
if (INVALID_GCC_RESULT != eResult)
|
|
{
|
|
g_pControlSap->ConductorPermitGrantConfirm(eResult, m_nConfID);
|
|
}
|
|
#endif // JASPER
|
|
|
|
DebugExitINT(CConf::ConductorPermitGrantRequest, rc);
|
|
return rc;
|
|
}
|
|
#endif // JASPER
|
|
|
|
|
|
/*
|
|
* GCCError ConductorInquireRequest ()
|
|
*
|
|
* Public Function Description
|
|
* This function is called when a node request conductorship information.
|
|
*/
|
|
GCCError CConf::
|
|
ConductorInquireRequest ( CBaseSap *pSap )
|
|
{
|
|
GCCError rc = GCC_NO_ERROR;
|
|
GCCResult eResult = INVALID_GCC_RESULT;
|
|
|
|
DebugEntry(CConf::ConductorInquireRequest);
|
|
|
|
if (m_fConfConductible)
|
|
{
|
|
if (m_nConductorNodeID != 0)
|
|
{
|
|
rc = m_pMcsUserObject->ConductorTokenTest();
|
|
|
|
/*
|
|
** We must "push" the command target to the to the list of
|
|
** outstanding conductor test request. When the test confirm
|
|
** comes back the command target will be "poped" of the list.
|
|
** Note that all test request must be processed in the order that
|
|
** they are requested.
|
|
*/
|
|
m_ConductorTestList.Append(pSap);
|
|
}
|
|
else
|
|
{
|
|
// If not in conducted mode send back NO conductor information
|
|
ERROR_OUT(("CConf::ConductorInquireRequest: not in conducted mode"));
|
|
eResult = GCC_RESULT_NOT_IN_CONDUCTED_MODE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERROR_OUT(("CConf::ConductorInquireRequest: not conductible"));
|
|
eResult = GCC_RESULT_NOT_CONDUCTIBLE;
|
|
}
|
|
|
|
if (INVALID_GCC_RESULT != eResult)
|
|
{
|
|
pSap->ConductorInquireConfirm(NULL,
|
|
eResult,
|
|
m_fConductorGrantedPermission,
|
|
FALSE,
|
|
m_nConfID);
|
|
}
|
|
|
|
DebugExitINT(CConf:ConductorInquireRequest, rc);
|
|
return rc;
|
|
}
|
|
|
|
/********************** Miscelaneous Finctions **********************/
|
|
|
|
|
|
/*
|
|
* GCCError ConferenceTimeRemainingRequest ()
|
|
*
|
|
* Public Function Description
|
|
* This function initiates a TimeRemainingRequest sequence.
|
|
*/
|
|
GCCError CConf::
|
|
ConferenceTimeRemainingRequest
|
|
(
|
|
UINT time_remaining,
|
|
UserID node_id
|
|
)
|
|
{
|
|
GCCError rc;
|
|
|
|
DebugEntry(CConf::ConferenceTimeRemainingRequest);
|
|
|
|
if (m_fConfIsEstablished)
|
|
{
|
|
rc = m_pMcsUserObject->TimeRemainingRequest(time_remaining, node_id);
|
|
#ifdef JASPER
|
|
if (rc == GCC_NO_ERROR)
|
|
{
|
|
g_pControlSap->ConfTimeRemainingConfirm(m_nConfID, GCC_RESULT_SUCCESSFUL);
|
|
}
|
|
#endif // JASPER
|
|
}
|
|
else
|
|
{
|
|
ERROR_OUT(("CConf::ConferenceTimeRemainingRequest: conference not established"));
|
|
rc = GCC_CONFERENCE_NOT_ESTABLISHED;
|
|
}
|
|
|
|
DebugExitINT(CConf::ConferenceTimeRemainingRequest, rc);
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*
|
|
* GCCError ConfTimeInquireRequest ()
|
|
*
|
|
* Public Function Description
|
|
* This function initiates a ConfTimeInquireRequest sequence.
|
|
*/
|
|
#ifdef JASPER
|
|
GCCError CConf::
|
|
ConfTimeInquireRequest ( BOOL time_is_conference_wide )
|
|
{
|
|
GCCError rc = GCC_NO_ERROR;
|
|
|
|
DebugEntry(CConf::ConfTimeInquireRequest);
|
|
|
|
if (m_fConfIsEstablished)
|
|
{
|
|
if ((m_eNodeType == CONVENER_NODE) ||
|
|
(m_eNodeType == TOP_PROVIDER_AND_CONVENER_NODE)||
|
|
(m_eNodeType == JOINED_CONVENER_NODE))
|
|
{
|
|
g_pControlSap->ConfTimeInquireIndication(
|
|
m_nConfID,
|
|
time_is_conference_wide,
|
|
m_pMcsUserObject->GetMyNodeID());
|
|
}
|
|
else
|
|
{
|
|
rc = m_pMcsUserObject->TimeInquireRequest(time_is_conference_wide);
|
|
}
|
|
|
|
#ifdef JASPER
|
|
if (rc == GCC_NO_ERROR)
|
|
{
|
|
g_pControlSap->ConfTimeInquireConfirm(m_nConfID, GCC_RESULT_SUCCESSFUL);
|
|
}
|
|
#endif // JASPER
|
|
}
|
|
else
|
|
{
|
|
ERROR_OUT(("CConf::ConfTimeInquireRequest: conference not established"));
|
|
rc = GCC_CONFERENCE_NOT_ESTABLISHED;
|
|
}
|
|
|
|
DebugExitINT(CConf::ConfTimeInquireRequest, rc);
|
|
|
|
return rc;
|
|
}
|
|
#endif // JASPER
|
|
|
|
|
|
/*
|
|
* GCCError ConfExtendRequest ()
|
|
*
|
|
* Public Function Description
|
|
* This function initiates a ConfExtendRequest sequence.
|
|
*/
|
|
#ifdef JASPER
|
|
GCCError CConf::
|
|
ConfExtendRequest
|
|
(
|
|
UINT extension_time,
|
|
BOOL time_is_conference_wide
|
|
)
|
|
{
|
|
GCCError rc = GCC_NO_ERROR;
|
|
|
|
DebugEntry(CConf::ConfExtendRequest);
|
|
|
|
if (m_fConfIsEstablished)
|
|
{
|
|
if ((m_eNodeType == CONVENER_NODE) ||
|
|
(m_eNodeType == TOP_PROVIDER_AND_CONVENER_NODE)||
|
|
(m_eNodeType == JOINED_CONVENER_NODE))
|
|
{
|
|
#ifdef JASPER
|
|
g_pControlSap->ConfExtendIndication(
|
|
m_nConfID,
|
|
extension_time,
|
|
time_is_conference_wide,
|
|
m_pMcsUserObject->GetMyNodeID());
|
|
#endif // JASPER
|
|
}
|
|
else
|
|
{
|
|
rc = m_pMcsUserObject->ConferenceExtendIndication(
|
|
extension_time,
|
|
time_is_conference_wide);
|
|
}
|
|
|
|
#ifdef JASPER
|
|
if (rc == GCC_NO_ERROR)
|
|
{
|
|
g_pControlSap->ConfExtendConfirm(
|
|
m_nConfID,
|
|
extension_time,
|
|
GCC_RESULT_SUCCESSFUL);
|
|
}
|
|
#endif // JASPER
|
|
}
|
|
else
|
|
{
|
|
ERROR_OUT(("CConf::ConfExtendRequest: conference not established"));
|
|
rc = GCC_CONFERENCE_NOT_ESTABLISHED;
|
|
}
|
|
|
|
DebugExitINT(CConf::ConfExtendRequest, rc);
|
|
return rc;
|
|
}
|
|
#endif // JASPER
|
|
|
|
|
|
/*
|
|
* GCCError ConfAssistanceRequest ()
|
|
*
|
|
* Public Function Description
|
|
* This function initiates a ConfAssistanceRequest sequence.
|
|
*/
|
|
#ifdef JASPER
|
|
GCCError CConf::
|
|
ConfAssistanceRequest
|
|
(
|
|
UINT number_of_user_data_members,
|
|
PGCCUserData *user_data_list
|
|
)
|
|
{
|
|
GCCError rc;
|
|
|
|
DebugEntry(CConf::ConfAssistanceRequest);
|
|
|
|
if (m_fConfIsEstablished)
|
|
{
|
|
rc = m_pMcsUserObject->ConferenceAssistanceIndication(
|
|
number_of_user_data_members,
|
|
user_data_list);
|
|
#ifdef JASPER
|
|
if (rc == GCC_NO_ERROR)
|
|
{
|
|
g_pControlSap->ConfAssistanceConfirm(m_nConfID, GCC_RESULT_SUCCESSFUL);
|
|
}
|
|
#endif // JASPER
|
|
}
|
|
else
|
|
{
|
|
ERROR_OUT(("CConf::ConfAssistanceRequest: conference not established"));
|
|
rc = GCC_CONFERENCE_NOT_ESTABLISHED;
|
|
}
|
|
|
|
DebugExitINT(CConf::ConfAssistanceRequest, rc);
|
|
return rc;
|
|
}
|
|
#endif // JASPER
|
|
|
|
/*
|
|
* GCCError AppInvokeRequest()
|
|
*
|
|
* Public Function Description
|
|
* This function initiates an ApplicationInvokeRequest sequence.
|
|
*/
|
|
GCCError CConf::
|
|
AppInvokeRequest
|
|
(
|
|
CInvokeSpecifierListContainer *invoke_list,
|
|
GCCSimpleNodeList *pNodeList,
|
|
CBaseSap *pSap,
|
|
GCCRequestTag nReqTag
|
|
)
|
|
{
|
|
GCCError rc;
|
|
|
|
DebugEntry(CConf::AppInvokeRequest);
|
|
|
|
if (m_fConfIsEstablished)
|
|
{
|
|
rc = m_pMcsUserObject->AppInvokeIndication(invoke_list, pNodeList);
|
|
if (rc == GCC_NO_ERROR)
|
|
{
|
|
pSap->AppInvokeConfirm(m_nConfID, invoke_list, GCC_RESULT_SUCCESSFUL, nReqTag);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERROR_OUT(("CConf::AppInvokeRequest: conference not established"));
|
|
rc = GCC_CONFERENCE_NOT_ESTABLISHED;
|
|
}
|
|
|
|
DebugExitINT(CConf::AppInvokeRequest, rc);
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*
|
|
* GCCError TextMessageRequest ()
|
|
*
|
|
* Public Function Description
|
|
* This function initiates an TextMessageRequest sequence.
|
|
*/
|
|
#ifdef JASPER
|
|
GCCError CConf::
|
|
TextMessageRequest
|
|
(
|
|
LPWSTR pwszTextMsg,
|
|
UserID destination_node
|
|
)
|
|
{
|
|
GCCError rc;
|
|
|
|
DebugEntry(CConf::TextMessageRequest);
|
|
|
|
if (m_fConfIsEstablished)
|
|
{
|
|
if (destination_node != m_pMcsUserObject->GetMyNodeID())
|
|
{
|
|
rc = m_pMcsUserObject->TextMessageIndication(pwszTextMsg, destination_node);
|
|
#ifdef JASPER
|
|
if (rc == GCC_NO_ERROR)
|
|
{
|
|
g_pControlSap->TextMessageConfirm(m_nConfID, GCC_RESULT_SUCCESSFUL);
|
|
}
|
|
#endif // JASPER
|
|
}
|
|
else
|
|
{
|
|
WARNING_OUT(("CConf::TextMessageRequest: invalid user ID"));
|
|
rc = GCC_INVALID_MCS_USER_ID;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERROR_OUT(("CConf::TextMessageRequest: conference not established"));
|
|
rc = GCC_CONFERENCE_NOT_ESTABLISHED;
|
|
}
|
|
|
|
DebugExitINT(CConf::TextMessageRequest, rc);
|
|
return rc;
|
|
}
|
|
#endif // JASPER
|
|
|
|
|
|
/*
|
|
* GCCError ConfTransferRequest ()
|
|
*
|
|
* Public Function Description
|
|
* This function initiates an ConfTransferRequest sequence.
|
|
*/
|
|
#ifdef JASPER
|
|
GCCError CConf::
|
|
ConfTransferRequest
|
|
(
|
|
PGCCConferenceName destination_conference_name,
|
|
GCCNumericString destination_conference_modifier,
|
|
CNetAddrListContainer *destination_address_list,
|
|
UINT number_of_destination_nodes,
|
|
PUserID destination_node_list,
|
|
CPassword *password
|
|
)
|
|
{
|
|
GCCError rc = GCC_NO_ERROR;
|
|
|
|
DebugEntry(CConf::ConfTransferRequest);
|
|
|
|
if (m_fConfIsEstablished)
|
|
{
|
|
if (IsConfTopProvider())
|
|
{
|
|
if (DoesRequesterHavePrivilege( m_pMcsUserObject->GetMyNodeID(),
|
|
TRANSFER_PRIVILEGE))
|
|
{
|
|
rc = m_pMcsUserObject->ConferenceTransferIndication(
|
|
destination_conference_name,
|
|
destination_conference_modifier,
|
|
destination_address_list,
|
|
number_of_destination_nodes,
|
|
destination_node_list,
|
|
password);
|
|
#ifdef JASPER
|
|
if (rc == GCC_NO_ERROR)
|
|
{
|
|
g_pControlSap->ConfTransferConfirm(
|
|
m_nConfID,
|
|
destination_conference_name,
|
|
destination_conference_modifier,
|
|
number_of_destination_nodes,
|
|
destination_node_list,
|
|
GCC_RESULT_SUCCESSFUL);
|
|
}
|
|
#endif // JASPER
|
|
}
|
|
else
|
|
{
|
|
WARNING_OUT(("CConf::ConfTransferRequest: insufficient privilege to transfer conference"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rc = m_pMcsUserObject->ConferenceTransferRequest(
|
|
destination_conference_name,
|
|
destination_conference_modifier,
|
|
destination_address_list,
|
|
number_of_destination_nodes,
|
|
destination_node_list,
|
|
password);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERROR_OUT(("CConf::ConfTransferRequest: conference not established"));
|
|
rc = GCC_CONFERENCE_NOT_ESTABLISHED;
|
|
}
|
|
|
|
DebugExitINT(CConf::ConfTransferRequest, rc);
|
|
return rc;
|
|
}
|
|
#endif // JASPER
|
|
|
|
|
|
/*
|
|
* GCCError ConfAddRequest ()
|
|
*
|
|
* Public Function Description
|
|
* This function initiates an ConfAddRequest sequence.
|
|
*/
|
|
#ifdef JASPER
|
|
GCCError CConf::
|
|
ConfAddRequest
|
|
(
|
|
CNetAddrListContainer *network_address_container,
|
|
UserID adding_node,
|
|
CUserDataListContainer *user_data_container
|
|
)
|
|
{
|
|
GCCError rc = GCC_NO_ERROR;
|
|
TagNumber conference_add_tag;
|
|
UserID target_node;
|
|
|
|
DebugEntry(CConf::ConfAddRequest);
|
|
|
|
if (! m_fConfIsEstablished)
|
|
{
|
|
ERROR_OUT(("CConf::ConfAddRequest: conference not established"));
|
|
rc = GCC_CONFERENCE_NOT_ESTABLISHED;
|
|
goto MyExit;
|
|
}
|
|
|
|
/*
|
|
** A node cannot tell itself to add because of the way the
|
|
** Add Response call works. Since an Add Response is sent non-
|
|
** uniformly directly to the node that made the request the response
|
|
** would never reach the requesting node. Therefore, this is flaged
|
|
** as an error condition here.
|
|
*/
|
|
if (adding_node == m_pMcsUserObject->GetMyNodeID())
|
|
{
|
|
ERROR_OUT(("CConf::ConfAddRequest: can't tell myself to add"));
|
|
rc = GCC_BAD_ADDING_NODE;
|
|
goto MyExit;
|
|
}
|
|
|
|
/*
|
|
** Note that the way the standard reads, it looks like you
|
|
** do not have to check the privileges for the top provider
|
|
** on an Add. We do though check to see if the Top Provider is
|
|
** making the request to a node other than the top provider. If
|
|
** not this is considered an error here.
|
|
*/
|
|
if (IsConfTopProvider())
|
|
{
|
|
/*
|
|
** If the adding node is zero at the top provider, this is
|
|
** the same as specifying ones self to be the adding node.
|
|
*/
|
|
if (adding_node == 0)
|
|
{
|
|
ERROR_OUT(("CConf::ConfAddRequest: can't tell myself to add"));
|
|
rc = GCC_BAD_ADDING_NODE;
|
|
goto MyExit;
|
|
}
|
|
else
|
|
{
|
|
target_node = adding_node;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
target_node = m_pMcsUserObject->GetTopNodeID();
|
|
}
|
|
|
|
// First determine the conference add tag
|
|
while (1)
|
|
{
|
|
conference_add_tag = ++m_nConfAddRequestTagNumber;
|
|
if (NULL == m_AddRequestList.Find(conference_add_tag))
|
|
break;
|
|
}
|
|
|
|
// Send out the PDU
|
|
rc = m_pMcsUserObject->ConferenceAddRequest(
|
|
conference_add_tag,
|
|
m_pMcsUserObject->GetMyNodeID(),
|
|
adding_node,
|
|
target_node,
|
|
network_address_container,
|
|
user_data_container);
|
|
if (GCC_NO_ERROR != rc)
|
|
{
|
|
ERROR_OUT(("CConf::ConfAddRequest: ConferenceAddRequest failed, rc=%d", rc));
|
|
goto MyExit;
|
|
}
|
|
|
|
/*
|
|
** We must lock the network address to keep it from
|
|
** being deleted upon returning.
|
|
*/
|
|
if (network_address_container != NULL)
|
|
{
|
|
network_address_container->LockNetworkAddressList();
|
|
}
|
|
|
|
// Add this entry to the add request list.
|
|
m_AddRequestList.Append(conference_add_tag, network_address_container);
|
|
|
|
ASSERT(GCC_NO_ERROR == rc);
|
|
|
|
MyExit:
|
|
|
|
DebugExitINT(CConf::ConfAddRequest, rc);
|
|
return rc;
|
|
}
|
|
#endif // JASPER
|
|
|
|
|
|
/*
|
|
* GCCError ConfAddResponse ()
|
|
*
|
|
* Public Function Description
|
|
* This call is made in response to an Add indication. It is initiated
|
|
* by the Node Controller.
|
|
*/
|
|
GCCError CConf::
|
|
ConfAddResponse
|
|
(
|
|
GCCResponseTag add_response_tag,
|
|
UserID requesting_node,
|
|
CUserDataListContainer *user_data_container,
|
|
GCCResult result
|
|
)
|
|
{
|
|
GCCError rc;
|
|
TagNumber lTagNum;
|
|
|
|
DebugEntry(CConf::ConfAddResponse);
|
|
|
|
if (m_fConfIsEstablished)
|
|
{
|
|
if (0 != (lTagNum = m_AddResponseList.Find(add_response_tag)))
|
|
{
|
|
// Send out the response PDU
|
|
rc = m_pMcsUserObject->ConferenceAddResponse(lTagNum, requesting_node,
|
|
user_data_container, result);
|
|
if (rc == GCC_NO_ERROR)
|
|
{
|
|
m_AddResponseList.Remove(add_response_tag);
|
|
}
|
|
else
|
|
{
|
|
ERROR_OUT(("CConf::ConfAddResponse: ConferenceAddResponse failed, rc=%d", rc));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERROR_OUT(("CConf::ConfAddResponse: invalid add response tag"));
|
|
rc = GCC_INVALID_ADD_RESPONSE_TAG;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERROR_OUT(("CConf::ConfAddResponse: conference not established"));
|
|
rc = GCC_CONFERENCE_NOT_ESTABLISHED;
|
|
}
|
|
|
|
DebugExitINT(CConf::ConfAddResponse, rc);
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*
|
|
** These calls are received from the User Attachment object via the
|
|
** Owner-Callback routine. Note that all calls received from the
|
|
** user attachment object are preceeded by the word Process.
|
|
*/
|
|
|
|
|
|
/*
|
|
* CConf::ProcessRosterUpdateIndication ()
|
|
*
|
|
* Private Function Description
|
|
* This routine is responsible for processing all the incomming roster
|
|
* update PDUs which are received from subordinate nodes. These
|
|
* roster updates typically only include additions, changes or deletions
|
|
* of a few records within each PDU.
|
|
*
|
|
* Formal Parameters:
|
|
* roster_update - This is the PDU structure that contains the data
|
|
* associated with the roster update.
|
|
* sender_id - User ID of node that sent the roster update.
|
|
*
|
|
* Return Value
|
|
* None.
|
|
*
|
|
* Side Effects
|
|
* None.
|
|
*
|
|
* Caveats
|
|
* None.
|
|
*/
|
|
void CConf::
|
|
ProcessRosterUpdatePDU
|
|
(
|
|
PGCCPDU roster_update,
|
|
UserID sender_id
|
|
)
|
|
{
|
|
GCCError err = GCC_NO_ERROR;
|
|
|
|
DebugEntry(CConf::ProcessRosterUpdatePDU);
|
|
|
|
if (m_pConfRosterMgr != NULL)
|
|
{
|
|
err = m_pConfRosterMgr->RosterUpdateIndication(roster_update, sender_id);
|
|
if (err != GCC_NO_ERROR)
|
|
{
|
|
goto MyExit;
|
|
}
|
|
|
|
// Process the whole PDU before performing the flush.
|
|
err = ProcessAppRosterIndicationPDU(roster_update, sender_id);
|
|
if (err != GCC_NO_ERROR)
|
|
{
|
|
goto MyExit;
|
|
}
|
|
|
|
UpdateNodeVersionList(roster_update, sender_id);
|
|
|
|
if (HasNM2xNode())
|
|
{
|
|
T120_QueryApplet(APPLET_ID_CHAT, APPLET_QUERY_NM2xNODE);
|
|
}
|
|
|
|
#ifdef CHECK_VERSION
|
|
if (GetNodeVersion(sender_id) >= NM_T120_VERSION_3) // after NM 3.0
|
|
{
|
|
if (!m_fFTEnrolled)
|
|
{
|
|
m_fFTEnrolled = DoesRosterPDUContainApplet(roster_update,
|
|
&FT_APP_PROTO_KEY, FALSE);
|
|
if (m_fFTEnrolled)
|
|
{
|
|
::T120_LoadApplet(APPLET_ID_FT, FALSE, m_nConfID, FALSE, NULL);
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
if (!m_fFTEnrolled)
|
|
{
|
|
m_fFTEnrolled = DoesRosterPDUContainApplet(roster_update,
|
|
&FT_APP_PROTO_KEY, FALSE);
|
|
if (m_fFTEnrolled)
|
|
{
|
|
::T120_LoadApplet(APPLET_ID_FT, FALSE, m_nConfID, FALSE, NULL);
|
|
}
|
|
}
|
|
#endif // CHECK_VERSION
|
|
|
|
if (!m_fWBEnrolled)
|
|
{
|
|
m_fWBEnrolled = DoesRosterPDUContainApplet(roster_update,
|
|
&WB_APP_PROTO_KEY, FALSE);
|
|
if (m_fWBEnrolled)
|
|
{
|
|
::T120_LoadApplet(APPLET_ID_WB, FALSE, m_nConfID, FALSE, NULL);
|
|
}
|
|
}
|
|
if (!m_fChatEnrolled)
|
|
{
|
|
m_fChatEnrolled = DoesRosterPDUContainApplet(roster_update,
|
|
&CHAT_APP_PROTO_KEY, FALSE);
|
|
if (m_fChatEnrolled)
|
|
{
|
|
::T120_LoadApplet(APPLET_ID_CHAT, FALSE, m_nConfID, FALSE, NULL);
|
|
}
|
|
}
|
|
|
|
/*
|
|
** If this is the top provider and we are adding new nodes
|
|
** then we must update the new node with various roster
|
|
** information. That is what is going on here. If no new
|
|
** nodes have been added we go ahead and perform the
|
|
** Flush here.
|
|
*/
|
|
if (IsConfTopProvider() &&
|
|
roster_update->u.indication.u.roster_update_indication.node_information.nodes_are_added)
|
|
{
|
|
err = UpdateNewConferenceNode ();
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We just got an roster update from the wire.
|
|
//
|
|
err = FlushRosterData();
|
|
}
|
|
}
|
|
|
|
MyExit:
|
|
|
|
if (err != GCC_NO_ERROR)
|
|
{
|
|
ERROR_OUT(("CConf::ProcessRosterUpdatePDU: error processing roster refresh indication"));
|
|
InitiateTermination(GCC_REASON_ERROR_TERMINATION, 0);
|
|
}
|
|
|
|
DebugExitVOID(CConf::ProcessRosterUpdatePDU);
|
|
}
|
|
|
|
/*
|
|
* GCCError ProcessAppRosterIndicationPDU ()
|
|
*
|
|
* Private Function Description
|
|
* This function operates specifically on the application roster
|
|
* portion of a roster PDU.
|
|
*
|
|
* Formal Parameters:
|
|
* roster_update - This is the PDU structure that contains the data
|
|
* associated with the roster update.
|
|
* sender_id - User ID of node that sent the roster update.
|
|
*
|
|
* Return Value
|
|
* GCC_NO_ERROR - No error.
|
|
* GCC_ALLOCATION_FAILURE - A resource error occured.
|
|
* GCC_BAD_SESSION_KEY - A bad session key exists in the update.
|
|
*
|
|
* Side Effects
|
|
* None.
|
|
*
|
|
* Caveats
|
|
* None.
|
|
*/
|
|
GCCError CConf::
|
|
ProcessAppRosterIndicationPDU
|
|
(
|
|
PGCCPDU roster_update,
|
|
UserID sender_id
|
|
)
|
|
{
|
|
GCCError rc = GCC_NO_ERROR;
|
|
PSetOfApplicationInformation set_of_application_info;
|
|
CAppRosterMgr *app_roster_manager;
|
|
CAppRosterMgr *new_app_roster_manager;
|
|
PSessionKey session_key;
|
|
|
|
DebugEntry(CConf::ProcessAppRosterIndicationPDU);
|
|
|
|
set_of_application_info = roster_update->u.indication.u.
|
|
roster_update_indication.application_information;
|
|
|
|
/*
|
|
** First we iterate through the complete set of application information
|
|
** to determine if there is information here for an application roster
|
|
** manager that does not yet exists. If we find one that does not
|
|
** exists we must go ahead and create it.
|
|
*/
|
|
while (set_of_application_info != NULL)
|
|
{
|
|
CAppRosterMgr *pMgr;
|
|
|
|
// First set up the session key PDU pointer
|
|
session_key = &set_of_application_info->value.session_key;
|
|
|
|
/*
|
|
** We first iterate through the complete list of application
|
|
** roster manager objects looking for one with an application key that
|
|
** matches the key in the PDU. If it is not found we create it.
|
|
*/
|
|
app_roster_manager = NULL;
|
|
new_app_roster_manager = NULL;
|
|
|
|
//
|
|
// LONCHANC: We should be able to move this as separate common subroutine.
|
|
//
|
|
m_AppRosterMgrList.Reset();
|
|
while (NULL != (pMgr = m_AppRosterMgrList.Iterate()))
|
|
{
|
|
if (pMgr->IsThisYourSessionKeyPDU(session_key))
|
|
{
|
|
// This application roster manager exist so return it.
|
|
app_roster_manager = pMgr;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
** If a roster manager associated with this app key does not exist
|
|
** we must create it here.
|
|
*/
|
|
if (app_roster_manager == NULL)
|
|
{
|
|
DBG_SAVE_FILE_LINE
|
|
app_roster_manager = new CAppRosterMgr(
|
|
NULL,
|
|
session_key,
|
|
m_nConfID,
|
|
m_pMcsUserObject,
|
|
this,
|
|
&rc);
|
|
if (NULL == app_roster_manager || GCC_NO_ERROR != rc)
|
|
{
|
|
ERROR_OUT(("CConf::ProcessAppRosterIndicationPDU: can't create app roster mgr, rc=%d", rc));
|
|
if (NULL != app_roster_manager)
|
|
{
|
|
app_roster_manager->Release();
|
|
}
|
|
else
|
|
{
|
|
rc = GCC_ALLOCATION_FAILURE;
|
|
}
|
|
goto MyExit;
|
|
}
|
|
|
|
new_app_roster_manager = app_roster_manager;
|
|
}
|
|
|
|
/*
|
|
** We no process this set of application information. We pass it
|
|
** to the app roster manager found or created above.
|
|
*/
|
|
rc = app_roster_manager->ProcessRosterUpdateIndicationPDU(
|
|
set_of_application_info,
|
|
sender_id);
|
|
if (GCC_NO_ERROR != rc)
|
|
{
|
|
//
|
|
// LONCHANC: We should delete the newly created roster mgr.
|
|
//
|
|
if (NULL != new_app_roster_manager)
|
|
{
|
|
new_app_roster_manager->Release();
|
|
}
|
|
goto MyExit;
|
|
}
|
|
|
|
/*
|
|
** Save the new application roster manager if one was created
|
|
** when processing this roster update.
|
|
*/
|
|
if (new_app_roster_manager != NULL)
|
|
{
|
|
m_AppRosterMgrList.Append(new_app_roster_manager);
|
|
}
|
|
|
|
// Load the next application information structure.
|
|
set_of_application_info = set_of_application_info->next;
|
|
}
|
|
|
|
ASSERT(GCC_NO_ERROR == rc);
|
|
|
|
MyExit:
|
|
|
|
DebugExitINT(CConf::ProcessAppRosterIndicationPDU, rc);
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*
|
|
* CConf::ProcessDetachUserIndication ()
|
|
*
|
|
* Private Function Description
|
|
* This routine sends the detach user indication to the node controler
|
|
* and updates the roster.
|
|
*
|
|
* Formal Parameters:
|
|
* detached_user - User ID of user that detached from the conference.
|
|
* reason - Reason that the user detached.
|
|
*
|
|
* Return Value
|
|
* None.
|
|
*
|
|
* Side Effects
|
|
* None.
|
|
*
|
|
* Caveats
|
|
* None.
|
|
*/
|
|
void CConf::
|
|
ProcessDetachUserIndication
|
|
(
|
|
UserID detached_user,
|
|
GCCReason reason
|
|
)
|
|
{
|
|
GCCError err = GCC_NO_ERROR;
|
|
UINT cRecords;
|
|
|
|
DebugEntry(CConf::ProcessDetachUserIndication);
|
|
|
|
if (m_fConfIsEstablished)
|
|
{
|
|
CAppRosterMgr *lpAppRosterMgr;
|
|
/*
|
|
** Send a disconnect indication to the node controller if this
|
|
** detached user corresponds to a GCC user id.
|
|
*/
|
|
if (m_pConfRosterMgr->Contains(detached_user))
|
|
{
|
|
g_pControlSap->ConfDisconnectIndication(
|
|
m_nConfID,
|
|
reason,
|
|
detached_user);
|
|
}
|
|
|
|
// Here we update the CConf Roster and the Application Roster.
|
|
err = m_pConfRosterMgr->RemoveUserReference(detached_user);
|
|
if (err == GCC_NO_ERROR)
|
|
{
|
|
if (IsConfTopProvider())
|
|
{
|
|
cRecords = m_pConfRosterMgr->GetNumberOfNodeRecords();
|
|
/*
|
|
** If only one record remains in the conference roster
|
|
** it must be the local nodes record. Therefore, if
|
|
** the conference is set up to be automatically
|
|
** terminated the owner object is notified to delete
|
|
** the conference.
|
|
*/
|
|
if ((m_eTerminationMethod == GCC_AUTOMATIC_TERMINATION_METHOD)
|
|
&& (cRecords == 1))
|
|
{
|
|
TRACE_OUT(("CConf::ProcessDetachUserIndication: AUTOMATIC_TERMINATION"));
|
|
InitiateTermination(GCC_REASON_NORMAL_TERMINATION, 0);
|
|
}
|
|
|
|
// If this is the convener set its node id back to 0
|
|
if (m_nConvenerNodeID == detached_user)
|
|
{
|
|
m_nConvenerNodeID = 0;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
if (err == GCC_INVALID_PARAMETER)
|
|
{
|
|
err = GCC_NO_ERROR;
|
|
}
|
|
|
|
/*
|
|
** Cleanup the Application Rosters of any records owned by this node.
|
|
*/
|
|
m_AppRosterMgrList.Reset();
|
|
while (NULL != (lpAppRosterMgr = m_AppRosterMgrList.Iterate()))
|
|
{
|
|
err = lpAppRosterMgr->RemoveUserReference(detached_user);
|
|
if (GCC_NO_ERROR != err)
|
|
{
|
|
WARNING_OUT(("CConf::ProcessDetachUserIndication: can't remove user reference from app roster mgr, err=%d", err));
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Remove ownership rights this user had on any registry entries.
|
|
m_pAppRegistry->RemoveNodeOwnership(detached_user);
|
|
|
|
// Cleanup Conductorship if detached user was the conductor
|
|
if (detached_user == m_nConductorNodeID)
|
|
{
|
|
ProcessConductorReleaseIndication(0);
|
|
}
|
|
|
|
/*
|
|
** Here we give the roster managers a chance to flush any PDUs
|
|
** or data that might have gotten queued when removing the user
|
|
** reference. An error here is considered FATAL in that the conference
|
|
** information base at this node is now corrupted therefore we
|
|
** terminate the conference.
|
|
*/
|
|
if (err == GCC_NO_ERROR)
|
|
{
|
|
//
|
|
// We just got detach user indication from the wire.
|
|
//
|
|
err = FlushRosterData();
|
|
}
|
|
|
|
if (err != GCC_NO_ERROR)
|
|
{
|
|
ERROR_OUT(("CConf::ProcessDetachUserIndication: Error occured when flushing the rosters, err=%d", err));
|
|
InitiateTermination((err == GCC_ALLOCATION_FAILURE) ?
|
|
GCC_REASON_ERROR_LOW_RESOURCES :
|
|
GCC_REASON_ERROR_TERMINATION,
|
|
0);
|
|
}
|
|
}
|
|
|
|
DebugExitVOID(CConf::ProcessDetachUserIndication);
|
|
}
|
|
|
|
|
|
/*
|
|
* CConf::ProcessTerminateRequest ()
|
|
*
|
|
* Private Function Description
|
|
* This routine processes a terminate request received from the MCSUser
|
|
* object.
|
|
*
|
|
* Formal Parameters:
|
|
* requester_id - User ID of node that is requesting the terminate.
|
|
* reason - Reason for termination.
|
|
*
|
|
* Return Value
|
|
* None.
|
|
*
|
|
* Side Effects
|
|
* None.
|
|
*
|
|
* Caveats
|
|
* None.
|
|
*/
|
|
void CConf::
|
|
ProcessTerminateRequest
|
|
(
|
|
UserID requester_id,
|
|
GCCReason reason
|
|
)
|
|
{
|
|
DebugEntry(CConf::ProcessTerminateRequest);
|
|
|
|
if (DoesRequesterHavePrivilege(requester_id, TERMINATE_PRIVILEGE))
|
|
{
|
|
TRACE_OUT(("CConf::ProcessTerminateRequest: Node has permission to terminate"));
|
|
|
|
/*
|
|
** Since the terminate was successful, we go ahead and set the
|
|
** m_fConfIsEstablished instance variable to FALSE. This prevents
|
|
** any other messages from flowing to the SAPs other than terminate
|
|
** messages.
|
|
*/
|
|
m_fConfIsEstablished = FALSE;
|
|
|
|
// Send a positive response to the requesting node
|
|
m_pMcsUserObject->ConferenceTerminateResponse(requester_id, GCC_RESULT_SUCCESSFUL);
|
|
|
|
/*
|
|
** This request will kick off a terminate at this node as well as
|
|
** all the nodes below this node in the connection hierarchy.
|
|
*/
|
|
m_pMcsUserObject->ConferenceTerminateIndication(reason);
|
|
}
|
|
else
|
|
{
|
|
WARNING_OUT(("CConf::ProcessTerminateRequest: Node does NOT have permission to terminate"));
|
|
// Send a negative response to the requesting node
|
|
m_pMcsUserObject->ConferenceTerminateResponse(requester_id, GCC_RESULT_INVALID_REQUESTER);
|
|
}
|
|
|
|
DebugExitVOID(CConf::ProcessTerminateRequest);
|
|
}
|
|
|
|
|
|
/*
|
|
* CConf::ProcessTerminateIndication ()
|
|
*
|
|
* Private Function Description
|
|
* This routine takes care of both a normal termination through
|
|
* a terminate pdu and termination that occurs due to a parent
|
|
* node disconnecting.
|
|
*
|
|
* Formal Parameters:
|
|
* reason - Reason for termination.
|
|
*
|
|
* Return Value
|
|
* None.
|
|
*
|
|
* Side Effects
|
|
* None.
|
|
*
|
|
* Caveats
|
|
* None.
|
|
*/
|
|
void CConf::
|
|
ProcessTerminateIndication ( GCCReason gcc_reason )
|
|
{
|
|
UserID user_id;
|
|
|
|
DebugEntry(CConf::ProcessTerminateIndication);
|
|
|
|
/*
|
|
** Setting this to true here will insure that a terminate indication
|
|
** will be delivered to the control SAP.
|
|
*/
|
|
m_fConfTerminatePending = TRUE;
|
|
|
|
if (gcc_reason == GCC_REASON_PARENT_DISCONNECTED)
|
|
{
|
|
TRACE_OUT(("CConf::ProcessTerminateIndication: Terminate due to parent disconnecting"));
|
|
user_id = m_pMcsUserObject->GetMyNodeID();
|
|
}
|
|
else
|
|
if (m_ConnHandleList.IsEmpty())
|
|
{
|
|
TRACE_OUT(("CConf: ProcessTerminateIndication: Terminate due to request (no child connections)"));
|
|
/*
|
|
** Since there is a flaw in the terminate indication PDU were the
|
|
** node id that requested the termination is not sent we always
|
|
** assume here that the request came from the top provider (which
|
|
** is only partially true).
|
|
*/
|
|
user_id = m_pMcsUserObject->GetTopNodeID();
|
|
}
|
|
else
|
|
{
|
|
TRACE_OUT(("CConf::ProcessTerminateIndication: Wait till children disconnect before terminating"));
|
|
|
|
/*
|
|
** Wait until disconnect provider indications are received on all the
|
|
** child connections before terminating the conference.
|
|
*/
|
|
|
|
m_eConfTerminateReason = gcc_reason;
|
|
|
|
DBG_SAVE_FILE_LINE
|
|
m_pConfTerminateAlarm = new Alarm (TERMINATE_TIMER_DURATION);
|
|
if (NULL != m_pConfTerminateAlarm)
|
|
{
|
|
// let's wait, bail out without initiating termination.
|
|
goto MyExit;
|
|
}
|
|
|
|
// Go ahead and terminate if there is a resource error
|
|
ERROR_OUT(("CConf: ProcessTerminateIndication: can't create terminate alarm"));
|
|
user_id = m_pMcsUserObject->GetTopNodeID();
|
|
}
|
|
|
|
InitiateTermination(gcc_reason, user_id);
|
|
|
|
MyExit:
|
|
|
|
DebugExitVOID(CConf::ProcessTerminateIndication);
|
|
}
|
|
|
|
|
|
/*
|
|
* CConf::ProcessUserIDIndication ()
|
|
*
|
|
* Private Function Description
|
|
* This routine is responsible for matching incomming user IDs with
|
|
* tag numbers returned by the subordinate node.
|
|
*
|
|
* Formal Parameters:
|
|
* tag_number - Tag used to match incomming user ID indication.
|
|
* user_id - User ID of node sending the indication.
|
|
*
|
|
* Return Value
|
|
* None.
|
|
*
|
|
* Side Effects
|
|
* None.
|
|
*
|
|
* Caveats
|
|
* None.
|
|
*/
|
|
// checkpoint
|
|
void CConf::
|
|
ProcessUserIDIndication
|
|
(
|
|
TagNumber tag_number,
|
|
UserID user_id
|
|
)
|
|
{
|
|
INVITE_REQ_INFO *invite_request_info;
|
|
ConnectionHandle nConnHdl;
|
|
|
|
DebugEntry(CConf::ProcessUserIDIndication);
|
|
|
|
if (0 != (nConnHdl = m_ConnHdlTagNumberList2.Remove(tag_number)))
|
|
{
|
|
INVITE_REQ_INFO *lpInvReqInfo;
|
|
|
|
if (m_pMcsUserObject != NULL)
|
|
{
|
|
TRACE_OUT(("CConf: ProcessUserIDIndication: ID is set"));
|
|
|
|
m_pMcsUserObject->SetChildUserIDAndConnection(user_id, nConnHdl);
|
|
}
|
|
else
|
|
{
|
|
TRACE_OUT(("CConf::UserIDIndication: Error User Att. is NULL"));
|
|
}
|
|
|
|
/*
|
|
** Here we send an indication informing the node controller that
|
|
** a subordinate node has completed initialization.
|
|
*/
|
|
g_pControlSap->SubInitializationCompleteIndication (user_id, nConnHdl);
|
|
|
|
/*
|
|
** Now we determine if the responding node is the convener and if it
|
|
** is we will set up the m_nConvenerNodeID. This node id is used to
|
|
** determine privileges on certain GCC operations.
|
|
*/
|
|
if (m_nConvenerUserIDTagNumber == tag_number)
|
|
{
|
|
TRACE_OUT(("CConf::UserIDIndication: Convener Node ID is being set"));
|
|
m_nConvenerUserIDTagNumber = 0;
|
|
m_nConvenerNodeID = user_id;
|
|
}
|
|
|
|
/*
|
|
** If this is a User ID from an invited node we must pass the invite
|
|
** confirm to the Node Controller.
|
|
*/
|
|
m_InviteRequestList.Reset();
|
|
invite_request_info = NULL;
|
|
while (NULL != (lpInvReqInfo = m_InviteRequestList.Iterate()))
|
|
{
|
|
if (tag_number == lpInvReqInfo->invite_tag)
|
|
{
|
|
invite_request_info = lpInvReqInfo;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (invite_request_info != NULL)
|
|
{
|
|
g_pControlSap->ConfInviteConfirm(
|
|
m_nConfID,
|
|
invite_request_info->user_data_list,
|
|
GCC_RESULT_SUCCESSFUL,
|
|
invite_request_info->connection_handle);
|
|
|
|
// Free up user data if it exists
|
|
if (invite_request_info->user_data_list != NULL)
|
|
{
|
|
invite_request_info->user_data_list->Release();
|
|
}
|
|
|
|
// Cleanup the invite request list
|
|
m_InviteRequestList.Remove(invite_request_info);
|
|
|
|
// Free up the invite request info structure
|
|
delete invite_request_info;
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TRACE_OUT(("CConf::ProcessUserIDIndication: Bad User ID Tag Number received"));
|
|
}
|
|
|
|
DebugExitVOID(CConf::ProcessUserIDIndication);
|
|
}
|
|
|
|
|
|
/*
|
|
* CConf::ProcessUserCreateConfirm ()
|
|
*
|
|
* Private Function Description
|
|
* This routine handles the processes that occur after a user
|
|
* create confirm is received. This process will differ depending
|
|
* on what the node type is.
|
|
*
|
|
* Formal Parameters:
|
|
* result_value - Result of the user attachment being created.
|
|
* node_id - This nodes node id.
|
|
*
|
|
* Return Value
|
|
* None.
|
|
*
|
|
* Side Effects
|
|
* None.
|
|
*
|
|
* Caveats
|
|
* None.
|
|
*/
|
|
void CConf::
|
|
ProcessUserCreateConfirm
|
|
(
|
|
UserResultType result_value,
|
|
UserID node_id
|
|
)
|
|
{
|
|
GCCError err = GCC_NO_ERROR;
|
|
PUChar encoded_pdu;
|
|
UINT encoded_pdu_length;
|
|
ConnectGCCPDU connect_pdu;
|
|
MCSError mcs_error;
|
|
GCCConferenceName conference_name;
|
|
GCCNumericString conference_modifier;
|
|
GCCNumericString remote_modifier = NULL;
|
|
BOOL is_top_provider;
|
|
|
|
DebugEntry(CConf::ProcessUserCreateConfirm);
|
|
|
|
if (result_value == USER_RESULT_SUCCESSFUL)
|
|
{
|
|
switch (m_eNodeType)
|
|
{
|
|
case TOP_PROVIDER_NODE:
|
|
/*
|
|
** Encode the tag number into the ConferenceCreateResponse
|
|
** PDU. If we have gotten this far the result is success.
|
|
*/
|
|
|
|
connect_pdu.choice = CONFERENCE_CREATE_RESPONSE_CHOSEN;
|
|
connect_pdu.u.conference_create_response.bit_mask = 0;
|
|
|
|
connect_pdu.u.conference_create_response.node_id = node_id;
|
|
|
|
/*
|
|
** Here we save this particular User ID tag and mark it as the
|
|
** conveners so that when the convener's user ID is returned
|
|
** the m_nConvenerNodeID instance variable can be properly
|
|
** initialized.
|
|
*/
|
|
m_nConvenerUserIDTagNumber = GetNewUserIDTag ();
|
|
connect_pdu.u.conference_create_response.tag = m_nConvenerUserIDTagNumber;
|
|
|
|
if (m_pUserDataList != NULL)
|
|
{
|
|
connect_pdu.u.conference_create_response.bit_mask |= CCRS_USER_DATA_PRESENT;
|
|
|
|
err = m_pUserDataList->GetUserDataPDU(
|
|
&connect_pdu.u.conference_create_response.ccrs_user_data);
|
|
if (err != GCC_NO_ERROR)
|
|
{
|
|
// Terminate conference due to resource error
|
|
InitiateTermination ( GCC_REASON_ERROR_LOW_RESOURCES,
|
|
0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
connect_pdu.u.conference_create_response.result =
|
|
::TranslateGCCResultToCreateResult(GCC_RESULT_SUCCESSFUL);
|
|
|
|
if (g_GCCCoder->Encode((LPVOID) &connect_pdu,
|
|
CONNECT_GCC_PDU,
|
|
PACKED_ENCODING_RULES,
|
|
&encoded_pdu,
|
|
&encoded_pdu_length))
|
|
{
|
|
mcs_error = g_pMCSIntf->ConnectProviderResponse (
|
|
m_hConvenerConnection,
|
|
&m_nConfID,
|
|
m_pDomainParameters,
|
|
RESULT_SUCCESSFUL,
|
|
encoded_pdu,
|
|
encoded_pdu_length);
|
|
|
|
g_GCCCoder->FreeEncoded(encoded_pdu);
|
|
|
|
if (mcs_error == MCS_NO_ERROR)
|
|
{
|
|
m_fConfIsEstablished = TRUE;
|
|
|
|
/*
|
|
** Add the user's tag number to the list of
|
|
** outstanding user ids along with its associated
|
|
** connection.
|
|
*/
|
|
ASSERT(0 != m_hConvenerConnection);
|
|
m_ConnHdlTagNumberList2.Append(connect_pdu.u.conference_create_response.tag,
|
|
m_hConvenerConnection);
|
|
}
|
|
else if (mcs_error == MCS_DOMAIN_PARAMETERS_UNACCEPTABLE)
|
|
{
|
|
/*
|
|
** Inform the node controller that the reason
|
|
** the conference was terminated was that the
|
|
** domain parameter passed in the Create Response
|
|
** were unacceptable.
|
|
*/
|
|
InitiateTermination(GCC_REASON_DOMAIN_PARAMETERS_UNACCEPTABLE, 0);
|
|
}
|
|
else
|
|
{
|
|
InitiateTermination(GCC_REASON_MCS_RESOURCE_FAILURE, 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
** A Fatal Resource error has occured. At this point
|
|
** the conference is invalid and should be terminated.
|
|
*/
|
|
ERROR_OUT(("CConf::ProcessUserCreateConfirm: can't encode. Terminate Conference"));
|
|
InitiateTermination(GCC_REASON_ERROR_LOW_RESOURCES, 0);
|
|
}
|
|
break;
|
|
|
|
case CONVENER_NODE:
|
|
|
|
if(g_pControlSap)
|
|
{
|
|
/*
|
|
** Send the GCC User ID is here. This will require a call to
|
|
** the User Object. The tag number that was returned in
|
|
** the ConfCreateResponse call is used here.
|
|
*/
|
|
if (m_pMcsUserObject != NULL)
|
|
{
|
|
m_pMcsUserObject->SendUserIDRequest(m_nParentIDTagNumber);
|
|
}
|
|
|
|
// Fill in the conference name data pointers.
|
|
GetConferenceNameAndModifier(&conference_name, &conference_modifier);
|
|
|
|
g_pControlSap->ConfCreateConfirm(&conference_name,
|
|
conference_modifier,
|
|
m_nConfID,
|
|
m_pDomainParameters,
|
|
m_pUserDataList,
|
|
GCC_RESULT_SUCCESSFUL,
|
|
m_hParentConnection);
|
|
|
|
// Free up the User Data List
|
|
if (m_pUserDataList != NULL)
|
|
{
|
|
m_pUserDataList->Release();
|
|
m_pUserDataList = NULL;
|
|
}
|
|
|
|
m_fConfIsEstablished = TRUE;
|
|
}
|
|
break;
|
|
|
|
case TOP_PROVIDER_AND_CONVENER_NODE:
|
|
if(g_pControlSap)
|
|
{
|
|
/*
|
|
** First set up the convener node id. In this case it is
|
|
** identical to the node ID of the Top Provider which is this
|
|
** node.
|
|
*/
|
|
m_nConvenerNodeID = m_pMcsUserObject->GetMyNodeID();
|
|
|
|
// Fill in the conference name data pointers.
|
|
GetConferenceNameAndModifier( &conference_name,
|
|
&conference_modifier);
|
|
|
|
g_pControlSap->ConfCreateConfirm(
|
|
&conference_name,
|
|
conference_modifier,
|
|
m_nConfID,
|
|
m_pDomainParameters,
|
|
NULL,
|
|
GCC_RESULT_SUCCESSFUL,
|
|
0); //Parent Connection
|
|
m_fConfIsEstablished = TRUE;
|
|
}
|
|
break;
|
|
|
|
case JOINED_NODE:
|
|
case JOINED_CONVENER_NODE:
|
|
if(g_pControlSap)
|
|
{
|
|
/*
|
|
** Send the GCC User ID is here. This will require a call to
|
|
** the User Object. The tag number that was returned in
|
|
** the ConfCreateResponse call is used here.
|
|
*/
|
|
if (m_pMcsUserObject != NULL)
|
|
{
|
|
m_pMcsUserObject->SendUserIDRequest(m_nParentIDTagNumber);
|
|
}
|
|
|
|
// Fill in the conference name data pointers.
|
|
GetConferenceNameAndModifier( &conference_name,
|
|
&conference_modifier);
|
|
|
|
if (m_pszRemoteModifier != NULL)
|
|
{
|
|
remote_modifier = (GCCNumericString) m_pszRemoteModifier;
|
|
}
|
|
|
|
g_pControlSap->ConfJoinConfirm(
|
|
&conference_name,
|
|
remote_modifier,
|
|
conference_modifier,
|
|
m_nConfID,
|
|
NULL,
|
|
m_pDomainParameters,
|
|
m_fClearPassword,
|
|
m_fConfLocked,
|
|
m_fConfListed,
|
|
m_fConfConductible,
|
|
m_eTerminationMethod,
|
|
m_pConductorPrivilegeList,
|
|
m_pConductModePrivilegeList,
|
|
m_pNonConductModePrivilegeList,
|
|
m_pwszConfDescription,
|
|
m_pUserDataList,
|
|
GCC_RESULT_SUCCESSFUL,
|
|
m_hParentConnection,
|
|
NULL,
|
|
0);
|
|
|
|
m_fConfIsEstablished = TRUE;
|
|
}
|
|
break;
|
|
|
|
case INVITED_NODE:
|
|
/*
|
|
** Send the GCC User ID here. This will require a call to
|
|
** the User Object.
|
|
*/
|
|
if (m_pMcsUserObject != NULL)
|
|
m_pMcsUserObject->SendUserIDRequest(m_nParentIDTagNumber);
|
|
|
|
m_fConfIsEstablished = TRUE;
|
|
break;
|
|
|
|
default:
|
|
TRACE_OUT(("CConf:UserCreateConfirm: Error: Bad User Type"));
|
|
break;
|
|
}
|
|
|
|
|
|
if (m_fConfIsEstablished)
|
|
{
|
|
/*
|
|
** We now instantiate the conference roster manager to be used
|
|
** with this conference.
|
|
*/
|
|
if ((m_eNodeType == TOP_PROVIDER_NODE) ||
|
|
(m_eNodeType == TOP_PROVIDER_AND_CONVENER_NODE))
|
|
{
|
|
is_top_provider = TRUE;
|
|
}
|
|
else
|
|
is_top_provider = FALSE;
|
|
|
|
DBG_SAVE_FILE_LINE
|
|
m_pConfRosterMgr = new CConfRosterMgr(
|
|
m_pMcsUserObject,
|
|
this,
|
|
is_top_provider,
|
|
&err);
|
|
if (m_pConfRosterMgr == NULL)
|
|
err = GCC_ALLOCATION_FAILURE;
|
|
|
|
/*
|
|
** We create the application registry object here because we now
|
|
** know the node type.
|
|
*/
|
|
if (err == GCC_NO_ERROR)
|
|
{
|
|
if ((m_eNodeType == TOP_PROVIDER_NODE) ||
|
|
(m_eNodeType == TOP_PROVIDER_AND_CONVENER_NODE))
|
|
{
|
|
DBG_SAVE_FILE_LINE
|
|
m_pAppRegistry = new CRegistry(
|
|
m_pMcsUserObject,
|
|
TRUE,
|
|
m_nConfID,
|
|
&m_AppRosterMgrList,
|
|
&err);
|
|
}
|
|
else
|
|
{
|
|
DBG_SAVE_FILE_LINE
|
|
m_pAppRegistry = new CRegistry(
|
|
m_pMcsUserObject,
|
|
FALSE,
|
|
m_nConfID,
|
|
&m_AppRosterMgrList,
|
|
&err);
|
|
}
|
|
}
|
|
|
|
if ((m_pAppRegistry != NULL) &&
|
|
(err == GCC_NO_ERROR))
|
|
{
|
|
/*
|
|
** Inform the node controller that it is time to do an announce
|
|
** presence for this conference.
|
|
*/
|
|
g_pControlSap->ConfPermissionToAnnounce(m_nConfID, node_id);
|
|
|
|
/*
|
|
** Make the owner callback to inform that the owner object that
|
|
** the conference object was successfully created. This also
|
|
** kicks off the permission to enroll process.
|
|
*/
|
|
g_pGCCController->ProcessConfEstablished(m_nConfID);
|
|
|
|
/*
|
|
** For all nodes except the top provider node we allocate a
|
|
** startup alarm that is used to hold back all roster flushes
|
|
** for a certain length of time giving all the local APEs
|
|
** time to enroll. An allocation failure here is not FATAL
|
|
** since everything will work with or without this alarm.
|
|
** Without the Alarm there may be a bit more network traffic
|
|
** during the startup process. Note that there is no need
|
|
** for a startup alarm if there are no application SAPs.
|
|
*/
|
|
if ((m_eNodeType != TOP_PROVIDER_NODE) &&
|
|
(m_eNodeType != TOP_PROVIDER_AND_CONVENER_NODE))
|
|
{
|
|
TRACE_OUT(("CConf:ProcessUserCreateConfirm: Creating Startup Alarm"));
|
|
// m_pConfStartupAlarm = new Alarm(STARTUP_TIMER_DURATION);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TRACE_OUT(("CConf: UserCreateConfirm: Error initializing"));
|
|
InitiateTermination(GCC_REASON_ERROR_LOW_RESOURCES, 0);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TRACE_OUT(("CConf: UserCreateConfirm: Create of User Att. Failed"));
|
|
|
|
/*
|
|
** Try to properly cleanup here. Since the user creation failed
|
|
** the conference is no longer valid and needs to be cleaned up.
|
|
*/
|
|
switch (m_eNodeType)
|
|
{
|
|
case TOP_PROVIDER_NODE:
|
|
g_pMCSIntf->ConnectProviderResponse (
|
|
m_hConvenerConnection,
|
|
&m_nConfID,
|
|
m_pDomainParameters,
|
|
RESULT_UNSPECIFIED_FAILURE,
|
|
NULL, 0);
|
|
break;
|
|
|
|
case CONVENER_NODE:
|
|
case TOP_PROVIDER_AND_CONVENER_NODE:
|
|
if(g_pControlSap)
|
|
{
|
|
GetConferenceNameAndModifier( &conference_name,
|
|
&conference_modifier);
|
|
|
|
g_pControlSap->ConfCreateConfirm(
|
|
&conference_name,
|
|
conference_modifier,
|
|
m_nConfID,
|
|
m_pDomainParameters,
|
|
NULL,
|
|
GCC_RESULT_RESOURCES_UNAVAILABLE,
|
|
m_hParentConnection);
|
|
}
|
|
break;
|
|
|
|
case JOINED_NODE:
|
|
case JOINED_CONVENER_NODE:
|
|
if(g_pControlSap)
|
|
{
|
|
GetConferenceNameAndModifier( &conference_name,
|
|
&conference_modifier);
|
|
|
|
if (m_pszRemoteModifier != NULL)
|
|
{
|
|
remote_modifier = (GCCNumericString) m_pszRemoteModifier;
|
|
}
|
|
|
|
g_pControlSap->ConfJoinConfirm(
|
|
&conference_name,
|
|
remote_modifier,
|
|
conference_modifier,
|
|
m_nConfID,
|
|
NULL,
|
|
m_pDomainParameters,
|
|
m_fClearPassword,
|
|
m_fConfLocked,
|
|
m_fConfListed,
|
|
m_fConfConductible,
|
|
m_eTerminationMethod,
|
|
m_pConductorPrivilegeList,
|
|
m_pConductModePrivilegeList,
|
|
m_pNonConductModePrivilegeList,
|
|
m_pwszConfDescription,
|
|
m_pUserDataList,
|
|
GCC_RESULT_RESOURCES_UNAVAILABLE,
|
|
m_hParentConnection,
|
|
NULL,
|
|
0);
|
|
}
|
|
break;
|
|
|
|
case INVITED_NODE:
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/*
|
|
** A Fatal Resource error has occured. At this point
|
|
** the conference is invalid and should be terminated.
|
|
*/
|
|
InitiateTermination(GCC_REASON_MCS_RESOURCE_FAILURE, 0);
|
|
}
|
|
|
|
DebugExitVOID(CConf::ProcessUserCreateConfirm);
|
|
}
|
|
|
|
|
|
// Calls received from the MCS interface
|
|
|
|
|
|
/*
|
|
* CConf::ProcessConnectProviderConfirm ()
|
|
*
|
|
* Private Function Description
|
|
* This routine processes connect provider confirms received
|
|
* directly from MCS.
|
|
*
|
|
* Formal Parameters:
|
|
* connect_provider_confirm - This structure contains the MCS related
|
|
* data such as sender id and connection
|
|
* Handle as well as the PDU data.
|
|
*
|
|
* Return Value
|
|
* None.
|
|
*
|
|
* Side Effects
|
|
* None.
|
|
*
|
|
* Caveats
|
|
* None.
|
|
*/
|
|
void CConf::
|
|
ProcessConnectProviderConfirm ( PConnectProviderConfirm connect_provider_confirm )
|
|
{
|
|
PPacket packet;
|
|
PConnectGCCPDU connect_pdu;
|
|
PacketError packet_error;
|
|
GCCResult result = GCC_RESULT_SUCCESSFUL;
|
|
GCCConferenceName conference_name;
|
|
GCCNumericString conference_modifier;
|
|
GCCNumericString remote_modifier = NULL;
|
|
INVITE_REQ_INFO *invite_request_info;
|
|
|
|
DebugEntry(CConf::ProcessConnectProviderConfirm);
|
|
|
|
if (connect_provider_confirm->user_data_length != 0)
|
|
{
|
|
/*
|
|
** If the result is success create the packet to be decoded from
|
|
** the PDU passed back in the MCS user data field. If creation
|
|
** failes this again is a FATAL error and the conference must be
|
|
** terminated.
|
|
*/
|
|
DBG_SAVE_FILE_LINE
|
|
packet = new Packet((PPacketCoder) g_GCCCoder,
|
|
PACKED_ENCODING_RULES,
|
|
connect_provider_confirm->user_data,
|
|
connect_provider_confirm->user_data_length,
|
|
CONNECT_GCC_PDU,
|
|
TRUE,
|
|
&packet_error);
|
|
if ((packet != NULL) && (packet_error == PACKET_NO_ERROR))
|
|
{
|
|
connect_pdu = (PConnectGCCPDU)packet->GetDecodedData();
|
|
/*
|
|
** If all the above succeeds then decode the packet based on
|
|
** which node type this is.
|
|
*/
|
|
switch (connect_pdu->choice)
|
|
{
|
|
case CONFERENCE_CREATE_RESPONSE_CHOSEN:
|
|
ProcessConferenceCreateResponsePDU (
|
|
&connect_pdu->u.conference_create_response,
|
|
connect_provider_confirm);
|
|
break;
|
|
|
|
case CONNECT_JOIN_RESPONSE_CHOSEN:
|
|
ProcessConferenceJoinResponsePDU (
|
|
&connect_pdu->u.connect_join_response,
|
|
connect_provider_confirm);
|
|
break;
|
|
|
|
case CONFERENCE_INVITE_RESPONSE_CHOSEN:
|
|
ProcessConferenceInviteResponsePDU (
|
|
&connect_pdu->u.conference_invite_response,
|
|
connect_provider_confirm );
|
|
break;
|
|
|
|
default:
|
|
ERROR_OUT(("CConf:ProcessConnectProviderConfirm: "
|
|
"Error: Received Invalid Connect Provider Confirm"));
|
|
break;
|
|
}
|
|
|
|
// Free the decoded packet
|
|
packet->Unlock ();
|
|
}
|
|
else
|
|
{
|
|
ERROR_OUT(("CConf: ProcessConnectProviderConfirm:"
|
|
"Incompatible protocol occured"));
|
|
result = GCC_RESULT_INCOMPATIBLE_PROTOCOL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERROR_OUT(("CConf::ProcessConnectProviderConfirm: result=%d", (UINT) connect_provider_confirm->result));
|
|
|
|
/*
|
|
** This section of the code assumes that there is no connect PDU in
|
|
** the returned packet. First determine what the result is. We
|
|
** assume that if the MCS connection was rejected due to
|
|
** parameters being unacceptable and no GCC pdu was returned that there
|
|
** was a protocol incompatibility.
|
|
*/
|
|
if (connect_provider_confirm->result == RESULT_PARAMETERS_UNACCEPTABLE)
|
|
result = GCC_RESULT_INCOMPATIBLE_PROTOCOL;
|
|
else
|
|
{
|
|
result = ::TranslateMCSResultToGCCResult(connect_provider_confirm->result);
|
|
}
|
|
}
|
|
|
|
// Handle any errors that might have occured.
|
|
if (result != GCC_RESULT_SUCCESSFUL)
|
|
{
|
|
INVITE_REQ_INFO *lpInvReqInfo;
|
|
|
|
// First check to see if there are any outstanding invite request
|
|
m_InviteRequestList.Reset();
|
|
invite_request_info = NULL;
|
|
while (NULL != (lpInvReqInfo = m_InviteRequestList.Iterate()))
|
|
{
|
|
if (connect_provider_confirm->connection_handle == lpInvReqInfo->connection_handle)
|
|
{
|
|
TRACE_OUT(("CConf: ProcessConnectProviderConfirm: Found Invite Request Match"));
|
|
invite_request_info = lpInvReqInfo;
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
if (invite_request_info != NULL)
|
|
{
|
|
// This must be the confirm of an invite
|
|
ProcessConferenceInviteResponsePDU (NULL, connect_provider_confirm);
|
|
}
|
|
else
|
|
{
|
|
switch (m_eNodeType)
|
|
{
|
|
case CONVENER_NODE:
|
|
case TOP_PROVIDER_AND_CONVENER_NODE:
|
|
GetConferenceNameAndModifier ( &conference_name,
|
|
&conference_modifier);
|
|
|
|
g_pControlSap->ConfCreateConfirm(
|
|
&conference_name,
|
|
conference_modifier,
|
|
m_nConfID,
|
|
m_pDomainParameters,
|
|
NULL,
|
|
result,
|
|
connect_provider_confirm->connection_handle);
|
|
|
|
InitiateTermination ( GCC_REASON_ERROR_TERMINATION,
|
|
0);
|
|
break;
|
|
|
|
case JOINED_NODE:
|
|
case JOINED_CONVENER_NODE:
|
|
TRACE_OUT(("CConf::ProcessConnectProviderConfirm:"
|
|
"Joined Node connect provider failed"));
|
|
GetConferenceNameAndModifier ( &conference_name,
|
|
&conference_modifier);
|
|
|
|
if (m_pszRemoteModifier != NULL)
|
|
{
|
|
remote_modifier = (GCCNumericString) m_pszRemoteModifier;
|
|
}
|
|
|
|
TRACE_OUT(("CConf::ProcessConnectProviderConfirm: Before conference Join Confirm"));
|
|
g_pControlSap->ConfJoinConfirm(
|
|
&conference_name,
|
|
remote_modifier,
|
|
conference_modifier,
|
|
m_nConfID,
|
|
NULL,
|
|
m_pDomainParameters,
|
|
m_fClearPassword,
|
|
m_fConfLocked,
|
|
m_fConfListed,
|
|
m_fConfConductible,
|
|
m_eTerminationMethod,
|
|
m_pConductorPrivilegeList,
|
|
m_pConductModePrivilegeList,
|
|
m_pNonConductModePrivilegeList,
|
|
NULL,
|
|
NULL,
|
|
result,
|
|
connect_provider_confirm->connection_handle,
|
|
NULL,
|
|
0);
|
|
|
|
TRACE_OUT(("CConf::ProcessConnectProviderConfirm: After conference Join Confirm"));
|
|
|
|
InitiateTermination(GCC_REASON_ERROR_TERMINATION, 0);
|
|
break;
|
|
|
|
default:
|
|
TRACE_OUT(("CConf: ProcessConnectProviderConfirm:"
|
|
"Assertion Failure: Bad confirm received"));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
DebugExitVOID(CConf::ProcessConnectProviderConfirm);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* void ProcessConferenceCreateResponsePDU ()
|
|
*
|
|
* Private Function Description
|
|
* This routine processes a Conference Create Response PDU that is
|
|
* delivered as part of a Connect Provider Confirm.
|
|
*
|
|
* Formal Parameters:
|
|
* create_response - This is the Conference Create response
|
|
* PDU.
|
|
* connect_provider_confirm - This structure contains the MCS related
|
|
* data such as sender id and connection
|
|
* Handle as well as the PDU data.
|
|
*
|
|
* Return Value
|
|
* None.
|
|
*
|
|
* Side Effects
|
|
* None.
|
|
*
|
|
* Caveats
|
|
* None.
|
|
*/
|
|
void CConf::
|
|
ProcessConferenceCreateResponsePDU
|
|
(
|
|
PConferenceCreateResponse create_response,
|
|
PConnectProviderConfirm connect_provider_confirm
|
|
)
|
|
{
|
|
GCCError err = GCC_NO_ERROR;
|
|
GCCResult result;
|
|
UserID top_gcc_node_id;
|
|
UserID parent_user_id;
|
|
GCCConferenceName conference_name;
|
|
GCCNumericString conference_modifier;
|
|
|
|
DebugEntry(CConf::ProcessConnectProviderConfirm);
|
|
|
|
// Translate the result back to GCC Result
|
|
result = ::TranslateCreateResultToGCCResult(create_response->result);
|
|
|
|
if ((result == GCC_RESULT_SUCCESSFUL) &&
|
|
(connect_provider_confirm->result == RESULT_SUCCESSFUL))
|
|
{
|
|
/*
|
|
** Save the domain parameters. The domain parameters returned in
|
|
** the connect provider confirm should always be up to date.
|
|
*/
|
|
if (m_pDomainParameters == NULL)
|
|
{
|
|
DBG_SAVE_FILE_LINE
|
|
m_pDomainParameters = new DomainParameters;
|
|
}
|
|
|
|
if (m_pDomainParameters != NULL)
|
|
*m_pDomainParameters = connect_provider_confirm->domain_parameters;
|
|
else
|
|
err = GCC_ALLOCATION_FAILURE;
|
|
|
|
// Get any user data that might exists
|
|
if ((create_response->bit_mask & CCRS_USER_DATA_PRESENT) &&
|
|
(err == GCC_NO_ERROR))
|
|
{
|
|
DBG_SAVE_FILE_LINE
|
|
m_pUserDataList = new CUserDataListContainer(create_response->ccrs_user_data, &err);
|
|
if (m_pUserDataList == NULL)
|
|
err = GCC_ALLOCATION_FAILURE;
|
|
}
|
|
|
|
if (err == GCC_NO_ERROR)
|
|
{
|
|
m_nParentIDTagNumber = create_response->tag;
|
|
|
|
top_gcc_node_id = create_response->node_id;
|
|
parent_user_id = top_gcc_node_id;
|
|
|
|
// Create the user attachment object.
|
|
DBG_SAVE_FILE_LINE
|
|
m_pMcsUserObject = new MCSUser(this, top_gcc_node_id, parent_user_id, &err);
|
|
if (m_pMcsUserObject == NULL || GCC_NO_ERROR != err)
|
|
{
|
|
if (NULL != m_pMcsUserObject)
|
|
{
|
|
m_pMcsUserObject->Release();
|
|
m_pMcsUserObject = NULL;
|
|
}
|
|
else
|
|
{
|
|
err = GCC_ALLOCATION_FAILURE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TRACE_OUT(("CConf: ProcessConnectProviderConfirm: conference create result was Failure"));
|
|
|
|
// Go ahead and translate the mcs error to a gcc error if one occured.
|
|
if ((result == GCC_RESULT_SUCCESSFUL) &&
|
|
(connect_provider_confirm->result != RESULT_SUCCESSFUL))
|
|
{
|
|
result = ::TranslateMCSResultToGCCResult(connect_provider_confirm->result);
|
|
}
|
|
|
|
// Get the conference name to pass back in the create confirm
|
|
GetConferenceNameAndModifier ( &conference_name,
|
|
&conference_modifier);
|
|
|
|
g_pControlSap->ConfCreateConfirm(
|
|
&conference_name,
|
|
conference_modifier,
|
|
m_nConfID,
|
|
m_pDomainParameters,
|
|
NULL,
|
|
result,
|
|
connect_provider_confirm->connection_handle);
|
|
|
|
// Terminate the conference
|
|
InitiateTermination ( GCC_REASON_NORMAL_TERMINATION,
|
|
0);
|
|
}
|
|
|
|
|
|
if (err != GCC_NO_ERROR)
|
|
{
|
|
InitiateTermination ( GCC_REASON_ERROR_LOW_RESOURCES,
|
|
0);
|
|
}
|
|
|
|
DebugExitVOID(CConf::ProcessConnectProviderConfirm);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* void ProcessConferenceJoinResponsePDU ()
|
|
*
|
|
* Private Function Description
|
|
* This routine processes a Conference Join Response PDU that is
|
|
* delivered as part of a Connect Provider Confirm.
|
|
*
|
|
* Formal Parameters:
|
|
* join_response - This is the Conference Join response
|
|
* PDU.
|
|
* connect_provider_confirm - This structure contains the MCS related
|
|
* data such as sender id and connection
|
|
* Handle as well as the PDU data.
|
|
*
|
|
* Return Value
|
|
* None.
|
|
*
|
|
* Side Effects
|
|
* None.
|
|
*
|
|
* Caveats
|
|
* None.
|
|
*/
|
|
void CConf::
|
|
ProcessConferenceJoinResponsePDU
|
|
(
|
|
PConferenceJoinResponse join_response,
|
|
PConnectProviderConfirm connect_provider_confirm
|
|
)
|
|
{
|
|
GCCError err = GCC_NO_ERROR;
|
|
GCCResult result;
|
|
UserID top_gcc_node_id;
|
|
UserID parent_user_id;
|
|
CPassword *password_challenge = NULL;
|
|
CUserDataListContainer *user_data_list = NULL;
|
|
GCCConferenceName conference_name;
|
|
GCCNumericString local_modifier;
|
|
GCCNumericString remote_modifier = NULL;
|
|
|
|
DebugEntry(CConf::ProcessConferenceJoinResponsePDU);
|
|
|
|
// Translate the result back to GCC Result
|
|
result = ::TranslateJoinResultToGCCResult (join_response->result);
|
|
|
|
if ((result == GCC_RESULT_SUCCESSFUL) &&
|
|
(connect_provider_confirm->result == RESULT_SUCCESSFUL))
|
|
{
|
|
/*
|
|
** Save the domain parameters. The domain parameters returned in
|
|
** the connect provider confirm should always be up to date.
|
|
*/
|
|
if (m_pDomainParameters == NULL)
|
|
{
|
|
DBG_SAVE_FILE_LINE
|
|
m_pDomainParameters = new DomainParameters;
|
|
}
|
|
|
|
if (m_pDomainParameters != NULL)
|
|
*m_pDomainParameters = connect_provider_confirm->domain_parameters;
|
|
else
|
|
err = GCC_ALLOCATION_FAILURE;
|
|
|
|
// Get the conference name alias if one exists
|
|
if ((join_response->bit_mask & CONFERENCE_NAME_ALIAS_PRESENT) &&
|
|
(err == GCC_NO_ERROR))
|
|
{
|
|
if (join_response->conference_name_alias.choice ==
|
|
NAME_SELECTOR_NUMERIC_CHOSEN)
|
|
{
|
|
delete m_pszConfNumericName;
|
|
if (NULL == (m_pszConfNumericName = ::My_strdupA(
|
|
join_response->conference_name_alias.u.name_selector_numeric)))
|
|
{
|
|
err = GCC_ALLOCATION_FAILURE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
delete m_pwszConfTextName;
|
|
if (NULL == (m_pwszConfTextName = ::My_strdupW2(
|
|
join_response->conference_name_alias.u.name_selector_text.length,
|
|
join_response->conference_name_alias.u.name_selector_text.value)))
|
|
{
|
|
err = GCC_ALLOCATION_FAILURE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Get the conductor privilege list if one exists
|
|
if ((join_response->bit_mask & CJRS_CONDUCTOR_PRIVS_PRESENT) &&
|
|
(err == GCC_NO_ERROR))
|
|
{
|
|
delete m_pConductorPrivilegeList;
|
|
DBG_SAVE_FILE_LINE
|
|
m_pConductorPrivilegeList = new PrivilegeListData(join_response->cjrs_conductor_privs);
|
|
if (m_pConductorPrivilegeList == NULL)
|
|
err = GCC_ALLOCATION_FAILURE;
|
|
}
|
|
|
|
// Get the conducted mode privilege list if one exists
|
|
if ((join_response->bit_mask & CJRS_CONDUCTED_PRIVS_PRESENT) &&
|
|
(err == GCC_NO_ERROR))
|
|
{
|
|
delete m_pConductModePrivilegeList;
|
|
DBG_SAVE_FILE_LINE
|
|
m_pConductModePrivilegeList = new PrivilegeListData(join_response->cjrs_conducted_privs);
|
|
if (m_pConductModePrivilegeList == NULL)
|
|
err = GCC_ALLOCATION_FAILURE;
|
|
}
|
|
|
|
// Get the non-conducted mode privilege list if one exists
|
|
if ((join_response->bit_mask & CJRS_NON_CONDUCTED_PRIVS_PRESENT) &&
|
|
(err == GCC_NO_ERROR))
|
|
{
|
|
delete m_pNonConductModePrivilegeList;
|
|
DBG_SAVE_FILE_LINE
|
|
m_pNonConductModePrivilegeList = new PrivilegeListData(join_response->cjrs_non_conducted_privs);
|
|
if (m_pNonConductModePrivilegeList == NULL)
|
|
err = GCC_ALLOCATION_FAILURE;
|
|
}
|
|
|
|
// Get the conference description if it exists
|
|
if ((join_response->bit_mask & CJRS_DESCRIPTION_PRESENT) &&
|
|
(err == GCC_NO_ERROR))
|
|
{
|
|
delete m_pwszConfDescription;
|
|
if (NULL == (m_pwszConfDescription = ::My_strdupW2(
|
|
join_response->cjrs_description.length,
|
|
join_response->cjrs_description.value)))
|
|
{
|
|
err = GCC_ALLOCATION_FAILURE;
|
|
}
|
|
}
|
|
|
|
// Get the user data if it exists
|
|
if ((join_response->bit_mask & CJRS_USER_DATA_PRESENT) &&
|
|
(err == GCC_NO_ERROR))
|
|
{
|
|
if (NULL != m_pUserDataList)
|
|
{
|
|
m_pUserDataList->Release();
|
|
}
|
|
DBG_SAVE_FILE_LINE
|
|
m_pUserDataList = new CUserDataListContainer(join_response->cjrs_user_data, &err);
|
|
// in case of err but valid m_pUserDataList, the destructor will clean it up.
|
|
if (m_pUserDataList == NULL)
|
|
{
|
|
err = GCC_ALLOCATION_FAILURE;
|
|
}
|
|
}
|
|
|
|
if (err == GCC_NO_ERROR)
|
|
{
|
|
parent_user_id = (join_response->bit_mask & CJRS_NODE_ID_PRESENT) ?
|
|
(UserID) join_response->cjrs_node_id :
|
|
(UserID) join_response->top_node_id;
|
|
|
|
m_nParentIDTagNumber = join_response->tag;
|
|
top_gcc_node_id = (UserID)join_response->top_node_id;
|
|
m_fClearPassword = join_response->clear_password_required;
|
|
m_fConfLocked = join_response->conference_is_locked;
|
|
m_fConfListed = join_response->conference_is_listed;
|
|
m_eTerminationMethod = (GCCTerminationMethod)join_response->termination_method;
|
|
m_fConfConductible = join_response->conference_is_conductible;
|
|
|
|
// Create the user attachment object.
|
|
ASSERT(NULL == m_pMcsUserObject);
|
|
DBG_SAVE_FILE_LINE
|
|
m_pMcsUserObject = new MCSUser(this, top_gcc_node_id, parent_user_id, &err);
|
|
// in case of err but valid m_pMcsUserObject, the destructor will clean it up.
|
|
if (m_pMcsUserObject == NULL)
|
|
{
|
|
err = GCC_ALLOCATION_FAILURE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((join_response->bit_mask & CJRS_PASSWORD_PRESENT) &&
|
|
(err == GCC_NO_ERROR))
|
|
{
|
|
DBG_SAVE_FILE_LINE
|
|
password_challenge = new CPassword(&join_response->cjrs_password, &err);
|
|
if (password_challenge == NULL)
|
|
{
|
|
err = GCC_ALLOCATION_FAILURE;
|
|
}
|
|
}
|
|
|
|
// Get the user data if it exists
|
|
if ((join_response->bit_mask & CJRS_USER_DATA_PRESENT) &&
|
|
(err == GCC_NO_ERROR))
|
|
{
|
|
DBG_SAVE_FILE_LINE
|
|
user_data_list = new CUserDataListContainer(join_response->cjrs_user_data, &err);
|
|
if (user_data_list == NULL)
|
|
{
|
|
err = GCC_ALLOCATION_FAILURE;
|
|
}
|
|
}
|
|
|
|
if (err == GCC_NO_ERROR)
|
|
{
|
|
/*
|
|
** Go ahead and translate the mcs error to a gcc error if
|
|
** one occured.
|
|
*/
|
|
if ((result == GCC_RESULT_SUCCESSFUL) &&
|
|
(connect_provider_confirm->result != RESULT_SUCCESSFUL))
|
|
{
|
|
result = ::TranslateMCSResultToGCCResult(connect_provider_confirm->result);
|
|
}
|
|
|
|
// Fill in the conference name data pointers.
|
|
GetConferenceNameAndModifier(&conference_name, &local_modifier);
|
|
|
|
if (m_pszRemoteModifier != NULL)
|
|
{
|
|
remote_modifier = (GCCNumericString) m_pszRemoteModifier;
|
|
}
|
|
|
|
//
|
|
// LONCHANC: To get rid of the conference object
|
|
// in GCC Controller's active conference list.
|
|
// The conference object will then be moved to
|
|
// the deletion list.
|
|
//
|
|
InitiateTermination ( GCC_REASON_NORMAL_TERMINATION, 0);
|
|
|
|
g_pControlSap->ConfJoinConfirm(
|
|
&conference_name,
|
|
remote_modifier,
|
|
local_modifier,
|
|
m_nConfID,
|
|
password_challenge,
|
|
m_pDomainParameters,
|
|
m_fClearPassword,
|
|
m_fConfLocked,
|
|
m_fConfListed,
|
|
m_fConfConductible,
|
|
m_eTerminationMethod,
|
|
m_pConductorPrivilegeList,
|
|
m_pConductModePrivilegeList,
|
|
m_pNonConductModePrivilegeList,
|
|
NULL,
|
|
user_data_list,
|
|
result,
|
|
connect_provider_confirm->connection_handle,
|
|
connect_provider_confirm->pb_cred,
|
|
connect_provider_confirm->cb_cred);
|
|
}
|
|
|
|
if (password_challenge != NULL)
|
|
{
|
|
password_challenge->Release();
|
|
}
|
|
|
|
if (user_data_list != NULL)
|
|
{
|
|
user_data_list->Release();
|
|
}
|
|
}
|
|
|
|
if (err != GCC_NO_ERROR)
|
|
{
|
|
InitiateTermination (GCC_REASON_ERROR_LOW_RESOURCES, 0);
|
|
}
|
|
|
|
DebugExitVOID(CConf::ProcessConferenceJoinResponsePDU);
|
|
}
|
|
|
|
|
|
/*
|
|
* void ProcessConferenceInviteResponsePDU ()
|
|
*
|
|
* Private Function Description
|
|
* This routine processes a Conference Invite Response PDU that is
|
|
* delivered as part of a Connect Provider Confirm.
|
|
*
|
|
* Formal Parameters:
|
|
* invite_response - This is the Conference Invite response
|
|
* PDU.
|
|
* connect_provider_confirm - This structure contains the MCS related
|
|
* data such as sender id and connection
|
|
* Handle as well as the PDU data.
|
|
*
|
|
* Return Value
|
|
* None.
|
|
*
|
|
* Side Effects
|
|
* None.
|
|
*
|
|
* Caveats
|
|
* None.
|
|
*/
|
|
void CConf::
|
|
ProcessConferenceInviteResponsePDU
|
|
(
|
|
PConferenceInviteResponse invite_response,
|
|
PConnectProviderConfirm connect_provider_confirm
|
|
)
|
|
{
|
|
GCCError err;
|
|
GCCResult result;
|
|
CUserDataListContainer *user_data_list = NULL;
|
|
INVITE_REQ_INFO *invite_request_info = NULL;
|
|
INVITE_REQ_INFO *lpInvReqInfo;
|
|
|
|
DebugEntry(CConf::ProcessConferenceInviteResponsePDU);
|
|
|
|
// First obtain the info request info structure.
|
|
m_InviteRequestList.Reset();
|
|
while (NULL != (lpInvReqInfo = m_InviteRequestList.Iterate()))
|
|
{
|
|
if (connect_provider_confirm->connection_handle == lpInvReqInfo->connection_handle)
|
|
{
|
|
invite_request_info = lpInvReqInfo;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (invite_request_info == NULL)
|
|
return;
|
|
|
|
if (invite_response != NULL)
|
|
{
|
|
// Get the user data list if one exists
|
|
if (invite_response->bit_mask & CIRS_USER_DATA_PRESENT)
|
|
{
|
|
DBG_SAVE_FILE_LINE
|
|
user_data_list = new CUserDataListContainer(invite_response->cirs_user_data, &err);
|
|
}
|
|
|
|
// Translate the result to GCCResult
|
|
result = ::TranslateInviteResultToGCCResult(invite_response->result);
|
|
}
|
|
else
|
|
{
|
|
result = (connect_provider_confirm->result == RESULT_USER_REJECTED) ?
|
|
GCC_RESULT_INCOMPATIBLE_PROTOCOL :
|
|
::TranslateMCSResultToGCCResult(connect_provider_confirm->result);
|
|
}
|
|
|
|
if ((result == GCC_RESULT_SUCCESSFUL) &&
|
|
(connect_provider_confirm->result == RESULT_SUCCESSFUL))
|
|
{
|
|
TRACE_OUT(("CConf::ProcessConferenceInviteResponsePDU:"
|
|
"Received Connect Provider confirm on Invite"));
|
|
|
|
/*
|
|
** Save the domain parameters. The domain parameters returned in
|
|
** the connect provider confirm should always be up to date.
|
|
*/
|
|
if (m_pDomainParameters == NULL)
|
|
{
|
|
DBG_SAVE_FILE_LINE
|
|
m_pDomainParameters = new DomainParameters;
|
|
}
|
|
|
|
if (m_pDomainParameters != NULL)
|
|
*m_pDomainParameters = connect_provider_confirm->domain_parameters;
|
|
else
|
|
err = GCC_ALLOCATION_FAILURE;
|
|
|
|
// Save the user data list for the invite confirm
|
|
invite_request_info->user_data_list = user_data_list;
|
|
|
|
// Wait for user ID from invited node before sending invite confirm.
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
** Go ahead and translate the mcs error to a gcc error if
|
|
** one occured.
|
|
*/
|
|
if ((result == GCC_RESULT_SUCCESSFUL) &&
|
|
(connect_provider_confirm->result != RESULT_SUCCESSFUL))
|
|
{
|
|
result = ::TranslateMCSResultToGCCResult(connect_provider_confirm->result);
|
|
}
|
|
|
|
// Cleanup the connection handle list
|
|
ASSERT(0 != connect_provider_confirm->connection_handle);
|
|
m_ConnHandleList.Remove(connect_provider_confirm->connection_handle);
|
|
|
|
// In case of error, the node controller will delete this conference.
|
|
// AddRef here to protect itself from going away.
|
|
AddRef();
|
|
|
|
g_pControlSap->ConfInviteConfirm(
|
|
m_nConfID,
|
|
user_data_list,
|
|
result,
|
|
connect_provider_confirm->connection_handle);
|
|
|
|
// Free up the user data
|
|
if (user_data_list != NULL)
|
|
{
|
|
user_data_list->Release();
|
|
}
|
|
|
|
// The reason that we check this is because in some cases, in the call to
|
|
// g_pControlSap->ConfInviteConfirm, someone was calling DeleteOutstandingInviteRequests
|
|
// which was killing the list via a call to m_InviteRequestList.Clear...
|
|
// This happens when the calee refuses to accept the call
|
|
if(m_InviteRequestList.Remove(invite_request_info))
|
|
{
|
|
// Free up the invite request info structure
|
|
delete invite_request_info;
|
|
}
|
|
|
|
// To match AddRef above.
|
|
Release();
|
|
}
|
|
|
|
DebugExitVOID(CConf::ProcessConferenceInviteResponsePDU);
|
|
}
|
|
|
|
|
|
/*
|
|
* CConf::ProcessEjectUserIndication ()
|
|
*
|
|
* Private Function Description
|
|
* This routine processes an Eject User Indication.
|
|
*
|
|
* Formal Parameters:
|
|
* reason - Reason that this node is being ejected.
|
|
*
|
|
* Return Value
|
|
* None.
|
|
*
|
|
* Side Effects
|
|
* None.
|
|
*
|
|
* Caveats
|
|
* None.
|
|
*/
|
|
void CConf::
|
|
ProcessEjectUserIndication ( GCCReason reason )
|
|
{
|
|
DebugEntry(CConf::ProcessEjectUserIndication);
|
|
|
|
if (m_fConfIsEstablished)
|
|
{
|
|
/*
|
|
** First inform the control SAP that this node has been ejected from this
|
|
** particular conference.
|
|
*/
|
|
g_pControlSap->ConfEjectUserIndication(
|
|
m_nConfID,
|
|
reason,
|
|
m_pMcsUserObject->GetMyNodeID());
|
|
|
|
/*
|
|
** Next we set conference established to FALSE since the conference is
|
|
** no longer established (this also prevents a terminate indication from
|
|
** being sent).
|
|
*/
|
|
m_fConfIsEstablished = FALSE;
|
|
|
|
InitiateTermination(reason, m_pMcsUserObject->GetMyNodeID());
|
|
}
|
|
|
|
DebugExitVOID(CConf::ProcessEjectUserIndication);
|
|
}
|
|
|
|
|
|
/*
|
|
* CConf::ProcessEjectUserRequest ()
|
|
*
|
|
* Private Function Description
|
|
* This routine processes an eject user request PDU. This routine should
|
|
* only be called from the Top Provider.
|
|
*
|
|
* Formal Parameters:
|
|
* eject_node_request - This is the PDU data associated with the
|
|
* eject user request.
|
|
*
|
|
* Return Value
|
|
* None.
|
|
*
|
|
* Side Effects
|
|
* None.
|
|
*
|
|
* Caveats
|
|
* None.
|
|
*/
|
|
void CConf::
|
|
ProcessEjectUserRequest ( PUserEjectNodeRequestInfo eject_node_request )
|
|
{
|
|
GCCResult result;
|
|
|
|
DebugEntry(CConf::ProcessEjectUserRequest);
|
|
|
|
// Check to make sure that the requesting node has the proper privileges
|
|
if (DoesRequesterHavePrivilege( eject_node_request->requester_id,
|
|
EJECT_USER_PRIVILEGE))
|
|
{
|
|
/*
|
|
** The user attachment object decides where the eject should
|
|
** be sent (either to the Top Provider or conference wide as
|
|
** an indication.
|
|
*/
|
|
m_pMcsUserObject->EjectNodeFromConference (
|
|
eject_node_request->node_to_eject,
|
|
eject_node_request->reason);
|
|
|
|
result = GCC_RESULT_SUCCESSFUL;
|
|
}
|
|
else
|
|
result = GCC_RESULT_INVALID_REQUESTER;
|
|
|
|
m_pMcsUserObject->SendEjectNodeResponse (eject_node_request->requester_id,
|
|
eject_node_request->node_to_eject,
|
|
result);
|
|
|
|
DebugExitVOID(CConf::ProcessEjectUserRequest);
|
|
}
|
|
|
|
|
|
/*
|
|
* CConf::ProcessEjectUserResponse ()
|
|
*
|
|
* Private Function Description
|
|
* This routine processes an eject user response PDU. This routine is
|
|
* called in response to an eject user request.
|
|
*
|
|
* Formal Parameters:
|
|
* eject_node_response - This is the PDU data associated with the
|
|
* eject user response.
|
|
*
|
|
* Return Value
|
|
* None.
|
|
*
|
|
* Side Effects
|
|
* None.
|
|
*
|
|
* Caveats
|
|
* None.
|
|
*/
|
|
void CConf::
|
|
ProcessEjectUserResponse ( PUserEjectNodeResponseInfo eject_node_response )
|
|
{
|
|
DebugEntry(CConf::ProcessEjectUserResponse);
|
|
|
|
if (m_EjectedNodeConfirmList.Remove(eject_node_response->node_to_eject))
|
|
{
|
|
#ifdef JASPER
|
|
g_pControlSap->ConfEjectUserConfirm(
|
|
m_nConfID,
|
|
eject_node_response->node_to_eject,
|
|
eject_node_response->result);
|
|
#endif // JASPER
|
|
}
|
|
else
|
|
{
|
|
ERROR_OUT(("CConf::ProcessEjectUserResponse: Assertion: Bad ejected node response received"));
|
|
}
|
|
|
|
DebugExitVOID(CConf::ProcessEjectUserResponse);
|
|
}
|
|
|
|
|
|
/*
|
|
* CConf::ProcessConferenceLockRequest()
|
|
*
|
|
* Private Function Description
|
|
* This routine processes a conference lock request PDU.
|
|
*
|
|
* Formal Parameters:
|
|
* requester_id - Node ID of node making the lock request.
|
|
*
|
|
* Return Value
|
|
* None.
|
|
*
|
|
* Side Effects
|
|
* None.
|
|
*
|
|
* Caveats
|
|
* None.
|
|
*/
|
|
void CConf::
|
|
ProcessConferenceLockRequest ( UserID requester_id )
|
|
{
|
|
DebugEntry(CConf::ProcessConferenceLockRequest);
|
|
|
|
if (DoesRequesterHavePrivilege (requester_id,
|
|
LOCK_UNLOCK_PRIVILEGE))
|
|
{
|
|
g_pControlSap->ConfLockIndication(m_nConfID, requester_id);
|
|
}
|
|
else
|
|
{
|
|
if (requester_id == m_pMcsUserObject->GetTopNodeID())
|
|
{
|
|
#ifdef JASPER
|
|
g_pControlSap->ConfLockConfirm(GCC_RESULT_INVALID_REQUESTER, m_nConfID);
|
|
#endif // JASPER
|
|
}
|
|
else
|
|
{
|
|
m_pMcsUserObject->SendConferenceLockResponse(
|
|
requester_id,
|
|
GCC_RESULT_INVALID_REQUESTER);
|
|
}
|
|
}
|
|
|
|
DebugExitVOID(CConf::ProcessConferenceLockRequest);
|
|
}
|
|
|
|
/*
|
|
* CConf::ProcessConferenceUnlockRequest()
|
|
*
|
|
* Private Function Description
|
|
* This routine processes a conference unlock request PDU.
|
|
*
|
|
* Formal Parameters:
|
|
* requester_id - Node ID of node making the unlock request.
|
|
*
|
|
* Return Value
|
|
* None.
|
|
*
|
|
* Side Effects
|
|
* None.
|
|
*
|
|
* Caveats
|
|
* None.
|
|
*/
|
|
void CConf::
|
|
ProcessConferenceUnlockRequest ( UserID requester_id )
|
|
{
|
|
DebugEntry(CConf::ProcessConferenceUnlockRequest);
|
|
|
|
if (DoesRequesterHavePrivilege (requester_id,
|
|
LOCK_UNLOCK_PRIVILEGE))
|
|
{
|
|
#ifdef JASPER
|
|
g_pControlSap->ConfUnlockIndication(m_nConfID, requester_id);
|
|
#endif // JASPER
|
|
}
|
|
else
|
|
{
|
|
if (requester_id == m_pMcsUserObject->GetTopNodeID())
|
|
{
|
|
#ifdef JASPER
|
|
g_pControlSap->ConfUnlockConfirm(GCC_RESULT_INVALID_REQUESTER, m_nConfID);
|
|
#endif // JASPER
|
|
}
|
|
else
|
|
{
|
|
m_pMcsUserObject->SendConferenceUnlockResponse(
|
|
requester_id,
|
|
GCC_RESULT_INVALID_REQUESTER);
|
|
}
|
|
}
|
|
|
|
DebugExitVOID(CConf::ProcessConferenceUnlockRequest);
|
|
}
|
|
|
|
|
|
/*
|
|
* CConf::ProcessConferenceLockIndication()
|
|
*
|
|
* Private Function Description
|
|
* This routine processes a conference lock indication PDU.
|
|
*
|
|
* Formal Parameters:
|
|
* source_id - Node ID which sent out the lock indication. Should
|
|
* only be sent by the top provider.
|
|
*
|
|
* Return Value
|
|
* None.
|
|
*
|
|
* Side Effects
|
|
* None.
|
|
*
|
|
* Caveats
|
|
* None.
|
|
*/
|
|
void CConf::
|
|
ProcessConferenceLockIndication ( UserID source_id )
|
|
{
|
|
DebugEntry(CConf::ProcessConferenceLockIndication);
|
|
|
|
if (source_id == m_pMcsUserObject->GetTopNodeID())
|
|
{
|
|
m_fConfLocked = CONFERENCE_IS_LOCKED;
|
|
#ifdef JASPER
|
|
g_pControlSap->ConfLockReport(m_nConfID, m_fConfLocked);
|
|
#endif // JASPER
|
|
}
|
|
|
|
DebugExitVOID(CConf::ProcessConferenceLockIndication);
|
|
}
|
|
|
|
|
|
/*
|
|
* CConf::ProcessConferenceUnlockIndication()
|
|
*
|
|
* Private Function Description
|
|
* This routine processes a conference unlock indication PDU.
|
|
*
|
|
* Formal Parameters:
|
|
* source_id - Node ID which sent out the unlock indication. Should
|
|
* only be sent by the top provider.
|
|
*
|
|
* Return Value
|
|
* None.
|
|
*
|
|
* Side Effects
|
|
* None.
|
|
*
|
|
* Caveats
|
|
* None.
|
|
*/
|
|
void CConf::
|
|
ProcessConferenceUnlockIndication ( UserID source_id )
|
|
{
|
|
DebugEntry(CConf::ProcessConferenceUnlockIndication);
|
|
|
|
if (source_id == m_pMcsUserObject->GetTopNodeID())
|
|
{
|
|
m_fConfLocked = CONFERENCE_IS_NOT_LOCKED;
|
|
#ifdef JASPER
|
|
g_pControlSap->ConfLockReport(m_nConfID, m_fConfLocked);
|
|
#endif // JASPER
|
|
}
|
|
|
|
DebugExitVOID(CConf::ProcessConferenceUnlockIndication);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* void ProcessConferenceTransferRequest ()
|
|
*
|
|
* Public Function Description
|
|
* This routine processes a conference transfer request PDU.
|
|
*
|
|
* Formal Parameters:
|
|
* requesting_node_id - Node ID that made the transfer
|
|
* request.
|
|
* destination_conference_name - The name of the conference to
|
|
* transfer to.
|
|
* destination_conference_modifier - The name of the conference modifier
|
|
* to transfer to.
|
|
* destination_address_list - Network address list of the
|
|
* conference to transfer to.
|
|
* number_of_destination_nodes - The number of nodes in the list of
|
|
* nodes that should perform the
|
|
* transfer.
|
|
* destination_node_list - The list of nodes that should
|
|
* perform the transfer.
|
|
* password - The password needed to join the
|
|
* new conference.
|
|
*
|
|
* Return Value
|
|
* None.
|
|
*
|
|
* Side Effects
|
|
* None.
|
|
*
|
|
* Caveats
|
|
* None.
|
|
*/
|
|
void CConf::
|
|
ProcessConferenceTransferRequest
|
|
(
|
|
UserID requesting_node_id,
|
|
PGCCConferenceName destination_conference_name,
|
|
GCCNumericString destination_conference_modifier,
|
|
CNetAddrListContainer *destination_address_list,
|
|
UINT number_of_destination_nodes,
|
|
PUserID destination_node_list,
|
|
CPassword *password
|
|
)
|
|
{
|
|
GCCResult result;
|
|
|
|
DebugEntry(CConf::ProcessConferenceTransferRequest);
|
|
|
|
if (DoesRequesterHavePrivilege( requesting_node_id,
|
|
TRANSFER_PRIVILEGE))
|
|
{
|
|
result = GCC_RESULT_SUCCESSFUL;
|
|
}
|
|
else
|
|
result = GCC_RESULT_INVALID_REQUESTER;
|
|
|
|
m_pMcsUserObject->ConferenceTransferResponse (
|
|
requesting_node_id,
|
|
destination_conference_name,
|
|
destination_conference_modifier,
|
|
number_of_destination_nodes,
|
|
destination_node_list,
|
|
result);
|
|
|
|
if (result == GCC_RESULT_SUCCESSFUL)
|
|
{
|
|
m_pMcsUserObject->ConferenceTransferIndication (
|
|
destination_conference_name,
|
|
destination_conference_modifier,
|
|
destination_address_list,
|
|
number_of_destination_nodes,
|
|
destination_node_list,
|
|
password);
|
|
}
|
|
|
|
DebugExitVOID(CConf::ProcessConferenceTransferRequest);
|
|
}
|
|
|
|
|
|
/*
|
|
* CConf::ProcessConferenceAddRequest ()
|
|
*
|
|
* Private Function Description
|
|
* This routine processes a conference add request PDU.
|
|
*
|
|
* Formal Parameters:
|
|
* requesting_node_id - Node ID that made the transfer
|
|
* request.
|
|
* destination_conference_name - The name of the conference to
|
|
* transfer to.
|
|
* destination_conference_modifier - The name of the conference modifier
|
|
* to transfer to.
|
|
* destination_address_list - Network address list of the
|
|
* conference to transfer to.
|
|
* number_of_destination_nodes - The number of nodes in the list of
|
|
* nodes that should perform the
|
|
* transfer.
|
|
* destination_node_list - The list of nodes that should
|
|
* perform the transfer.
|
|
* password - The password needed to join the
|
|
* new conference.
|
|
*
|
|
* Return Value
|
|
* None.
|
|
*
|
|
* Side Effects
|
|
* None.
|
|
*
|
|
* Caveats
|
|
* None.
|
|
*/
|
|
void CConf::
|
|
ProcessConferenceAddRequest
|
|
(
|
|
CNetAddrListContainer *network_address_list,
|
|
CUserDataListContainer *user_data_list,
|
|
UserID adding_node,
|
|
TagNumber add_request_tag,
|
|
UserID requesting_node
|
|
)
|
|
{
|
|
BOOL generate_add_indication = FALSE;
|
|
GCCResponseTag add_response_tag;
|
|
|
|
DebugEntry(CConf::ProcessConferenceAddRequest);
|
|
|
|
if (m_pMcsUserObject->GetMyNodeID() == m_pMcsUserObject->GetTopNodeID())
|
|
{
|
|
if (DoesRequesterHavePrivilege(requesting_node, ADD_PRIVILEGE))
|
|
{
|
|
if ((m_pMcsUserObject->GetMyNodeID() == adding_node) ||
|
|
(adding_node == 0))
|
|
{
|
|
generate_add_indication = TRUE;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
** Here we send the add request on to the MCU that is
|
|
** supposed to do the adding.
|
|
*/
|
|
m_pMcsUserObject->ConferenceAddRequest(
|
|
add_request_tag,
|
|
requesting_node,
|
|
adding_node,
|
|
adding_node,
|
|
network_address_list,
|
|
user_data_list);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Send back negative response stating inproper privileges
|
|
m_pMcsUserObject->ConferenceAddResponse(
|
|
add_request_tag,
|
|
requesting_node,
|
|
NULL,
|
|
GCC_RESULT_INVALID_REQUESTER);
|
|
}
|
|
|
|
}
|
|
else if (m_pMcsUserObject->GetMyNodeID() == adding_node)
|
|
{
|
|
/*
|
|
** This is the node that is supposed to get the add indication
|
|
** so send it on.
|
|
*/
|
|
generate_add_indication = TRUE;
|
|
}
|
|
|
|
if (generate_add_indication)
|
|
{
|
|
// First set up the Add Response Tag
|
|
while (1)
|
|
{
|
|
add_response_tag = m_nConfAddResponseTag++;
|
|
|
|
if (0 == m_AddResponseList.Find(add_response_tag))
|
|
break;
|
|
}
|
|
|
|
m_AddResponseList.Append(add_response_tag, add_request_tag);
|
|
|
|
g_pControlSap->ConfAddIndication(m_nConfID,
|
|
add_response_tag,
|
|
network_address_list,
|
|
user_data_list,
|
|
requesting_node);
|
|
}
|
|
|
|
DebugExitVOID(CConf::ProcessConferenceAddRequest);
|
|
}
|
|
|
|
|
|
/***************Conductorship Callbacks from User object*******************/
|
|
|
|
|
|
/*
|
|
* void ProcessConductorGrabConfirm ()
|
|
*
|
|
* Private Function Description
|
|
* The routine processes a conductor grab confirm received from the
|
|
* MCSUser object.
|
|
*
|
|
* Formal Parameters:
|
|
* result - This is the result from the grab request.
|
|
*
|
|
* Return Value
|
|
* None.
|
|
*
|
|
* Side Effects
|
|
* None.
|
|
*
|
|
* Caveats
|
|
* None.
|
|
*/
|
|
void CConf::
|
|
ProcessConductorGrabConfirm ( GCCResult result )
|
|
{
|
|
DebugEntry(CConf::ProcessConductorGrabConfirm);
|
|
|
|
TRACE_OUT(("CConf::ProcessConductorGrabConfirm: result = %d", result));
|
|
|
|
if ((m_eNodeType == TOP_PROVIDER_NODE) ||
|
|
(m_eNodeType == TOP_PROVIDER_AND_CONVENER_NODE))
|
|
{
|
|
#ifdef JASPER
|
|
// Inform the control SAP of the result
|
|
g_pControlSap->ConductorAssignConfirm ( result,
|
|
m_nConfID);
|
|
#endif // JASPER
|
|
|
|
/*
|
|
** If we were successful, we must send a Conductor Assign Indication
|
|
** PDU to every node in the conference to inform them that the
|
|
** conductor has changed.
|
|
*/
|
|
if (result == GCC_RESULT_SUCCESSFUL)
|
|
{
|
|
/*
|
|
** We use NULL for the conductor ID because the conductor can be
|
|
** determined from the sender of the Assign Indication PDU.
|
|
*/
|
|
m_pMcsUserObject->SendConductorAssignIndication(
|
|
m_pMcsUserObject->GetTopNodeID());
|
|
m_nConductorNodeID = m_pMcsUserObject->GetMyNodeID();
|
|
m_fConductorGrantedPermission = TRUE;
|
|
}
|
|
|
|
// Reset the Assign Request Pending flag back to FALSE.
|
|
m_fConductorAssignRequestPending = FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (result == GCC_RESULT_SUCCESSFUL)
|
|
{
|
|
/*
|
|
** If this node is not the Top Provider, we must try to Give the
|
|
** Conductor token to the Top Provider. The Top Provider is used to
|
|
** monitor the use of the conductor token. I the give to the Top
|
|
** Provider is unsuccessful then this node is the new conductor.
|
|
*/
|
|
m_pMcsUserObject->ConductorTokenGive(m_pMcsUserObject->GetTopNodeID());
|
|
}
|
|
else
|
|
{
|
|
#ifdef JASPER
|
|
// Inform the control SAP of the result
|
|
g_pControlSap->ConductorAssignConfirm(result, m_nConfID);
|
|
#endif // JASPER
|
|
}
|
|
}
|
|
|
|
DebugExitVOID(CConf::ProcessConductorGrabConfirm);
|
|
}
|
|
|
|
|
|
/*
|
|
* void ProcessConductorAssignIndication ()
|
|
*
|
|
* Private Function Description
|
|
* This routine processes a conductor assign indication received from
|
|
* the MCSUser object.
|
|
*
|
|
* Formal Parameters:
|
|
* new_conductor_id - This is the node id of the new conductor.
|
|
* sender_id - Node ID of node that sent the indication.
|
|
* Should be the Top Provider.
|
|
*
|
|
* Return Value
|
|
* None.
|
|
*
|
|
* Side Effects
|
|
* None.
|
|
*
|
|
* Caveats
|
|
* None.
|
|
*/
|
|
void CConf::
|
|
ProcessConductorAssignIndication
|
|
(
|
|
UserID new_conductor_id,
|
|
UserID sender_id
|
|
)
|
|
{
|
|
DebugEntry(CConf::ProcessConductorAssignIndication);
|
|
|
|
if (sender_id == m_pMcsUserObject->GetTopNodeID())
|
|
{
|
|
TRACE_OUT(("CConf: ConductAssignInd: Received from top provider"));
|
|
|
|
// Ignore this indication if the conference is not conductible
|
|
if (m_fConfConductible)
|
|
{
|
|
// Save UserID of the new conductor if not the Top Provider
|
|
if (sender_id != m_pMcsUserObject->GetMyNodeID())
|
|
{
|
|
m_nConductorNodeID = new_conductor_id;
|
|
}
|
|
|
|
/*
|
|
** Inform the control SAP and all the enrolled application SAPs
|
|
** that there is a new conductor.
|
|
*/
|
|
TRACE_OUT(("CConf: ConductAssignInd: Send to Control SAP"));
|
|
g_pControlSap->ConductorAssignIndication(m_nConductorNodeID, m_nConfID);
|
|
|
|
/*
|
|
** We iterate on a temporary list to avoid any problems
|
|
** if the application sap leaves during the callback.
|
|
*/
|
|
CAppSap *pAppSap;
|
|
CAppSapList TempList(m_RegisteredAppSapList);
|
|
TempList.Reset();
|
|
while (NULL != (pAppSap = TempList.Iterate()))
|
|
{
|
|
if (DoesSAPHaveEnrolledAPE(pAppSap))
|
|
{
|
|
pAppSap->ConductorAssignIndication(m_nConductorNodeID, m_nConfID);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERROR_OUT(("CConf:ProcessConductorAssignInd: Conductor Assign sent in non-conductible conference"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERROR_OUT(("CConf:ProcessConductorAssignInd: Conductor Assign sent from NON-Top Provider"));
|
|
}
|
|
|
|
DebugExitVOID(CConf::ProcessConductorAssignIndication);
|
|
}
|
|
|
|
|
|
/*
|
|
* void ProcessConductorReleaseIndication ()
|
|
*
|
|
* Private Function Description
|
|
* This routine processes a conductor release indication received from
|
|
* the MCSUser object.
|
|
*
|
|
* Formal Parameters:
|
|
* sender_id - Node ID of node that sent the indication.
|
|
* Should be the Top Provider or the conductor.
|
|
*
|
|
* Return Value
|
|
* None.
|
|
*
|
|
* Side Effects
|
|
* None.
|
|
*
|
|
* Caveats
|
|
* None.
|
|
*/
|
|
void CConf::
|
|
ProcessConductorReleaseIndication ( UserID sender_id )
|
|
{
|
|
DebugEntry(CConf::ProcessConductorReleaseIndication);
|
|
|
|
if ((sender_id == m_pMcsUserObject->GetTopNodeID()) ||
|
|
(sender_id == m_nConductorNodeID) ||
|
|
(sender_id == 0))
|
|
{
|
|
// Ignore this indication if the conference is not conductible
|
|
if (m_fConfConductible)
|
|
{
|
|
m_fConductorGrantedPermission = FALSE;
|
|
|
|
// Reset to Non-Conducted mode
|
|
m_nConductorNodeID = 0;
|
|
|
|
/*
|
|
** Inform the control SAP and all the enrolled application SAPs
|
|
** that the conductor was released.
|
|
*/
|
|
g_pControlSap->ConductorReleaseIndication( m_nConfID );
|
|
|
|
/*
|
|
** We iterate on a temporary list to avoid any problems
|
|
** if the application sap leaves during the callback.
|
|
*/
|
|
CAppSap *pAppSap;
|
|
CAppSapList TempList(m_RegisteredAppSapList);
|
|
TempList.Reset();
|
|
while (NULL != (pAppSap = TempList.Iterate()))
|
|
{
|
|
if (DoesSAPHaveEnrolledAPE(pAppSap))
|
|
{
|
|
pAppSap->ConductorReleaseIndication(m_nConfID);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
DebugExitVOID(CConf::ProcessConductorReleaseIndication);
|
|
}
|
|
|
|
|
|
/*
|
|
* void ProcessConductorGiveIndication ()
|
|
*
|
|
* Private Function Description
|
|
* This routine processes a conductor give indication received from
|
|
* the MCSUser object.
|
|
*
|
|
* Formal Parameters:
|
|
* giving_node_id - Node ID of node that is givving up
|
|
* conductorship.
|
|
*
|
|
* Return Value
|
|
* None.
|
|
*
|
|
* Side Effects
|
|
* None.
|
|
*
|
|
* Caveats
|
|
* None.
|
|
*/
|
|
void CConf::
|
|
ProcessConductorGiveIndication ( UserID giving_node_id )
|
|
{
|
|
DebugEntry(CConf::ProcessConductorGiveIndication);
|
|
|
|
// Ignore this indication if the conference is not conductible
|
|
if (m_fConfConductible)
|
|
{
|
|
/*
|
|
** If this node is the Top Provider and node giving conductor ship is
|
|
** not the current Conductor, this node must check to make sure that
|
|
** it is valid for this node to become the Top Conductor. Otherwise,
|
|
** we can assume this is a real give.
|
|
*/
|
|
if ((giving_node_id == m_nConductorNodeID) ||
|
|
(m_pMcsUserObject->GetMyNodeID() != m_pMcsUserObject->GetTopNodeID()))
|
|
{
|
|
// This flag is set when there is an outstanding give.
|
|
m_fConductorGiveResponsePending = TRUE;
|
|
|
|
/*
|
|
** Inform the control SAP.
|
|
*/
|
|
g_pControlSap->ConductorGiveIndication(m_nConfID);
|
|
}
|
|
else
|
|
{
|
|
TRACE_OUT(("CConf: ProcessConductorGiveInd: Send REAL Assign Ind"));
|
|
m_nConductorNodeID = giving_node_id;
|
|
m_pMcsUserObject->SendConductorAssignIndication(m_nConductorNodeID);
|
|
m_pMcsUserObject->ConductorTokenGiveResponse(RESULT_USER_REJECTED);
|
|
}
|
|
}
|
|
|
|
DebugExitVOID(CConf::ProcessConductorGiveIndication);
|
|
}
|
|
|
|
|
|
/*
|
|
* void ProcessConductorGiveConfirm ()
|
|
*
|
|
* Private Function Description
|
|
* This routine processes a conductor give confirm received from
|
|
* the MCSUser object.
|
|
*
|
|
* Formal Parameters:
|
|
* result - This is the result of the give request.
|
|
*
|
|
* Return Value
|
|
* None.
|
|
*
|
|
* Side Effects
|
|
* None.
|
|
*
|
|
* Caveats
|
|
* None.
|
|
*/
|
|
void CConf::
|
|
ProcessConductorGiveConfirm ( GCCResult result )
|
|
{
|
|
DebugEntry(CConf::ProcessConductorGiveConfirm);
|
|
|
|
TRACE_OUT(("CConf::ProcessConductorGiveConfirm: result = %d", result));
|
|
|
|
// Ignore this indication if the conference is not conductible
|
|
if (m_fConfConductible)
|
|
{
|
|
/*
|
|
** First we must determine if this Give Confirm is from
|
|
** a Give Request to the Top Provider that was associated with an
|
|
** Assign Request. This type of Give Confirm is from the Top Provider.
|
|
** If not, we check to make sure that this is a Give Confirm associated
|
|
** with a give request issued by the Node Controller. Otherwise, we
|
|
** dont process it.
|
|
*/
|
|
if (m_fConductorAssignRequestPending)
|
|
{
|
|
#ifdef JASPER
|
|
/*
|
|
** The proper result is for the Top Provider to reject the give
|
|
** to the Donor User ID that is the new Conductor. This is
|
|
** straight out of the T.124 document.
|
|
*/
|
|
if (result != GCC_RESULT_SUCCESSFUL)
|
|
result = GCC_RESULT_SUCCESSFUL;
|
|
else
|
|
result = GCC_RESULT_UNSPECIFIED_FAILURE;
|
|
|
|
// Inform the control SAP of the result
|
|
g_pControlSap->ConductorAssignConfirm(result, m_nConfID);
|
|
#endif // JASPER
|
|
|
|
m_fConductorAssignRequestPending = FALSE;
|
|
}
|
|
else if (m_nPendingConductorNodeID != 0)
|
|
{
|
|
if (result == GCC_RESULT_SUCCESSFUL)
|
|
m_fConductorGrantedPermission = FALSE;
|
|
|
|
#ifdef JASPER
|
|
g_pControlSap->ConductorGiveConfirm(result, m_nConfID, m_nPendingConductorNodeID);
|
|
#endif // JASPER
|
|
|
|
// Set the pending conductor node ID back to zero.
|
|
m_nPendingConductorNodeID = 0;
|
|
}
|
|
}
|
|
|
|
DebugExitVOID(CConf::ProcessConductorGiveConfirm);
|
|
}
|
|
|
|
|
|
/*
|
|
* void ProcessConductorPermitGrantInd ()
|
|
*
|
|
* Private Function Description
|
|
* This routine processes a conductor permission grant indication received
|
|
* from the MCSUser object.
|
|
*
|
|
* Formal Parameters:
|
|
* permission_grant_indication - This is the PDU data structure
|
|
* associated with the conductor
|
|
* permission grant indication.
|
|
* sender_id - This is the node ID of the node
|
|
* that sent the indication.
|
|
*
|
|
* Return Value
|
|
* None.
|
|
*
|
|
* Side Effects
|
|
* None.
|
|
*
|
|
* Caveats
|
|
* None.
|
|
*/
|
|
void CConf::
|
|
ProcessConductorPermitGrantInd
|
|
(
|
|
PUserPermissionGrantIndicationInfo permission_grant_indication,
|
|
UserID sender_id
|
|
)
|
|
{
|
|
UINT i;
|
|
|
|
DebugEntry(CConf::ProcessConductorPermitGrantInd);
|
|
|
|
if (m_fConfConductible)
|
|
{
|
|
if (sender_id == m_nConductorNodeID)
|
|
{
|
|
// First check to see if we have been given permission
|
|
m_fConductorGrantedPermission = FALSE;
|
|
for (i = 0; i < permission_grant_indication->number_granted; i++)
|
|
{
|
|
if (permission_grant_indication->granted_node_list[i] ==
|
|
m_pMcsUserObject->GetMyNodeID())
|
|
{
|
|
TRACE_OUT(("CConf::ProcessConductorPermitGrantInd: Permission was Granted"));
|
|
m_fConductorGrantedPermission = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
** This indication goes to the control SAP and all the application
|
|
** SAPs.
|
|
*/
|
|
g_pControlSap->ConductorPermitGrantIndication (
|
|
m_nConfID,
|
|
permission_grant_indication->number_granted,
|
|
permission_grant_indication->granted_node_list,
|
|
permission_grant_indication->number_waiting,
|
|
permission_grant_indication->waiting_node_list,
|
|
m_fConductorGrantedPermission);
|
|
|
|
/*
|
|
** We iterate on a temporary list to avoid any problems
|
|
** if the application sap leaves during the callback.
|
|
*/
|
|
CAppSap *pAppSap;
|
|
CAppSapList TempList(m_RegisteredAppSapList);
|
|
TempList.Reset();
|
|
while (NULL != (pAppSap = TempList.Iterate()))
|
|
{
|
|
if (DoesSAPHaveEnrolledAPE(pAppSap))
|
|
{
|
|
pAppSap->ConductorPermitGrantIndication(
|
|
m_nConfID,
|
|
permission_grant_indication->number_granted,
|
|
permission_grant_indication->granted_node_list,
|
|
permission_grant_indication->number_waiting,
|
|
permission_grant_indication->waiting_node_list,
|
|
m_fConductorGrantedPermission);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
DebugExitVOID(CConf::ProcessConductorPermitGrantInd);
|
|
}
|
|
|
|
|
|
/*
|
|
* void ProcessConductorTestConfirm ()
|
|
*
|
|
* Private Function Description
|
|
* This routine processes a conductor test confirm received
|
|
* from the MCSUser object.
|
|
*
|
|
* Formal Parameters:
|
|
* result - This is the result of the conductor test request
|
|
*
|
|
* Return Value
|
|
* None.
|
|
*
|
|
* Side Effects
|
|
* None.
|
|
*
|
|
* Caveats
|
|
* None.
|
|
*/
|
|
void CConf::
|
|
ProcessConductorTestConfirm ( GCCResult result )
|
|
{
|
|
BOOL conducted_mode;
|
|
CBaseSap *pSap;
|
|
|
|
DebugEntry(CConf::ProcessConductorTestConfirm);
|
|
|
|
if (! m_ConductorTestList.IsEmpty())
|
|
{
|
|
if (result == GCC_RESULT_SUCCESSFUL)
|
|
conducted_mode = TRUE;
|
|
else
|
|
conducted_mode = FALSE;
|
|
|
|
/*
|
|
** Pop the next command target of the list of command targets.
|
|
** Note that all token test request are processed in the order
|
|
** that they were issued so we are gauranteed to send the confirms
|
|
** to the correct target.
|
|
*/
|
|
|
|
pSap = m_ConductorTestList.Get();
|
|
|
|
pSap->ConductorInquireConfirm(m_nConductorNodeID,
|
|
result,
|
|
m_fConductorGrantedPermission,
|
|
conducted_mode,
|
|
m_nConfID);
|
|
}
|
|
|
|
DebugExitVOID(CConf::ProcessConductorTestConfirm);
|
|
}
|
|
|
|
|
|
/*************************************************************************/
|
|
|
|
|
|
/*
|
|
* CConf::InitiateTermination ()
|
|
*
|
|
* Private Function Description
|
|
* This routine informs the owner object that the conference has
|
|
* self terminated. It also directs a disconnect provider request at
|
|
* the parent connection.
|
|
*
|
|
* Formal Parameters:
|
|
* reason - This is the reason for the termination.
|
|
* requesting_node_id - This is the node ID of the node that is
|
|
* making the request,
|
|
*
|
|
* Return Value
|
|
* None.
|
|
*
|
|
* Side Effects
|
|
* None.
|
|
*
|
|
* Caveats
|
|
* None.
|
|
*/
|
|
void CConf::
|
|
InitiateTermination
|
|
(
|
|
GCCReason reason,
|
|
UserID requesting_node_id
|
|
)
|
|
{
|
|
DebugEntry(CConf::InitiateTermination);
|
|
|
|
if (! m_fTerminationInitiated)
|
|
{
|
|
m_fTerminationInitiated = TRUE;
|
|
|
|
if (m_fConfIsEstablished ||
|
|
(reason == GCC_REASON_DOMAIN_PARAMETERS_UNACCEPTABLE) ||
|
|
m_fConfTerminatePending)
|
|
{
|
|
g_pControlSap->ConfTerminateIndication(m_nConfID, requesting_node_id, reason);
|
|
m_fConfIsEstablished = FALSE;
|
|
}
|
|
|
|
// Disconnect from the MCS parent connection if it exists
|
|
if (m_hParentConnection != NULL)
|
|
{
|
|
g_pMCSIntf->DisconnectProviderRequest(m_hParentConnection);
|
|
m_hParentConnection = NULL;
|
|
}
|
|
|
|
g_pGCCController->ProcessConfTerminated(m_nConfID, reason);
|
|
|
|
/*
|
|
** Here we cleanup the registered application list. If any Application
|
|
** SAPs are still registered we will first send them PermitToEnroll
|
|
** indications revoking the permission to enroll and then we will
|
|
** unregister them (the unregister call takes care of this). First set up
|
|
** a temporary list of the registered applications to iterate on since
|
|
** members of this list will be removed during this process.
|
|
*/
|
|
if (! m_RegisteredAppSapList.IsEmpty())
|
|
{
|
|
CAppSapList TempList(m_RegisteredAppSapList);
|
|
CAppSap *pAppSap;
|
|
TempList.Reset();
|
|
while (NULL != (pAppSap = TempList.Iterate()))
|
|
{
|
|
UnRegisterAppSap(pAppSap);
|
|
}
|
|
}
|
|
}
|
|
|
|
DebugExitVOID(CConf::InitiateTermination);
|
|
}
|
|
|
|
|
|
/*
|
|
* CConf::GetConferenceNameAndModifier ()
|
|
*
|
|
* Private Function Description
|
|
* This routine returns pointers to the conference name and modifier.
|
|
*
|
|
* Formal Parameters:
|
|
* conference_name - Pointer to structure that holds the conference
|
|
* name.
|
|
* requesting_node_id - This is a pointer to a pointer that holds the
|
|
* conference modifier.
|
|
*
|
|
* Return Value
|
|
* None.
|
|
*
|
|
* Side Effects
|
|
* None.
|
|
*
|
|
* Caveats
|
|
* None.
|
|
*/
|
|
void CConf::
|
|
GetConferenceNameAndModifier
|
|
(
|
|
PGCCConferenceName pConfName,
|
|
PGCCNumericString ppszConfModifier
|
|
)
|
|
{
|
|
pConfName->numeric_string = m_pszConfNumericName;
|
|
pConfName->text_string = m_pwszConfTextName;
|
|
*ppszConfModifier = (GCCNumericString) m_pszConfModifier;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
* CAppRosterMgr * CConf::GetAppRosterManager ()
|
|
*
|
|
* Private Function Description
|
|
* This call returns a pointer to the application manager that
|
|
* matches the passed in key. It returns NULL is the application
|
|
* does not exists.
|
|
*
|
|
* Formal Parameters:
|
|
* session_key - This is the session key associated with the
|
|
* application roster manager that is being
|
|
* requested.
|
|
*
|
|
* Return Value
|
|
* A pointer to the appropriate application roster manager.
|
|
* NULL if on does not exists.
|
|
*
|
|
* Side Effects
|
|
* None.
|
|
*
|
|
* Caveats
|
|
* None.
|
|
*/
|
|
CAppRosterMgr * CConf::
|
|
GetAppRosterManager ( PGCCSessionKey session_key )
|
|
{
|
|
CAppRosterMgr *app_roster_manager = NULL;
|
|
|
|
if (session_key != NULL)
|
|
{
|
|
CAppRosterMgr *lpAppRosterMgr;
|
|
|
|
m_AppRosterMgrList.Reset();
|
|
while (NULL != (lpAppRosterMgr = m_AppRosterMgrList.Iterate()))
|
|
{
|
|
if (lpAppRosterMgr->IsThisYourSessionKey(session_key))
|
|
{
|
|
app_roster_manager = lpAppRosterMgr;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return (app_roster_manager);
|
|
}
|
|
|
|
|
|
/*
|
|
* CConf::GetNewUserIDTag ()
|
|
*
|
|
* Private Function Description
|
|
* This routine generates a User ID Tag number that is used in a
|
|
* User ID indication sent betweek two connected nodes.
|
|
*
|
|
* Formal Parameters:
|
|
* None.
|
|
*
|
|
* Return Value
|
|
* This is the User ID tag number generated by this routine.
|
|
*
|
|
* Side Effects
|
|
* None.
|
|
*
|
|
* Caveats
|
|
* Zero is not a valid. We initialize the convener user ID tag to
|
|
* zero which is an invalid tag.
|
|
*/
|
|
TagNumber CConf::
|
|
GetNewUserIDTag ( void )
|
|
{
|
|
/*
|
|
** Determine the tag number to associate with the GCC User ID
|
|
** that will be returned after the pending request or confirm.
|
|
*/
|
|
while (1)
|
|
{
|
|
if (++m_nUserIDTagNumber != 0)
|
|
{
|
|
if (m_ConnHdlTagNumberList2.Find(m_nUserIDTagNumber) == 0)
|
|
break;
|
|
}
|
|
}
|
|
|
|
return (m_nUserIDTagNumber);
|
|
}
|
|
|
|
|
|
/*
|
|
* CConf::DoesRequesterHavePrivilege ()
|
|
*
|
|
* Private Function Description
|
|
* This routine determines if the specified user has the specified
|
|
* privilege.
|
|
*
|
|
* Formal Parameters:
|
|
* requester_id - This is the node ID that is being checked for
|
|
* the specified privilege.
|
|
* privilege - Privilege being checked for.
|
|
*
|
|
* Return Value
|
|
* TRUE - If requester has privilege.
|
|
* FALSE - If requester does NOT have privilege.
|
|
*
|
|
* Side Effects
|
|
* None.
|
|
*
|
|
* Caveats
|
|
* None.
|
|
*/
|
|
BOOL CConf::
|
|
DoesRequesterHavePrivilege
|
|
(
|
|
UserID requester_id,
|
|
ConferencePrivilegeType privilege
|
|
)
|
|
{
|
|
BOOL rc = FALSE;
|
|
|
|
if (requester_id == m_nConvenerNodeID)
|
|
rc = TRUE;
|
|
else
|
|
{
|
|
/*
|
|
** First check to see if the node is the conductor and a conductor
|
|
** privilege list exists. Next check to see if the conference is in
|
|
** conducted mode and a conducted mode privilege list exists.
|
|
** Else, if not in conducted mode and a Non-Conducted mode privilege
|
|
** list exists use it.
|
|
*/
|
|
if (m_nConductorNodeID == requester_id)
|
|
{
|
|
if (m_pConductorPrivilegeList != NULL)
|
|
{
|
|
rc = m_pConductorPrivilegeList->
|
|
IsPrivilegeAvailable(privilege);
|
|
}
|
|
}
|
|
|
|
if (rc == FALSE)
|
|
{
|
|
if (m_nConductorNodeID != 0)
|
|
{
|
|
if (m_pConductModePrivilegeList != NULL)
|
|
{
|
|
rc = m_pConductModePrivilegeList->IsPrivilegeAvailable(privilege);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (m_pNonConductModePrivilegeList != NULL)
|
|
{
|
|
rc = m_pNonConductModePrivilegeList->IsPrivilegeAvailable(privilege);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*
|
|
* CConf::SendFullRosterRefresh ()
|
|
*
|
|
* Private Function Description
|
|
* When a new node is added to the conference it is the Top Provider's
|
|
* responsiblity to send out a complete refresh of all the rosters
|
|
* including both the conference roster and all the application rosters.
|
|
* That is the responsiblity of the routine.
|
|
*
|
|
* Formal Parameters:
|
|
* None.
|
|
*
|
|
* Return Value
|
|
* GCC_NO_ERROR - No error.
|
|
* GCC_ALLOCATION_FAILURE - A resource error occured.
|
|
*
|
|
* Side Effects
|
|
* None.
|
|
*
|
|
* Caveats
|
|
* None.
|
|
*/
|
|
GCCError CConf::
|
|
SendFullRosterRefresh ( void )
|
|
{
|
|
GCCError rc;
|
|
GCCPDU gcc_pdu;
|
|
PSetOfApplicationInformation * application_information;
|
|
PSetOfApplicationInformation next_set_of_information;
|
|
|
|
DebugEntry(CConf::SendFullRosterRefresh);
|
|
|
|
/*
|
|
** Start building the roster update indication. Not that this update
|
|
** will include the conference roster as well as all the application
|
|
** rosters.
|
|
*/
|
|
gcc_pdu.choice = INDICATION_CHOSEN;
|
|
|
|
gcc_pdu.u.indication.choice = ROSTER_UPDATE_INDICATION_CHOSEN;
|
|
|
|
gcc_pdu.u.indication.u.roster_update_indication.application_information =
|
|
NULL;
|
|
|
|
gcc_pdu.u.indication.u.roster_update_indication.refresh_is_full = TRUE;
|
|
|
|
// Call on the base class to fill in the PDU structure
|
|
rc = m_pConfRosterMgr->GetFullRosterRefreshPDU (
|
|
&gcc_pdu.u.indication.u.roster_update_indication.node_information);
|
|
|
|
/*
|
|
** If the conference roster get was successful we will iterate through
|
|
** all the application roster managers making the same request for a
|
|
** full refresh. Note that the application_information pointer is updated
|
|
** after every request to an app roster manager. This is because new
|
|
** sets of application information are being allocated everytime this call
|
|
** is made.
|
|
*/
|
|
if (rc == GCC_NO_ERROR)
|
|
{
|
|
CAppRosterMgr *lpAppRosterMgr;
|
|
|
|
application_information = &gcc_pdu.u.indication.u.
|
|
roster_update_indication.application_information;
|
|
|
|
m_AppRosterMgrList.Reset();
|
|
while (NULL != (lpAppRosterMgr = m_AppRosterMgrList.Iterate()))
|
|
{
|
|
next_set_of_information = lpAppRosterMgr->GetFullRosterRefreshPDU (
|
|
application_information,
|
|
&rc);
|
|
if (rc == GCC_NO_ERROR)
|
|
{
|
|
if (next_set_of_information != NULL)
|
|
application_information = &next_set_of_information->next;
|
|
|
|
//
|
|
// LONCHANC: If next_set_of_information is NULL,
|
|
// then application_information is unchanged.
|
|
// This means we effectively ignore this iteration.
|
|
// This is good because we do not lose anything.
|
|
//
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
** If no errors have occured up to this point we will go ahead and send
|
|
** out the PDU.
|
|
*/
|
|
if (rc == GCC_NO_ERROR)
|
|
m_pMcsUserObject->RosterUpdateIndication (&gcc_pdu, FALSE);
|
|
|
|
DebugExitINT(CConf::SendFullRosterRefresh, rc);
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*
|
|
* CConf::UpdateNewConferenceNode ()
|
|
*
|
|
* Private Function Description
|
|
*
|
|
* Formal Parameters:
|
|
* None.
|
|
*
|
|
* Return Value
|
|
* GCC_NO_ERROR - No error.
|
|
* GCC_ALLOCATION_FAILURE - A resource error occured.
|
|
*
|
|
* Side Effects
|
|
* None.
|
|
*
|
|
* Caveats
|
|
* None.
|
|
*/
|
|
GCCError CConf::
|
|
UpdateNewConferenceNode ( void )
|
|
{
|
|
GCCError rc = GCC_NO_ERROR;
|
|
|
|
DebugEntry(CConf::UpdateNewConferenceNode);
|
|
|
|
// Here we send a full roster refresh for the node that added
|
|
rc = SendFullRosterRefresh ();
|
|
|
|
if (rc == GCC_NO_ERROR)
|
|
{
|
|
/*
|
|
** We must inform the new node of the current conductorship
|
|
** status. Note that we only do this if the conference is
|
|
** conductible and we are the Top Provider.
|
|
*/
|
|
if (m_fConfLocked == CONFERENCE_IS_LOCKED)
|
|
{
|
|
m_pMcsUserObject->SendConferenceLockIndication(
|
|
TRUE, // Indicates uniform send
|
|
0);
|
|
}
|
|
else
|
|
{
|
|
m_pMcsUserObject->SendConferenceUnlockIndication(
|
|
TRUE, // Indicates uniform send
|
|
0);
|
|
}
|
|
|
|
if (m_fConfConductible)
|
|
{
|
|
if (m_nConductorNodeID != 0)
|
|
{
|
|
m_pMcsUserObject->SendConductorAssignIndication(m_nConductorNodeID);
|
|
}
|
|
else
|
|
m_pMcsUserObject->SendConductorReleaseIndication();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERROR_OUT(("CConf: UpdateNewConferenceNode: Error sending full refresh"));
|
|
InitiateTermination(GCC_REASON_ERROR_LOW_RESOURCES, 0);
|
|
}
|
|
|
|
DebugExitINT(CConf::UpdateNewConferenceNode, rc);
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*
|
|
** Before we start the disconnect/termination process we must remove all the
|
|
** outstanding invite request from our list and send back associated
|
|
** confirms. Here we go ahead disconnect all connection associated with
|
|
** the invites.
|
|
*/
|
|
void CConf::
|
|
DeleteOutstandingInviteRequests ( void )
|
|
{
|
|
INVITE_REQ_INFO *pInvReqInfo;
|
|
while (NULL != (pInvReqInfo = m_InviteRequestList.Get()))
|
|
{
|
|
DeleteInviteRequest(pInvReqInfo);
|
|
}
|
|
}
|
|
|
|
|
|
void CConf::
|
|
CancelInviteRequest ( ConnectionHandle hInviteReqConn )
|
|
{
|
|
INVITE_REQ_INFO *pInvReqInfo;
|
|
m_InviteRequestList.Reset();
|
|
while (NULL != (pInvReqInfo = m_InviteRequestList.Iterate()))
|
|
{
|
|
if (hInviteReqConn == pInvReqInfo->connection_handle)
|
|
{
|
|
m_InviteRequestList.Remove(pInvReqInfo);
|
|
DeleteInviteRequest(pInvReqInfo);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CConf::
|
|
DeleteInviteRequest ( INVITE_REQ_INFO *pInvReqInfo )
|
|
{
|
|
// Cleanup the connection handle list
|
|
ASSERT(NULL != pInvReqInfo);
|
|
ASSERT(0 != pInvReqInfo->connection_handle);
|
|
m_ConnHandleList.Remove(pInvReqInfo->connection_handle);
|
|
|
|
g_pMCSIntf->DisconnectProviderRequest(pInvReqInfo->connection_handle);
|
|
|
|
// Send the invite confirm
|
|
g_pControlSap->ConfInviteConfirm(m_nConfID,
|
|
NULL,
|
|
GCC_RESULT_INVALID_CONFERENCE,
|
|
pInvReqInfo->connection_handle);
|
|
|
|
// Free up the invite request info structure
|
|
if (NULL != pInvReqInfo->user_data_list)
|
|
{
|
|
pInvReqInfo->user_data_list->Release();
|
|
}
|
|
delete pInvReqInfo;
|
|
}
|
|
|
|
|
|
void CConf::
|
|
ProcessConfJoinResponse
|
|
(
|
|
PUserJoinResponseInfo join_response_info
|
|
)
|
|
{
|
|
BOOL_PTR bptr;
|
|
|
|
if (NULL != (bptr = m_JoinRespNamePresentConnHdlList2.Remove(join_response_info->connection_handle)))
|
|
{
|
|
ConfJoinIndResponse (
|
|
(ConnectionHandle)join_response_info->connection_handle,
|
|
join_response_info->password_challenge,
|
|
join_response_info->user_data_list,
|
|
(bptr != FALSE_PTR),
|
|
FALSE,
|
|
join_response_info->result);
|
|
}
|
|
}
|
|
|
|
|
|
void CConf::
|
|
ProcessAppInvokeIndication
|
|
(
|
|
CInvokeSpecifierListContainer *pInvokeList,
|
|
UserID uidInvoker
|
|
)
|
|
{
|
|
/*
|
|
** Here we pass the invoke along to all the enrolled application
|
|
** SAPs as well as the control SAP.
|
|
*/
|
|
g_pControlSap->AppInvokeIndication(m_nConfID, pInvokeList, uidInvoker);
|
|
|
|
/*
|
|
** We iterate on a temporary list to avoid any problems
|
|
** if the application sap leaves during the callback.
|
|
*/
|
|
CAppSap *pAppSap;
|
|
CAppSapList TempList(m_RegisteredAppSapList);
|
|
TempList.Reset();
|
|
while (NULL != (pAppSap = TempList.Iterate()))
|
|
{
|
|
if (DoesSAPHaveEnrolledAPE(pAppSap))
|
|
{
|
|
pAppSap->AppInvokeIndication(m_nConfID, pInvokeList, uidInvoker);
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef JASPER
|
|
void CConf::
|
|
ProcessConductorPermitAskIndication
|
|
(
|
|
PPermitAskIndicationInfo indication_info
|
|
)
|
|
{
|
|
// Ignore this indication if the conference is not conductible
|
|
if (m_fConfConductible &&
|
|
(m_nConductorNodeID == m_pMcsUserObject->GetMyNodeID()))
|
|
{
|
|
g_pControlSap->ConductorPermitAskIndication(
|
|
m_nConfID,
|
|
indication_info->permission_is_granted,
|
|
indication_info->sender_id);
|
|
}
|
|
}
|
|
#endif // JASPER
|
|
|
|
|
|
void CConf::
|
|
ProcessConfAddResponse
|
|
(
|
|
PAddResponseInfo add_response_info
|
|
)
|
|
{
|
|
CNetAddrListContainer *network_address_list;
|
|
|
|
if (NULL != (network_address_list = m_AddRequestList.Remove(add_response_info->add_request_tag)))
|
|
{
|
|
g_pControlSap->ConfAddConfirm(
|
|
m_nConfID,
|
|
network_address_list,
|
|
add_response_info->user_data_list,
|
|
add_response_info->result);
|
|
|
|
// Unlock and remove the net address list
|
|
network_address_list->UnLockNetworkAddressList();
|
|
}
|
|
}
|
|
|
|
|
|
void CConf::
|
|
ConfRosterReportIndication ( CConfRosterMsg * pMsg )
|
|
{
|
|
// First send the update to the Control Sap.
|
|
g_pControlSap->ConfRosterReportIndication(m_nConfID, pMsg);
|
|
|
|
// Next send the update to all the Enrolled Application Saps
|
|
|
|
#if 0 // LONCHANC: app sap does not support conf roster report indication
|
|
/*
|
|
** We iterate on a temporary list to avoid any problems
|
|
** if the application sap leaves during the callback.
|
|
*/
|
|
CAppSap *pAppSap;
|
|
CAppSapList TempList(m_RegisteredAppSapList);
|
|
TempList.Reset();
|
|
while (NULL != (pAppSap = TempList.Iterate()))
|
|
{
|
|
if (DoesSAPHaveEnrolledAPE(pAppSap))
|
|
{
|
|
pAppSap->ConfRosterReportIndication(m_nConfID, pMsg);
|
|
}
|
|
}
|
|
#endif // 0
|
|
}
|
|
|
|
|
|
|
|
int KeyCompare(const struct Key *key1, const struct Key *key2)
|
|
{
|
|
if (key1->choice != key2->choice)
|
|
return 1;
|
|
|
|
switch (key1->choice) {
|
|
case object_chosen:
|
|
return ASN1objectidentifier_cmp((struct ASN1objectidentifier_s **) &key1->u.object,
|
|
(struct ASN1objectidentifier_s **) &key2->u.object);
|
|
|
|
case h221_non_standard_chosen:
|
|
if (key1->u.h221_non_standard.length != key2->u.h221_non_standard.length)
|
|
return 1;
|
|
return memcmp(&key1->u.h221_non_standard.value,
|
|
&key2->u.h221_non_standard.value,
|
|
key1->u.h221_non_standard.length);
|
|
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
|
|
BOOL CConf::
|
|
DoesRosterPDUContainApplet(PGCCPDU roster_update,
|
|
const struct Key *app_proto_key, BOOL refreshonly)
|
|
{
|
|
BOOL rc = FALSE;
|
|
PSetOfApplicationInformation set_of_application_info;
|
|
ASN1choice_t choice;
|
|
PSessionKey session_key;
|
|
|
|
DebugEntry(CConf::DoesRosterPDUContainApplet);
|
|
|
|
set_of_application_info = roster_update->u.indication.u.
|
|
roster_update_indication.application_information;
|
|
|
|
|
|
while (set_of_application_info != NULL)
|
|
{
|
|
choice = set_of_application_info->value.application_record_list.choice;
|
|
session_key = &set_of_application_info->value.session_key;
|
|
|
|
if (refreshonly && (choice != application_record_refresh_chosen))
|
|
continue;
|
|
if (!refreshonly && (choice == application_no_change_chosen))
|
|
continue;
|
|
|
|
if (0 == KeyCompare(&session_key->application_protocol_key,
|
|
app_proto_key))
|
|
{
|
|
rc = TRUE;
|
|
break;
|
|
}
|
|
set_of_application_info = set_of_application_info->next;
|
|
}
|
|
|
|
DebugExitINT(CConf::DoesRosterPDUContainApplet, rc);
|
|
return rc;
|
|
}
|
|
|
|
|
|
UINT HexaStringToUINT(LPCTSTR pcszString)
|
|
{
|
|
ASSERT(pcszString);
|
|
UINT uRet = 0;
|
|
LPTSTR pszStr = (LPTSTR) pcszString;
|
|
while (_T('\0') != pszStr[0])
|
|
{
|
|
if ((pszStr[0] >= _T('0')) && (pszStr[0] <= _T('9')))
|
|
{
|
|
uRet = (16 * uRet) + (BYTE) (pszStr[0] - _T('0'));
|
|
}
|
|
else if ((pszStr[0] >= _T('a')) && (pszStr[0] <= _T('f')))
|
|
{
|
|
uRet = (16 * uRet) + (BYTE) (pszStr[0] - _T('a') + 10);
|
|
}
|
|
else if ((pszStr[0] >= _T('A')) && (pszStr[0] <= _T('F')))
|
|
{
|
|
uRet = (16 * uRet) + (BYTE) (pszStr[0] - _T('A') + 10);
|
|
}
|
|
else
|
|
ASSERT(0);
|
|
|
|
pszStr++; // NOTE: DBCS characters are not allowed!
|
|
}
|
|
return uRet;
|
|
}
|
|
|
|
|
|
void CConf::AddNodeVersion(UserID NodeId, NodeRecord *pNodeRecord)
|
|
{
|
|
PSetOfUserData set_of_user_data;
|
|
ASN1octetstring_t user_data;
|
|
ASN1octet_t *currpos;
|
|
TCHAR szVersion[256];
|
|
|
|
if (pNodeRecord->bit_mask&RECORD_USER_DATA_PRESENT)
|
|
{
|
|
set_of_user_data = pNodeRecord->record_user_data;
|
|
while (set_of_user_data)
|
|
{
|
|
if (set_of_user_data->user_data_element.bit_mask & USER_DATA_FIELD_PRESENT)
|
|
{
|
|
user_data = set_of_user_data->user_data_element.user_data_field;
|
|
// Looking for the octet string L"VER:"
|
|
currpos = user_data.value;
|
|
while (currpos + sizeof(L"VER:") < user_data.value + user_data.length)
|
|
{
|
|
if (!memcmp(currpos, L"VER:", 8))
|
|
{
|
|
break;
|
|
}
|
|
currpos++;
|
|
}
|
|
if (currpos + sizeof(L"VER:") < user_data.value + user_data.length)
|
|
{ // found
|
|
WideCharToMultiByte(CP_ACP, 0, (const unsigned short*)(currpos+8),
|
|
4 /* only need version num, "0404" */,
|
|
szVersion, 256, 0, 0);
|
|
szVersion[4] = '\0';
|
|
DWORD dwVer = HexaStringToUINT(szVersion);
|
|
m_NodeVersionList2.Append(NodeId, dwVer);
|
|
WARNING_OUT(("Insert version %x0x for node %d.\n", dwVer, NodeId));
|
|
}
|
|
}
|
|
set_of_user_data = set_of_user_data->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
GCCError CConf::UpdateNodeVersionList(PGCCPDU roster_update,
|
|
GCCNodeID sender_id)
|
|
{
|
|
GCCError rc = GCC_NO_ERROR;
|
|
NodeRecordList node_record_list;
|
|
ASN1choice_t choice;
|
|
PSetOfNodeRecordRefreshes set_of_node_refresh;
|
|
PSetOfNodeRecordUpdates set_of_node_update;
|
|
UserID node_id;
|
|
NodeRecord *pNodeRecord;
|
|
|
|
node_record_list = roster_update->u.indication.u.roster_update_indication.
|
|
node_information.node_record_list;
|
|
|
|
switch(node_record_list.choice)
|
|
{
|
|
case node_no_change_chosen:
|
|
break;
|
|
|
|
case node_record_refresh_chosen:
|
|
set_of_node_refresh = node_record_list.u.node_record_refresh;
|
|
while (set_of_node_refresh)
|
|
{
|
|
node_id = set_of_node_refresh->value.node_id;
|
|
pNodeRecord = &set_of_node_refresh->value.node_record;
|
|
AddNodeVersion(node_id, pNodeRecord);
|
|
set_of_node_refresh = set_of_node_refresh->next;
|
|
}
|
|
break;
|
|
|
|
case node_record_update_chosen:
|
|
set_of_node_update = node_record_list.u.node_record_update;
|
|
while (set_of_node_update)
|
|
{
|
|
node_id = set_of_node_update->value.node_id;
|
|
switch(set_of_node_update->value.node_update.choice)
|
|
{
|
|
case node_remove_record_chosen:
|
|
m_NodeVersionList2.Remove(node_id);
|
|
break;
|
|
|
|
case node_add_record_chosen:
|
|
pNodeRecord = &set_of_node_update->value.node_update.u.node_add_record;
|
|
AddNodeVersion(node_id, pNodeRecord);
|
|
break;
|
|
}
|
|
|
|
set_of_node_update = set_of_node_update->next;
|
|
}
|
|
break;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
|
|
BOOL CConf::HasNM2xNode(void)
|
|
{
|
|
DWORD_PTR dwVer;
|
|
m_NodeVersionList2.Reset();
|
|
while (NULL != (dwVer = m_NodeVersionList2.Iterate()))
|
|
{
|
|
if (dwVer < 0x0404)
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
DWORD_PTR WINAPI T120_GetNodeVersion(GCCConfID ConfId, GCCNodeID NodeId)
|
|
{
|
|
CConf *pConf = g_pGCCController->GetConfObject(ConfId);
|
|
DWORD_PTR version;
|
|
if (pConf)
|
|
{
|
|
version = pConf->GetNodeVersion(NodeId);
|
|
return version;
|
|
}
|
|
return 0;
|
|
}
|
|
|