2025-04-27 07:49:33 -04:00

392 lines
7.8 KiB
C++

// File: icallin.cpp
#include "precomp.h"
#include "cncodes.h" // needed for CN_
#include "icall_in.h"
#include "imanager.h"
extern HRESULT OnNotifyCallError(IUnknown *pCallNotify, PVOID pv, REFIID riid);
static HRESULT OnNotifyCallAccepted(IUnknown *pCallNotify, PVOID pv, REFIID riid);
// Internal code to indicate that there was no security data available in an incoming call.
const int CALL_NO_SECURITY_DATA = -1;
static const IID * g_apiidCP_Call[] =
{
{&IID_INmCallNotify}
};
CIncomingCall::CIncomingCall(
COprahNCUI * pOprahNCUI,
BOOL fInvite,
CONF_HANDLE hConf,
PCWSTR pcwszNodeName) :
CConnectionPointContainer(g_apiidCP_Call, ARRAY_ELEMENTS(g_apiidCP_Call)),
m_pOprahNCUI(pOprahNCUI),
m_fInvite(fInvite),
m_hConf(hConf),
m_bstrCaller(SysAllocString(pcwszNodeName)),
m_State(NM_CALL_INIT),
m_dwFlags(0)
{
DebugEntry(CIncomingCall::CIncomingCall[T120]);
DebugExitVOID(CIncomingCall::CIncomingCall);
}
CIncomingCall::CIncomingCall(COprahNCUI *pOprahNCUI,
DWORD dwFlags) :
CConnectionPointContainer(g_apiidCP_Call, ARRAY_ELEMENTS(g_apiidCP_Call)),
m_pOprahNCUI(pOprahNCUI),
m_fInvite(FALSE),
m_hConf(NULL),
m_bstrCaller(NULL),
m_State(NM_CALL_INIT),
m_dwFlags(dwFlags),
m_fMemberAdded(FALSE)
{
DebugEntry(CIncomingCall::CIncomingCall);
DebugExitVOID(CIncomingCall::CIncomingCall);
}
CIncomingCall::~CIncomingCall()
{
DebugEntry(CIncomingCall::~CIncomingCall);
SysFreeString(m_bstrCaller);
DebugExitVOID(CIncomingCall::CIncomingCall);
}
void CIncomingCall::Ring()
{
m_State = NM_CALL_RING;
NotifySink((PVOID) m_State, OnNotifyCallStateChanged);
}
VOID CIncomingCall::OnIncomingT120Call(BOOL fInvite)
{
m_fInvite = fInvite;
}
HRESULT CIncomingCall::OnT120ConferenceEnded()
{
m_hConf = NULL;
if (NM_CALL_RING == m_State)
{
m_State = NM_CALL_CANCELED;
NotifySink((PVOID) m_State, OnNotifyCallStateChanged);
}
return S_OK;
}
HRESULT CIncomingCall::Terminate(BOOL fReject)
{
HRESULT hr = E_FAIL;
// need to make sure that we are still ringing
if ((NM_CALL_ACCEPTED != m_State) &&
(NM_CALL_REJECTED != m_State) &&
(NM_CALL_CANCELED != m_State))
{
m_State = fReject ? NM_CALL_REJECTED : NM_CALL_CANCELED;
TRACE_OUT(("CIncomingCall: Call not accepted - responding"));
if (NULL != m_hConf)
{
CONF_HANDLE hConf = m_hConf;
m_hConf = NULL;
if (m_fInvite)
{
hConf->InviteResponse(FALSE);
}
else
{
CConfObject *pco = ::GetConfObject();
ASSERT(pco);
if (pco->GetConfHandle() == hConf)
{
hConf->JoinResponse(FALSE);
}
}
}
NotifySink((PVOID) m_State, OnNotifyCallStateChanged);
hr = S_OK;
}
return hr;
}
STDMETHODIMP_(ULONG) CIncomingCall::AddRef(void)
{
return RefCount::AddRef();
}
STDMETHODIMP_(ULONG) CIncomingCall::Release(void)
{
return RefCount::Release();
}
HRESULT STDMETHODCALLTYPE CIncomingCall::QueryInterface(REFIID riid, PVOID *ppv)
{
HRESULT hr = S_OK;
if ((riid == IID_INmCall) || (riid == IID_IUnknown))
{
*ppv = (INmCall *)this;
TRACE_OUT(("CIncomingCall::QueryInterface()"));
}
else if (riid == IID_IConnectionPointContainer)
{
*ppv = (IConnectionPointContainer *) this;
TRACE_OUT(("CIncomingCall::QueryInterface(): Returning IConnectionPointContainer."));
}
else
{
hr = E_NOINTERFACE;
*ppv = NULL;
TRACE_OUT(("CIncomingCall::QueryInterface(): Called on unknown interface."));
}
if (S_OK == hr)
{
AddRef();
}
return hr;
}
HRESULT CIncomingCall::IsIncoming(void)
{
return S_OK;
}
HRESULT CIncomingCall::GetState(NM_CALL_STATE *pState)
{
HRESULT hr = E_POINTER;
if (NULL != pState)
{
*pState = m_State;
hr = S_OK;
}
return hr;
}
HRESULT CIncomingCall::GetAddress(BSTR * pbstrName)
{
if (NULL == pbstrName)
return E_POINTER;
*pbstrName = SysAllocString(m_bstrCaller);
return (*pbstrName ? S_OK : E_FAIL);
}
HRESULT CIncomingCall::GetConference(INmConference **ppConference)
{
#ifdef NOTYET
*ppConference = NULL;
CConfObject *pco = ::GetConfObject();
if (NULL != pco)
{
if (pco->GetConfHandle() == m_hConf)
{
*ppConference = pco;
return S_OK;
}
return E_UNEXPECTED;
}
#endif
return S_FALSE;
}
HRESULT CIncomingCall::Accept(void)
{
HRESULT hr = E_FAIL;
// need to make sure that we are still ringing
if (NM_CALL_RING == m_State)
{
m_pOprahNCUI->OnIncomingCallAccepted();
CConfObject *pco = ::GetConfObject();
ASSERT(pco);
if ((NULL != m_hConf) && (pco->GetConfHandle() == m_hConf))
{
if (m_fInvite)
{
hr = m_hConf->InviteResponse(TRUE);
}
else
if (pco->GetConfHandle() == m_hConf)
{
hr = m_hConf->JoinResponse(TRUE);
}
}
if (S_OK == hr)
{
// notify all call observers that the call was accepted
m_State = NM_CALL_ACCEPTED;
NotifySink((INmConference *) pco, OnNotifyCallAccepted);
}
else
{
// call went away before it was accepted
m_State = NM_CALL_CANCELED;
NotifySink((PVOID)CN_RC_CONFERENCE_ENDED_BEFORE_ACCEPTED, OnNotifyCallError);
}
// notify all call observers of the state change
NotifySink((PVOID) m_State, OnNotifyCallStateChanged);
}
else
{
hr = ((NM_CALL_ACCEPTED == m_State) ? S_OK : E_FAIL);
}
return hr;
}
HRESULT CIncomingCall::Reject(void)
{
return Terminate(TRUE);
}
HRESULT CIncomingCall::Cancel(void)
{
return Terminate(FALSE);
}
/* O N N O T I F Y C A L L A C C E P T E D */
/*-------------------------------------------------------------------------
%%Function: OnNotifyCallAccepted
-------------------------------------------------------------------------*/
HRESULT OnNotifyCallAccepted(IUnknown *pCallNotify, PVOID pv, REFIID riid)
{
ASSERT(NULL != pCallNotify);
((INmCallNotify*)pCallNotify)->Accepted((INmConference *) pv);
return S_OK;
}
CIncomingCallManager::CIncomingCallManager()
{
}
CIncomingCallManager::~CIncomingCallManager()
{
// Empty the call list:
while (!m_CallList.IsEmpty())
{
CIncomingCall* pCall = (CIncomingCall*) m_CallList.RemoveHead();
// Shouldn't have any NULL entries:
ASSERT(pCall);
pCall->Release();
}
}
VOID CIncomingCallManager::OnT120ConferenceEnded(CONF_HANDLE hConference)
{
POSITION pos = m_CallList.GetHeadPosition();
POSITION posItem;
while (posItem = pos)
{
CIncomingCall* pCall = (CIncomingCall*) m_CallList.GetNext(pos);
if ((NULL != pCall) &&
(hConference == pCall->GetConfHandle()))
{
if (S_OK == pCall->OnT120ConferenceEnded())
{
m_CallList.RemoveAt(posItem);
pCall->Release();
}
}
}
}
HRESULT CIncomingCallManager::OnIncomingT120Call(
COprahNCUI *pManager,
BOOL fInvite,
CONF_HANDLE hConf,
PCWSTR pcwszNodeName,
BOOL fSecure)
{
HRESULT hr = S_OK;
CIncomingCall *pCall = new CIncomingCall(pManager,
fInvite,
hConf,
pcwszNodeName);
if (NULL != pCall)
{
// currently we don't add T120 calls to the call list
pManager->OnIncomingCallCreated(pCall);
pCall->Ring();
// we're not holding on to the call so release it
pCall->Release();
}
else
{
// unable to accept call
if (fInvite)
{
hr = hConf->InviteResponse(FALSE);
}
else
{
hConf->JoinResponse(FALSE);
}
hr = E_OUTOFMEMORY;
}
return hr;
}
VOID CIncomingCallManager::CancelCalls()
{
DebugEntry(CIncomingCallManager::CancelCalls);
POSITION pos = m_CallList.GetHeadPosition();
POSITION posItem;
while (posItem = pos)
{
CIncomingCall* pCall = (CIncomingCall*) m_CallList.GetNext(pos);
if (NULL != pCall)
{
if (SUCCEEDED(pCall->Terminate(FALSE)))
{
m_CallList.RemoveAt(posItem);
pCall->Release();
}
}
}
DebugExitVOID(CIncomingCallManager::CancelCalls);
}