|
|
// File: icall.cpp
#include "precomp.h"
#include "icall.h"
#include "imanager.h"
#include <service.h>
#include <confguid.h>
typedef struct { BOOL fMCU; PWSTR * pwszConfNames; BSTR * pbstrConfToJoin; } REMOTE_CONFERENCE;
typedef struct { BSTR bstrConference; BSTR *pbstrPassword; PBYTE pbRemoteCred; DWORD cbRemoteCred; BOOL fIsService; } REMOTE_PASSWORD;
HRESULT OnNotifyCallError(IUnknown *pCallNotify, PVOID pv, REFIID riid);
static HRESULT OnNotifyRemoteConference(IUnknown *pCallNotify, PVOID pv, REFIID riid); static HRESULT OnNotifyRemotePassword(IUnknown *pCallNotify, PVOID pv, REFIID riid);
static const IID * g_apiidCP[] = { {&IID_INmCallNotify} };
// String Functions
inline VOID FreeBstr(BSTR *pbstr) { if (NULL != pbstr) { SysFreeString(*pbstr); *pbstr = NULL; } }
/* P S Z A L L O C */ /*-------------------------------------------------------------------------
%%Function: PszAlloc
-------------------------------------------------------------------------*/ LPTSTR PszAlloc(LPCTSTR pszSrc) { if (NULL == pszSrc) return NULL;
LPTSTR pszDest = new TCHAR[lstrlen(pszSrc) + 1]; if (NULL != pszDest) { lstrcpy(pszDest, pszSrc); } return pszDest; }
COutgoingCall::COutgoingCall ( CConfObject* pco, DWORD dwFlags, NM_ADDR_TYPE addrType, BSTR bstrAddr, BSTR bstrConference, BSTR bstrPassword ) : CConnectionPointContainer(g_apiidCP, ARRAY_ELEMENTS(g_apiidCP)), m_pConfObject (pco), m_addrType (addrType), m_dwFlags (dwFlags), m_bstrAddr (SysAllocString(bstrAddr)), m_bstrConfToJoin (SysAllocString(bstrConference)), m_bstrPassword (SysAllocString(bstrPassword)), m_hRequest (NULL), m_fCanceled (FALSE), m_cnResult (CN_RC_NOERROR), m_cnState (CNS_IDLE), m_fService (FALSE) { m_pszAddr = PszAlloc(CUSTRING(bstrAddr)); TRACE_OUT(("Obj: %08X created COutgoingCall", this)); }
COutgoingCall::~COutgoingCall() { if (m_pszAddr) { delete m_pszAddr; m_pszAddr = NULL; }
if (m_bstrAddr) { SysFreeString(m_bstrAddr); m_bstrAddr = NULL; }
TRACE_OUT(("Obj: %08X destroyed COutgoingCall", this)); }
/* P L A C E C A L L */ /*-------------------------------------------------------------------------
%%Function: PlaceCall
-------------------------------------------------------------------------*/ VOID COutgoingCall::PlaceCall(void) { DebugEntry(COutgoingCall::PlaceCall);
COprahNCUI *pOprahNCUI = COprahNCUI::GetInstance(); ASSERT(NULL != pOprahNCUI);
SetCallState(CNS_SEARCHING);
if (NULL != g_pNodeController) { // Start placing the T.120 call
CNSTATUS cnResult = CN_RC_NOERROR;
if (NULL == m_bstrConfToJoin) { // conference name not specified
// need to start out with a QueryRemote
SetCallState(CNS_QUERYING_REMOTE);
HRESULT hr = g_pNodeController->QueryRemote(this, m_pszAddr, m_pConfObject->IsConfObjSecure(), m_pConfObject->IsConferenceActive()); if (S_OK != hr) { cnResult = CN_RC_QUERY_FAILED; } } else { ASSERT(m_pConfObject); // conference name has been specified
// time to do a JoinConference
SetCallState(CNS_JOINING_REMOTE);
HRESULT hr = m_pConfObject->JoinConference(m_bstrConfToJoin, m_bstrPassword, m_pszAddr); if (S_OK != hr) { cnResult = CN_RC_JOIN_FAILED; } }
if (CN_RC_NOERROR != cnResult) { m_cnResult = cnResult; SetCallState(CNS_COMPLETE); } } else { m_cnResult = CN_RC_TRANSPORT_FAILURE; SetCallState(CNS_COMPLETE); }
DebugExitVOID(COutgoingCall::PlaceCall); }
BOOL COutgoingCall::OnConferenceEnded() { DebugEntry(COutgoingCall::OnConferenceEnded);
BOOL bRet = FALSE;
switch (m_cnState) { case CNS_INVITING_REMOTE: { TRACE_OUT(("COutgoingCall (calling) rec. UNEXPECTED ConfEnded event"));
SetCallState(CNS_COMPLETE);
bRet = TRUE; break; }
case CNS_JOINING_REMOTE: { // JoinConference failed!
TRACE_OUT(("COutgoingCall (joining) received ConferenceEnded event"));
m_cnResult = CN_RC_CONFERENCE_JOIN_DENIED; SetCallState(CNS_COMPLETE);
bRet = TRUE; break; }
case CNS_TERMINATING_AFTER_INVITE: { TRACE_OUT(("COutgoingCall (terminating after invite) received ConferenceEnded event"));
SetCallState(CNS_QUERYING_REMOTE_AFTER_INVITE);
ASSERT(g_pNodeController);
HRESULT hr = g_pNodeController->QueryRemote(this, m_pszAddr, m_pConfObject->IsConfObjSecure(), m_pConfObject->IsConferenceActive()); if (S_OK != hr) { m_cnResult = CN_RC_QUERY_FAILED; SetCallState(CNS_COMPLETE); }
bRet = TRUE; break; }
default: { WARNING_OUT(("COutgoingCall received unexpected ConfEnded event")); } }
DebugExitBOOL(COutgoingCall::OnConferenceEnded, bRet); return bRet; }
BOOL COutgoingCall::OnInviteResult(HRESULT ncsResult, UINT uNodeID) { DebugEntry(COutgoingCall::OnInviteResult);
BOOL bRet = TRUE;
ASSERT(CNS_INVITING_REMOTE == m_cnState);
TRACE_OUT(("COutgoingCall (calling) received InviteResult event"));
// Clear the current request handle
m_hRequest = NULL; if (0 == ncsResult) { SetCallState(CNS_COMPLETE); } else { if (UI_RC_USER_REJECTED == ncsResult) { SetCallState(CNS_TERMINATING_AFTER_INVITE);
// Issue "soft" leave attempt (to allow auto-terminate)
ASSERT(m_pConfObject); if (S_OK != m_pConfObject->LeaveConference(FALSE)) { m_cnResult = CN_RC_CONFERENCE_INVITE_DENIED; SetCallState(CNS_COMPLETE); } } else { // make sure that we are not recieving this notification due to
// the conference going away
ASSERT(m_pConfObject); if (CS_GOING_DOWN != m_pConfObject->GetT120State()) { TRACE_OUT(("COutgoingCall - invite failed / couldn't connect -> leaving")); m_cnResult = CN_RC_INVITE_FAILED; SetCallState(CNS_COMPLETE);
// Issue "soft" leave attempt (to allow auto-terminate)
ASSERT(m_pConfObject); m_pConfObject->LeaveConference(FALSE); } } }
DebugExitBOOL(COutgoingCall::OnInviteResult, bRet); return bRet; }
BOOL COutgoingCall::OnQueryRemoteResult(HRESULT ncsResult, BOOL fMCU, PWSTR pwszConfNames[], PWSTR pwszConfDescriptors[]) { DebugEntry(COutgoingCall::OnQueryRemoteResult);
ASSERT ((CNS_QUERYING_REMOTE == m_cnState) || (CNS_QUERYING_REMOTE_AFTER_INVITE == m_cnState)); ASSERT (NULL == m_bstrConfToJoin);
if (SUCCEEDED(ncsResult)) { BOOL fRemoteInConf = FALSE; if ((NULL != pwszConfNames) && (NULL != pwszConfNames[0])) { fRemoteInConf = TRUE; }
m_fService = FALSE; if (fRemoteInConf && (NULL != pwszConfDescriptors) && (NULL != pwszConfDescriptors[0])) { if (0 == UnicodeCompare(pwszConfDescriptors[0],RDS_CONFERENCE_DESCRIPTOR)) { m_fService = TRUE; } }
if (m_pConfObject->IsConferenceActive()) { if (fMCU) { TRACE_OUT(("COutgoingCall - QR ok, but is MCU -> complete")); m_cnResult = CN_RC_CANT_INVITE_MCU; } else if (fRemoteInConf) { TRACE_OUT(("COutgoingCall - QR ok, but callee is in a conference")); m_cnResult = CN_RC_INVITE_DENIED_REMOTE_IN_CONF; } else { if (CNS_QUERYING_REMOTE_AFTER_INVITE == m_cnState) { m_cnResult = CN_RC_CONFERENCE_INVITE_DENIED; SetCallState(CNS_COMPLETE); } else { SetCallState(CNS_INVITING_REMOTE);
HRESULT hr = m_pConfObject->InviteConference(m_pszAddr, &m_hRequest); if (S_OK != hr) { // Failure while inviting:
m_cnResult = CN_RC_INVITE_FAILED; } } }
if (CN_RC_NOERROR != m_cnResult) { SetCallState(CNS_COMPLETE); } } else if (fRemoteInConf || fMCU) { TRACE_OUT(("COutgoingCall - QR succeeded (>0 conf) -> joining")); TRACE_OUT(("\tfMCU is %d", fMCU)); // There are remote conferences
HRESULT hr = E_FAIL; // Assume a failure
SetCallState(CNS_JOINING_REMOTE);
if (!fMCU && (NULL == pwszConfNames[1])) { // we're not calling an MCU and we have just one conference, so join it
m_bstrConfToJoin = SysAllocString(pwszConfNames[0]); hr = m_pConfObject->JoinConference( m_bstrConfToJoin, m_bstrPassword, m_pszAddr); } else { ASSERT(NULL == m_bstrConfToJoin); REMOTE_CONFERENCE remoteConf; remoteConf.fMCU = fMCU; remoteConf.pwszConfNames = pwszConfNames; remoteConf.pbstrConfToJoin = &m_bstrConfToJoin;
// Ask the app which conference to join
NotifySink(&remoteConf, OnNotifyRemoteConference);
if (NULL != m_bstrConfToJoin) { hr = m_pConfObject->JoinConference( m_bstrConfToJoin, m_bstrPassword, m_pszAddr); } }
if (S_OK != hr) { // JoinConference failed!
m_cnResult = CN_RC_JOIN_FAILED; SetCallState(CNS_COMPLETE); } } else { if (CNS_QUERYING_REMOTE_AFTER_INVITE == m_cnState) { m_cnResult = CN_RC_CONFERENCE_INVITE_DENIED; SetCallState(CNS_COMPLETE); } else { // No conferences on remote machine, so create local:
TRACE_OUT(("COutgoingCall - QR succeeded (no conf)-> creating local"));
// Create local conf
ASSERT(m_pConfObject); SetCallState(CNS_CREATING_LOCAL); HRESULT hr = m_pConfObject->CreateConference();
if (S_OK != hr) { // CreateConference failed!
m_cnResult = CN_RC_CONFERENCE_CREATE_FAILED; SetCallState(CNS_COMPLETE); } } } } else { // The QueryRemote failed
switch( ncsResult ) { case UI_RC_USER_REJECTED: // The initial QueryRemote failed because GCC symmetry determined
// that the other node is calling someone, and it might be us
// See Bug 1886
TRACE_OUT(("COutgoingCall - QueryRemote rejected -> complete")); m_cnResult = CN_RC_REMOTE_PLACING_CALL; break; case UI_RC_T120_REMOTE_REQUIRE_SECURITY: m_cnResult = CN_RC_CONNECT_REMOTE_REQUIRE_SECURITY; break; case UI_RC_T120_SECURITY_FAILED: m_cnResult = CN_RC_SECURITY_FAILED; break; case UI_RC_T120_REMOTE_NO_SECURITY: m_cnResult = CN_RC_CONNECT_REMOTE_NO_SECURITY; break; case UI_RC_T120_REMOTE_DOWNLEVEL_SECURITY: m_cnResult = CN_RC_CONNECT_REMOTE_DOWNLEVEL_SECURITY; break; case UI_RC_T120_AUTHENTICATION_FAILED: m_cnResult = CN_RC_CONNECT_AUTHENTICATION_FAILED; break; default: m_cnResult = CN_RC_CONNECT_FAILED; break; } SetCallState(CNS_COMPLETE); }
DebugExitBOOL(COutgoingCall::OnQueryRemoteResult, TRUE); return TRUE; }
BOOL COutgoingCall::OnConferenceStarted(CONF_HANDLE hNewConf, HRESULT ncsResult) { DebugEntry(COutgoingCall::OnConferenceStarted);
switch (m_cnState) { case CNS_CREATING_LOCAL: { TRACE_OUT(("COutgoingCall (inviting) received ConferenceStarted event")); if (0 == ncsResult) { ASSERT(m_pConfObject); ASSERT(NULL == m_hRequest);
SetCallState(CNS_INVITING_REMOTE);
HRESULT hr = m_pConfObject->InviteConference(m_pszAddr, &m_hRequest); if (S_OK != hr) { m_hRequest = NULL; m_cnResult = CN_RC_INVITE_FAILED; SetCallState(CNS_COMPLETE); // Issue "soft" leave attempt (to allow auto-terminate)
ASSERT(m_pConfObject); HRESULT hr = m_pConfObject->LeaveConference(FALSE); if (FAILED(hr)) { WARNING_OUT(("Couldn't leave after failed invite")); } } } else { WARNING_OUT(("CreateConference (local) failed - need UI here!")); m_cnResult = CN_RC_CONFERENCE_CREATE_FAILED; SetCallState(CNS_COMPLETE); } break; }
case CNS_JOINING_REMOTE: { TRACE_OUT(("COutgoingCall (joining) received ConferenceStarted event"));
if (0 == ncsResult) { SetCallState(CNS_COMPLETE); } else if (UI_RC_INVALID_PASSWORD == ncsResult) { TRACE_OUT(("COutgoingCall - invalid password, prompt for password"));
BSTR bstrPassword = NULL; REMOTE_PASSWORD remotePw; remotePw.bstrConference = m_bstrConfToJoin; remotePw.pbstrPassword = &bstrPassword; if (NO_ERROR != hNewConf->GetCred(&remotePw.pbRemoteCred, &remotePw.cbRemoteCred)) { remotePw.pbRemoteCred = NULL; remotePw.cbRemoteCred = 0; } remotePw.fIsService = m_fService; NotifySink(&remotePw, OnNotifyRemotePassword);
if (NULL != bstrPassword) { SysFreeString(m_bstrPassword); m_bstrPassword = bstrPassword;
// reissue join with new password
ASSERT(m_pConfObject); HRESULT ncs = m_pConfObject->JoinConference( m_bstrConfToJoin, m_bstrPassword, m_pszAddr, TRUE); // retry
if (0 != ncs) { // JoinConference failed!
m_cnResult = CN_RC_JOIN_FAILED; SetCallState(CNS_COMPLETE); } } else { // cancel from pw dlg
m_cnResult = CN_RC_INVALID_PASSWORD; SetCallState(CNS_COMPLETE); ASSERT(m_pConfObject); HRESULT hr = m_pConfObject->LeaveConference(TRUE); if (FAILED(hr)) { ERROR_OUT(("Couldn't leave after cancelling pw join!")); } } } else if (UI_RC_UNKNOWN_CONFERENCE == ncsResult) { TRACE_OUT(("Join failed (conf does not exist) " "- notifying user")); // error while joining
m_cnResult = CN_RC_CONFERENCE_DOES_NOT_EXIST; SetCallState(CNS_COMPLETE); } else { TRACE_OUT(("Join failed - notifying user")); // error while joining
m_cnResult = CN_RC_CONFERENCE_JOIN_DENIED; SetCallState(CNS_COMPLETE); }
break; }
default: { if (m_pConfObject->GetConfHandle() == hNewConf) { WARNING_OUT(("COutgoingCall received unexpected ConferenceStarted event")); } else { TRACE_OUT(("COutgoingCall ignoring ConferenceStarted event - not our conf")); } } }
DebugExitBOOL(COutgoingCall::OnConferenceStarted, TRUE); return TRUE; }
void COutgoingCall::CallComplete() { DebugEntry(COutgoingCall::CallComplete);
// If this fails, we are being destructed unexpectedly
ASSERT( (m_cnState == CNS_IDLE) || (m_cnState == CNS_COMPLETE));
// The request handle should have been reset
ASSERT(NULL == m_hRequest);
if (!FCanceled() && (CN_RC_NOERROR != m_cnResult)) { ReportError(m_cnResult); }
NM_CALL_STATE state; GetState(&state); NotifySink((PVOID) state, OnNotifyCallStateChanged);
TRACE_OUT(("ConfNode destroying addr %s", m_pszAddr)); DebugExitVOID(COutgoingCall::CallComplete); }
BOOL COutgoingCall::ReportError(CNSTATUS cns) { DebugEntry(COutgoingCall::ReportError); TRACE_OUT(("CNSTATUS 0x%08x", cns)); NotifySink((PVOID)cns, OnNotifyCallError);
DebugExitBOOL(COutgoingCall::ReportError, TRUE); return TRUE; }
VOID COutgoingCall::SetCallState(CNODESTATE cnState) { NM_CALL_STATE stateOld; NM_CALL_STATE stateNew; GetState(&stateOld);
m_cnState = cnState;
// completion state will be fired off later
if (CNS_COMPLETE != cnState) { GetState(&stateNew); if (stateOld != stateNew) { NotifySink((PVOID) stateNew, OnNotifyCallStateChanged); } } }
HRESULT COutgoingCall::_Cancel(BOOL fLeaving) { DebugEntry(COutgoingCall::Cancel);
BOOL fAbortT120 = (m_cnState != CNS_COMPLETE);
if (fAbortT120) { m_fCanceled = TRUE;
// Abort T.120 Call:
// Attempt to make this transition regardless of our
// current state:
SetCallState(CNS_COMPLETE);
ASSERT(m_pConfObject);
if (NULL != m_hRequest) { REQUEST_HANDLE hRequest = m_hRequest; m_hRequest = NULL; m_pConfObject->CancelInvite(hRequest); }
if (!fLeaving && m_pConfObject->IsConferenceActive()) { HRESULT hr = m_pConfObject->LeaveConference(FALSE); if (FAILED(hr)) { WARNING_OUT(("Couldn't leave after disconnecting")); } } }
DebugExitULONG(COutgoingCall::Abort, m_cnResult);
return CN_RC_NOERROR ? S_OK : E_FAIL; }
STDMETHODIMP_(ULONG) COutgoingCall::AddRef(void) { return RefCount::AddRef(); } STDMETHODIMP_(ULONG) COutgoingCall::Release(void) { return RefCount::Release(); }
HRESULT STDMETHODCALLTYPE COutgoingCall::QueryInterface(REFIID riid, PVOID *ppv) { HRESULT hr = S_OK;
if ((riid == IID_INmCall) || (riid == IID_IUnknown)) { *ppv = (INmCall *)this; TRACE_OUT(("COutgoingCall::QueryInterface()")); } else if (riid == IID_IConnectionPointContainer) { *ppv = (IConnectionPointContainer *) this; TRACE_OUT(("CNmCall::QueryInterface(): Returning IConnectionPointContainer.")); } else { hr = E_NOINTERFACE; *ppv = NULL; TRACE_OUT(("COutgoingCall::QueryInterface(): Called on unknown interface.")); }
if (S_OK == hr) { AddRef(); }
return hr; }
HRESULT COutgoingCall::IsIncoming(void) { return S_FALSE; }
HRESULT COutgoingCall::GetState(NM_CALL_STATE *pState) { HRESULT hr = E_POINTER;
if (NULL != pState) { if (FCanceled()) { *pState = NM_CALL_CANCELED; } else { switch (m_cnState) { case CNS_IDLE: *pState = NM_CALL_INIT; break;
case CNS_SEARCHING: *pState = NM_CALL_SEARCH; break;
case CNS_WAITING_T120_OPEN: case CNS_QUERYING_REMOTE: case CNS_CREATING_LOCAL: case CNS_INVITING_REMOTE: case CNS_JOINING_REMOTE: *pState = NM_CALL_WAIT; break;
case CNS_COMPLETE: switch (m_cnResult) { case CN_RC_NOERROR: *pState = NM_CALL_ACCEPTED; break; case CN_RC_CONFERENCE_JOIN_DENIED: case CN_RC_CONFERENCE_INVITE_DENIED: case CN_RC_CONFERENCE_DOES_NOT_EXIST: case CN_RC_CONNECT_REMOTE_NO_SECURITY: case CN_RC_CONNECT_REMOTE_DOWNLEVEL_SECURITY: case CN_RC_CONNECT_REMOTE_REQUIRE_SECURITY: case CN_RC_TRANSPORT_FAILURE: case CN_RC_QUERY_FAILED: case CN_RC_CONNECT_FAILED: *pState = NM_CALL_REJECTED; break;
case CN_RC_ALREADY_IN_CONFERENCE: case CN_RC_CANT_INVITE_MCU: case CN_RC_CANT_JOIN_ALREADY_IN_CALL: case CN_RC_INVITE_DENIED_REMOTE_IN_CONF: case CN_RC_REMOTE_PLACING_CALL: case CN_RC_ALREADY_IN_CONFERENCE_MCU: case CN_RC_INVALID_PASSWORD: default: *pState = NM_CALL_CANCELED; break; } break;
default: *pState = NM_CALL_INVALID; break; } }
hr = S_OK; } return hr; }
HRESULT COutgoingCall::GetAddress(BSTR * pbstrAddr) { if (NULL == pbstrAddr) return E_POINTER;
*pbstrAddr = SysAllocString(m_bstrAddr); return (*pbstrAddr ? S_OK : E_FAIL); }
HRESULT COutgoingCall::GetConference(INmConference **ppConference) { HRESULT hr = E_POINTER;
if (NULL != ppConference) { *ppConference = m_pConfObject; return S_OK; }
return hr; }
HRESULT COutgoingCall::Accept(void) { return E_UNEXPECTED; }
HRESULT COutgoingCall::Reject(void) { return E_UNEXPECTED; }
HRESULT COutgoingCall::Cancel(void) { DebugEntry(COutgoingCall::Cancel);
AddRef(); // protect against Release() while processing
// disconnect related indications & callbacks
HRESULT hr = _Cancel(FALSE); if (FIsComplete()) { COprahNCUI *pOprahNCUI = COprahNCUI::GetInstance(); ASSERT(NULL !=pOprahNCUI); pOprahNCUI->OnOutgoingCallCanceled(this); }
DebugExitULONG(COutgoingCall::Abort, m_cnResult);
Release();
return hr; }
/* O N N O T I F Y C A L L E R R O R */ /*-------------------------------------------------------------------------
%%Function: OnNotifyCallError -------------------------------------------------------------------------*/ HRESULT OnNotifyCallError(IUnknown *pCallNotify, PVOID pv, REFIID riid) { ASSERT(NULL != pCallNotify); CNSTATUS cnStatus = (CNSTATUS)((DWORD_PTR)pv); switch (cnStatus) { case CN_RC_ALREADY_IN_CONFERENCE: case CN_RC_CANT_INVITE_MCU: case CN_RC_CANT_JOIN_ALREADY_IN_CALL: case CN_RC_INVITE_DENIED_REMOTE_IN_CONF: case CN_RC_REMOTE_PLACING_CALL: case CN_RC_ALREADY_IN_CONFERENCE_MCU: ((INmCallNotify*)pCallNotify)->NmUI(CONFN_CALL_IN_CONFERENCE); break; case CN_RC_CONFERENCE_JOIN_DENIED: case CN_RC_CONFERENCE_INVITE_DENIED: case CN_RC_CONFERENCE_DOES_NOT_EXIST: case CN_RC_CONNECT_REMOTE_NO_SECURITY: case CN_RC_CONNECT_REMOTE_DOWNLEVEL_SECURITY: case CN_RC_CONNECT_REMOTE_REQUIRE_SECURITY: ((INmCallNotify*)pCallNotify)->NmUI(CONFN_CALL_IGNORED); break; case CN_RC_CONNECT_FAILED: ((INmCallNotify*)pCallNotify)->NmUI(CONFN_CALL_FAILED); break; default: break; }
if (IID_INmCallNotify == riid) { ((INmCallNotify*)pCallNotify)->CallError(cnStatus); } return S_OK; }
/* O N N O T I F Y R E M O T E C O N F E R E N C E */ /*-------------------------------------------------------------------------
%%Function: OnNotifyRemoteConference -------------------------------------------------------------------------*/ HRESULT OnNotifyRemoteConference(IUnknown *pCallNotify, PVOID pv, REFIID riid) { REMOTE_CONFERENCE *prc = (REMOTE_CONFERENCE *)pv;
// WARNING: pwszConfName is an PWSTR array, not a BSTR
ASSERT(NULL != pCallNotify); ((INmCallNotify*)pCallNotify)->RemoteConference(prc->fMCU, (BSTR *) prc->pwszConfNames, prc->pbstrConfToJoin); return S_OK; }
/* O N N O T I F Y R E M O T E P A S S W O R D */ /*-------------------------------------------------------------------------
%%Function: OnNotifyRemotePassword -------------------------------------------------------------------------*/ HRESULT OnNotifyRemotePassword(IUnknown *pCallNotify, PVOID pv, REFIID riid) { REMOTE_PASSWORD *prp = (REMOTE_PASSWORD *)pv;
ASSERT(NULL != pCallNotify); ((INmCallNotify*)pCallNotify)->RemotePassword(prp->bstrConference, prp->pbstrPassword, prp->pbRemoteCred, prp->cbRemoteCred); return S_OK; }
COutgoingCallManager::COutgoingCallManager() { }
COutgoingCallManager::~COutgoingCallManager() { // Empty the call list:
while (!m_CallList.IsEmpty()) { COutgoingCall* pCall = (COutgoingCall*) m_CallList.RemoveHead(); // Shouldn't have any NULL entries:
ASSERT(pCall); pCall->Release(); } }
UINT COutgoingCallManager::GetCallCount() { UINT nNodes = 0; POSITION pos = m_CallList.GetHeadPosition(); while (pos) { nNodes++; m_CallList.GetNext(pos); } return nNodes; }
HRESULT COutgoingCallManager::Call( INmCall **ppCall, COprahNCUI* pManager, DWORD dwFlags, NM_ADDR_TYPE addrType, BSTR bstrAddr, BSTR bstrConference, BSTR bstrPassword) { DebugEntry(COutgoingCallManager::CallConference); HRESULT hr = E_FAIL; COutgoingCall* pCall = NULL; CConfObject* pConfObject = pManager->GetConfObject(); if (NULL != ppCall) { *ppCall = NULL; }
if (pConfObject->IsConferenceActive() && (NULL != bstrConference)) { hr= NM_CALLERR_IN_CONFERENCE; } else { if (!pConfObject->IsConferenceActive()) { pConfObject->SetConfSecurity(0 != (CRPCF_SECURE & dwFlags)); }
pCall = new COutgoingCall( pConfObject, dwFlags, addrType, bstrAddr, bstrConference, bstrPassword); if (NULL != pCall) { m_CallList.AddTail(pCall);
if (NULL != ppCall) { pCall->AddRef();
// This MUST be set before OnNotifyCallCreated
*ppCall = pCall; }
pCall->AddRef();
pManager->OnOutgoingCallCreated(pCall);
pCall->PlaceCall();
if (pCall->FIsComplete()) { RemoveFromList(pCall); }
pCall->Release();
// let the caller know that we successfully created the call
// any error will be reported asynchronously
hr = S_OK; } }
DebugExitHRESULT(COutgoingCallManager::CallConference, hr); return hr; }
BOOL COutgoingCallManager::RemoveFromList(COutgoingCall* pCall) { DebugEntry(COutgoingCallManager::RemoveFromList); ASSERT(pCall); BOOL bRet = FALSE;
POSITION pos = m_CallList.GetPosition(pCall); if (NULL != pos) { m_CallList.RemoveAt(pos);
pCall->CallComplete(); pCall->Release();
bRet = TRUE; } else { WARNING_OUT(("COutgoingCallManager::RemoveFromList() could not match call")); }
DebugExitBOOL(COutgoingCallManager::RemoveFromList, bRet); return bRet; }
VOID COutgoingCallManager::OnConferenceStarted(CONF_HANDLE hConference, HRESULT hResult) { DebugEntry(COutgoingCallManager::OnConferenceStarted);
// Tell all ConfNode's that a conference has started
POSITION pos = m_CallList.GetHeadPosition(); while (pos) { COutgoingCall* pCall = (COutgoingCall*) m_CallList.GetNext(pos);
if (NULL != pCall) { pCall->AddRef(); pCall->OnConferenceStarted(hConference, hResult); if (pCall->FIsComplete()) { RemoveFromList(pCall); } pCall->Release(); } }
DebugExitVOID(COutgoingCallManager::OnConferenceStarted); }
VOID COutgoingCallManager::OnQueryRemoteResult(PVOID pvCallerContext, HRESULT hResult, BOOL fMCU, PWSTR* ppwszConferenceNames, PWSTR* ppwszConfDescriptors) { DebugEntry(COutgoingCallManager::OnQueryRemoteResult);
POSITION pos = m_CallList.GetHeadPosition(); while (pos) { COutgoingCall* pCall = (COutgoingCall*) m_CallList.GetNext(pos);
// Notify the node that issued the query:
if ((COutgoingCall*) pvCallerContext == pCall) { pCall->AddRef(); pCall->OnQueryRemoteResult( hResult, fMCU, ppwszConferenceNames, ppwszConfDescriptors); if (pCall->FIsComplete()) { RemoveFromList(pCall); } pCall->Release(); break; } } DebugExitVOID(COutgoingCallManager::OnQueryRemoteResult); }
VOID COutgoingCallManager::OnInviteResult( CONF_HANDLE hConference, REQUEST_HANDLE hRequest, UINT uNodeID, HRESULT hResult) { DebugEntry(COutgoingCallManager::OnInviteResult);
POSITION pos = m_CallList.GetHeadPosition(); while (pos) { COutgoingCall* pCall = (COutgoingCall*) m_CallList.GetNext(pos);
if ((NULL != pCall) && (pCall->GetCurrentRequestHandle() == hRequest)) { pCall->AddRef(); pCall->OnInviteResult(hResult, uNodeID); if (pCall->FIsComplete()) { RemoveFromList(pCall); } pCall->Release(); break; } }
DebugExitVOID(COutgoingCallManager::OnInviteResult); }
VOID COutgoingCallManager::OnConferenceEnded(CONF_HANDLE hConference) { DebugEntry(COutgoingCallManager::OnConferenceEnded);
// Tell all ConfNode's that a conference has started
POSITION pos = m_CallList.GetHeadPosition(); while (pos) { COutgoingCall* pCall = (COutgoingCall*) m_CallList.GetNext(pos);
if (NULL != pCall) { pCall->AddRef(); pCall->OnConferenceEnded(); if (pCall->FIsComplete()) { RemoveFromList(pCall); } pCall->Release(); } }
DebugExitVOID(COutgoingCallManager::OnConferenceEnded); }
VOID COutgoingCallManager::CancelCalls() { DebugEntry(COutgoingCallManager::CancelCalls);
// Tell all ConfNode's that a conference has started
POSITION pos = m_CallList.GetHeadPosition(); while (pos) { COutgoingCall* pCall = (COutgoingCall*) m_CallList.GetNext(pos);
if (NULL != pCall) { pCall->AddRef(); pCall->_Cancel(TRUE); if (pCall->FIsComplete()) { RemoveFromList(pCall); } pCall->Release(); } }
DebugExitVOID(COutgoingCallManager::CancelCalls); }
|