Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1212 lines
26 KiB

// 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);
}