/****************************************************************************/ /* */ /* ERNCCONF.CPP */ /* */ /* Base Conference class for the Reference System Node Controller. */ /* */ /* Copyright Data Connection Ltd. 1995 */ /* */ /****************************************************************************/ /* Changes: */ /* */ /* 12Jul95 NFC Created. */ /* 05Oct95 NFC SFR 6206 Treat a "Join" as an incoming call. */ /* 11Oct95 PM Relax checks on conference termination to */ /* prevent "no win" situations */ /* Support START_ALTERNATE from TPhys API */ /* */ /****************************************************************************/ #include "precomp.h" DEBUG_FILEZONE(ZONE_GCC_NC); #include "ernccons.h" #include "nccglbl.hpp" #include "erncvrsn.hpp" #include #include "connect.h" #include "erncconf.hpp" #include "ernctrc.h" #include "ernccm.hpp" #include "plgxprt.h" #include extern PController g_pMCSController; DCRNCConference:: DCRNCConference ( LPCWSTR pwcszConfName, GCCConfID nConfID, BOOL fSecure, HRESULT *pRetCode ) : CRefCount(MAKE_STAMP_ID('N','C','C','F')), m_fNotifyToDo(FALSE), m_fActive(TRUE), #ifdef _DEBUG m_fAppendedToConfList(FALSE), #endif m_pInviteUI(NULL), m_pszFirstRemoteNodeAddress(NULL), m_nConfID(nConfID), m_eState(CONF_ST_UNINITIALIZED), m_fIncoming(FALSE), m_pbHashedPassword(NULL), m_cbHashedPassword(0), m_pwszPassword(NULL), m_pszNumericPassword(NULL), // T120 conference m_eT120State(T120C_ST_IDLE), m_nidMyself(0), m_fSecure(fSecure), m_nInvalidPasswords(0) { DebugEntry(DCRNCConference::DCRNCConference); // Save the conference name. DBG_SAVE_FILE_LINE m_pwszConfName = ::My_strdupW(pwcszConfName); if (! ::IsEmptyStringW(m_pwszConfName)) { *pRetCode = NO_ERROR; } else { *pRetCode = (NULL == m_pwszConfName) ? UI_RC_OUT_OF_MEMORY : UI_RC_NO_CONFERENCE_NAME; } // T120 conference m_ConfName.numeric_string = NULL; m_ConfName.text_string = NULL; DebugExitVOID(DCRNCConference::DCRNCConference); } /****************************************************************************/ /* Destructor - see erncconf.h */ /****************************************************************************/ DCRNCConference:: ~DCRNCConference(void) { DebugEntry(DCRNCConference::~DCRNCConference); ASSERT(! m_fAppendedToConfList); // delete all the name strings LPSTR pszStr; while (NULL != (pszStr = m_NodeIdNameList.Get())) { delete [] pszStr; } // Delete all the usr data CNCUserDataList *pUserDataList; while (NULL != (pUserDataList = m_UserDataList.Get())) { delete pUserDataList; } delete m_pwszConfName; // If there is a password, delete it. delete []m_pbHashedPassword; delete m_pwszPassword; delete m_pszNumericPassword; delete m_pszFirstRemoteNodeAddress; // T120 conference delete m_ConfName.numeric_string; DebugExitVOID(DCRNCConference::~DCRNCConference); } void DCRNCConference:: OnRemoved(BOOL fReleaseNow) { DebugEntry(DCRNCConference::OnRemoved); CLogicalConnection *pConEntry; #ifdef _DEBUG m_fAppendedToConfList = FALSE; #endif // Issue a request to leave the conference. // This request may fail, but may as well let leave validate // itself, rather than put an extra check in here. // See comments in RemoveConference() and Leave() for more details // if interested. if (T120C_ST_PENDING_DISCONNECT != m_eT120State && T120C_ST_PENDING_TERMINATE != m_eT120State) { Leave(); } // Take the conference out of the list of pending invites. g_pNCConfMgr->RemoveInviteIndWorkItem(m_pInviteUI); // End all physical connections in use by this conference, // and inform the user of the results of pending events. while (NULL != (pConEntry = m_ConnList.Get())) { pConEntry->Delete(UI_RC_CONFERENCE_GOING_DOWN); } // // LONCHANC: This destructor may be called inside // ConfMgr::ReleaseInterface(). As a result, the global pointer // to the callback interface may already be nulled out. // Check it before use it. // // ASSERT(2 == GetRefCount()); // Tell UI its handle to conference is no longer valid. if (NULL != g_pCallbackInterface) { g_pCallbackInterface->OnConferenceEnded((CONF_HANDLE) this); } else { ERROR_OUT(("DCRNCConference::OnRemoved: g_pCallbackInterface is null")); } // ASSERT(1 == GetRefCount()); if (fReleaseNow) { ReleaseNow(); } else { Release(); } DebugExitVOID(DCRNCConference::OnRemoved); } // // IDataConference Interface // STDMETHODIMP_(void) DCRNCConference:: ReleaseInterface(void) { DebugEntry(DCRNCConference::ReleaseInterface); InterfaceEntry(); Release(); DebugExitVOID(DCRNCConference::ReleaseInterface); } STDMETHODIMP_(UINT) DCRNCConference:: GetConferenceID(void) { DebugEntry(DCRNCConference::GetConferenceID); InterfaceEntry(); DebugExitINT(DCRNCConference::GetConferenceID, (UINT) m_nConfID); return m_nConfID; } STDMETHODIMP DCRNCConference:: Leave(void) { DebugEntry(DCRNCConference::Leave); InterfaceEntry(); GCCError GCCrc; HRESULT hr; switch (m_eT120State) { // LONCHANC: Added the following two cases for cancellation. case T120C_ST_PENDING_START_CONFIRM: case T120C_ST_PENDING_JOIN_CONFIRM: case T120C_ST_PENDING_ROSTER_ENTRY: case T120C_ST_PENDING_ROSTER_MESSAGE: case T120C_ST_PENDING_ANNOUNCE_PERMISSION: // User has called leave on a conference when it is being brought up. // Drop through to issue a disconnect request to T120. case T120C_ST_CONF_STARTED: // Set the state of the conference to note that we are // disconnecting from T120. // LONCHANC: this is a must to avoid reentrance of this Leave() // when direct InviteConfirm hits Node Controller later. m_eT120State = T120C_ST_PENDING_DISCONNECT; // User has requested to leave the conference after it has been // started as a T120 conference, so ask T120 to end the conference // before removing internal data structures. GCCrc = g_pIT120ControlSap->ConfDisconnectRequest(m_nConfID); hr = ::GetGCCRCDetails(GCCrc); TRACE_OUT(("GCC call: g_pIT120ControlSap->ConfDisconnectRequest, rc=%d", GCCrc)); if (NO_ERROR == hr) { break; } // T120 won't let us leave a conference that we think we are in. // Take this to mean that T120 doesn't know about the conference // anymore and just destroy our own knowledge of the conference. WARNING_OUT(("DCRNCConference::Leave: Failed to leave conference, GCC error %d", GCCrc)); // Drop through to destroy our references. case T120C_ST_IDLE: // User has requested to leave a conference that has not been // started. // This should only happen when told that a conference join // request supplied an invalid password and the user gives up // on attempting to join the conference (or shuts down conferencing). // Just do the same processing as would be done when a T120 // disconnect confirmation fires. g_pNCConfMgr->RemoveConference(this); hr = NO_ERROR; break; case T120C_ST_PENDING_DISCONNECT: case T120C_ST_PENDING_TERMINATE: // User has requested to leave a conference that is already // going down (most likely because of a prior request to leave). hr = UI_RC_CONFERENCE_GOING_DOWN; WARNING_OUT(("DCRNCConference::Leave: conference already going down, state=%d", m_eT120State)); break; default: // User has called leave on a conference when he shouldn't // (e.g. when it is being brought up). // This is very unlikely to happen as the user doesn't know // the conference handle at this point. hr = UI_RC_INVALID_REQUEST; ERROR_OUT(("DCRNCConference::Leave: invalid state=%d", m_eT120State)); break; } DebugExitHRESULT(DCRNCConference::Leave, hr); return hr; } STDMETHODIMP DCRNCConference:: EjectUser ( UINT nidEjected ) { DebugEntry(DCRNCConference::EjectUser); InterfaceEntry(); GCCError GCCrc = g_pIT120ControlSap->ConfEjectUserRequest(m_nConfID, (UserID) nidEjected, GCC_REASON_USER_INITIATED); HRESULT hr = ::GetGCCRCDetails(GCCrc); if (NO_ERROR != hr) { ERROR_OUT(("DCRNCConference::EjectUser: Failed to eject user conference, GCC error %d", GCCrc)); } CLogicalConnection *pConEntry = GetConEntryByNodeID((GCCNodeID) nidEjected); if (NULL != pConEntry) { pConEntry->Delete(UI_RC_USER_DISCONNECTED); } DebugExitHRESULT(DCRNCConference::EjectUser, hr); return hr; } STDMETHODIMP DCRNCConference:: Invite ( LPCSTR pcszNodeAddress, REQUEST_HANDLE * phRequest ) { DebugEntry(DCRNCConference::Invite); InterfaceEntry(); HRESULT hr; #if defined(TEST_PLUGGABLE) && defined(_DEBUG) if (g_fWinsockDisabled) { pcszNodeAddress = ::FakeNodeAddress(pcszNodeAddress); } #endif if (NULL != pcszNodeAddress && NULL != phRequest) { // if winsock is disabled, block any IP address or machine name if (g_fWinsockDisabled) { if (! IsValidPluggableTransportName(pcszNodeAddress)) { return UI_RC_NO_WINSOCK; } } // Check that person is not already in the conference. if (GetConEntry((LPSTR) pcszNodeAddress)) { hr = UI_RC_ALREADY_IN_CONFERENCE; } else { hr = StartConnection((LPSTR) pcszNodeAddress, CONF_CON_PENDING_INVITE, m_fSecure, phRequest); } if (NO_ERROR != hr) { ERROR_OUT(("Error adding connection")); } } else { hr = (pcszNodeAddress == NULL) ? UI_RC_NO_ADDRESS : UI_RC_BAD_PARAMETER; ERROR_OUT(("DCRNCConference::Invite: invalid parameters, hr=0x%x", (UINT) hr)); } // Sit and wait for the connection to complete before continuing. DebugExitHRESULT(DCRNCConference::Invite, hr); return hr; } STDMETHODIMP DCRNCConference:: CancelInvite ( REQUEST_HANDLE hRequest ) { DebugEntry(DCRNCConference::CancelInvite); InterfaceEntry(); HRESULT hr; CLogicalConnection *pConEntry = (CLogicalConnection *) hRequest; if (NULL != pConEntry) { ConnectionHandle hConn = pConEntry->GetInviteReqConnHandle(); ASSERT(NULL != hConn); g_pIT120ControlSap->CancelInviteRequest(m_nConfID, hConn); hr = NO_ERROR; } else { hr = UI_RC_BAD_PARAMETER; } DebugExitHRESULT(DCRNCConference::CancelInvite, hr); return hr; } STDMETHODIMP DCRNCConference:: GetCred ( PBYTE *ppbCred, DWORD *pcbCred ) { DebugEntry(DCRNCConference::GetCred); HRESULT hr = UI_RC_INTERNAL_ERROR; if (m_pbCred) { *ppbCred = m_pbCred; *pcbCred = m_cbCred; hr = NO_ERROR; } DebugExitHRESULT(DCRNCConference::GetCred, hr); return hr; } STDMETHODIMP DCRNCConference:: InviteResponse ( BOOL fResponse ) { DebugEntry(DCRNCConference::InviteResponse); InterfaceEntry(); HRESULT hrResponse = fResponse ? NO_ERROR : UI_RC_USER_REJECTED; HRESULT hr = InviteResponse(hrResponse); DebugExitHRESULT(DCRNCConferenceManager::InviteResponse, hr); return hr; } HRESULT DCRNCConference:: InviteResponse ( HRESULT hrResponse ) { DebugEntry(DCRNCConference::InviteResponse); InterfaceEntry(); GCCResult Result = ::MapRCToGCCResult(hrResponse); GCCError GCCrc = g_pIT120ControlSap->ConfInviteResponse( m_nConfID, NULL, m_fSecure, NULL, // domain parms 0, // number_of_network_addresses NULL, // local_network_address_list 0, NULL, Result); if ((GCCrc == GCC_RESULT_SUCCESSFUL) && (Result == GCC_RESULT_SUCCESSFUL)) { // Have successfully posted an invite response acceptance. // Note that the conference is expecting permission to // announce its presence. m_eT120State = T120C_ST_PENDING_ANNOUNCE_PERMISSION; } else { // Have rejected/failed a request to be invited into a conference. // Remove the references that were created to track the potential // new conference. g_pNCConfMgr->RemoveConference(this); } HRESULT hr = ::GetGCCRCDetails(GCCrc); DebugExitHRESULT(DCRNCConferenceManager::InviteResponse, hr); return hr; } STDMETHODIMP DCRNCConference:: JoinResponse ( BOOL fResponse ) { DebugEntry(DCRNCConference::JoinResponse); InterfaceEntry(); HRESULT hr; CJoinIndWork *pJoinUI = g_pNCConfMgr->PeekFirstJoinIndWorkItem(); if (NULL != pJoinUI) { if (pJoinUI->GetConference() == this) { if (fResponse && pJoinUI->GetConEntry()->NewLocalAddress()) { AnnouncePresence(); } hr = pJoinUI->Respond(fResponse ? GCC_RESULT_SUCCESSFUL : GCC_RESULT_USER_REJECTED); // Done responding to event, so can now remove from list and process // another pending event. // Note: since the handling of the previous event is still // potentially on the stack, this can cause the stack to grow, // but this should not be a problem for Win32. g_pNCConfMgr->RemoveJoinIndWorkItem(pJoinUI); } else { hr = UI_RC_BAD_PARAMETER; } } else { ERROR_OUT(("DCRNCConference::JoinResponse: Empty m_JoinIndWorkList, fResponse=%u", fResponse)); hr = UI_RC_INTERNAL_ERROR; } DebugExitHRESULT(DCRNCConference::JoinResponse, hr); return hr; } STDMETHODIMP DCRNCConference:: LaunchGuid ( const GUID *pcGUID, UINT auNodeIDs[], UINT cNodes ) { DebugEntry(DCRNCConference::LaunchGuid); InterfaceEntry(); HRESULT hr; if (NULL != pcGUID) { // // We probably should support conference-wide app invoke by // cNodes==0 and auNodeIDs==NULL. // Implement it later... // if ((0 != cNodes) || (NULL != auNodeIDs)) { // UserID is a short. We have to translate these UserID to a new array. // Try not to allocate memory for small array. UserID *pNodeIDs; const UINT c_cRemote = 16; UserID auidRemote[c_cRemote]; if (cNodes <= c_cRemote) { pNodeIDs = auidRemote; } else { pNodeIDs = new UserID[cNodes]; if (NULL == pNodeIDs) { hr = UI_RC_OUT_OF_MEMORY; goto MyExit; } } // Copy all the node IDs. for (UINT i = 0; i < cNodes; i++) { pNodeIDs[i] = (UserID)auNodeIDs[i]; } // Construct the key GCCError GCCrc; GCCObjectKey * pAppKey; GCCAppProtocolEntity AppEntity; GCCAppProtocolEntity * pAppEntity; BYTE h221Key[CB_H221_GUIDKEY]; ::CreateH221AppKeyFromGuid(h221Key, (GUID *) pcGUID); ::ZeroMemory(&AppEntity, sizeof(AppEntity)); pAppKey = &AppEntity.session_key.application_protocol_key; pAppKey->key_type = GCC_H221_NONSTANDARD_KEY; pAppKey->h221_non_standard_id.length = sizeof(h221Key); pAppKey->h221_non_standard_id.value = h221Key; // AppEntity.session_key.session_id = 0; // default session // AppEntity.number_of_expected_capabilities = 0; // no capabilities // AppEntity.expected_capabilities_list = NULL; AppEntity.startup_channel_type = MCS_NO_CHANNEL_TYPE_SPECIFIED; AppEntity.must_be_invoked = TRUE; pAppEntity = &AppEntity; GCCrc = g_pIT120ControlSap->AppletInvokeRequest(m_nConfID, 1, &pAppEntity, cNodes, pNodeIDs); hr = ::GetGCCRCDetails(GCCrc); if (NO_ERROR != hr) { ERROR_OUT(("DCRNCConference::LaunchGuid: AppletInvokeRequest failed, GCCrc=%u", GCCrc)); } if (pNodeIDs != auidRemote) { delete [] pNodeIDs; } } else { hr = UI_RC_BAD_PARAMETER; ERROR_OUT(("DCRNCConference::LaunchGuid: invalid combination, cNodes=%u. auNodeIDs=0x%p", cNodes, auNodeIDs)); } } else { hr = UI_RC_BAD_PARAMETER; ERROR_OUT(("DCRNCConference::LaunchGuid: null pcGUID")); } MyExit: DebugExitHRESULT(DCRNCConference::LaunchGuid, hr); return hr; } STDMETHODIMP DCRNCConference:: SetUserData ( const GUID *pcGUID, UINT cbData, LPVOID pData ) { DebugEntry(DCRNCConference::SetUserData); InterfaceEntry(); HRESULT hr; if (0 != cbData || NULL != pData) { hr = m_LocalUserData.AddUserData((GUID *) pcGUID, cbData, pData); } else { hr = UI_RC_BAD_PARAMETER; ERROR_OUT(("DCRNCConference::SetUserData: invalid combination, cbData=%u. pData=0x%p", cbData, pData)); } DebugExitHRESULT(DCRNCConference::SetUserData, hr); return hr; } STDMETHODIMP_(BOOL) DCRNCConference:: IsSecure () { return m_fSecure; } STDMETHODIMP DCRNCConference:: SetSecurity ( BOOL fSecure ) { m_fSecure = fSecure; return S_OK; } STDMETHODIMP DCRNCConference:: UpdateUserData(void) { DebugEntry(DCRNCConference::UpdateUserData); InterfaceEntry(); HRESULT hr = AnnouncePresence(); DebugExitHRESULT(DCRNCConference::UpdateUserData, hr); return hr; } STDMETHODIMP DCRNCConference:: GetLocalAddressList ( LPWSTR pwszBuffer, UINT cchBuffer ) { DebugEntry(DCRNCConference::GetLocalAddressList); InterfaceEntry(); HRESULT hr; UINT cAddrs; LPCSTR *pAddresses = NULL; ASSERT(cchBuffer > 1); // buffer should have enough room for a double NULL terminator hr = m_LocalAddressList.GetLocalAddressList(&cAddrs, &pAddresses); if (NO_ERROR == hr) { LPWSTR pwszPos = pwszBuffer; for (UINT i = 0; i < cAddrs; i++) { ASSERT(pAddresses[i]); LPWSTR pwszAddress = ::AnsiToUnicode(pAddresses[i]); UINT cchAddress = ::My_strlenW(pwszAddress); if ((cchBuffer - (pwszPos - pwszBuffer)) < (RNC_GCC_TRANSPORT_AND_SEPARATOR_LENGTH + cchAddress + 2)) { // NOTE: +2 insures room for the two '\0' chars // If there isn't room, break out here: break; } LStrCpyW(pwszPos, RNC_GCC_TRANSPORT_AND_SEPARATOR_UNICODE); pwszPos += RNC_GCC_TRANSPORT_AND_SEPARATOR_LENGTH; LStrCpyW(pwszPos, pwszAddress); pwszPos += cchAddress; *pwszPos = L'\0'; pwszPos++; delete pwszAddress; } if ((UINT)(pwszPos - pwszBuffer) < cchBuffer) { *pwszPos = L'\0'; } if (0 == cAddrs) { // No addresses in the string, so insure that the string returned is L"\0\0" pwszPos[1] = L'\0'; } delete [] pAddresses; } else { ERROR_OUT(("DCRNCConference::GetLocalAddressList: GetLocalAddressList failed, hr=0x%x", (UINT) hr)); } DebugExitHRESULT(DCRNCConference::GetLocalAddressList, hr); return hr; } STDMETHODIMP_(UINT) DCRNCConference:: GetParentNodeID(void) { DebugEntry(DCRNCConference::GetConferenceID); InterfaceEntry(); GCCNodeID nidParent = 0; g_pIT120ControlSap->GetParentNodeID(m_nConfID, &nidParent); DebugExitINT(DCRNCConference::GetConferenceID, (UINT) nidParent); return (UINT) nidParent; } CLogicalConnection * DCRNCConference:: GetConEntry ( ConnectionHandle hInviteIndConn ) { CLogicalConnection *pConEntry = NULL; m_ConnList.Reset(); while (NULL != (pConEntry = m_ConnList.Iterate())) { if (pConEntry->GetInviteReqConnHandle() == hInviteIndConn) { break; } } return pConEntry; } CLogicalConnection * DCRNCConference:: GetConEntry ( LPSTR pszNodeAddress ) { CLogicalConnection *pConEntry = NULL; m_ConnList.Reset(); while (NULL != (pConEntry = m_ConnList.Iterate())) { if (0 == ::lstrcmpA(pConEntry->GetNodeAddress(), pszNodeAddress)) { break; } } return pConEntry; } CLogicalConnection * DCRNCConference:: GetConEntryByNodeID ( GCCNodeID nid ) { CLogicalConnection *pConEntry = NULL; m_ConnList.Reset(); while (NULL != (pConEntry = m_ConnList.Iterate())) { if (nid == pConEntry->GetConnectionNodeID()) { break; } } return pConEntry; } void DCRNCConference:: FirstRoster(void) { DebugEntry(DCRNCConference::FirstRoster); // Great! We are now in a conference and outside of any // T120 callback, so that calling back into T120 will not // deadlock applications. // Let the applications know about the conference, // and then ask for a roster update. if (m_eT120State == T120C_ST_PENDING_ROSTER_MESSAGE) { m_eT120State = T120C_ST_CONF_STARTED; NotifyConferenceComplete(NO_ERROR); RefreshRoster(); } DebugExitVOID(DCRNCConference::FirstRoster); } /****************************************************************************/ /* HandleGCCCallback() - see erncconf.h */ /****************************************************************************/ // LONCHANC: Merged to T120 Conference. /****************************************************************************/ /* ValidatePassword() - Validates a join request by checking the supplied */ /* password with the one set when the conference was setup. */ /****************************************************************************/ BOOL DCRNCConference:: ValidatePassword ( GCCChallengeRequestResponse *pPasswordChallenge ) { PBYTE pbPasswordChallenge = NULL; DWORD cbPasswordChallenge = 0; CHash hashObj; OSVERSIONINFO osvi; osvi.dwOSVersionInfoSize = sizeof(osvi); if (FALSE == ::GetVersionEx (&osvi)) { ERROR_OUT(("GetVersionEx() failed!")); } if (!(VER_PLATFORM_WIN32_NT == osvi.dwPlatformId && g_bRDS) && (NULL == m_pbHashedPassword) && (NULL == m_pszNumericPassword) && (NULL == m_pwszPassword)) { return TRUE; } if ((pPasswordChallenge == NULL) || (pPasswordChallenge->password_challenge_type != GCC_PASSWORD_IN_THE_CLEAR)) { return FALSE; } // // We are going to verify the password as a logon // if ( VER_PLATFORM_WIN32_NT == osvi.dwPlatformId && g_bRDS) { BYTE InfoBuffer[1024]; PTOKEN_GROUPS ptgGroups = (PTOKEN_GROUPS)InfoBuffer; HANDLE hToken; BOOL bSuccess = FALSE; DWORD dwInfoBufferSize; UINT x; PSID psidAdministrators; SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY; CHAR lpszBuf[1024]; ASSERT(NULL != pPasswordChallenge->u.password_in_the_clear.text_string); WideCharToMultiByte( CP_ACP, 0, pPasswordChallenge->u.password_in_the_clear.text_string, -1,lpszBuf,256,NULL,NULL); CHAR* lp = (CHAR *)_StrChr(lpszBuf, ':'); if (NULL == lp) { ERROR_OUT(("Expected separator in logon pwd")); return FALSE; } *lp++ = '\0'; CHAR* lpPw = (CHAR *)_StrChr(lp, ':'); if (NULL == lpPw) { ERROR_OUT(("Expected 2nd separator in logon pwd")); return FALSE; } *lpPw++ = '\0'; if (0 == strlen(lpPw)) { WARNING_OUT(("Short password in logon pwd")); return FALSE; } bSuccess = LogonUser(lpszBuf, lp, lpPw, LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, &hToken); if (!bSuccess) { WARNING_OUT(("LogonUser failed %d", GetLastError())); return FALSE; } bSuccess = GetTokenInformation(hToken, TokenGroups, ptgGroups, 1024, &dwInfoBufferSize); if (!bSuccess) { ERROR_OUT(("GetTokenInformation failed: %d", GetLastError())); return FALSE; } if( !AllocateAndInitializeSid(&siaNtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID,DOMAIN_ALIAS_RID_ADMINS, 0,0,0,0,0,0, &psidAdministrators )) { ERROR_OUT(("Error getting admin group sid: %d", GetLastError())); return FALSE; } // assume that we don't find the admin SID. bSuccess = FALSE; for ( x=0; x < ptgGroups->GroupCount; x++ ) { if( EqualSid(psidAdministrators, ptgGroups->Groups[x].Sid) ) { bSuccess = TRUE; break; } } FreeSid(psidAdministrators); // // If this worked there is no need to go on // if ( bSuccess ) return TRUE; // // Check for group membership in the RDS users group on // the local machine. // ASSERT(FALSE == bSuccess); DWORD cbSid = 0; DWORD cbDomain = 0; SID_NAME_USE SidNameUse = SidTypeGroup; if ( LookupAccountName ( NULL, SZRDSGROUP, NULL, &cbSid, NULL, &cbDomain, &SidNameUse ) || ERROR_INSUFFICIENT_BUFFER == GetLastError() ) { PSID pSid = new BYTE[cbSid]; LPTSTR lpszDomain = new TCHAR[cbDomain]; if ( pSid && lpszDomain ) { if ( LookupAccountName ( NULL, SZRDSGROUP, pSid, &cbSid, lpszDomain, &cbDomain, &SidNameUse )) { // // Make sure what we found is a group // if ( SidTypeGroup == SidNameUse || SidTypeAlias == SidNameUse ) { for ( x=0; x < ptgGroups->GroupCount; x++ ) { if( EqualSid(pSid, ptgGroups->Groups[x].Sid) ) { bSuccess = TRUE; break; } } } else { WARNING_OUT(("SZRDSGROUP was not a group or alias? its a %d", SidNameUse )); } } else { ERROR_OUT(("LookupAccountName (2) failed: %d", GetLastError())); } } else { ERROR_OUT(("Alloc of sid or domain failed")); } delete pSid; delete lpszDomain; } else { WARNING_OUT(("LookupAccountName (1) failed: %d", GetLastError())); } return bSuccess; } // // We are going to hash the password and compare it to the // stored hash // if (m_pbHashedPassword != NULL) { if (NULL != pPasswordChallenge->u.password_in_the_clear.text_string) { cbPasswordChallenge = hashObj.GetHashedData((LPBYTE)pPasswordChallenge->u.password_in_the_clear.text_string, sizeof(WCHAR)*lstrlenW(pPasswordChallenge->u.password_in_the_clear.text_string), (void **) &pbPasswordChallenge); } else if (NULL != pPasswordChallenge->u.password_in_the_clear.numeric_string) { int cch = lstrlenA((PSTR)pPasswordChallenge->u.password_in_the_clear.numeric_string); LPWSTR lpwszNumPassword = new WCHAR[cch+1]; MultiByteToWideChar(CP_ACP, 0, (PSTR)pPasswordChallenge->u.password_in_the_clear.numeric_string, -1, lpwszNumPassword, cch+1); int cwch = lstrlenW(lpwszNumPassword); cbPasswordChallenge = hashObj.GetHashedData((LPBYTE)lpwszNumPassword, sizeof(WCHAR)*lstrlenW(lpwszNumPassword), (void **) &pbPasswordChallenge); delete []lpwszNumPassword; } else { return FALSE; } if (m_cbHashedPassword != cbPasswordChallenge) return FALSE; if (0 == memcmp(m_pbHashedPassword, pbPasswordChallenge, cbPasswordChallenge)) { return TRUE; } else { return FALSE; } } else if (m_pwszPassword != NULL) { // We have a text password if ((pPasswordChallenge->u.password_in_the_clear.text_string == NULL) || (0 != ::My_strcmpW(m_pwszPassword, pPasswordChallenge->u.password_in_the_clear.text_string))) { return FALSE; } else { return TRUE; } } else { // We have a numeric password if ((pPasswordChallenge->u.password_in_the_clear.numeric_string == NULL) || (::lstrcmpA(m_pszNumericPassword, (PSTR) pPasswordChallenge->u.password_in_the_clear.numeric_string))) { return FALSE; } else { return TRUE; } } } /****************************************************************************/ /* Join() - see erncconf.h */ /****************************************************************************/ HRESULT DCRNCConference:: Join ( LPSTR pszNodeAddress, LPCWSTR _wszPassword ) { HRESULT hr = NO_ERROR; DebugEntry(DCRNCConference::Join); /* * Set the password that will be used by the JoinWrapper() method. * The password will be deleted after the Join is complete. * The m_pwszPassword member is only set for the top providers * protecting conferences. */ if (! ::IsEmptyStringW (_wszPassword)) { // Store the password; we will need it later m_pwszPassword = ::My_strdupW(_wszPassword); if (NULL == m_pwszPassword) { hr = UI_RC_OUT_OF_MEMORY; } } /************************************************************************/ /* SFR 6206. The apps treat joining a conference at a remote site as */ /* an "incoming" call. (i.e they discard any local data and accept the */ /* msgs/WB contents from the conference we are joining). */ /************************************************************************/ if (NO_ERROR == hr) { m_fIncoming = TRUE; hr = StartConnection(pszNodeAddress, CONF_CON_PENDING_JOIN, m_fSecure); } if (NO_ERROR != hr) { ERROR_OUT(("Error starting connection")); } /************************************************************************/ /* We now sit and wait for the connection to complete before */ /* continuing. */ /************************************************************************/ DebugExitHRESULT(DCRNCConference::Join, hr); return hr; } /****************************************************************************/ /* NotifyConferenceComplete() - the generic conference has finished its */ /* attempt to start. */ /****************************************************************************/ void DCRNCConference:: NotifyConferenceComplete ( HRESULT hr ) { DebugEntry(DCRNCConference::NotifyConferenceComplete); /************************************************************************/ /* If the attempt fails, action depends on whether this is the first or */ /* second attempt. */ /************************************************************************/ if (NO_ERROR != hr) { TRACE_OUT(("Attempt to start failed")); // LONCHANC: please do not remove this chunk of code. #ifdef ENABLE_START_REMOTE if (m_eState == CONF_ST_PENDING_START_REMOTE_FIRST) { TRACE_OUT(("Try second conference type")); StartSecondConference(hr); return; } #endif // ENABLE_START_REMOTE } else { TRACE_OUT(("Conference started OK.")); m_eState = CONF_ST_STARTED; } g_pNCConfMgr->NotifyConferenceComplete(this, m_fIncoming, hr); DebugExitVOID(DCRNCConference::NotifyConferenceComplete); } /****************************************************************************/ /* NotifyConnectionComplete() - see erncconf.h */ /****************************************************************************/ HRESULT DCRNCConference:: NotifyConnectionComplete ( CLogicalConnection *pConEntry, HRESULT hr ) { DebugEntry(DCRNCConference::NotifyConnectionComplete); // This function is the state machine // for bringing up a conferencing protocol. // It manages getting the physical connection and trying // T120 and R1.1. // A connection has started. // Subsequent action depends on the pending state for the connection. // First filter out internal (success) return codes. if (NO_ERROR != hr) { // Failed to get a physical connection. WARNING_OUT(("Failed to start connection")); if (pConEntry->GetState() != CONF_CON_PENDING_INVITE) { // Put the connection in a failed state before notifying the user. // This is because notifying the user can cause GCC events to fire, // and, in particular, a JoinRequest failure which must be ignored. pConEntry->SetState(CONF_CON_ERROR); g_pNCConfMgr->NotifyConferenceComplete(this, m_fIncoming, hr); goto MyExit; } // Drop through for invite failures. } switch (pConEntry->GetState()) { // LONCHANC: please do not remove this chunk of code. #ifdef ENABLE_START_REMOTE case CONF_CON_PENDING_START: /****************************************************************/ /* Check we are in the correct state. */ /****************************************************************/ if ( (m_eState != CONF_ST_PENDING_CONNECTION) && (m_eState != CONF_ST_LOCAL_PENDING_RECREATE)) { ERROR_OUT(("Bad state to start in...")); goto MyExit; } pConEntry->SetState(CONF_CON_CONNECTED); /****************************************************************/ /* The connection has started OK. we now try to establish */ /* either a T120 or a backlevel conference, depending on the */ /* starting order. */ /****************************************************************/ if (NO_ERROR == hr) { hr = StartFirstConference(); } else { ERROR_OUT(("Invalid response in notify connection complete")); } break; #endif // ENABLE_START_REMOTE case CONF_CON_PENDING_JOIN: // pConEntry->m_eState = CONF_CON_CONNECTED; // Joining a new conference. // Create a new generic conference and // call its Join() entry point. hr = NewT120Conference(); if (NO_ERROR == hr) { hr = JoinWrapper(pConEntry, m_pwszPassword); // Delete the set password if (m_pwszPassword != NULL) { delete m_pwszPassword; m_pwszPassword = NULL; } } else { ERROR_OUT(("Error %d joining conference", hr)); goto MyExit; } break; case CONF_CON_PENDING_INVITE: hr = pConEntry->InviteConnectResult(hr); break; default : ERROR_OUT(("Unknown action %d", pConEntry->GetState())); break; } MyExit: DebugExitVOID(DCRNCConference::NotifyConnectionComplete); return hr; } HRESULT DCRNCConference:: JoinWrapper ( CLogicalConnection *pConEntry, LPCWSTR _wszPassword ) { DebugEntry(DCRNCConference::JoinWrapper); // Going asynchronous, so allow events to fire. pConEntry->ReArm(); HRESULT hr = T120Join(pConEntry->GetNodeAddress(), pConEntry->IsConnectionSecure(), m_pwszConfName, pConEntry->GetUserDataList(), _wszPassword); if (NO_ERROR == hr) { m_eState = CONF_ST_STARTED; } else { pConEntry->Grab(); ERROR_OUT(("Error %d joining conference", hr)); g_pNCConfMgr->NotifyConferenceComplete(this, m_fIncoming, hr); } DebugExitHRESULT(DCRNCConference::JoinWrapper, hr); return hr; } /****************************************************************************/ /* NotifyRosterChanged() - see erncconf.hpp. */ /****************************************************************************/ void DCRNCConference:: NotifyRosterChanged ( PNC_ROSTER pRoster ) { DebugEntry(DCRNCConference::NotifyRosterChanged); // Add the conference name and ID to the roster. pRoster->pwszConferenceName = m_pwszConfName; pRoster->uConferenceID = m_nConfID; /************************************************************************/ /* Pass the new roster up to the CM */ /************************************************************************/ g_pCallbackInterface->OnRosterChanged((CONF_HANDLE) this, pRoster); DebugExitVOID(DCRNCConference::NotifyRosterChanged); } /****************************************************************************/ /* StartConnection - add a new connection to our connection list. */ /****************************************************************************/ HRESULT DCRNCConference:: StartConnection ( LPSTR pszNodeAddress, LOGICAL_CONN_STATE eAction, BOOL fSecure, REQUEST_HANDLE * phRequest ) { HRESULT hr; CLogicalConnection *pConEntry; DebugEntry(DCRNCConference::StartConnection); DBG_SAVE_FILE_LINE pConEntry = NewLogicalConnection(eAction, NULL, fSecure); if (NULL != pConEntry) { hr = NO_ERROR; if (phRequest) { // Return context as the connection entry, if required. *phRequest = (REQUEST_HANDLE *)pConEntry; } // Set node address pConEntry->SetNodeAddress(::My_strdupA(pszNodeAddress)); // // LONCHANC: Fire the conn-entry event. // hr = NotifyConnectionComplete(pConEntry, NO_ERROR); } else { hr = UI_RC_OUT_OF_MEMORY; } DebugExitHRESULT(DCRNCConference::StartConnection, hr); return hr; } // LONCHANC: please do not remove this chunk of code. #ifdef ENABLE_START_REMOTE /****************************************************************************/ /* StartFirstConference() - start the first attempt to create a conference. */ /****************************************************************************/ void DCRNCConference:: StartFirstConference(void) { BOOL result = FALSE; HRESULT hr; DebugEntry(DCRNCConference::StartFirstConference); hr = NewT120Conference(); if (NO_ERROR != hr) { ERROR_OUT(("Failed to create new conference")); m_eState = CONF_ST_UNINITIALIZED; goto MyExit; } /************************************************************************/ /* Call the StartRemote() entry point. */ /************************************************************************/ hr = T120StartRemote(m_pszFirstRemoteNodeAddress); if (hr) { WARNING_OUT(("Failed to start remote, rc %d", hr)); goto MyExit; } m_eState = CONF_ST_PENDING_START_REMOTE_FIRST; result = TRUE; MyExit: /************************************************************************/ /* If we failed to start the first conference, try to start the second */ /* type of conference in the starting order. */ /************************************************************************/ if (!result) { TRACE_OUT(("Failed to start first conference.")); StartSecondConference(hr); } DebugExitVOID(DCRNCConference::StartFirstConference); } #endif // ENABLE_START_REMOTE // LONCHANC: please do not remove this chunk of code. #ifdef ENABLE_START_REMOTE /****************************************************************************/ /* StartSecondConference() - start the second attempt to create a */ /* conference. */ /****************************************************************************/ void DCRNCConference:: StartSecondConference ( HRESULT FirstConferenceStatus ) { BOOL result = FALSE; HRESULT hr = NO_ERROR; DebugEntry(DCRNCConference::StartSecondConference); hr = FirstConferenceStatus; #if 0 // LONCHANC: very weird code goto MyExit; /************************************************************************/ /* Call the StartRemote() entry point. */ /************************************************************************/ hr = T120StartRemote(m_pszFirstRemoteNodeAddress); if (NO_ERROR != hr) { WARNING_OUT(("Failed to start remote, rc %d", hr)); goto MyExit; } m_eState = CONF_ST_PENDING_START_REMOTE_SECOND; result = TRUE; MyExit: #endif // 0 /************************************************************************/ /* If we have failed to start any type of conference, tell CM about it. */ /************************************************************************/ if (!result) { TRACE_OUT(("Failed to start Second conference.")); g_pNCConfMgr->NotifyConferenceComplete(this, m_fIncoming, hr); } DebugExitVOID(DCRNCConference::StartSecondConference); } #endif // ENABLE_START_REMOTE /****************************************************************************/ /* StartLocal() - see erncconf.h */ /****************************************************************************/ HRESULT DCRNCConference:: StartLocal ( LPCWSTR _wszPassword, PBYTE pbHashedPassword, DWORD cbHashedPassword) { HRESULT hr = NO_ERROR; DebugEntry(DCRNCConference::StartLocal); /* * Set the password that will be used to protect the conference. * against unauthorized Join requests. * The password is only set for the top providers * protecting conferences. * If the password is a number it will be stored in m_pszNumericPassword. * Otherwise, it will be stored in m_pwszPassword. */ if (NULL != pbHashedPassword) { m_pbHashedPassword = new BYTE[cbHashedPassword]; if (NULL == m_pbHashedPassword) { hr = UI_RC_OUT_OF_MEMORY; } else { memcpy(m_pbHashedPassword, pbHashedPassword, cbHashedPassword); m_cbHashedPassword = cbHashedPassword; } } else if (! ::IsEmptyStringW(_wszPassword)) { if (::UnicodeIsNumber(_wszPassword)) { m_pszNumericPassword = ::UnicodeToAnsi(_wszPassword); if (m_pszNumericPassword == NULL) { hr = UI_RC_OUT_OF_MEMORY; } } else { m_pwszPassword = ::My_strdupW(_wszPassword); if (NULL == m_pwszPassword) { hr = UI_RC_OUT_OF_MEMORY; } } } /************************************************************************/ /* Dont need to bother getting a physical connection. Just create a */ /* new T120 conference and call its StartLocal() entry point */ /************************************************************************/ if (NO_ERROR == hr) { hr = NewT120Conference(); if (NO_ERROR == hr) { hr = T120StartLocal(m_fSecure); if (NO_ERROR == hr) { m_eState = CONF_ST_PENDING_T120_START_LOCAL; } } } DebugExitHRESULT(DCRNCConference::StartLocal, hr); return hr; } // LONCHANC: please do not remove this chunk of code. #ifdef ENABLE_START_REMOTE /****************************************************************************/ /* StartRemote() - see erncconf.h */ /****************************************************************************/ HRESULT DCRNCConference:: StartRemote ( LPSTR pszNodeAddress ) { HRESULT hr; DebugEntry(DCRNCConference::StartRemote); /************************************************************************/ /* Store the node details */ /************************************************************************/ m_pszFirstRemoteNodeAddress = ::My_strdupA(pszNodeAddress); if (NULL != m_pszFirstRemoteNodeAddress) { /************************************************************************/ /* We need to set the conference state before trying to start a new */ /* connection - the connection may synchronously call us back and we */ /* want to be able to handle the callback correctly. */ /************************************************************************/ m_eState = CONF_ST_PENDING_CONNECTION; /************************************************************************/ /* Start a new physical connection. */ /************************************************************************/ hr = StartConnection(m_pszFirstRemoteNodeAddress, CONF_CON_PENDING_START, NULL, NULL); if (NO_ERROR != hr) { ERROR_OUT(("Error adding connection")); m_eState = CONF_ST_UNINITIALIZED; } /************************************************************************/ /* We now sit and wait for the connection to complete before */ /* continuing. */ /************************************************************************/ } else { ERROR_OUT(("DCRNCConference::StartRemote: can't duplicate node address")); hr = UI_RC_OUT_OF_MEMORY; m_eState = CONF_ST_UNINITIALIZED; } DebugExitHRESULT(DCRNCConference::StartRemote, hr); return hr; } #endif // ENABLE_START_REMOTE /****************************************************************************/ /* StartIncoming() - see erncconf.h */ /****************************************************************************/ HRESULT DCRNCConference:: StartIncoming(void) { DebugEntry(DCRNCConference::StartIncoming); /************************************************************************/ /* Set the incoming flag. */ /************************************************************************/ m_fIncoming = TRUE; /************************************************************************/ /* Create a new T120 conference and call its StartIncoming entry point. */ /************************************************************************/ HRESULT hr = NewT120Conference(); if (NO_ERROR == hr) { m_eState = CONF_ST_STARTED; } else { WARNING_OUT(("Failed to create new local conference")); } DebugExitHRESULT(DCRNCConference::StartIncoming, hr); return hr; } CLogicalConnection:: CLogicalConnection ( PCONFERENCE pConf, LOGICAL_CONN_STATE eAction, ConnectionHandle hConnection, BOOL fSecure ) : CRefCount(MAKE_STAMP_ID('C','L','N','E')), m_pszNodeAddress(NULL), m_eState(eAction), m_pConf(pConf), m_nidConnection(0), m_hInviteReqConn(hConnection), m_hConnection(hConnection), m_pLocalAddress(NULL), m_fEventGrabbed(FALSE), m_fSecure(fSecure) { DebugEntry(CLogicalConnection::CLogicalConnection); if ((eAction == CONF_CON_INVITED) || (eAction == CONF_CON_JOINED)) { Grab(); // No events to fire. } DebugExitVOID(CLogicalConnection::CLogicalConnection); } CLogicalConnection:: ~CLogicalConnection(void) { DebugEntry(CLogicalConnection::~CLogicalConnection); ASSERT((m_eState == CONF_CON_CONNECTED) || (m_eState == CONF_CON_ERROR)); delete m_pszNodeAddress; DebugExitVOID(CLogicalConnection::~CLogicalConnection); } BOOL CLogicalConnection:: NewLocalAddress(void) { BOOL bNewAddress; m_pConf->AddLocalAddress(m_hConnection, &bNewAddress, &m_pLocalAddress); return bNewAddress; } HRESULT CLogicalConnection:: InviteConnectResult ( HRESULT hr ) { DebugEntry(CLogicalConnection::InviteConnectResult); if (NO_ERROR == hr) { /****************************************************************/ /* Check the state - we should be fully initialized and have a */ /* generic conference by this stage. */ /****************************************************************/ if (m_pConf->m_eState != CONF_ST_STARTED) { ERROR_OUT(("Bad state %d", m_pConf->m_eState)); hr = UI_NO_SUCH_CONFERENCE; } else { // Now have a connection to the conference, so go do invite. // Note that this may not be the only invite if the user invites // several people into the conference before the connection is up. ReArm(); // So that connection going down fires off event handling hr = m_pConf->T120Invite(m_pszNodeAddress, m_fSecure, &m_UserDataInfoList, &m_hInviteReqConn); if (NO_ERROR != hr) { Grab(); } } } if (NO_ERROR != hr) { InviteComplete(hr); } DebugExitHRESULT(CLogicalConnection::InviteConnectResult, hr); return hr; } void DCRNCConference:: InviteComplete ( ConnectionHandle hInviteReqConn, HRESULT result ) { CLogicalConnection * pConEntry; DebugEntry(DCRNCConference::InviteComplete); pConEntry = GetConEntry(hInviteReqConn); if (pConEntry == NULL) { ERROR_OUT(("Unable to match invite response with request")); return; } pConEntry->SetConnectionHandle(hInviteReqConn); pConEntry->InviteComplete(result); DebugExitVOID(DCRNCConference::InviteComplete); } HRESULT CLocalAddressList:: AddLocalAddress ( ConnectionHandle connection_handle, BOOL *pbNewAddress, CLocalAddress **ppLocalAddrToRet ) { HRESULT hr = UI_RC_OUT_OF_MEMORY; CLocalAddress * pLocalAddress = NULL; char szLocalAddress[64]; int nLocalAddress = sizeof(szLocalAddress); DebugEntry(CLocalAddressList::AddLocalAddress); *pbNewAddress = FALSE; ASSERT (g_pMCSController != NULL); if (g_pMCSController->GetLocalAddress (connection_handle, szLocalAddress, &nLocalAddress)) { DBG_SAVE_FILE_LINE pLocalAddress = new CLocalAddress(szLocalAddress); if (pLocalAddress) { if (!IS_EMPTY_STRING(pLocalAddress->m_pszLocalAddress)) { BOOL fFound = FALSE; CLocalAddress *p; Reset(); while (NULL != (p = Iterate())) { if (0 == ::lstrcmpA(p->m_pszLocalAddress, szLocalAddress)) { fFound = TRUE; break; } } if (! fFound) { ASSERT(NULL == p); Append(pLocalAddress); } else { ASSERT(NULL != p); pLocalAddress->Release(); (pLocalAddress = p)->AddRef(); } hr = NO_ERROR; } else { pLocalAddress->Release(); // Remove when no longer referenced pLocalAddress = NULL; } } } *ppLocalAddrToRet = pLocalAddress; DebugExitHRESULT(CLocalAddressList::AddLocalAddress, hr); return hr; } HRESULT CLocalAddressList:: GetLocalAddressList ( UINT *pnAddresses, LPCSTR **ppaAddresses ) { CLocalAddress * pAddress; LPCSTR * pConnection; LPCSTR * apConn = NULL; HRESULT hr = NO_ERROR; DebugEntry(CLocalAddressList::GetLocalAddressList); if (! IsEmpty()) { DBG_SAVE_FILE_LINE if (NULL == (apConn = new LPCSTR[GetCount()])) { hr = UI_RC_OUT_OF_MEMORY; } } if (NULL == apConn) { *pnAddresses = 0; } else { hr = NO_ERROR; *pnAddresses = GetCount(); pConnection = apConn; Reset(); while (NULL != (pAddress = Iterate())) { *pConnection++ = pAddress->m_pszLocalAddress; } } *ppaAddresses = apConn; DebugExitHRESULT(CLocalAddressList::GetLocalAddressList, hr); return hr; } void CLocalAddressList:: EndReference ( CLocalAddress *pLocalAddress ) { DebugEntry(CLocalAddressList::EndReference); if (pLocalAddress->Release() == 0) { Remove(pLocalAddress); } DebugExitVOID(CLocalAddressList::EndReference); } CLocalAddress::CLocalAddress(PCSTR szLocalAddress) : CRefCount(MAKE_STAMP_ID('L','A','D','R')) { m_pszLocalAddress = ::My_strdupA(szLocalAddress); } void CLogicalConnection:: InviteComplete ( HRESULT hrStatus ) { DebugEntry(CLogicalConnection::InviteComplete); // Don't want user calling us back in // InviteConferenceResult to delete the conference // causing this object to be deleted whilst // in it. AddRef(); // Should only handle an invite complete if there is one pending. // Otherwise, this is most likely the result of entering this function // after telling the user that the invite has failed for some other // reason (e.g. a physical connection going down). // In these cases, just ignore the invite complete event. if (m_eState == CONF_CON_PENDING_INVITE) { // Invite complete will generate an event, so grab it. Grab(); if (hrStatus) { m_eState = CONF_CON_ERROR; } else { m_eState = CONF_CON_CONNECTED; if (NewLocalAddress()) { m_pConf->AnnouncePresence(); } } g_pCallbackInterface->OnInviteResult( (CONF_HANDLE) m_pConf, (REQUEST_HANDLE) this, m_nidConnection, hrStatus); if (hrStatus) { // Remove conentry from conference if invite fails. Delete(hrStatus); } } Release(); DebugExitVOID(CLogicalConnection::InviteComplete); } void CLogicalConnection:: Delete ( HRESULT hrReason ) { DebugEntry(CLogicalConnection::Delete); // WARNING, WARNING, WARNING: // This method gets re-entered on the stack. // Note guards in code below. if (NULL != m_pConf) { PCONFERENCE pThisConf = m_pConf; PCONFERENCE pConfToFree = NULL; m_pConf = NULL; // The connection is going away, so remove the reference to the // associated local connection (if any). if (NULL != m_pLocalAddress) { pThisConf->EndReference(m_pLocalAddress); m_pLocalAddress = NULL; } if (m_eState == CONF_CON_INVITED) { // The conference associated with the entry was invited into the conference, // so remove the conference and all of its connections. m_eState = CONF_CON_ERROR; // Only do this once pConfToFree = pThisConf; } // If there is a pending event on the connection, // then try to grab it and notify the requestor // that the request has failed. // Note that the event handler may itself end up // recalling this function, so it refcounts the // CLogicalConnection to prevent it from being destructed // too soon. if (Grab()) { pThisConf->NotifyConnectionComplete(this, hrReason); } // Set the connection state to be in error. // Note that this is done after firing the event because // otherwise a failed connection attempt to a disabled transport // would cause the local conference to be destroyed by // NotifyConnectionComplete(). m_eState = CONF_CON_ERROR; // Sever the connection entry with the conference record. pThisConf->m_ConnList.Remove(this); // Now destroy the conentry once any pending event has fired - // there is only a pending connection request or a pending // request to join/invite/create a conference, and never both. Release(); if (NULL != pConfToFree) { g_pNCConfMgr->RemoveConference(pConfToFree); } } DebugExitVOID(CLogicalConnection::Delete); } BOOL FindSocketNumber(DWORD nid, SOCKET * socket_number) { (*socket_number) = 0; ASSERT(g_pNCConfMgr != NULL); return g_pNCConfMgr->FindSocketNumber((GCCNodeID) nid, socket_number); } // DCRNCConference::FindSocketNumber // Given a GCCNodeID, finds a socket number associated with that id. // Returns TRUE if we are directly connected topology-wise to the node, FALSE if not. BOOL DCRNCConference:: FindSocketNumber ( GCCNodeID nid, SOCKET *socket_number ) { CLogicalConnection *pConEntry; m_ConnList.Reset(); while (NULL != (pConEntry = m_ConnList.Iterate())) { if (pConEntry->GetConnectionNodeID() == nid) { // Found it! g_pMCSController->FindSocketNumber(pConEntry->GetConnectionHandle(), socket_number); return TRUE; } } return FALSE; } ULONG DCRNCConference:: GetNodeName(GCCNodeID NodeId, LPSTR pszBuffer, ULONG cbBufSize) { LPSTR pszName = m_NodeIdNameList.Find(NodeId); if (pszName) { ::lstrcpynA(pszBuffer, pszName, cbBufSize); return lstrlenA(pszName); } return 0; } ULONG DCRNCConference:: GetUserGUIDData(GCCNodeID NodeId, GUID *pGuid, LPBYTE pbBuffer, ULONG cbBufSize) { CNCUserDataList *pUserDataList = m_UserDataList.Find(NodeId); GCCUserData *pUserData; if (pUserDataList) { pUserData = pUserDataList->GetUserGUIDData(pGuid); if (pUserData) { if (pbBuffer) { ::CopyMemory(pbBuffer, pUserData->octet_string->value + sizeof(GUID), min(cbBufSize, pUserData->octet_string->length - sizeof(GUID))); } return pUserData->octet_string->length - sizeof(GUID); } // The GUID is not found } // The NodeId is not found return 0; } void DCRNCConference:: UpdateNodeIdNameListAndUserData(PGCCMessage message) { GCCNodeID NodeId; LPSTR pszName; LPWSTR pwszNodeName; GCCNodeRecord *pNodeRecord; PGCCConferenceRoster pConfRost; USHORT count; PGCCUserData pGccUserData; USHORT count2; CNCUserDataList *pUserDataList; ASSERT (message->message_type == GCC_ROSTER_REPORT_INDICATION); pConfRost = message->u.conf_roster_report_indication.conference_roster; for (count = 0; count < pConfRost->number_of_records; count++) { pNodeRecord = pConfRost->node_record_list[count]; NodeId = pNodeRecord->node_id; pwszNodeName = pNodeRecord->node_name; pszName = m_NodeIdNameList.Find(NodeId); if (!pszName) { int ccnsize = (lstrlenW(pwszNodeName) + 1) * sizeof(WCHAR); DBG_SAVE_FILE_LINE pszName = new char[ccnsize]; if (pszName) { if (WideCharToMultiByte(CP_ACP, 0, pwszNodeName, -1, pszName, ccnsize, NULL, NULL)) { m_NodeIdNameList.Append(NodeId, pszName); } else { ERROR_OUT(("ConfMgr::UpdateNodeIdNameList: cannot convert unicode node name")); } } else { ERROR_OUT(("ConfMgr::UpdateNodeIdNameList: cannot duplicate unicode node name")); } } for (count2 = 0; count2 < pNodeRecord->number_of_user_data_members; count2++) { pGccUserData = pNodeRecord->user_data_list[count2]; if (pGccUserData->octet_string->length <= sizeof(GUID)) continue; // not real user data pUserDataList = m_UserDataList.Find(NodeId); if (!pUserDataList) { DBG_SAVE_FILE_LINE pUserDataList = new CNCUserDataList; m_UserDataList.Append(NodeId, pUserDataList); } pUserDataList->AddUserData((GUID *)pGccUserData->octet_string->value, pGccUserData->octet_string->length - sizeof(GUID), pGccUserData->octet_string->value + sizeof(GUID)); } } }