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.
2003 lines
47 KiB
2003 lines
47 KiB
// File: icall.cpp
|
|
|
|
#include "precomp.h"
|
|
|
|
#include "icall.h"
|
|
#include "rostinfo.h"
|
|
#include "imanager.h"
|
|
#include "mperror.h"
|
|
#include "nmremote.h"
|
|
#include "util.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},
|
|
{&IID_INmCallNotify2}
|
|
};
|
|
|
|
// 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 bstrName, BSTR bstrDest, BSTR bstrAlias,
|
|
BSTR bstrConference, BSTR bstrPassword, BSTR bstrUserString) :
|
|
CConnectionPointContainer(g_apiidCP, ARRAY_ELEMENTS(g_apiidCP)),
|
|
m_pConfObject (pco),
|
|
m_addrType (addrType),
|
|
m_dwFlags (dwFlags),
|
|
m_bstrName (SysAllocString(bstrName)),
|
|
m_bstrAlias (SysAllocString(bstrAlias)),
|
|
m_bstrConfToJoin (SysAllocString(bstrConference)),
|
|
m_bstrPassword (SysAllocString(bstrPassword)),
|
|
m_bstrUserString (SysAllocString(bstrUserString)),
|
|
m_hRequest (NULL),
|
|
m_pH323Connection (NULL),
|
|
m_fCanceled (FALSE),
|
|
m_cnResult (CN_RC_NOERROR),
|
|
m_cnState (CNS_IDLE),
|
|
m_fService (FALSE)
|
|
{
|
|
m_pszAddr = PszAlloc(CUSTRING(bstrDest));
|
|
DbgMsg(iZONE_OBJECTS, "Obj: %08X created COutgoingCall", this);
|
|
}
|
|
|
|
COutgoingCall::~COutgoingCall()
|
|
{
|
|
delete m_pszAddr;
|
|
|
|
FreeBstr(&m_bstrName);
|
|
FreeBstr(&m_bstrAlias);
|
|
FreeBstr(&m_bstrConfToJoin);
|
|
FreeBstr(&m_bstrPassword);
|
|
FreeBstr(&m_bstrUserString);
|
|
|
|
ASSERT(NULL == m_pH323Connection);
|
|
|
|
DbgMsg(iZONE_OBJECTS, "Obj: %08X destroyed COutgoingCall", this);
|
|
}
|
|
|
|
|
|
BOOL COutgoingCall::MatchActiveCallee(LPCTSTR pszAddr, BSTR bstrAlias, BSTR bstrConference)
|
|
{
|
|
return ((0 == lstrcmp(pszAddr, m_pszAddr)) &&
|
|
(0 == UnicodeCompare(bstrAlias, m_bstrAlias)));
|
|
|
|
}
|
|
|
|
/* 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 ((CRPCF_H323CC & m_dwFlags) && (NULL != g_pH323UI))
|
|
{
|
|
SetCallState(CNS_CONNECTING_H323);
|
|
|
|
// Start placing the H.323 call:
|
|
CNSTATUS cnResult = ConnectH323();
|
|
if (CN_RC_NOERROR != cnResult)
|
|
{
|
|
m_cnResult = cnResult;
|
|
SetCallState(CNS_COMPLETE);
|
|
}
|
|
}
|
|
else if ((CRPCF_DATA & m_dwFlags) && (NULL != g_pNodeController))
|
|
{
|
|
// Start placing the T.120 call
|
|
CNSTATUS cnResult = StartT120Call();
|
|
if (CN_RC_NOERROR != cnResult)
|
|
{
|
|
m_cnResult = cnResult;
|
|
SetCallState(CNS_COMPLETE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_cnResult = CN_RC_TRANSPORT_FAILURE;
|
|
SetCallState(CNS_COMPLETE);
|
|
}
|
|
|
|
DebugExitVOID(COutgoingCall::PlaceCall);
|
|
}
|
|
|
|
CNSTATUS COutgoingCall::ConnectH323()
|
|
{
|
|
DBGENTRY(COutgoingCall::ConnectH323);
|
|
H323ALIASLIST AliasList;
|
|
H323ALIASNAME AliasName;
|
|
P_H323ALIASLIST pAliasList = &AliasList;
|
|
SOCKADDR_IN sin;
|
|
LPCWSTR pcwszPhone = NULL;
|
|
CNSTATUS cnResult = CN_RC_NOERROR;
|
|
|
|
if (NULL == g_pH323UI)
|
|
return cnResult;
|
|
|
|
AliasName.aType = AT_H323_ID;
|
|
AliasName.lpwData = m_bstrAlias;
|
|
AliasName.wDataLength = (WORD)SysStringLen(m_bstrAlias);// # of unicode chars, w/o NULL terminator
|
|
AliasList.wCount = 1;
|
|
AliasList.pItems = &AliasName;
|
|
|
|
sin.sin_family = AF_INET;
|
|
sin.sin_addr.s_addr = inet_addr(m_pszAddr);
|
|
|
|
switch (m_addrType)
|
|
{
|
|
case NM_ADDR_PSTN:
|
|
case NM_ADDR_H323_GATEWAY:
|
|
case NM_ADDR_ALIAS_E164:
|
|
// overide alias type and phone number
|
|
AliasName.aType = AT_H323_E164;
|
|
pcwszPhone = m_bstrAlias;
|
|
break;
|
|
|
|
case NM_ADDR_IP:
|
|
case NM_ADDR_MACHINENAME:
|
|
// overide alias list
|
|
pAliasList = NULL;
|
|
break;
|
|
|
|
case NM_ADDR_ALIAS_ID:
|
|
case NM_ADDR_ULS:
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (INADDR_NONE != sin.sin_addr.s_addr)
|
|
{
|
|
HRESULT hr;
|
|
ASSERT(g_pH323UI);
|
|
|
|
DWORD dwUserData = 0;
|
|
APP_CALL_SETUP_DATA acsd;
|
|
P_APP_CALL_SETUP_DATA pacsd = NULL;
|
|
BYTE *pbUserData = NULL;
|
|
|
|
COprahNCUI *pOprahNCUI = COprahNCUI::GetInstance();
|
|
ASSERT(NULL !=pOprahNCUI);
|
|
|
|
if (CRPCF_DATA & m_dwFlags)
|
|
{
|
|
if (CRPCF_SECURE & m_dwFlags)
|
|
{
|
|
dwUserData |= H323UDF_SECURE;
|
|
}
|
|
|
|
if (m_pConfObject->IsConferenceActive())
|
|
{
|
|
dwUserData |= H323UDF_INVITE;
|
|
}
|
|
else if (m_bstrConfToJoin != NULL)
|
|
{
|
|
dwUserData |= H323UDF_JOIN;
|
|
}
|
|
else
|
|
{
|
|
dwUserData |= H323UDF_INVITE | H323UDF_JOIN;
|
|
}
|
|
}
|
|
|
|
if (CRPCF_AUDIO & m_dwFlags)
|
|
{
|
|
dwUserData |= H323UDF_AUDIO;
|
|
}
|
|
if (CRPCF_VIDEO & m_dwFlags)
|
|
{
|
|
dwUserData |= H323UDF_VIDEO;
|
|
}
|
|
|
|
CRosterInfo ri;
|
|
PVOID pvRosterData;
|
|
UINT cbRosterData = 0;
|
|
|
|
if (pOprahNCUI->GetULSName(&ri))
|
|
{
|
|
if (FAILED(ri.Save(&pvRosterData, &cbRosterData)))
|
|
{
|
|
cbRosterData = 0;
|
|
}
|
|
}
|
|
|
|
UINT cbUserString = 0;
|
|
if (m_bstrUserString)
|
|
{
|
|
cbUserString = SysStringByteLen(m_bstrUserString);
|
|
}
|
|
|
|
DWORD dwTotalSize = sizeof(DWORD);
|
|
if (cbRosterData)
|
|
{
|
|
dwTotalSize += sizeof(GUID) + sizeof(DWORD) + cbRosterData;
|
|
}
|
|
if (cbUserString)
|
|
{
|
|
dwTotalSize += sizeof(GUID) + sizeof(DWORD) + cbUserString;
|
|
}
|
|
dwTotalSize += sizeof(GUID) + sizeof(DWORD) + sizeof(GUID);
|
|
|
|
pbUserData = new BYTE [dwTotalSize];
|
|
if (NULL != pbUserData)
|
|
{
|
|
BYTE *pb = pbUserData;
|
|
|
|
// H323UDF_ first
|
|
*((DWORD*)pb) = dwUserData;
|
|
pb += sizeof(DWORD);
|
|
|
|
if(cbRosterData)
|
|
{
|
|
// RosterInfo GUID next
|
|
*((GUID*)pb) = g_csguidRostInfo,
|
|
pb += sizeof(GUID);
|
|
|
|
// then RosterInfo size (a DWORD)
|
|
*((DWORD*)pb) = cbRosterData;
|
|
pb += sizeof(DWORD);
|
|
|
|
// then RosterInfo data
|
|
CopyMemory(pb, pvRosterData, cbRosterData);
|
|
pb += cbRosterData;
|
|
}
|
|
|
|
if(cbUserString)
|
|
{
|
|
// string GUID next
|
|
*((GUID*)pb) = g_csguidUserString,
|
|
pb += sizeof(GUID);
|
|
|
|
// then string size (a DWORD)
|
|
*((DWORD*)pb) = cbUserString;
|
|
pb += sizeof(DWORD);
|
|
|
|
// then string data
|
|
CopyMemory(pb, m_bstrUserString, cbUserString);
|
|
pb += cbUserString;
|
|
}
|
|
|
|
{
|
|
// string GUID next
|
|
*((GUID*)pb) = g_csguidNodeIdTag,
|
|
pb += sizeof(GUID);
|
|
|
|
// then string size (a DWORD)
|
|
*((DWORD*)pb) = sizeof(GUID);
|
|
pb += sizeof(DWORD);
|
|
|
|
// then GUID data
|
|
*(GUID*)pb = g_guidLocalNodeId;
|
|
pb += sizeof(GUID);
|
|
}
|
|
|
|
acsd.dwDataSize = dwTotalSize;
|
|
acsd.lpData = pbUserData;
|
|
pacsd = &acsd;
|
|
}
|
|
|
|
sin.sin_port = htons(H323_PORT);
|
|
hr = Connect(&sin, pAliasList, pcwszPhone, pacsd, PID_H323, &m_pH323Connection);
|
|
delete [] pbUserData;
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
TRACE_OUT(("COutgoingCall - Connect() succeeded!"));
|
|
cnResult = CN_RC_NOERROR;
|
|
}
|
|
else
|
|
{
|
|
WARNING_OUT(("COutgoingCall - Connect() failed!"));
|
|
if (CONN_E_GK_NOT_REGISTERED == hr)
|
|
{
|
|
cnResult = CN_RC_GK_NOT_REGISTERED;
|
|
}
|
|
else
|
|
{
|
|
cnResult = CN_RC_AUDIO_CONNECT_FAILED;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING_OUT(("COutgoingCall - inet_addr failed!"));
|
|
cnResult = CN_RC_NAME_RESOLUTION_FAILED;
|
|
}
|
|
return cnResult;
|
|
}
|
|
|
|
|
|
HRESULT COutgoingCall::Connect( PSOCKADDR_IN psin,
|
|
P_H323ALIASLIST pAliasList,
|
|
LPCWSTR pcwszPSTNAddress,
|
|
P_APP_CALL_SETUP_DATA lpvMNMData,
|
|
GUID PIDofProtocolType,
|
|
IH323Endpoint * *ppConnection)
|
|
{
|
|
DebugEntry(CH323UI::Connect);
|
|
|
|
HRESULT hr = E_ACCESSDENIED;
|
|
|
|
*ppConnection = NULL;
|
|
|
|
COprahNCUI *pOprahNCUI = COprahNCUI::GetInstance();
|
|
ASSERT(NULL != pOprahNCUI);
|
|
|
|
IH323CallControl * pH323CallControl = g_pH323UI->GetH323CallControl();
|
|
|
|
// create the connection
|
|
IH323Endpoint* pConn = NULL;
|
|
ASSERT(pH323CallControl);
|
|
|
|
hr = pH323CallControl->CreateConnection(&pConn, PIDofProtocolType);
|
|
if (FAILED(hr) || (NULL == pConn))
|
|
{
|
|
ERROR_OUT(("Could not create a connection, hr=0x%lx", hr));
|
|
}
|
|
else
|
|
{
|
|
// if the following operations fail, we still can delete this conn obj
|
|
*ppConnection = pConn;
|
|
|
|
if (!pOprahNCUI->AcquireAV(pConn))
|
|
{
|
|
// we did not get AV, clear out the flags
|
|
m_dwFlags &= ~(CRPCF_AUDIO | CRPCF_VIDEO);
|
|
}
|
|
|
|
hr = pConn->SetAdviseInterface (pOprahNCUI);
|
|
ASSERT(SUCCEEDED(hr));
|
|
|
|
// if we are using an alias, tell the Gatekeeper to resolve it
|
|
BOOL fUseGKResolution = (NULL != pAliasList);
|
|
|
|
// start the connection
|
|
hr = pConn->PlaceCall (fUseGKResolution, psin, pAliasList, NULL, pcwszPSTNAddress, lpvMNMData);
|
|
if (FAILED(hr))
|
|
{
|
|
// ERROR_OUT(("COutgoingCall::Connect: couldn't StartConnection, hr=0x%lx", hr));
|
|
if(hr == CONN_E_GK_NOT_REGISTERED)
|
|
{
|
|
WARNING_OUT(("COutgoingCall::Connect: not registered. Do you want to re-register..., hr=0x%lx", hr));
|
|
}
|
|
*ppConnection = NULL;
|
|
|
|
pConn->Release();
|
|
|
|
pOprahNCUI->ReleaseAV(pConn);
|
|
}
|
|
}
|
|
|
|
DebugExitULONG(CH323UI::Connect, hr);
|
|
|
|
return hr;
|
|
}
|
|
|
|
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);
|
|
if (m_pH323Connection)
|
|
{
|
|
m_pConfObject->OnT120Connected(m_pH323Connection, uNodeID);
|
|
}
|
|
}
|
|
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[],
|
|
PT120PRODUCTVERSION pVersion,
|
|
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_bstrUserString, &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,
|
|
m_bstrUserString);
|
|
}
|
|
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,
|
|
m_bstrUserString);
|
|
}
|
|
}
|
|
|
|
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_bstrUserString, &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);
|
|
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);
|
|
if (m_pH323Connection)
|
|
{
|
|
UINT uNodeID = hNewConf->GetParentNodeID();
|
|
|
|
m_pConfObject->OnT120Connected(m_pH323Connection, uNodeID);
|
|
}
|
|
}
|
|
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,
|
|
m_bstrUserString,
|
|
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;
|
|
}
|
|
|
|
BOOL COutgoingCall::OnH323Connected(IH323Endpoint * pConnection)
|
|
{
|
|
DebugEntry(COutgoingCall::OnH323Connected);
|
|
|
|
BOOL bRet = TRUE;
|
|
|
|
ASSERT(m_pH323Connection == pConnection);
|
|
|
|
if (m_dwFlags & CRPCF_DATA)
|
|
{
|
|
PCC_VENDORINFO pLocalVendorInfo;
|
|
PCC_VENDORINFO pRemoteVendorInfo;
|
|
|
|
pConnection->GetVersionInfo(&pLocalVendorInfo, &pRemoteVendorInfo);
|
|
H323VERSION version = GetH323Version(pRemoteVendorInfo);
|
|
|
|
if (H323_NetMeeting20 == version)
|
|
{
|
|
if ((m_addrType != NM_ADDR_H323_GATEWAY) &&
|
|
(m_addrType != NM_ADDR_PSTN) &&
|
|
(m_addrType != NM_ADDR_ALIAS_ID) &&
|
|
(m_addrType != NM_ADDR_ALIAS_E164))
|
|
{
|
|
CNSTATUS cnResult = StartT120Call();
|
|
if (CN_RC_NOERROR != cnResult)
|
|
{
|
|
m_cnResult = cnResult;
|
|
SetCallState(CNS_COMPLETE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SetCallState(CNS_COMPLETE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// wait for results of T.120 open logical channel
|
|
TRACE_OUT(("COutgoingCall - H323Connected received -> waiting for T120 channel open"));
|
|
SetCallState(CNS_WAITING_T120_OPEN);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// no T120 for this call
|
|
TRACE_OUT(("COutgoingCall - our H323 call started -> complete"));
|
|
SetCallState(CNS_COMPLETE);
|
|
}
|
|
|
|
CConfObject *pco = ::GetConfObject();
|
|
if (NULL != pco)
|
|
{
|
|
// add member if we are calling with A/V
|
|
BOOL fAddMember = m_dwFlags & (CRPCF_AUDIO | CRPCF_VIDEO);
|
|
|
|
pco->OnH323Connected(pConnection, m_dwFlags, fAddMember, GUID_NULL);
|
|
}
|
|
|
|
DebugExitBOOL(COutgoingCall::OnH323Connected, bRet);
|
|
return bRet;
|
|
}
|
|
|
|
BOOL COutgoingCall::OnH323Disconnected(IH323Endpoint * pConnection)
|
|
{
|
|
DebugEntry(COutgoingCall::OnH323Disconnected);
|
|
|
|
BOOL bRet = TRUE;
|
|
|
|
ASSERT(m_pH323Connection == pConnection);
|
|
|
|
HRESULT hSummary = m_pH323Connection->GetSummaryCode();
|
|
// Check summary code for gatekeeper-caused disconnect
|
|
// Note: this applies only to MY gatekeeper, not the callee's gatekeeper
|
|
if(CUSTOM_FACILITY(hSummary) == FACILITY_GKIADMISSION)
|
|
{
|
|
DWORD dwRejectReason;
|
|
dwRejectReason = CUSTOM_FACILITY_CODE(hSummary);
|
|
|
|
// should the T.120 call be placed anyway?
|
|
switch (dwRejectReason)
|
|
{
|
|
case ARJ_CALLEE_NOT_REGISTERED:
|
|
m_cnResult = CN_RC_GK_CALLEE_NOT_REGISTERED;
|
|
break;
|
|
case ARJ_TIMEOUT:
|
|
m_cnResult = CN_RC_GK_TIMEOUT;
|
|
break;
|
|
case ARJ_INVALID_PERMISSION:
|
|
case ARJ_REQUEST_DENIED:
|
|
case ARJ_UNDEFINED:
|
|
case ARJ_CALLER_NOT_REGISTERED:
|
|
case ARJ_ROUTE_TO_GK:
|
|
case ARJ_INVALID_ENDPOINT_ID:
|
|
case ARJ_RESOURCE_UNAVAILABLE:
|
|
case ARJ_SECURTY_DENIAL:
|
|
case ARJ_QOS_CONTROL_NOT_SUPPORTED:
|
|
case ARJ_INCOMPLETE_ADDRESS:
|
|
default:
|
|
m_cnResult = CN_RC_GK_REJECTED;
|
|
break;
|
|
}
|
|
|
|
SetCallState(CNS_COMPLETE);
|
|
}
|
|
else if (CNS_CONNECTING_H323 == m_cnState)
|
|
{
|
|
// attempted an H.323 call without success.
|
|
|
|
TRACE_OUT(("COutgoingCall - our leading H323 call ended -> complete"));
|
|
|
|
// check for cases of remote refusing the call
|
|
switch (hSummary)
|
|
{
|
|
case CCR_REMOTE_DISCONNECT:
|
|
case CCR_REMOTE_REJECTED:
|
|
m_cnResult = CN_RC_CONFERENCE_INVITE_DENIED;
|
|
SetCallState(CNS_COMPLETE);
|
|
break;
|
|
case CCR_LOCAL_DISCONNECT:
|
|
// cancelled by user, do not report error
|
|
m_cnResult = CN_RC_LOCAL_CANCELED;
|
|
m_fCanceled = TRUE;
|
|
SetCallState(CNS_COMPLETE);
|
|
break;
|
|
case CCR_GK_NO_RESOURCES:
|
|
// callee's gatekeeper would not let callee answer
|
|
// do the same as CCR_REMOTE_REJECTED
|
|
// as a temporary measure !!!!
|
|
m_cnResult = CN_RC_CONFERENCE_INVITE_DENIED;
|
|
SetCallState(CNS_COMPLETE);
|
|
break;
|
|
case CCR_REMOTE_SECURITY_DENIED:
|
|
if (m_pConfObject->IsConfObjSecure())
|
|
{
|
|
m_cnResult = CN_RC_CONNECT_REMOTE_NO_SECURITY;
|
|
}
|
|
else
|
|
{
|
|
m_cnResult = CN_RC_CONNECT_REMOTE_REQUIRE_SECURITY;
|
|
}
|
|
SetCallState(CNS_COMPLETE);
|
|
break;
|
|
case CCR_REMOTE_BUSY:
|
|
if (m_pConfObject->IsConferenceActive())
|
|
{
|
|
m_cnResult = CN_RC_INVITE_DENIED_REMOTE_IN_CONF;
|
|
SetCallState(CNS_COMPLETE);
|
|
break;
|
|
}
|
|
// else fall through
|
|
|
|
default:
|
|
if ((m_dwFlags & CRPCF_DATA) &&
|
|
(m_addrType != NM_ADDR_H323_GATEWAY) &&
|
|
(m_addrType != NM_ADDR_PSTN) &&
|
|
(m_addrType != NM_ADDR_ALIAS_ID) &&
|
|
(m_addrType != NM_ADDR_ALIAS_E164))
|
|
{
|
|
// The endpoint is not there, not listening for H.323 calls, or is busy,
|
|
// and the address is a resolvable type (not an H.323 alias or E.164 number)
|
|
// go back into the T.120 call state path
|
|
CNSTATUS cnResult = StartT120Call();
|
|
if (CN_RC_NOERROR != cnResult)
|
|
{
|
|
m_cnResult = cnResult;
|
|
SetCallState(CNS_COMPLETE);
|
|
bRet = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (hSummary)
|
|
{
|
|
case CCR_REMOTE_BUSY:
|
|
m_cnResult = CN_RC_INVITE_DENIED_REMOTE_IN_CONF;
|
|
break;
|
|
case CCR_REMOTE_MEDIA_ERROR:
|
|
m_cnResult = CN_RC_AUDIO_IN_USE_REMOTE;
|
|
break;
|
|
case CCR_LOCAL_MEDIA_ERROR:
|
|
m_cnResult = CN_RC_AUDIO_IN_USE_LOCAL;
|
|
break;
|
|
case CCR_GK_NO_RESOURCES:
|
|
m_cnResult = CN_RC_GK_REJECTED;
|
|
break;
|
|
default:
|
|
m_cnResult = CN_RC_AUDIO_CONNECT_FAILED;
|
|
break;
|
|
}
|
|
SetCallState(CNS_COMPLETE);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else if (CNS_WAITING_T120_OPEN == m_cnState)
|
|
{
|
|
TRACE_OUT(("COutgoingCall - OnH323Disconnected received -> call is canceled"));
|
|
m_cnResult = CN_RC_CONFERENCE_INVITE_DENIED;
|
|
SetCallState(CNS_COMPLETE);
|
|
}
|
|
else
|
|
{
|
|
TRACE_OUT(("COutgoingCall - OnH323Disconnected received -> canceling call"));
|
|
ASSERT(m_pConfObject);
|
|
|
|
if (NULL != m_hRequest)
|
|
{
|
|
REQUEST_HANDLE hRequest = m_hRequest;
|
|
m_hRequest = NULL;
|
|
m_pConfObject->CancelInvite(hRequest);
|
|
}
|
|
|
|
if (m_pConfObject->IsConferenceActive())
|
|
{
|
|
// Issue "soft" leave attempt (to allow auto-terminate)
|
|
m_pConfObject->LeaveConference(FALSE);
|
|
}
|
|
}
|
|
|
|
// the connection may have been released due to the LeaveConference above
|
|
// bug 3996
|
|
if (m_pH323Connection)
|
|
{
|
|
m_pH323Connection->Release();
|
|
m_pH323Connection = NULL;
|
|
}
|
|
|
|
DebugExitBOOL(COutgoingCall::OnH323Disconnected, bRet);
|
|
return bRet;
|
|
}
|
|
|
|
BOOL COutgoingCall::OnT120ChannelOpen(ICommChannel *pIChannel, DWORD dwStatus)
|
|
{
|
|
DebugEntry(COutgoingCall::OnT120ChannelOpen);
|
|
|
|
BOOL bRet = TRUE;
|
|
|
|
// sometimes we get an extra T120 channel open
|
|
// this is most likely due the master/slave anomolies that
|
|
// venkatg discovered.
|
|
if (CNS_WAITING_T120_OPEN == m_cnState)
|
|
{
|
|
switch(dwStatus)
|
|
{
|
|
case CHANNEL_OPEN:
|
|
{
|
|
// start the T.120 part of the call
|
|
// get the negotiated address
|
|
SOCKADDR_IN sin_T120;
|
|
HRESULT hr = pIChannel->GetRemoteAddress(&sin_T120);
|
|
delete m_pszAddr; // we won't be needing this anymore
|
|
|
|
TCHAR szAddress[256]; // allow plenty of room for conversion from numberic to string
|
|
wsprintf(szAddress, "%s:%d", inet_ntoa(sin_T120.sin_addr), ntohs(sin_T120.sin_port));
|
|
m_pszAddr = PszAlloc(szAddress);
|
|
|
|
CNSTATUS cnResult = StartT120Call();
|
|
if (CN_RC_NOERROR != cnResult)
|
|
{
|
|
m_cnResult = cnResult;
|
|
SetCallState(CNS_COMPLETE);
|
|
}
|
|
}
|
|
break;
|
|
case CHANNEL_CLOSED:
|
|
// if the T.120 channel is being closed
|
|
// the H.323 call is going down, so don't continue waiting for
|
|
// T.120 to connect!
|
|
m_cnResult = CN_RC_CONNECT_FAILED;
|
|
SetCallState(CNS_COMPLETE);
|
|
|
|
if (NULL != m_hRequest)
|
|
{
|
|
REQUEST_HANDLE hRequest = m_hRequest;
|
|
m_hRequest = NULL;
|
|
ASSERT(m_pConfObject);
|
|
m_pConfObject->CancelInvite(hRequest);
|
|
}
|
|
break;
|
|
|
|
case CHANNEL_NO_CAPABILITY:
|
|
case CHANNEL_REJECTED:
|
|
case CHANNEL_OPEN_ERROR:
|
|
default:
|
|
m_cnResult = CN_RC_CONNECT_FAILED;
|
|
SetCallState(CNS_COMPLETE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
DebugExitBOOL(COutgoingCall::OnT120ChannelOpen, bRet);
|
|
return bRet;
|
|
}
|
|
|
|
|
|
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);
|
|
|
|
// make sure that the H323 connection is released
|
|
if (m_pH323Connection)
|
|
{
|
|
if (!IsDataOnly() &&
|
|
((CN_RC_TRANSPORT_FAILURE == m_cnResult) ||
|
|
(CN_RC_QUERY_FAILED == m_cnResult) ||
|
|
(CN_RC_CONNECT_FAILED == m_cnResult)))
|
|
{
|
|
m_cnResult = CN_RC_NOERROR;
|
|
}
|
|
|
|
if (CN_RC_NOERROR != m_cnResult)
|
|
{
|
|
m_pH323Connection->Disconnect();
|
|
}
|
|
m_pH323Connection->Release();
|
|
m_pH323Connection = NULL;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
CNSTATUS COutgoingCall::StartT120Call()
|
|
{
|
|
DebugEntry(COutgoingCall::StartT120Call);
|
|
|
|
CNSTATUS cnResult = CN_RC_NOERROR;
|
|
|
|
if (NULL == m_bstrConfToJoin)
|
|
{
|
|
// conference name not specified
|
|
// need to start out with a QueryRemote
|
|
SetCallState(CNS_QUERYING_REMOTE);
|
|
|
|
ASSERT(g_pNodeController);
|
|
|
|
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,
|
|
m_bstrUserString);
|
|
if (S_OK != hr)
|
|
{
|
|
cnResult = CN_RC_JOIN_FAILED;
|
|
}
|
|
}
|
|
|
|
DebugExitINT(COutgoingCall::StartT120Call, cnResult);
|
|
return cnResult;
|
|
}
|
|
|
|
|
|
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"));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (NULL != m_pH323Connection)
|
|
{
|
|
m_fCanceled = TRUE;
|
|
|
|
// Abort H.323 Call:
|
|
m_pH323Connection->Disconnect();
|
|
}
|
|
|
|
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;
|
|
ApiDebugMsg(("COutgoingCall::QueryInterface()"));
|
|
}
|
|
else if (riid == IID_IConnectionPointContainer)
|
|
{
|
|
*ppv = (IConnectionPointContainer *) this;
|
|
ApiDebugMsg(("CNmCall::QueryInterface(): Returning IConnectionPointContainer."));
|
|
}
|
|
else
|
|
{
|
|
hr = E_NOINTERFACE;
|
|
*ppv = NULL;
|
|
ApiDebugMsg(("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_CONNECTING_H323:
|
|
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_AUDIO_CONNECT_FAILED:
|
|
case CN_RC_GK_CALLEE_NOT_REGISTERED:
|
|
case CN_RC_GK_TIMEOUT:
|
|
case CN_RC_GK_REJECTED:
|
|
case CN_RC_GK_NOT_REGISTERED:
|
|
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::GetName(BSTR * pbstrName)
|
|
{
|
|
if (NULL == pbstrName)
|
|
return E_POINTER;
|
|
|
|
*pbstrName = SysAllocString(m_bstrName);
|
|
return (*pbstrName ? S_OK : E_FAIL);
|
|
}
|
|
|
|
|
|
HRESULT COutgoingCall::GetAddr(BSTR *pbstrAddr, NM_ADDR_TYPE *puType)
|
|
{
|
|
if ((NULL == pbstrAddr) || (NULL == puType))
|
|
return E_POINTER;
|
|
|
|
*pbstrAddr = SysAllocString(CUSTRING(m_pszAddr));
|
|
*puType = m_addrType;
|
|
|
|
return *pbstrAddr ? S_OK : E_FAIL;
|
|
}
|
|
|
|
HRESULT COutgoingCall::GetUserData(REFGUID rguid, BYTE **ppb, ULONG *pcb)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
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_GK_CALLEE_NOT_REGISTERED:
|
|
case CN_RC_GK_TIMEOUT:
|
|
case CN_RC_GK_REJECTED:
|
|
case CN_RC_GK_NOT_REGISTERED:
|
|
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:
|
|
case CN_RC_AUDIO_CONNECT_FAILED:
|
|
((INmCallNotify*)pCallNotify)->NmUI(CONFN_CALL_FAILED);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (IID_INmCallNotify2 == riid)
|
|
{
|
|
((INmCallNotify2*)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);
|
|
((INmCallNotify2*)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);
|
|
((INmCallNotify2*)pCallNotify)->RemotePassword(prp->bstrConference, prp->pbstrPassword, prp->pbRemoteCred, prp->cbRemoteCred, prp->fIsService);
|
|
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;
|
|
}
|
|
|
|
COutgoingCall* COutgoingCallManager::FindCall(IH323Endpoint * lpConnection)
|
|
{
|
|
POSITION pos = m_CallList.GetHeadPosition();
|
|
while (pos)
|
|
{
|
|
COutgoingCall* pCall = (COutgoingCall*) m_CallList.GetNext(pos);
|
|
|
|
if ((NULL != pCall) &&
|
|
(pCall->GetH323Connection() == lpConnection))
|
|
{
|
|
return pCall;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
BOOL COutgoingCallManager::MatchActiveCallee(LPCTSTR pszDest, BSTR bstrAlias, BSTR bstrConference)
|
|
{
|
|
// Try to find a matching callee
|
|
POSITION pos = m_CallList.GetHeadPosition();
|
|
while (pos)
|
|
{
|
|
COutgoingCall* pCall = (COutgoingCall*) m_CallList.GetNext(pos);
|
|
|
|
if (NULL != pCall)
|
|
{
|
|
if (pCall->MatchActiveCallee(pszDest, bstrAlias, bstrConference))
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
HRESULT COutgoingCallManager::Call(
|
|
INmCall **ppCall,
|
|
COprahNCUI* pManager,
|
|
DWORD dwFlags,
|
|
NM_ADDR_TYPE addrType,
|
|
BSTR bstrName,
|
|
BSTR bstrSetup,
|
|
BSTR bstrDest,
|
|
BSTR bstrAlias,
|
|
BSTR bstrURL,
|
|
BSTR bstrConference,
|
|
BSTR bstrPassword,
|
|
BSTR bstrUserString)
|
|
{
|
|
DebugEntry(COutgoingCallManager::CallConference);
|
|
HRESULT hr = E_FAIL;
|
|
COutgoingCall* pCall = NULL;
|
|
CConfObject* pConfObject = pManager->GetConfObject();
|
|
|
|
if (NULL != ppCall)
|
|
{
|
|
*ppCall = NULL;
|
|
}
|
|
|
|
if (MatchActiveCallee(CUSTRING(bstrDest), bstrAlias, bstrConference))
|
|
{
|
|
hr = NM_CALLERR_ALREADY_CALLING;
|
|
}
|
|
else if (pConfObject->IsConferenceActive() && (NULL != bstrConference))
|
|
{
|
|
hr= NM_CALLERR_IN_CONFERENCE;
|
|
}
|
|
else
|
|
{
|
|
if (!pConfObject->IsConferenceActive())
|
|
{
|
|
pConfObject->SetConfSecurity(0 != (CRPCF_SECURE & dwFlags));
|
|
}
|
|
|
|
//
|
|
// Check outgoing call settings
|
|
//
|
|
if (pConfObject->GetNumMembers() >= pConfObject->GetConfMaxParticipants())
|
|
{
|
|
ASSERT(pConfObject->GetNumMembers() == pConfObject->GetConfMaxParticipants());
|
|
WARNING_OUT(("Outgoing call denied, reached limit of participants"));
|
|
goto END_CALL;
|
|
}
|
|
|
|
if ((pConfObject->IsHosting() != S_OK) &&
|
|
!(pConfObject->GetConfAttendeePermissions() & NM_PERMIT_OUTGOINGCALLS))
|
|
{
|
|
WARNING_OUT(("Outgoing call denied, not permitted by meeting settings"));
|
|
goto END_CALL;
|
|
}
|
|
|
|
pCall = new COutgoingCall( pConfObject,
|
|
dwFlags,
|
|
addrType,
|
|
bstrName,
|
|
bstrDest,
|
|
bstrAlias,
|
|
bstrConference,
|
|
bstrPassword,
|
|
bstrUserString);
|
|
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;
|
|
}
|
|
}
|
|
|
|
END_CALL:
|
|
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;
|
|
}
|
|
|
|
BOOL COutgoingCallManager::OnH323Connected(IH323Endpoint* lpConnection)
|
|
{
|
|
DebugEntry(COutgoingCallManager::OnH323Connected);
|
|
|
|
BOOL fFound = FALSE;
|
|
|
|
COutgoingCall* pCall = FindCall(lpConnection);
|
|
if (pCall)
|
|
{
|
|
fFound = TRUE;
|
|
|
|
pCall->AddRef();
|
|
pCall->OnH323Connected(lpConnection);
|
|
if (pCall->FIsComplete())
|
|
{
|
|
RemoveFromList(pCall);
|
|
}
|
|
pCall->Release();
|
|
}
|
|
|
|
DebugExitBOOL(COutgoingCallManager::OnH323Connected, fFound);
|
|
|
|
return fFound;
|
|
}
|
|
|
|
|
|
BOOL COutgoingCallManager::OnH323Disconnected(IH323Endpoint * lpConnection)
|
|
{
|
|
DebugEntry(COutgoingCallManager::OnH323Disconnected);
|
|
|
|
BOOL fFound = FALSE;
|
|
|
|
COutgoingCall* pCall = FindCall(lpConnection);
|
|
if (pCall)
|
|
{
|
|
fFound = TRUE;
|
|
|
|
pCall->AddRef();
|
|
pCall->OnH323Disconnected(lpConnection);
|
|
if (pCall->FIsComplete())
|
|
{
|
|
RemoveFromList(pCall);
|
|
}
|
|
pCall->Release();
|
|
}
|
|
|
|
DebugExitBOOL(COutgoingCallManager::OnH323Disconnected, fFound);
|
|
|
|
return fFound;
|
|
}
|
|
|
|
VOID COutgoingCallManager::OnT120ChannelOpen(ICommChannel *pIChannel, IH323Endpoint * lpConnection, DWORD dwStatus)
|
|
{
|
|
DebugEntry(COutgoingCallManager::OnT120ChannelOpen);
|
|
|
|
COutgoingCall* pCall = FindCall(lpConnection);
|
|
if (pCall)
|
|
{
|
|
pCall->AddRef();
|
|
pCall->OnT120ChannelOpen(pIChannel, dwStatus);
|
|
if (pCall->FIsComplete())
|
|
{
|
|
RemoveFromList(pCall);
|
|
}
|
|
pCall->Release();
|
|
}
|
|
|
|
DebugExitVOID(COutgoingCallManager::OnT120ChannelOpen);
|
|
}
|
|
|
|
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,
|
|
PT120PRODUCTVERSION pVersion,
|
|
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,
|
|
pVersion,
|
|
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,
|
|
PT120PRODUCTVERSION pVersion)
|
|
{
|
|
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);
|
|
}
|