Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

1419 lines
57 KiB

/****************************************************************************/
/* */
/* ERNCGCCC.CPP */
/* */
/* T120 Conference class for the Reference System Node Controller. */
/* */
/* Copyright Data Connection Ltd. 1995 */
/* */
/****************************************************************************/
/* Changes: */
/* */
/* 14Jul95 NFC Created. */
/* 13Sep95 NFC Added handler for GCC_EJECT_USER_INDICATION */
/* 26Sep95 NFC Reset conference state in HandleEjectUser(). */
/* 11Oct95 PM Relax conference termination checks to avoid */
/* "no win" situations. The user wants it down */
/* then bring it down, whatever the state! */
/* */
/****************************************************************************/
#include "precomp.h"
DEBUG_FILEZONE(ZONE_GCC_NC);
#include "ernccons.h"
#include "nccglbl.hpp"
#include "erncvrsn.hpp"
#include "cuserdta.hpp"
#include "ernccm.hpp"
#include "ernctrc.h"
#include "nmremote.h"
static UINT s_nNumericNameCounter = 0;
__inline UINT GetNewNumericNameCounter(void) { return ++s_nNumericNameCounter; }
HRESULT DCRNCConference::
NewT120Conference(void)
{
DebugEntry(DCRNCConference::NewT120Conference);
m_eT120State = T120C_ST_IDLE;
HRESULT hr;
PCONFERENCE pConf;
GCCNumericString pszNewNumericName;
m_ConfName.numeric_string = NULL; // No numeric name yet.
hr = ::GetGCCFromUnicode(m_pwszConfName, &pszNewNumericName, &m_ConfName.text_string);
if (NO_ERROR == hr)
{
if (! ::IsEmptyStringA((LPCSTR) pszNewNumericName))
{
// Conference has a preassigned numeric name.
// Validate that it does not conflict with another
// conferences numeric name.
pConf = g_pNCConfMgr->GetConferenceFromNumber(pszNewNumericName);
if (NULL == pConf)
{
hr = NO_ERROR;
}
else
{
ERROR_OUT(("DCRNCConference::NewT120Conference: conference already exists"));
hr = UI_RC_CONFERENCE_ALREADY_EXISTS;
}
}
else
{
// Conference does not have a numeric name.
// Go get it a unique one.
DBG_SAVE_FILE_LINE
pszNewNumericName = (GCCNumericString)new CHAR[10];
if (NULL != pszNewNumericName)
{
do
{
// Do not allocate a conference number that is the same as
// an existing conference.
// bugbug: T120 should really do this, but it doesn't.
::wsprintfA((LPSTR) pszNewNumericName, "%u", ::GetNewNumericNameCounter());
pConf = g_pNCConfMgr->GetConferenceFromNumber(pszNewNumericName);
if (NULL == pConf)
{
hr = NO_ERROR; // Name good.
break;
}
}
while (TRUE); // Assumes not a DWORDs worth of conferences active.
}
else
{
ERROR_OUT(("DCRNCConference::NewT120Conference: can't create numeric name"));
hr = UI_RC_OUT_OF_MEMORY;
}
}
}
else
{
ERROR_OUT(("DCRNCConference::NewT120Conference: GetGCCFromUnicode failed, hr=0x%x", (UINT) hr));
}
// Done looking for numeric name, so can now insert into list.
m_ConfName.numeric_string = pszNewNumericName;
// In case of failure, be sure to notify nmcom.
if (NO_ERROR != hr)
{
g_pNCConfMgr->NotifyConferenceComplete(this, m_fIncoming, hr);
}
DebugExitHRESULT(DCRNCConference::NewT120Conference, hr);
return hr;
}
/****************************************************************************/
/* AnnouncePresence() - announce this nodes participation in the */
/* conference. */
/****************************************************************************/
HRESULT DCRNCConference::
AnnouncePresence(void)
{
GCCError GCCrc = GCC_INVALID_CONFERENCE;
HRESULT hr;
GCCNodeType nodeType;
GCCNodeProperties nodeProperties;
LPWSTR nodeName;
UINT nRecords;
GCCUserData ** ppUserData;
DebugEntry(DCRNCConference::AnnouncePresence);
if (0 != m_nConfID)
{
// bugbug: handle errors that cause failure to announce presence.
// Obtain the local addresses for the local user and
// publish them in the roster.
g_pCallbackInterface->OnUpdateUserData(this);
/************************************************************************/
/* Load the node type, node properties and node name from the RNC INI */
/* file. */
/************************************************************************/
nodeName = NULL;
::LoadAnnouncePresenceParameters(
&nodeType,
&nodeProperties,
&nodeName,
NULL); // &siteInfo)) : Not used right now.
/************************************************************************/
/* Announce our presence in the conference. */
/************************************************************************/
hr = m_LocalUserData.GetUserDataList(&nRecords, &ppUserData);
if (NO_ERROR == hr)
{
GCCrc = g_pIT120ControlSap->AnnouncePresenceRequest(
m_nConfID,
nodeType,
nodeProperties,
nodeName,
0, /* number_of_participants */
NULL, //partNameList, /* participant_name_list */
NULL, /* pwszSiteInfo */
0, /* number_of_network_addresses */
NULL, /* network_address_list */
NULL, //pAltID, /* alternative_node_id */
nRecords,/* number_of_user_data_members */
ppUserData /* user_data_list */
);
hr = ::GetGCCRCDetails(GCCrc);
}
delete nodeName;
}
if (GCC_NO_ERROR != GCCrc)
{
if (GCC_CONFERENCE_NOT_ESTABLISHED == GCCrc ||
GCC_INVALID_CONFERENCE == GCCrc)
{
TRACE_OUT(("DCRNCConference::AnnouncePresence: conf is gone."));
}
else
{
ERROR_OUT(("DCRNCConference::AnnouncePresence: failed, gcc_rc=%u", GCCrc));
}
}
DebugExitHRESULT(DCRNCConference::AnnouncePresence, hr);
return hr;
}
/****************************************************************************/
/* HandleGCCCallback() - see erncgccc.hpp */
/****************************************************************************/
void DCRNCConference::
HandleGCCCallback ( GCCMessage *pGCCMessage )
{
DebugEntry(DCRNCConference::HandleGCCCallback);
TRACE_OUT(("DCRNCConference::HandleGCCCallback: msg id=%u", pGCCMessage->message_type));
/************************************************************************/
/* Note that GCC_CREATE_IND and GCC_INVITE_IND callbacks are handled */
/* higher up the stack by the conference manager and are not passed */
/* onto us. */
/************************************************************************/
switch (pGCCMessage->message_type)
{
case GCC_CREATE_CONFIRM:
HandleCreateConfirm(&(pGCCMessage->u.create_confirm));
break;
case GCC_INVITE_CONFIRM:
HandleInviteConfirm(&(pGCCMessage->u.invite_confirm));
break;
case GCC_ADD_CONFIRM:
HandleAddConfirm(&(pGCCMessage->u.add_confirm));
break;
case GCC_DISCONNECT_INDICATION:
HandleDisconnectInd(&(pGCCMessage->u.disconnect_indication));
break;
case GCC_DISCONNECT_CONFIRM:
HandleDisconnectConfirm(
&(pGCCMessage->u.disconnect_confirm));
break;
case GCC_TERMINATE_INDICATION:
HandleTerminateInd(&(pGCCMessage->u.terminate_indication));
break;
case GCC_TERMINATE_CONFIRM:
HandleTerminateConfirm(&(pGCCMessage->u.terminate_confirm));
break;
case GCC_ANNOUNCE_PRESENCE_CONFIRM:
HandleAnnounceConfirm(&(pGCCMessage->u.announce_presence_confirm));
break;
case GCC_ROSTER_REPORT_INDICATION:
HandleRosterReport(pGCCMessage->u.conf_roster_report_indication.conference_roster);
break;
case GCC_ROSTER_INQUIRE_CONFIRM:
HandleRosterReport(pGCCMessage->u.conf_roster_inquire_confirm.conference_roster);
break;
case GCC_PERMIT_TO_ANNOUNCE_PRESENCE:
HandlePermitToAnnounce(&(pGCCMessage->u.permit_to_announce_presence));
break;
case GCC_EJECT_USER_INDICATION:
HandleEjectUser(&(pGCCMessage->u.eject_user_indication));
break;
case GCC_CONNECTION_BROKEN_INDICATION:
HandleConnectionBrokenIndication(&(pGCCMessage->u.connection_broken_indication));
break;
default :
WARNING_OUT(("Unrecognised event %d", pGCCMessage->message_type));
break;
}
DebugExitVOID(DCRNCConference::HandleGCCCallback);
}
void DCRNCConference::
HandleConnectionBrokenIndication ( ConnectionBrokenIndicationMessage * pConnDownMsg )
{
DebugEntry(DCRNCConference::HandleConnectionBrokenIndication);
// A logical connection in a conference has gone away.
// Find the associated logical connection (if it is still around)
// and Delete() it.
// This function is what causes a modem line to drop when someone
// invited into a conference over a modem leaves the conference.
CLogicalConnection *pConEntry = GetConEntry(pConnDownMsg->connection_handle);
if (NULL != pConEntry)
{
pConEntry->Delete(UI_RC_USER_DISCONNECTED);
}
DebugExitVOID(DCRNCConference::HandleConnectionBrokenIndication);
}
/****************************************************************************/
/* HandleAddConfirm - handle a GCC_ADD_CONFIRM message */
/****************************************************************************/
/****************************************************************************/
/* HandleAnnounceConfirm - handle a GCC_ANNOUNCE_PRESENCE_CONFIRM message */
/****************************************************************************/
void DCRNCConference::
HandleAnnounceConfirm ( AnnouncePresenceConfirmMessage * pAnnounceConf )
{
DebugEntry(DCRNCConference::HandleAnnounceConfirm);
/************************************************************************/
/* Map the return code to a conference return code. */
/************************************************************************/
HRESULT hr = ::GetGCCResultDetails(pAnnounceConf->result);
TRACE_OUT(("GCC event: GCC_ANNOUNCE_PRESENCE_CONFIRM"));
TRACE_OUT(("Result=%u", pAnnounceConf->result));
/************************************************************************/
/* If this failed, tell the base conference that we failed to start. */
/************************************************************************/
if (NO_ERROR != hr)
{
ERROR_OUT(("Failed to announce presence in conference"));
NotifyConferenceComplete(hr);
// bugbug: ??? Should we leave the conference here???
}
/************************************************************************/
/* Now sit and wait for our entry to appear in the conference roster. */
/************************************************************************/
DebugExitHRESULT(DCRNCConference::HandleAnnounceConfirm, hr);
}
/****************************************************************************/
/* HandleCreateConfirm - handle a GCC_CREATE_CONFIRM message. */
/****************************************************************************/
void DCRNCConference::
HandleCreateConfirm ( CreateConfirmMessage * pCreateConfirm )
{
DebugEntry(DCRNCConference::HandleCreateConfirm);
/************************************************************************/
/* Map the GCC result onto CONF_RC_ return code. */
/************************************************************************/
HRESULT hr = ::GetGCCResultDetails(pCreateConfirm->result);
TRACE_OUT(("GCC event: GCC_CREATE_CONFIRM"));
TRACE_OUT(("Result=%u", pCreateConfirm->result));
TRACE_OUT(("Conference ID %ld", pCreateConfirm->conference_id));
/************************************************************************/
/* Result of our attempt to start a new conference */
/************************************************************************/
if (NO_ERROR == hr)
{
/************************************************************************/
/* Store the conference ID. */
/************************************************************************/
m_nConfID = pCreateConfirm->conference_id;
}
else
{
ERROR_OUT(("Error %d creating new conference", hr));
/************************************************************************/
/* Pass any failure result onto the base conference. */
/************************************************************************/
NotifyConferenceComplete(hr);
}
DebugExitVOID(DCRNCConference::HandleCreateConfirm);
}
/****************************************************************************/
/* HandleDisconnectConfirm - handle a GCC_DISCONNECT_CONFIRM message. */
/****************************************************************************/
void DCRNCConference::
HandleDisconnectConfirm ( DisconnectConfirmMessage * pDiscConf )
{
DebugEntry(DCRNCConference::HandleDisconnectConfirm);
/************************************************************************/
/* Check the state. */
/************************************************************************/
if (m_eT120State != T120C_ST_PENDING_DISCONNECT)
{
WARNING_OUT(("Bad state %d, expecting %d",
T120C_ST_PENDING_DISCONNECT,
m_eT120State));
}
/************************************************************************/
/* Map the GCC result onto CONF_RC_ return code. */
/************************************************************************/
TRACE_OUT(("GCC event: GCC_DISCONNECT_CONFIRM"));
TRACE_OUT(("Result=%u", pDiscConf->result));
TRACE_OUT(("Conference ID %ld", pDiscConf->conference_id));
/************************************************************************/
/* We have successsfully left the conference, so tell the base */
/* conference about it. */
/************************************************************************/
g_pNCConfMgr->RemoveConference(this);
DebugExitVOID(DCRNCConference::HandleDisconnectConfirm);
}
/****************************************************************************/
/* HandleDisconnectInd - handle a GCC_DISCONNECT_INDICATION message. */
/****************************************************************************/
void DCRNCConference::
HandleDisconnectInd ( DisconnectIndicationMessage * pDiscInd )
{
DebugEntry(DCRNCConference::HandleDisconnectInd);
/************************************************************************/
/* Check the state. */
/************************************************************************/
TRACE_OUT(("GCC event: GCC_DISCONNECT_INDICATION"));
TRACE_OUT(("Conference ID %d", pDiscInd->conference_id));
TRACE_OUT(("Reason=%u", pDiscInd->reason));
TRACE_OUT(("Disconnected Node ID %d", pDiscInd->disconnected_node_id));
/************************************************************************/
/* If this is our node ID, we have left the conference, tell the CM we */
/* are dead. */
/************************************************************************/
if (pDiscInd->disconnected_node_id == m_nidMyself)
{
WARNING_OUT(("We have been disconnected from conference"));
// m_eT120State = T120C_ST_IDLE;
g_pNCConfMgr->RemoveConference(this);
}
DebugExitVOID(DCRNCConference::HandleDisconnectInd);
}
/****************************************************************************/
/* HandleEjectUser - handle a GCC_EJECT_USER_INDICATION message. */
/****************************************************************************/
void DCRNCConference::
HandleEjectUser ( EjectUserIndicationMessage * pEjectInd )
{
DebugEntry(DCRNCConference::HandleEjectUser);
TRACE_OUT(("GCC_EJECT_USER_INDICATION"));
TRACE_OUT(("Conference ID %ld", pEjectInd->conference_id));
TRACE_OUT(("Ejected node ID %d", pEjectInd->ejected_node_id));
TRACE_OUT(("Reason=%u", pEjectInd->reason));
/************************************************************************/
/* If the ejected node ID is ours, we have been tossed out of the */
/* conference, so tell CM about it. */
/************************************************************************/
if (pEjectInd->ejected_node_id == m_nidMyself)
{
/********************************************************************/
/* Reset the conference state first. */
/********************************************************************/
m_eT120State = T120C_ST_IDLE;
WARNING_OUT(("We have been thrown out of the conference"));
g_pNCConfMgr->RemoveConference(this);
}
DebugExitVOID(DCRNCConference::HandleEjectUser);
}
/****************************************************************************/
/* HandleInviteConfirm - handle a GCC_INVITE_CONFIRM message. */
/****************************************************************************/
void DCRNCConference::
HandleInviteConfirm ( InviteConfirmMessage * pInviteConf )
{
PT120PRODUCTVERSION pVersion;
DebugEntry(DCRNCConference::HandleInviteConfirm);
/************************************************************************/
/* Map the GCC result onto CONF_RC_ return code. */
/************************************************************************/
TRACE_OUT(("GCC event: GCC_INVITE_CONFIRM"));
TRACE_OUT(("Result=%u", pInviteConf->result));
if (pInviteConf->result == GCC_RESULT_SUCCESSFUL)
{
TRACE_OUT(("New node successfully invited into conference"));
ASSERT((ConnectionHandle)pInviteConf->connection_handle);
}
else
{
TRACE_OUT(("Error %d inviting new node into conference", pInviteConf->result));
}
// Notify the base conference that the invite has completed.
pVersion = ::GetVersionData(pInviteConf->number_of_user_data_members,
pInviteConf->user_data_list);
InviteComplete(pInviteConf->connection_handle,
::GetGCCResultDetails(pInviteConf->result),
pVersion);
DebugExitVOID(DCRNCConference::HandleInviteConfirm);
}
/****************************************************************************/
/* HandleJoinConfirm - handle a GCC_JOIN_CONFIRM message. */
/****************************************************************************/
void DCRNCConference::
HandleJoinConfirm ( JoinConfirmMessage * pJoinConf )
{
DebugEntry(DCRNCConference::HandleJoinConfirm);
m_nConfID = pJoinConf->conference_id;
HRESULT hr;
CLogicalConnection *pConEntry;
PT120PRODUCTVERSION pVersion;
hr = ::GetGCCResultDetails(pJoinConf->result);
TRACE_OUT(("GCC event: GCC_JOIN_CONFIRM"));
TRACE_OUT(("Result=%u", pJoinConf->result));
TRACE_OUT(("Conference ID %ld", pJoinConf->conference_id));
TRACE_OUT(("Locked %d", pJoinConf->conference_is_locked));
TRACE_OUT(("Listed %d", pJoinConf->conference_is_listed));
TRACE_OUT(("Conductible %d", pJoinConf->conference_is_conductible));
TRACE_OUT(("Connection Handle %d", pJoinConf->connection_handle));
TRACE_OUT(("Termination method %d", pJoinConf->termination_method));
pVersion = ::GetVersionData(pJoinConf->number_of_user_data_members,
pJoinConf->user_data_list);
// Check the state.
// If we are not expecting a join confirm at this point, then
// it is most likely that the connection went down whilst we
// were waiting for a join confirmation and we are in the middle of
// telling the user. In this case, just ignore the event.
if (m_eT120State != T120C_ST_PENDING_JOIN_CONFIRM)
{
WARNING_OUT(("Bad state %d, expecting %d",
T120C_ST_PENDING_JOIN_CONFIRM,
m_eT120State));
return;
}
if (NULL == m_ConnList.PeekHead())
{
WARNING_OUT(("Join confirm without a connection"));
return;
}
pConEntry = m_ConnList.PeekHead();
if ((pConEntry->GetState() != CONF_CON_PENDING_JOIN) &&
(pConEntry->GetState() != CONF_CON_PENDING_PASSWORD))
{
if (pConEntry->GetState() != CONF_CON_ERROR)
{
TRACE_OUT(("Join confirm indication ignored"));
}
return;
}
pConEntry->Grab(); // Grab the pending result to the user.
pConEntry->SetConnectionHandle(pJoinConf->connection_handle);
/************************************************************************/
/* Expected result of our attempt to join a conference. */
/* */
/* If it worked, save the conference ID, otherwise tell the base */
/* conference that our attempt to join has failed. */
/************************************************************************/
// There will always be a pConEntry when a JoinConfirm fires,
// even if a physical disconnect is racing the JoinConfirm
// because the physical disconnect handler will cause this code
// to be entered before the physical connection is destroyed,
// as this gives the most accurate return codes.
if (NO_ERROR == hr)
{
TRACE_OUT(("Join worked"));
pConEntry->SetState(CONF_CON_CONNECTED);
m_nConfID = pJoinConf->conference_id;
}
// If the result is an invalid password, then tell the UI
// so that it can put up an invalid password dialog.
// The UI is then supposed to either reissue the join request
// with a new password or end the conference.
// It is done this way to keep the connection up whilst the
// user is entering the password, and not re-connect.
if (UI_RC_INVALID_PASSWORD == hr)
{
// Put the conference in the correct state for allowing
// a second join attempt.
pConEntry->SetState(CONF_CON_PENDING_PASSWORD);
m_eT120State = T120C_ST_IDLE;
m_pbCred = pJoinConf->pb_remote_cred;
m_cbCred = pJoinConf->cb_remote_cred;
// Now tell the user about the result.
g_pCallbackInterface->OnConferenceStarted(this, hr);
}
else
// If the result is an error, then end the conference.
if (NO_ERROR != hr)
{
NotifyConferenceComplete(hr);
}
DebugExitVOID(DCRNCConference::HandleJoinConfirm);
}
/****************************************************************************/
/* HandlePermitToAnnounce - handle a GCC_PERMIT_TO_ANNOUNCE_PRESENCE */
/* message. */
/****************************************************************************/
void DCRNCConference::
HandlePermitToAnnounce ( PermitToAnnouncePresenceMessage * pAnnounce )
{
DebugEntry(DCRNCConference::HandlePermitToAnnounce);
TRACE_OUT(("GCC event: GCC_PERMIT_TO_ANNOUNCE_PRESENCE"));
TRACE_OUT(("Conference ID %ld", pAnnounce->conference_id));
TRACE_OUT(("Node ID %d", pAnnounce->node_id));
/************************************************************************/
/* Store the node ID. */
/************************************************************************/
m_nidMyself = pAnnounce->node_id;
// See if there is a new local connection that needs publishing in the roster.
if (! m_ConnList.IsEmpty())
{
m_ConnList.PeekHead()->NewLocalAddress();
}
/************************************************************************/
/* Announce our presence in the conference. */
/************************************************************************/
HRESULT hr = AnnouncePresence();
if (NO_ERROR == hr)
{
m_eT120State = T120C_ST_PENDING_ROSTER_ENTRY;
}
else
{
ERROR_OUT(("Failed to announce presence in conference, error %d", hr));
// bugbug: end conference?
}
DebugExitVOID(DCRNCConference::HandlePermitToAnnounce);
}
/****************************************************************************/
/* HandleRosterReportInd - handle a GCC_ROSTER_REPORT_INDICATION message. */
/****************************************************************************/
void DCRNCConference::
HandleRosterReport ( GCCConferenceRoster * pConferenceRoster )
{
PNC_ROSTER pRoster;
UINT i;
UINT numRecords = pConferenceRoster->number_of_records;
DebugEntry(DCRNCConference::HandleRosterReport);
TRACE_OUT(("GCC event: GCC_ROSTER_REPORT_INDICATION"));
TRACE_OUT(("Nodes added ? %d", pConferenceRoster->nodes_were_added));
TRACE_OUT(("Nodes removed ? %d", pConferenceRoster->nodes_were_removed));
TRACE_OUT(("Number of records %d", numRecords));
/************************************************************************/
/* If we are still setting up the conference, see whether we have */
/* appeared in the conference roster. */
/************************************************************************/
if (m_eT120State == T120C_ST_PENDING_ROSTER_ENTRY)
{
for (i = 0; i < numRecords ; i++)
{
if (pConferenceRoster->node_record_list[i]->node_id == m_nidMyself)
{
TRACE_OUT(("Found our entry in the roster"));
// We are in the roster! The conference has been
// successfully started so set the state and post
// a message to continue processing.
// This is so that callbacks can be made without getting
// blocked in T120.
m_eT120State = T120C_ST_PENDING_ROSTER_MESSAGE;
g_pNCConfMgr->PostWndMsg(NCMSG_FIRST_ROSTER_RECVD, (LPARAM) this);
}
}
}
/************************************************************************/
/* If we have successfully started, build an RNC roster from the */
/* conference roster and pass it up to the CM. */
/************************************************************************/
if (m_eT120State == T120C_ST_CONF_STARTED)
{
/********************************************************************/
/* Allocate memory for a roster large enough to hold all the */
/* entries. */
/********************************************************************/
DBG_SAVE_FILE_LINE
pRoster = (PNC_ROSTER) new BYTE[(sizeof(NC_ROSTER) +
((numRecords - 1) * sizeof(NC_ROSTER_NODE_ENTRY)))];
if (pRoster == NULL)
{
ERROR_OUT(("Failed to create new conference roster."));
}
else
{
pRoster->uNumNodes = numRecords;
pRoster->uLocalNodeID = m_nidMyself;
// Add the node details to the roster.
for (i = 0; i < numRecords ; i++)
{
pRoster->nodes[i].uNodeID = pConferenceRoster->node_record_list[i]->node_id;
pRoster->nodes[i].uSuperiorNodeID = pConferenceRoster->node_record_list[i]->superior_node_id;
pRoster->nodes[i].fMCU = (pConferenceRoster->node_record_list[i]->node_type == GCC_MCU);
pRoster->nodes[i].pwszNodeName = pConferenceRoster->node_record_list[i]->node_name;
pRoster->nodes[i].hUserData = pConferenceRoster->node_record_list[i];
// If we have been invited into the conference, then the CLogicalConnection
// list maintained by the conference will not have our superior node's UserID,
// so we need to fill that in here.
if (pRoster->nodes[i].uNodeID == pRoster->uLocalNodeID &&
pRoster->nodes[i].uSuperiorNodeID != 0)
{
// We do have a superior node, so find its CLogicalConnection and fill in the
// UserID. It turns out that the UserIDs of subordinate nodes are filled in
// by another mechanism, so the superior node should be the only entry with
// zero for a UserID.
#ifdef DEBUG
int nSuperiorNode = 0;
#endif
CLogicalConnection * pConEntry;
m_ConnList.Reset();
while (NULL != (pConEntry = m_ConnList.Iterate()))
{
if (pConEntry->GetConnectionNodeID() == 0)
{
pConEntry->SetConnectionNodeID((GCCNodeID)pRoster->nodes[i].uSuperiorNodeID);
#ifdef DEBUG
nSuperiorNode++;
#else
break;
#endif
}
}
ASSERT (nSuperiorNode <= 1);
}
}
NotifyRosterChanged(pRoster);
delete pRoster;
}
}
DebugExitVOID(DCRNCConference::HandleRosterReport);
}
/****************************************************************************/
/* HandleTerminateConfirm - handle a GCC_TERMINATE_CONFIRM message. */
/****************************************************************************/
void DCRNCConference::
HandleTerminateConfirm ( TerminateConfirmMessage * pTermConf )
{
DebugEntry(DCRNCConference::HandleTerminateConfirm);
/************************************************************************/
/* Check the state */
/************************************************************************/
if (m_eT120State != T120C_ST_PENDING_TERMINATE)
{
WARNING_OUT(("Bad state: unexpected terminate confirm")); // Go ahead anyway
}
/************************************************************************/
/* Map the GCC result onto CONF_RC_ return code. */
/************************************************************************/
TRACE_OUT(("GCC event: GCC_TERMINATE_CONFIRM"));
TRACE_OUT(("Result=%u", pTermConf->result));
TRACE_OUT(("Conference ID %d", pTermConf->conference_id));
/************************************************************************/
/* If the request failed, reset our state and tell the FE? */
/************************************************************************/
if (pTermConf->result != GCC_RESULT_SUCCESSFUL)
{
ERROR_OUT(("Error %d attempting to terminate conference", pTermConf->result));
m_eT120State = T120C_ST_CONF_STARTED;
}
/************************************************************************/
/* Our request to end the conference has worked - wait for the */
/* termination indication before telling the FE that we have died. */
/************************************************************************/
DebugExitVOID(DCRNCConference::HandleTerminateConfirm);
}
/****************************************************************************/
/* HandleTerminateInd - handle a GCC_TERMINATE_INDICATION message. */
/****************************************************************************/
void DCRNCConference::
HandleTerminateInd ( TerminateIndicationMessage * pTermInd )
{
DebugEntry(DCRNCConference::HandleTerminateInd);
TRACE_OUT(("GCC event: GCC_TERMINATE_INDICATION"));
TRACE_OUT(("Conference ID %d", pTermInd->conference_id));
TRACE_OUT(("Requesting node ID %d", pTermInd->requesting_node_id));
TRACE_OUT(("Reason=%u", pTermInd->reason));
/************************************************************************/
/* The conference has ended beneath us. Reset our internal state and */
/* tell the base conference about it. */
/************************************************************************/
m_eT120State = T120C_ST_IDLE;
g_pNCConfMgr->RemoveConference(this);
DebugExitVOID(DCRNCConference::HandleTerminateInd);
}
HRESULT DCRNCConference::
RefreshRoster(void)
{
DebugEntry(DCRNCConference::RefreshRoster);
// Check the state.
if (m_eT120State != T120C_ST_CONF_STARTED)
{
ERROR_OUT(("Bad state: refresh roster requested before conference up"));
return(UI_RC_CONFERENCE_NOT_READY);
}
// Issue the request
GCCError GCCrc = g_pIT120ControlSap->ConfRosterInqRequest(m_nConfID); // Conference ID
// Handle the result
HRESULT hr = ::GetGCCRCDetails(GCCrc);
TRACE_OUT(("GCC call: g_pIT120ControlSap->ConfRosterInqRequest, rc=%d", GCCrc));
DebugExitHRESULT(DCRNCConference::RefreshRoster, hr);
return hr;
}
/****************************************************************************/
/* Invite() - see erncgccc.hpp */
/****************************************************************************/
HRESULT DCRNCConference::
T120Invite
(
LPSTR pszNodeAddress,
BOOL fSecure,
CNCUserDataList *pUserDataInfoList,
ConnectionHandle *phInviteReqConn
)
{
GCCError GCCrc = GCC_NO_ERROR;
HRESULT hr;
UINT nUserDataRecords = 0;
GCCUserData **ppInfoUserData = NULL;
UINT nData;
PVOID pData;
char szAddress[RNC_MAX_NODE_STRING_LEN];
DebugEntry(DCRNCConference::T120Invite);
ASSERT(phInviteReqConn != NULL);
/************************************************************************/
/* Check the state. */
/************************************************************************/
if (m_eT120State != T120C_ST_CONF_STARTED)
{
ERROR_OUT(("Bad state: refresh roster requested before conference up"));
return(UI_RC_CONFERENCE_NOT_READY);
}
/************************************************************************/
/* Build the address from the node details. */
/************************************************************************/
::BuildAddressFromNodeDetails(pszNodeAddress, &szAddress[0]);
/************************************************************************/
/* Invite the specified node into the conference. */
/************************************************************************/
LPWSTR pwszNodeName;
// If there is any user data to be sent
if (pUserDataInfoList)
{
// Add versioning data
if (NO_ERROR == ::GetUserData(g_nVersionRecords, g_ppVersionUserData, &g_csguidVerInfo, &nData, &pData))
{
pUserDataInfoList->AddUserData(&g_csguidVerInfo, nData, pData);
}
pUserDataInfoList->GetUserDataList(&nUserDataRecords,&ppInfoUserData);
}
else
{
ppInfoUserData = g_ppVersionUserData;
nUserDataRecords = g_nVersionRecords;
}
if (NULL != (pwszNodeName = ::GetNodeName()))
{
GCCrc = g_pIT120ControlSap->ConfInviteRequest(
m_nConfID,
pwszNodeName, // caller_identifier
NULL, // calling_address
&szAddress[0], // called_address
fSecure, // secure connection?
nUserDataRecords, // number_of_user_data_members
ppInfoUserData, // user_data_list
phInviteReqConn // returned connection_handle
);
hr = ::GetGCCRCDetails(GCCrc);
TRACE_OUT(("GCC call: g_pIT120ControlSap->ConfInviteRequest, rc=%d", GCCrc));
TRACE_OUT(("Transport handle %d", (UINT) *phInviteReqConn));
TRACE_OUT(("Called address '%s'", &szAddress[0]));
delete pwszNodeName;
}
else
{
hr = UI_RC_OUT_OF_MEMORY;
}
DebugExitHRESULT(DCRNCConference::T120Invite, hr);
return hr;
}
/****************************************************************************/
/* Terminate() - see erncgccc.hpp */
/****************************************************************************/
#if 0 // LONCHANC
HRESULT DCRNCConference::
Terminate(void)
{
DebugEntry(DCRNCConference::Terminate);
/************************************************************************/
/* Request to terminate the conference. */
/************************************************************************/
GCCError GCCrc = ::GCCConferenceTerminateRequest(m_nConfID, GCC_REASON_USER_INITIATED);
HRESULT hr = ::GetGCCRCDetails(GCCrc);
TRACE_OUT(("GCC call: GCCConferenceTerminateRequest, rc=%d", GCCrc));
if (NO_ERROR == hr)
{
// Set the state to show we are about to die.
m_eT120State = T120C_ST_PENDING_TERMINATE;
}
else
{
ERROR_OUT(("Failed to terminate conference, GCC error %d", GCCrc));
}
DebugExitHRESULT(DCRNCConference::Terminate, hr);
return hr;
}
#endif // 0
/****************************************************************************/
/* SendText() - see erncgccc.hpp */
/****************************************************************************/
#if 0 // LONCHANC: not used
HRESULT DCRNCConference::
SendText
(
LPWSTR pwszTextMsg,
GCCNodeID node_id
)
{
DebugEntry(DCRNCConference::SendText);
/************************************************************************/
/* Request to send text to node in the conference. */
/************************************************************************/
GCCError GCCrc = ::GCCTextMessageRequest(m_nConfID, pwszTextMsg, node_id);
HRESULT hr = ::GetGCCRCDetails(GCCrc);
TRACE_OUT(("GCC call: GCCTextMessageRequest, rc=%d", GCCrc));
if (NO_ERROR != hr)
{
ERROR_OUT(("Failed to send text to user, GCC error %d", GCCrc));
}
DebugExitHRESULT(DCRNCConference::SendText, hr);
return hr;
}
#endif // 0
#if 0 // LONCHANC: not used
HRESULT DCRNCConference::
TimeRemaining
(
UINT nTimeRemaining,
GCCNodeID nidDestination
)
{
DebugEntry(DCRNCConference::TimeRemaining);
/************************************************************************/
/* Request remaining time of the conference */
/************************************************************************/
GCCError GCCrc = g_pIT120ControlSap->ConfTimeRemainingRequest(m_nConfID, nTimeRemaining, nidDestination);
HRESULT hr = ::GetGCCRCDetails(GCCrc);
TRACE_OUT(("GCC call: g_pIT120ControlSap->ConfTimeRemainingRequest, rc=%d", GCCrc));
if (NO_ERROR != hr)
{
ERROR_OUT(("Failed to send the time remaining to user, GCC error %d", GCCrc));
}
DebugExitHRESULT(DCRNCConference::TimeRemaining, hr);
return hr;
}
#endif // 0
/****************************************************************************/
/* Join() - see erncgccc.hpp */
/****************************************************************************/
HRESULT DCRNCConference::
T120Join
(
LPSTR pszNodeAddress,
BOOL fSecure,
LPCWSTR conferenceName,
CNCUserDataList *pUserDataInfoList,
LPCWSTR wszPassword
// REQUEST_HANDLE *phRequest
)
{
GCCError GCCrc = GCC_NO_ERROR;
HRESULT hr = NO_ERROR;
ConnectionHandle connectionHandle = 0;
GCCChallengeRequestResponse Password_Challenge;
GCCChallengeRequestResponse *pPassword_Challenge = NULL;
Password_Challenge.u.password_in_the_clear.numeric_string = NULL;
UINT nUserDataRecords = 0;
GCCUserData **ppInfoUserData = NULL;
UINT nData;
LPVOID pData;
char szAddress[RNC_MAX_NODE_STRING_LEN];
DebugEntry(DCRNCConference::T120Join);
/************************************************************************/
/* Check the state */
/************************************************************************/
ASSERT(m_eT120State == T120C_ST_IDLE);
/************************************************************************/
/* Build the address from the node details. */
/************************************************************************/
::BuildAddressFromNodeDetails(pszNodeAddress, &szAddress[0]);
// Set up password rubbish
if (! ::IsEmptyStringW(wszPassword))
{
pPassword_Challenge = & Password_Challenge;
Password_Challenge.password_challenge_type = GCC_PASSWORD_IN_THE_CLEAR;
hr = ::GetGCCFromUnicode(wszPassword,
&Password_Challenge.u.password_in_the_clear.numeric_string,
&Password_Challenge.u.password_in_the_clear.text_string);
}
if (NO_ERROR == hr)
{
LPWSTR pwszNodeName;
if (NULL != (pwszNodeName = ::GetNodeName()))
{
// Do not specify a numeric and text name when trying
// to join a conference because if a numeric name was
// autogenerated, rather than specified by the user,
// then it will not be correct on the node being joined.
// Consequently, remove the numeric name from the request
// and rediscover it, if needed, from the GCC_JOIN_CONFIRM indication
// (this is not currently done).
if ((m_ConfName.numeric_string != NULL) && (m_ConfName.text_string != NULL))
{
delete m_ConfName.numeric_string;
m_ConfName.numeric_string = NULL;
}
// If there is any user data to be sent
if (pUserDataInfoList)
{
// Add versioning data
if (NO_ERROR == ::GetUserData(g_nVersionRecords, g_ppVersionUserData, &g_csguidVerInfo, &nData, &pData))
{
pUserDataInfoList->AddUserData(&g_csguidVerInfo, nData, pData);
}
pUserDataInfoList->GetUserDataList(&nUserDataRecords,&ppInfoUserData);
}
else
{
ppInfoUserData = g_ppVersionUserData;
nUserDataRecords = g_nVersionRecords;
}
GCCrc = g_pIT120ControlSap->ConfJoinRequest(&m_ConfName,
NULL, // called_node_modifier
NULL, // calling_node_modifier
NULL, // convener_password
pPassword_Challenge, // password_challenge
pwszNodeName, // caller_identifier
NULL, // calling_address
&szAddress[0], // called_address
fSecure,
NULL, // domain_parameters
0, // number_of_network_addresses
NULL, // local_network_address_list
nUserDataRecords, // number_of_user_data_members
ppInfoUserData, // user_data_list
&connectionHandle, // connection_handle
&m_nConfID
);
delete pwszNodeName;
hr = ::GetGCCRCDetails(GCCrc);
TRACE_OUT(("GCC call: g_pIT120ControlSap->ConfJoinRequest, rc=%d", GCCrc));
TRACE_OUT(("Called address '%s'", &szAddress[0]));
if (NO_ERROR == hr)
{
m_eT120State = T120C_ST_PENDING_JOIN_CONFIRM;
}
}
else
{
hr = UI_RC_OUT_OF_MEMORY;
}
}
delete Password_Challenge.u.password_in_the_clear.numeric_string;
DebugExitHRESULT(DCRNCConference::T120Join, hr);
return hr;
}
/****************************************************************************/
/* StartLocal() - see erncgccc.hpp */
/****************************************************************************/
HRESULT DCRNCConference::
T120StartLocal(BOOL fSecure)
{
GCCError GCCrc;
HRESULT hr;
ConnectionHandle hConnection = 0;
GCCConferencePrivileges priv = {1,1,1,1,1};
WCHAR pwszRDS[] = RDS_CONFERENCE_DESCRIPTOR;
DebugEntry(DCRNCConference::T120StartLocal);
/************************************************************************/
/* Call GCC_Conference_Create_Request and wait for the confirmation */
/* event. */
/************************************************************************/
GCCConfCreateRequest ccr;
::ZeroMemory(&ccr, sizeof(ccr));
ccr.Core.conference_name = &m_ConfName;
// ccr.Core.conference_modifier = NULL;
// ccr.Core.use_password_in_the_clear = 0;
// ccr.Core.conference_is_locked = 0;
ccr.Core.conference_is_listed = 1;
// ccr.Core.conference_is_conductible = 0;
ccr.Core.termination_method = GCC_MANUAL_TERMINATION_METHOD;
ccr.Core.conduct_privilege_list = &priv; // Conductor priveleges
ccr.Core.conduct_mode_privilege_list = &priv; // Member priveleges in conducted conference
ccr.Core.non_conduct_privilege_list = &priv; // Member priveleges in non-conducted conference
// ccr.Core.pwszConfDescriptor = NULL;
OSVERSIONINFO osvi;
osvi.dwOSVersionInfoSize = sizeof(osvi);
if (FALSE == ::GetVersionEx (&osvi))
{
ERROR_OUT(("GetVersionEx() failed!"));
}
if ( VER_PLATFORM_WIN32_NT == osvi.dwPlatformId && g_bRDS)
{
ccr.Core.pwszConfDescriptor = pwszRDS;
}
// ccr.Core.pwszCallerID = NULL;
// ccr.Core.calling_address = NULL;
// ccr.Core.called_address = NULL;
// ccr.Core.domain_parameters = NULL;
// ccr.Core.number_of_network_addresses = 0;
// ccr.Core.network_address_list = NULL;
ccr.Core.connection_handle = &hConnection;
// ccr.convener_password = NULL;
// ccr.password = NULL;
// ccr.number_of_user_data_members = 0;
// ccr.user_data_list = NULL;
ccr.fSecure = fSecure;
GCCrc = g_pIT120ControlSap->ConfCreateRequest(&ccr, &m_nConfID);
hr = ::GetGCCRCDetails(GCCrc);
TRACE_OUT(("GCC call: g_pIT120ControlSap->ConfCreateRequest"));
TRACE_OUT(("LOCAL CONFERENCE"));
TRACE_OUT(("Connection handle %d", (UINT) hConnection));
/************************************************************************/
/* Map the GCC return code to a conference return code. */
/************************************************************************/
if (NO_ERROR == hr)
{
// Set the state.
m_eT120State = T120C_ST_PENDING_START_CONFIRM;
}
else
{
ERROR_OUT(("GCC Error %d starting local conference", GCCrc));
}
DebugExitHRESULT(DCRNCConference::T120StartLocal, hr);
return hr;
}
// LONCHANC: please do not remove this chunk of code.
#ifdef ENABLE_START_REMOTE
/****************************************************************************/
/* StartRemote() - see erncgccc.hpp */
/****************************************************************************/
HRESULT DCRNCConference::
T120StartRemote ( LPSTR pszNodeAddress )
{
// Do not allow attempts to create T120 conferences on remote nodes.
// The code that was written to do this is left here in case someone
// wants to resurrect this functionality in the future.
GCCError GCCrc;
HRESULT hr;
ConnectionHandle connectionHandle = 0;
GCCConferencePrivileges priv = {1,1,1,1,1};
char szAddress[RNC_MAX_NODE_STRING_LEN];
DebugEntry(DCRNCConference::T120StartRemote);
/************************************************************************/
/* Build the address from the node details. */
/************************************************************************/
::BuildAddressFromNodeDetails(pszNodeAddress, &szAddress[0]);
/************************************************************************/
/* Call GCC_Conference_Create_Request and wait for the confirmation */
/* event. */
/************************************************************************/
TRACE_OUT(("Starting New Remote Conference..."));
/************************************************************************/
/* Call GCC_Conference_Create_Request and wait for the confirmation */
/* event. */
/************************************************************************/
GCCConfCreateRequest ccr;
::ZeroMemory(&ccr, sizeof(ccr));
ccr.Core.conference_name = &m_ConfName;
ccr.Core.conference_modifier = NULL;
// ccr.Core.use_password_in_the_clear = 0;
// ccr.Core.conference_is_locked = 0;
ccr.Core.conference_is_listed = 1;
ccr.Core.conference_is_conductible = 1;
ccr.Core.termination_method = GCC_AUTOMATIC_TERMINATION_METHOD;
ccr.Core.conduct_privilege_list = &priv; // Conductor priveleges
ccr.Core.conduct_mode_privilege_list = &priv; // Member priveleges in conducted conference
ccr.Core.non_conduct_privilege_list = &priv; // Member priveleges in non-conducted conference
// ccr.Core.pwszConfDescriptor = NULL;
// ccr.Core.pwszCallerID = NULL;
// ccr.Core.calling_address = NULL;
ccr.Core.called_address = &szAddress[0];
// ccr.Core.domain_parameters = NULL;
// ccr.Core.number_of_network_addresses = 0;
// ccr.Core.network_address_list = NULL;
ccr.Core.connection_handle = &connectionHandle;
// ccr.convener_password = NULL;
// ccr.password = NULL;
// ccr.number_of_user_data_members = 0;
// ccr.user_data_list = NULL;
GCCrc = g_pIT120ControlSap->ConfCreateRequest(&ccr, &m_nConfID);
hr = ::GetGCCRCDetails(GCCrc);
TRACE_OUT(("GCC call: g_pIT120ControlSap->ConfCreateRequest"));
TRACE_OUT(("Called address '%s'", &szAddress[0]));
TRACE_OUT(("Connection handle %d", connectionHandle));
/************************************************************************/
/* Map the GCC return code to a conference return code. */
/************************************************************************/
if (NO_ERROR != hr)
{
ERROR_OUT(("GCC Error %d starting local conference", GCCrc));
}
else
{
// Set the state.
m_eT120State = T120C_ST_PENDING_START_CONFIRM;
}
DebugExitHRESULT(DCRNCConference::T120StartRemote, hr);
return hr;
}
#endif // ENABLE_START_REMOTE
void LoadAnnouncePresenceParameters
(
GCCNodeType *nodeType,
GCCNodeProperties *nodeProperties,
LPWSTR *ppwszNodeName,
LPWSTR *ppwszSiteInformation
)
{
DebugEntry(LoadAnnouncePresenceParameters);
/* The following key does not currently exist.
* If we ever decide to use it, we should un-comment this call
* and following calls in this function, designed to access the
* registry entries under this key.
* Some of the rest of the registry calls are under #if 0, #else, #endif
* clauses.
*/
#if 0
RegEntry ConferenceKey(DATA_CONFERENCING_KEY, HKEY_LOCAL_MACHINE);
#endif // 0
// Get the type of node controller.
if (nodeType)
{
#if 0
*nodeType = ConferenceKey.GetNumber(REGVAL_NODE_CONTROLLER_MODE, GCC_MULTIPORT_TERMINAL);
#else // 0
*nodeType = GCC_MULTIPORT_TERMINAL;
#endif // 0
TRACE_OUT(("Node type %d", *nodeType));
}
// Load the node properties.
if (nodeProperties)
{
#if 0
*nodeProperties = ConferenceKey.GetNumber(REGVAL_NODE_CONTROLLER_PROPERTY,
GCC_NEITHER_PERIPHERAL_NOR_MANAGEMENT);
#else // 0
*nodeProperties = GCC_NEITHER_PERIPHERAL_NOR_MANAGEMENT;
#endif // 0
TRACE_OUT(("Node properties %d", *nodeProperties));
}
// Get site information.
// Ignore if no site info.
#if 0
if (ppwszSiteInformation)
{
*ppwszSiteInformation = ::AnsiToUnicode(ConferenceKey.GetString(REGVAL_NODE_CONTROLLER_SITE_INFO));
}
#endif // 0
if (ppwszNodeName)
{
// Rely upon GetNodeName returning NULL pointer if error.
// Note that successful if got this, so no need to free on error.
*ppwszNodeName = ::GetNodeName();
}
DebugExitVOID(LoadAnnouncePresenceParameters);
}
/****************************************************************************/
/* Build the address from the node details. */
/****************************************************************************/
void BuildAddressFromNodeDetails
(
LPSTR pszNodeAddress,
LPSTR pszDstAddress
)
{
DebugEntry(BuildAddressFromNodeDetails);
/************************************************************************/
/* GCC address take the form <transport type>:address. */
/************************************************************************/
TRACE_OUT(("BuildAddressFromNodeDetails:: TCP address '%s'", pszNodeAddress));
/************************************************************************/
/* Add the prefix for this transport type. */
/************************************************************************/
/************************************************************************/
/* Add the separator followed by the actual address. */
/************************************************************************/
::lstrcpyA(pszDstAddress, RNC_GCC_TRANSPORT_AND_SEPARATOR);
::lstrcatA(pszDstAddress, pszNodeAddress);
DebugExitVOID(BuildAddressFromNodeDetails);
}