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.
1100 lines
25 KiB
1100 lines
25 KiB
// File: icallin.cpp
|
|
|
|
#include "precomp.h"
|
|
|
|
#include <regentry.h>
|
|
|
|
#include "cncodes.h" // needed for CN_
|
|
#include "icall_in.h"
|
|
#include "imanager.h"
|
|
#include "util.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},
|
|
{&IID_INmCallNotify2}
|
|
};
|
|
|
|
CIncomingCall::CIncomingCall(
|
|
COprahNCUI * pOprahNCUI,
|
|
BOOL fInvite,
|
|
CONF_HANDLE hConf,
|
|
PCWSTR pcwszNodeName,
|
|
PUSERDATAINFO pUserDataInfoEntries,
|
|
UINT cUserDataEntries) :
|
|
CConnectionPointContainer(g_apiidCP_Call, ARRAY_ELEMENTS(g_apiidCP_Call)),
|
|
m_pOprahNCUI(pOprahNCUI),
|
|
m_pConnection(NULL),
|
|
m_fInvite(fInvite),
|
|
m_hConf(hConf),
|
|
m_bstrCaller(SysAllocString(pcwszNodeName)),
|
|
m_State(NM_CALL_INIT),
|
|
m_dwFlags(0)
|
|
{
|
|
DebugEntry(CIncomingCall::CIncomingCall[T120]);
|
|
|
|
ProcessT120UserData(pUserDataInfoEntries, cUserDataEntries);
|
|
|
|
|
|
DebugExitVOID(CIncomingCall::CIncomingCall);
|
|
}
|
|
|
|
CIncomingCall::CIncomingCall(COprahNCUI *pOprahNCUI,
|
|
IH323Endpoint* pConnection, P_APP_CALL_SETUP_DATA lpvMNMData,
|
|
DWORD dwFlags) :
|
|
CConnectionPointContainer(g_apiidCP_Call, ARRAY_ELEMENTS(g_apiidCP_Call)),
|
|
m_pOprahNCUI(pOprahNCUI),
|
|
m_pConnection(pConnection),
|
|
m_fInvite(FALSE),
|
|
m_hConf(NULL),
|
|
m_bstrCaller(NULL),
|
|
m_State(NM_CALL_INIT),
|
|
m_guidNode(GUID_NULL),
|
|
m_dwFlags(dwFlags),
|
|
m_fMemberAdded(FALSE)
|
|
{
|
|
DebugEntry(CIncomingCall::CIncomingCall[H323]);
|
|
HRESULT hr;
|
|
ASSERT(m_pConnection);
|
|
|
|
m_pConnection->AddRef();
|
|
|
|
WCHAR wszCaller[MAX_CALLER_NAME];
|
|
if (SUCCEEDED(m_pConnection->GetRemoteUserName(wszCaller, MAX_CALLER_NAME)))
|
|
{
|
|
m_bstrCaller = SysAllocString(wszCaller);
|
|
}
|
|
|
|
if ((NULL != lpvMNMData) && (lpvMNMData->dwDataSize > sizeof(DWORD)))
|
|
{
|
|
BYTE *pbData = ((BYTE*)lpvMNMData->lpData) + sizeof(DWORD);
|
|
DWORD cbRemaining = lpvMNMData->dwDataSize - sizeof(DWORD);
|
|
|
|
while ((sizeof(GUID) + sizeof(DWORD)) < cbRemaining)
|
|
{
|
|
DWORD cbData = *(DWORD*)(pbData + sizeof(GUID));
|
|
DWORD cbRecord = cbData + sizeof(GUID) + sizeof(DWORD);
|
|
|
|
if (cbRemaining < cbRecord)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (*(GUID *)pbData == g_csguidNodeIdTag)
|
|
{
|
|
m_guidNode = *(GUID *)(pbData + sizeof(GUID) + sizeof(DWORD));
|
|
}
|
|
|
|
m_UserData.AddUserData((GUID *)pbData,
|
|
(unsigned short)cbData,
|
|
pbData + sizeof(GUID) + sizeof(DWORD));
|
|
cbRemaining -= cbRecord;
|
|
pbData += cbRecord;
|
|
}
|
|
}
|
|
|
|
DebugExitVOID(CIncomingCall::CIncomingCall);
|
|
}
|
|
|
|
CIncomingCall::~CIncomingCall()
|
|
{
|
|
DebugEntry(CIncomingCall::~CIncomingCall);
|
|
|
|
if(m_pConnection)
|
|
{
|
|
m_pConnection->Release();
|
|
m_pConnection = NULL;
|
|
}
|
|
|
|
SysFreeString(m_bstrCaller);
|
|
|
|
DebugExitVOID(CIncomingCall::CIncomingCall);
|
|
}
|
|
|
|
VOID CIncomingCall::ProcessT120UserData(
|
|
PUSERDATAINFO pUserDataInfoEntries,
|
|
UINT cUserDataEntries)
|
|
{
|
|
if (cUserDataEntries > 0)
|
|
{
|
|
ASSERT(pUserDataInfoEntries);
|
|
for (UINT u = 0; u < cUserDataEntries; u++)
|
|
{
|
|
m_UserData.AddUserData(pUserDataInfoEntries[u].pGUID,
|
|
(unsigned short)pUserDataInfoEntries[u].cbData,
|
|
pUserDataInfoEntries[u].pData);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL CIncomingCall::MatchAcceptedCaller(PCWSTR pcwszNodeName)
|
|
{
|
|
// check to see if this caller matches someone whom we already accepted
|
|
if ((NULL != m_pConnection) &&
|
|
(NM_CALL_ACCEPTED == m_State) &&
|
|
(GUID_NULL == m_guidNode) &&
|
|
(NULL != m_bstrCaller) &&
|
|
(0 == UnicodeCompare(m_bstrCaller, pcwszNodeName)) )
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL CIncomingCall::MatchAcceptedCaller(GUID* pguidNodeId)
|
|
{
|
|
// check to see if this caller matches someone whom we already accepted
|
|
if ((NULL != m_pConnection) &&
|
|
((NM_CALL_INIT == m_State) ||
|
|
(NM_CALL_ACCEPTED == m_State)) &&
|
|
(GUID_NULL != m_guidNode) &&
|
|
(*pguidNodeId == m_guidNode))
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL CIncomingCall::MatchActiveCaller(GUID* pguidNodeId)
|
|
{
|
|
// check to see if this caller matches someone whom we already accepted
|
|
// or is in the process of calling us
|
|
if ((NULL != m_pConnection) &&
|
|
((NM_CALL_INIT == m_State) ||
|
|
(NM_CALL_RING == m_State) ||
|
|
(NM_CALL_ACCEPTED == m_State)) &&
|
|
(GUID_NULL != m_guidNode) &&
|
|
(*pguidNodeId == m_guidNode))
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void CIncomingCall::Ring()
|
|
{
|
|
m_State = NM_CALL_RING;
|
|
NotifySink((PVOID) m_State, OnNotifyCallStateChanged);
|
|
}
|
|
|
|
HRESULT CIncomingCall::OnH323Connected()
|
|
{
|
|
CConfObject *pco = ::GetConfObject();
|
|
if (NULL != pco)
|
|
{
|
|
BOOL fAddMember = DidUserAccept();
|
|
|
|
pco->OnH323Connected(m_pConnection, m_dwFlags, fAddMember, m_guidNode);
|
|
|
|
m_fMemberAdded = fAddMember;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CIncomingCall::OnH323Disconnected()
|
|
{
|
|
if (NM_CALL_RING == m_State)
|
|
{
|
|
if (m_hConf)
|
|
{
|
|
CONF_HANDLE hConf = m_hConf;
|
|
m_hConf = NULL;
|
|
// if there is an invite or join pending, kill it
|
|
if ( m_fInvite )
|
|
hConf->InviteResponse(FALSE);
|
|
else
|
|
hConf->JoinResponse(FALSE);
|
|
}
|
|
}
|
|
|
|
if(m_pConnection)
|
|
{
|
|
m_pConnection->Release();
|
|
m_pConnection = NULL;
|
|
}
|
|
|
|
if ((NM_CALL_RING == m_State) ||
|
|
(NM_CALL_INIT == m_State))
|
|
{
|
|
m_State = NM_CALL_CANCELED;
|
|
NotifySink((PVOID) m_State, OnNotifyCallStateChanged);
|
|
}
|
|
|
|
return m_hConf ? S_FALSE : S_OK;
|
|
}
|
|
|
|
VOID CIncomingCall::OnIncomingT120Call(
|
|
BOOL fInvite,
|
|
PUSERDATAINFO pUserDataInfoEntries,
|
|
UINT cUserDataEntries)
|
|
{
|
|
m_fInvite = fInvite;
|
|
|
|
ProcessT120UserData(pUserDataInfoEntries, cUserDataEntries);
|
|
}
|
|
|
|
HRESULT CIncomingCall::OnT120ConferenceEnded()
|
|
{
|
|
m_hConf = NULL;
|
|
|
|
if(!m_fMemberAdded && m_pConnection)
|
|
{
|
|
// we didn't hand off this connection to the member
|
|
IH323Endpoint* pConnection = m_pConnection;
|
|
m_pConnection = NULL;
|
|
pConnection->Disconnect();
|
|
pConnection->Release();
|
|
}
|
|
|
|
if (NM_CALL_RING == m_State)
|
|
{
|
|
m_State = NM_CALL_CANCELED;
|
|
NotifySink((PVOID) m_State, OnNotifyCallStateChanged);
|
|
}
|
|
|
|
return m_pConnection ? S_FALSE : 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();
|
|
if ((NULL != pco) && (pco->GetConfHandle() == hConf))
|
|
{
|
|
hConf->JoinResponse(FALSE);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (NULL != m_pConnection)
|
|
{
|
|
ConnectStateType state;
|
|
hr = m_pConnection->GetState(&state);
|
|
ASSERT(SUCCEEDED(hr));
|
|
if(CLS_Alerting == state)
|
|
{
|
|
IH323Endpoint* pConn = m_pConnection;
|
|
m_pConnection = NULL;
|
|
pConn->AcceptRejectConnection(CRR_REJECT);
|
|
pConn->Release();
|
|
m_pOprahNCUI->ReleaseAV(pConn);
|
|
}
|
|
}
|
|
|
|
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;
|
|
ApiDebugMsg(("CIncomingCall::QueryInterface()"));
|
|
}
|
|
else if (riid == IID_IConnectionPointContainer)
|
|
{
|
|
*ppv = (IConnectionPointContainer *) this;
|
|
ApiDebugMsg(("CIncomingCall::QueryInterface(): Returning IConnectionPointContainer."));
|
|
}
|
|
else
|
|
{
|
|
hr = E_NOINTERFACE;
|
|
*ppv = NULL;
|
|
ApiDebugMsg(("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::GetName(BSTR * pbstrName)
|
|
{
|
|
if (NULL == pbstrName)
|
|
return E_POINTER;
|
|
|
|
*pbstrName = SysAllocString(m_bstrCaller);
|
|
return (*pbstrName ? S_OK : E_FAIL);
|
|
}
|
|
|
|
HRESULT CIncomingCall::GetAddr(BSTR * pbstrAddr, NM_ADDR_TYPE *puType)
|
|
{
|
|
// for now we just do the same thing as NM2.11
|
|
if ((NULL == pbstrAddr) || (NULL == puType))
|
|
return E_POINTER;
|
|
|
|
*puType = NM_ADDR_UNKNOWN;
|
|
*pbstrAddr = SysAllocString(L"");
|
|
return (*pbstrAddr ? S_OK : E_FAIL);
|
|
}
|
|
|
|
HRESULT CIncomingCall::GetUserData(REFGUID rguid, BYTE **ppb, ULONG *pcb)
|
|
{
|
|
return m_UserData.GetUserData(rguid,ppb,pcb);
|
|
}
|
|
|
|
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) && ( NULL != pco ) && (pco->GetConfHandle() == m_hConf))
|
|
{
|
|
if (m_fInvite)
|
|
{
|
|
hr = m_hConf->InviteResponse(TRUE);
|
|
}
|
|
else
|
|
if (pco->GetConfHandle() == m_hConf)
|
|
{
|
|
hr = m_hConf->JoinResponse(TRUE);
|
|
}
|
|
}
|
|
else if (NULL != m_pConnection)
|
|
{
|
|
ConnectStateType state;
|
|
HRESULT hrTemp = m_pConnection->GetState(&state);
|
|
ASSERT(SUCCEEDED(hrTemp));
|
|
if(CLS_Alerting == state)
|
|
{
|
|
hr = m_pConnection->AcceptRejectConnection(CRR_ACCEPT);
|
|
}
|
|
}
|
|
|
|
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);
|
|
if(m_pOprahNCUI)
|
|
{
|
|
m_pOprahNCUI->OnH323Disconnected(m_pConnection);
|
|
}
|
|
}
|
|
|
|
// 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();
|
|
}
|
|
}
|
|
|
|
CREQ_RESPONSETYPE CIncomingCallManager::OnIncomingH323Call(
|
|
COprahNCUI *pManager,
|
|
IH323Endpoint* pConnection,
|
|
P_APP_CALL_SETUP_DATA lpvMNMData)
|
|
{
|
|
CREQ_RESPONSETYPE resp;
|
|
|
|
///////////////////////////////////////////////////
|
|
// first we determine the capabilities the caller
|
|
///////////////////////////////////////////////////
|
|
|
|
BOOL fRequestAutoAccept = FALSE;
|
|
// don't assume anything about security
|
|
BOOL fT120SecureCall = FALSE;
|
|
BOOL fT120NonSecureCall = FALSE;
|
|
// assume that the caller can do an invite or a join
|
|
BOOL fT120Invite = TRUE;
|
|
BOOL fT120Join = TRUE;
|
|
// assume that the caller wants a/v
|
|
BOOL fRequestAV = TRUE;
|
|
// assume that the caller is not NM2.X
|
|
BOOL fCallerNM2x = FALSE;
|
|
|
|
PCC_VENDORINFO pLocalVendorInfo;
|
|
PCC_VENDORINFO pRemoteVendorInfo;
|
|
if (S_OK == pConnection->GetVersionInfo(&pLocalVendorInfo, &pRemoteVendorInfo))
|
|
{
|
|
H323VERSION version = GetH323Version(pRemoteVendorInfo);
|
|
|
|
switch (version)
|
|
{
|
|
case H323_NetMeeting20:
|
|
case H323_NetMeeting21:
|
|
case H323_NetMeeting211:
|
|
fCallerNM2x = TRUE;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ((NULL != lpvMNMData) &&
|
|
(lpvMNMData->dwDataSize >= sizeof(DWORD)))
|
|
{
|
|
DWORD dwUserData = *((LPDWORD)lpvMNMData->lpData);
|
|
if (fCallerNM2x)
|
|
{
|
|
fRequestAutoAccept = (H323UDF_ALREADY_IN_T120_CALL == dwUserData);
|
|
fT120SecureCall = FALSE;
|
|
fT120NonSecureCall = TRUE;
|
|
fT120Invite = TRUE;
|
|
fT120Join = TRUE;
|
|
fRequestAV = TRUE;
|
|
}
|
|
else if (0 != dwUserData)
|
|
{
|
|
fT120SecureCall = (H323UDF_SECURE & dwUserData);
|
|
fT120NonSecureCall = !fT120SecureCall;
|
|
fT120Invite = (H323UDF_INVITE & dwUserData);
|
|
fT120Join = (H323UDF_JOIN & dwUserData);
|
|
fRequestAV = ((H323UDF_AUDIO | H323UDF_VIDEO) & dwUserData);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////
|
|
// next we determine the state of us the callee
|
|
////////////////////////////////////////////////
|
|
|
|
DWORD dwFlags = CRPCF_DATA;
|
|
BOOL fAcceptSecure = TRUE;
|
|
BOOL fAcceptNonSecure = TRUE;
|
|
|
|
CConfObject *pco = ::GetConfObject();
|
|
if( NULL == pco )
|
|
{
|
|
ERROR_OUT(( "CConfObject not found" ));
|
|
resp = CRR_REJECT;
|
|
goto REJECT_CALL;
|
|
}
|
|
|
|
BOOL fInActiveConference = pco->IsConferenceActive();
|
|
|
|
if (fInActiveConference)
|
|
{
|
|
//
|
|
// If we've reached our limit of attendees, reject it. Also reject
|
|
// it if incoming calls are prevented by settings.
|
|
//
|
|
if (pco->GetNumMembers() >= pco->GetConfMaxParticipants())
|
|
{
|
|
ASSERT(pco->GetNumMembers() == pco->GetConfMaxParticipants());
|
|
|
|
WARNING_OUT(("Rejecting incoming H.323 call, reached limit setting of %d",
|
|
pco->GetConfMaxParticipants()));
|
|
resp = CRR_REJECT;
|
|
goto REJECT_CALL;
|
|
}
|
|
|
|
if ((pco->IsHosting() != S_OK) &&
|
|
!(pco->GetConfAttendeePermissions() & NM_PERMIT_INCOMINGCALLS))
|
|
{
|
|
WARNING_OUT(("Rejecting incoming H.323 call, not permitted by meeting setting"));
|
|
resp = CRR_REJECT;
|
|
goto REJECT_CALL;
|
|
}
|
|
|
|
//
|
|
// We're in a conference, the security settings are whatever those
|
|
// of the conference are. The user prefs are just for establishing
|
|
// the first call.
|
|
//
|
|
if (pco->IsConfObjSecure())
|
|
{
|
|
fAcceptNonSecure = FALSE;
|
|
}
|
|
else
|
|
{
|
|
fAcceptSecure = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// we are not in a conference so use the prefered settings
|
|
|
|
RegEntry reConf(POLICIES_KEY, HKEY_CURRENT_USER);
|
|
switch (reConf.GetNumber(REGVAL_POL_SECURITY, DEFAULT_POL_SECURITY))
|
|
{
|
|
case DISABLED_POL_SECURITY:
|
|
fAcceptSecure = FALSE;
|
|
break;
|
|
|
|
case REQUIRED_POL_SECURITY:
|
|
fAcceptNonSecure = FALSE;
|
|
break;
|
|
|
|
default:
|
|
{
|
|
RegEntry rePref(CONFERENCING_KEY, HKEY_CURRENT_USER);
|
|
|
|
// Is incoming required to be secure by preference?
|
|
if (rePref.GetNumber(REGVAL_SECURITY_INCOMING_REQUIRED,
|
|
DEFAULT_SECURITY_INCOMING_REQUIRED))
|
|
{
|
|
fAcceptNonSecure = FALSE;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////
|
|
// now we weed out non acceptable callers
|
|
//////////////////////////////////////////
|
|
|
|
if (fCallerNM2x && !fAcceptNonSecure)
|
|
{
|
|
// NetMeeting 2.X cannot speak security
|
|
return CRR_REJECT;
|
|
}
|
|
|
|
if (fT120SecureCall || !fAcceptNonSecure)
|
|
{
|
|
//
|
|
// If we insist on security, or the call is secure and we can
|
|
// handle it, the result is secure.
|
|
//
|
|
dwFlags |= CRPCF_SECURE;
|
|
}
|
|
else if (fRequestAV && pManager->AcquireAV(pConnection))
|
|
{
|
|
dwFlags |= CRPCF_VIDEO | CRPCF_AUDIO;
|
|
}
|
|
|
|
if (fCallerNM2x && (0 == ((CRPCF_VIDEO | CRPCF_AUDIO) & dwFlags)))
|
|
{
|
|
// a/v is not available
|
|
// if leading with H323, caller will try again with T120
|
|
// else their done
|
|
resp = CRR_BUSY;
|
|
}
|
|
else if (fRequestAutoAccept)
|
|
{
|
|
// Auto accept this call if it came from NetMeeting 2.X and the caller is telling
|
|
// us that we are already in a T.120 call with them. This allows audio after data
|
|
// calls to be accepted and also means that you aren't prompted when someone
|
|
// switches a/v using the UI's "Send audio and video to..."
|
|
|
|
if (fInActiveConference)
|
|
{
|
|
// we most likely have a matching call already but may not be able to find it
|
|
CIncomingCall *pCall = new CIncomingCall(pManager, pConnection, lpvMNMData, dwFlags);
|
|
// This transfers the implicit reference of pConnection to the
|
|
// new CIncomingCall. It will Release().
|
|
if (NULL != pCall)
|
|
{
|
|
// add call to the list of incoming calls
|
|
m_CallList.AddTail(pCall);
|
|
|
|
resp = CRR_ACCEPT;
|
|
}
|
|
else
|
|
{
|
|
resp = CRR_REJECT;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// we're not really in a T120 call like the caller said. reject this call!
|
|
resp = CRR_REJECT;
|
|
}
|
|
}
|
|
else if (!fT120Join && fInActiveConference)
|
|
{
|
|
// need to change this to CRR_IN_CONFERENCE
|
|
resp = CRR_BUSY;
|
|
TRACE_OUT(("Can only accept joins; in a conference"));
|
|
}
|
|
else if (fT120Join && !fT120Invite && !fInActiveConference)
|
|
{
|
|
resp = CRR_REJECT;
|
|
TRACE_OUT(("Cannot accept H323 Join Request; not in a conference"));
|
|
}
|
|
else if (!fRequestAV && !fT120Join && !fT120Invite && !fInActiveConference)
|
|
{
|
|
resp = CRR_REJECT;
|
|
TRACE_OUT(("No av/ or data; reject"));
|
|
}
|
|
else if (fT120SecureCall && !fAcceptSecure)
|
|
{
|
|
resp = CRR_SECURITY_DENIED;
|
|
TRACE_OUT(("Can not accept secure H323 Call"));
|
|
}
|
|
else if (fT120NonSecureCall && !fAcceptNonSecure)
|
|
{
|
|
resp = CRR_SECURITY_DENIED;
|
|
TRACE_OUT(("Can not accept non secure H323 Call"));
|
|
}
|
|
else
|
|
{
|
|
CIncomingCall *pCall = new CIncomingCall(pManager, pConnection, lpvMNMData, dwFlags);
|
|
// This transfers the implicit reference of pConnection to the
|
|
// new CIncomingCall. It will Release().
|
|
if (NULL != pCall)
|
|
{
|
|
if (g_guidLocalNodeId != *pCall->GetNodeGuid())
|
|
{
|
|
// Check for multiple calls from the same caller
|
|
if (!MatchActiveCaller(pCall->GetNodeGuid()))
|
|
{
|
|
// add call to the list of incoming calls
|
|
m_CallList.AddTail(pCall);
|
|
|
|
pManager->OnIncomingCallCreated(pCall);
|
|
|
|
// Don't ring on data only calls.
|
|
// Wait for T120 call to come in.
|
|
if (pCall->IsDataOnly())
|
|
{
|
|
resp = CRR_ACCEPT;
|
|
}
|
|
else
|
|
{
|
|
pCall->Ring();
|
|
|
|
resp = CRR_ASYNC;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// we're already in call with this person
|
|
delete pCall;
|
|
|
|
resp = CRR_REJECT;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// we somehow called ourself
|
|
delete pCall;
|
|
|
|
resp = CRR_REJECT;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
resp = CRR_REJECT;
|
|
}
|
|
}
|
|
|
|
REJECT_CALL:
|
|
if ((resp != CRR_ACCEPT) && (resp != CRR_ASYNC))
|
|
{
|
|
// make sure we are not holding on to AV
|
|
pManager->ReleaseAV(pConnection);
|
|
}
|
|
|
|
return resp;
|
|
}
|
|
|
|
VOID CIncomingCallManager::OnH323Connected(IH323Endpoint* lpConnection)
|
|
{
|
|
POSITION pos = m_CallList.GetHeadPosition();
|
|
POSITION posItem;
|
|
while (posItem = pos)
|
|
{
|
|
CIncomingCall* pCall = (CIncomingCall*) m_CallList.GetNext(pos);
|
|
|
|
if ((NULL != pCall) &&
|
|
(lpConnection == pCall->GetH323Connection()))
|
|
{
|
|
pCall->OnH323Connected();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID CIncomingCallManager::OnH323Disconnected(IH323Endpoint * lpConnection)
|
|
{
|
|
POSITION pos = m_CallList.GetHeadPosition();
|
|
POSITION posItem;
|
|
while (posItem = pos)
|
|
{
|
|
CIncomingCall* pCall = (CIncomingCall*) m_CallList.GetNext(pos);
|
|
|
|
if ((NULL != pCall) &&
|
|
(lpConnection == pCall->GetH323Connection()))
|
|
{
|
|
if (S_OK == pCall->OnH323Disconnected())
|
|
{
|
|
m_CallList.RemoveAt(posItem);
|
|
pCall->Release();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
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,
|
|
PUSERDATAINFO pUserDataInfoEntries,
|
|
UINT cUserDataEntries,
|
|
BOOL fSecure)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
// need to scan through all accepted calls passing the T120 params
|
|
// if someone returns S_OK, we accept the call
|
|
|
|
CIncomingCall *pMatchedCall = NULL;
|
|
|
|
GUID* pguidNodeID = GetGuidFromT120UserData(pUserDataInfoEntries, cUserDataEntries);
|
|
if (pguidNodeID)
|
|
{
|
|
pMatchedCall = MatchAcceptedCaller(pguidNodeID);
|
|
}
|
|
else
|
|
{
|
|
pMatchedCall = MatchAcceptedCaller(pcwszNodeName);
|
|
}
|
|
|
|
if (pMatchedCall)
|
|
{
|
|
pMatchedCall->SetConfHandle(hConf);
|
|
|
|
// we should always ring the client when the call is secure
|
|
// or when we haven't rang already
|
|
if (!pMatchedCall->DidUserAccept())
|
|
{
|
|
pMatchedCall->OnIncomingT120Call(fInvite,
|
|
pUserDataInfoEntries,
|
|
cUserDataEntries);
|
|
|
|
pMatchedCall->Ring();
|
|
}
|
|
else
|
|
{
|
|
if (fInvite)
|
|
{
|
|
hr = hConf->InviteResponse(TRUE);
|
|
}
|
|
else
|
|
{
|
|
hr = hConf->JoinResponse(TRUE);
|
|
}
|
|
}
|
|
pMatchedCall->Release();
|
|
}
|
|
else
|
|
{
|
|
CIncomingCall *pCall = new CIncomingCall(pManager,
|
|
fInvite,
|
|
hConf,
|
|
pcwszNodeName,
|
|
pUserDataInfoEntries,
|
|
cUserDataEntries);
|
|
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;
|
|
}
|
|
|
|
|
|
CIncomingCall* CIncomingCallManager::MatchAcceptedCaller(PCWSTR pcwszNodeName)
|
|
{
|
|
// we won't auto accept anyone who is already in the roster
|
|
CNmMember* pMember = PDataMemberFromName(pcwszNodeName);
|
|
if (NULL != pMember)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
POSITION pos = m_CallList.GetHeadPosition();
|
|
while (pos)
|
|
{
|
|
CIncomingCall* pCall = (CIncomingCall*) m_CallList.GetNext(pos);
|
|
|
|
if ((NULL != pCall) &&
|
|
pCall->MatchAcceptedCaller(pcwszNodeName))
|
|
{
|
|
TRACE_OUT(("Matched accepted caller"));
|
|
pCall->AddRef();
|
|
return pCall;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
CIncomingCall* CIncomingCallManager::MatchAcceptedCaller(GUID* pguidNodeId)
|
|
{
|
|
if (GUID_NULL == *pguidNodeId)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// we wont auto accept anyone who is already in the roster
|
|
CNmMember* pMember = PMemberFromNodeGuid(*pguidNodeId);
|
|
if ((NULL != pMember) && pMember->FHasData())
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
POSITION pos = m_CallList.GetHeadPosition();
|
|
while (pos)
|
|
{
|
|
CIncomingCall* pCall = (CIncomingCall*) m_CallList.GetNext(pos);
|
|
|
|
if ((NULL != pCall) &&
|
|
pCall->MatchAcceptedCaller(pguidNodeId))
|
|
{
|
|
TRACE_OUT(("Matched accepted caller"));
|
|
pCall->AddRef();
|
|
return pCall;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
CIncomingCall* CIncomingCallManager::MatchActiveCaller(GUID* pguidNodeId)
|
|
{
|
|
if (GUID_NULL == *pguidNodeId)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
POSITION pos = m_CallList.GetHeadPosition();
|
|
while (pos)
|
|
{
|
|
CIncomingCall* pCall = (CIncomingCall*) m_CallList.GetNext(pos);
|
|
|
|
if ((NULL != pCall) &&
|
|
pCall->MatchActiveCaller(pguidNodeId))
|
|
{
|
|
TRACE_OUT(("Matched active caller"));
|
|
pCall->AddRef();
|
|
return pCall;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
GUID* CIncomingCallManager::GetGuidFromT120UserData(
|
|
PUSERDATAINFO pUserDataInfoEntries,
|
|
UINT cUserDataEntries)
|
|
{
|
|
if (cUserDataEntries > 0)
|
|
{
|
|
ASSERT(pUserDataInfoEntries);
|
|
for (UINT u = 0; u < cUserDataEntries; u++)
|
|
{
|
|
if ((*pUserDataInfoEntries[u].pGUID == g_csguidNodeIdTag) &&
|
|
(pUserDataInfoEntries[u].cbData == sizeof(GUID)))
|
|
{
|
|
return (GUID*)pUserDataInfoEntries[u].pData;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
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);
|
|
}
|