/****************************************************************************/ /* */ /* 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 = UI_RC_OUT_OF_MEMORY; 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 :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); }