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.
1282 lines
44 KiB
1282 lines
44 KiB
/****************************************************************************
|
|
*
|
|
* $Archive: S:/STURGEON/SRC/CALLCONT/VCS/q931man.c_v $
|
|
*
|
|
* INTEL Corporation Prorietary Information
|
|
*
|
|
* This listing is supplied under the terms of a license agreement
|
|
* with INTEL Corporation and may not be copied nor disclosed except
|
|
* in accordance with the terms of that agreement.
|
|
*
|
|
* Copyright (c) 1993-1994 Intel Corporation.
|
|
*
|
|
* $Revision: 1.138 $
|
|
* $Date: 04 Mar 1997 09:43:22 $
|
|
* $Author: MANDREWS $
|
|
*
|
|
* Deliverable:
|
|
*
|
|
* Abstract:
|
|
*
|
|
*
|
|
* Notes:
|
|
*
|
|
***************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
|
|
#include "apierror.h"
|
|
#include "incommon.h"
|
|
#include "callcont.h"
|
|
#include "q931.h"
|
|
#include "ccmain.h"
|
|
#include "listman.h"
|
|
#include "q931man.h"
|
|
#include "userman.h"
|
|
#include "callman.h"
|
|
#include "confman.h"
|
|
#include "h245man.h"
|
|
#include "linkapi.h"
|
|
#include "ccutils.h"
|
|
|
|
|
|
extern CALL_CONTROL_STATE CallControlState;
|
|
extern THREADCOUNT ThreadCount;
|
|
extern CC_CONFERENCEID InvalidConferenceID;
|
|
|
|
|
|
HRESULT InitQ931Manager()
|
|
{
|
|
return CC_OK;
|
|
}
|
|
|
|
|
|
|
|
HRESULT DeInitQ931Manager()
|
|
{
|
|
return CC_OK;
|
|
}
|
|
|
|
|
|
|
|
DWORD _GenerateListenCallback( PLISTEN pListen,
|
|
HQ931CALL hQ931Call,
|
|
PCSS_CALL_INCOMING pCallIncomingData)
|
|
{
|
|
HRESULT status;
|
|
CC_HLISTEN hListen;
|
|
CC_LISTEN_CALLBACK_PARAMS ListenCallbackParams;
|
|
PCALL pCall;
|
|
CC_HCALL hCall;
|
|
|
|
ASSERT(pListen != NULL);
|
|
ASSERT(pCallIncomingData != NULL);
|
|
|
|
hListen = pListen->hListen;
|
|
|
|
status = AllocAndLockCall(
|
|
&hCall, // pointer to call handle
|
|
CC_INVALID_HANDLE, // conference handle
|
|
hQ931Call, // Q931 call handle
|
|
CC_INVALID_HANDLE, // Q931 call handle for third party invitor
|
|
pCallIncomingData->pCalleeAliasList,
|
|
pCallIncomingData->pCallerAliasList,
|
|
NULL, // pPeerExtraAliasNames
|
|
NULL, // pPeerExtension
|
|
NULL, // local non-standard data
|
|
pCallIncomingData->pNonStandardData, // remote non-standard data
|
|
NULL, // local display value
|
|
pCallIncomingData->pszDisplay, // remote display value
|
|
pCallIncomingData->pSourceEndpointType->pVendorInfo,// remote vendor info
|
|
pCallIncomingData->pLocalAddr, // local address
|
|
pCallIncomingData->pCallerAddr, // connect address
|
|
NULL, // destination address
|
|
pCallIncomingData->pSourceAddr, // source call signal address
|
|
CALLEE, // call direction
|
|
pCallIncomingData->bCallerIsMC,
|
|
0, // user token; user will specify in AcceptRejectCall
|
|
INCOMING, // initial call state
|
|
&pCallIncomingData->CallIdentifier, // H225 CallIdentifier
|
|
&pCallIncomingData->ConferenceID, // conference ID
|
|
&pCall); // pointer to call object
|
|
|
|
if (status != CC_OK) {
|
|
UnlockListen(pListen);
|
|
Q931RejectCall(hQ931Call, // Q931 call handle
|
|
CC_REJECT_UNDEFINED_REASON, // reject reason
|
|
&pCallIncomingData->ConferenceID,
|
|
NULL, // alternate address
|
|
NULL); // non-standard data
|
|
return 1;
|
|
}
|
|
|
|
// Map from Q.931 goals to Call Control goals
|
|
switch (pCallIncomingData->wGoal) {
|
|
case CSG_JOIN:
|
|
ListenCallbackParams.wGoal = CC_GOAL_JOIN;
|
|
break;
|
|
case CSG_CREATE:
|
|
ListenCallbackParams.wGoal = CC_GOAL_CREATE;
|
|
break;
|
|
case CSG_INVITE:
|
|
ListenCallbackParams.wGoal = CC_GOAL_INVITE;
|
|
break;
|
|
}
|
|
|
|
ListenCallbackParams.hCall = hCall;
|
|
ListenCallbackParams.pCallerAliasNames = pCallIncomingData->pCallerAliasList;
|
|
ListenCallbackParams.pCalleeAliasNames = pCallIncomingData->pCalleeAliasList;
|
|
ListenCallbackParams.pNonStandardData = pCallIncomingData->pNonStandardData;
|
|
ListenCallbackParams.pszDisplay = pCallIncomingData->pszDisplay;
|
|
ListenCallbackParams.pVendorInfo = pCallIncomingData->pSourceEndpointType->pVendorInfo;
|
|
ListenCallbackParams.ConferenceID = pCallIncomingData->ConferenceID;
|
|
ListenCallbackParams.pCallerAddr = pCallIncomingData->pCallerAddr;
|
|
ListenCallbackParams.pCalleeAddr = pCallIncomingData->pLocalAddr;
|
|
ListenCallbackParams.dwListenToken = pListen->dwListenToken;
|
|
|
|
UnlockCall(pCall);
|
|
|
|
// Invoke the user callback -- the listen object is locked during the callback,
|
|
// but the associated call object is unlocked (to prevent deadlock if
|
|
// CC_AcceptCall() or CC_RejectCall() is called during the callback from a
|
|
// different thread, and the callback thread blocks pending completion of
|
|
// CC_AcceptCall() or CC_RejectCall())
|
|
InvokeUserListenCallback(pListen,
|
|
CC_OK,
|
|
&ListenCallbackParams);
|
|
|
|
// Need to validate the listen handle; the associated object may have been
|
|
// deleted during the user callback by this thread
|
|
if (ValidateListen(hListen) == CC_OK)
|
|
UnlockListen(pListen);
|
|
|
|
status = LockCall(hCall, &pCall);
|
|
if ((status == CC_OK) && (pCall->CallState == INCOMING)) {
|
|
UnlockCall(pCall);
|
|
return 0; // cause a ringing condition to occur
|
|
} else {
|
|
// call object has been deleted, or exists in a non-incoming state
|
|
if (status == CC_OK)
|
|
// call object exists in a non-incoming state; AcceptRejectCall
|
|
// may have been invoked from the user callback
|
|
UnlockCall(pCall);
|
|
// return 1; // don't cause a ringing condition to occur
|
|
}
|
|
|
|
// // We should never reach this point
|
|
// ASSERT(0);
|
|
return 1;
|
|
}
|
|
|
|
|
|
|
|
DWORD _Q931CallIncoming( HQ931CALL hQ931Call,
|
|
CC_HLISTEN hListen,
|
|
PCSS_CALL_INCOMING pCallIncomingData)
|
|
{
|
|
HRESULT status;
|
|
PLISTEN pListen;
|
|
PCONFERENCE pConference;
|
|
PCALL pCall;
|
|
CC_HCALL hCall;
|
|
|
|
ASSERT(hListen != CC_INVALID_HANDLE);
|
|
ASSERT(pCallIncomingData != NULL);
|
|
ASSERT(!EqualConferenceIDs(&pCallIncomingData->ConferenceID, &InvalidConferenceID));
|
|
|
|
if ((pCallIncomingData->wGoal != CSG_CREATE) &&
|
|
(pCallIncomingData->wGoal != CSG_JOIN) &&
|
|
(pCallIncomingData->wGoal != CSG_INVITE)) {
|
|
Q931RejectCall(hQ931Call, // Q931 call handle
|
|
CC_REJECT_UNDEFINED_REASON, // reject reason
|
|
&pCallIncomingData->ConferenceID,
|
|
NULL, // alternate address
|
|
NULL); // non-standard data
|
|
return 1;
|
|
}
|
|
|
|
status = LockListen(hListen, &pListen);
|
|
if (status != CC_OK) {
|
|
// the listen was presumably cancelled by the user,
|
|
// but we haven't informed Call Setup yet
|
|
Q931RejectCall(hQ931Call, // Q931 call handle
|
|
CC_REJECT_UNDEFINED_REASON, // reject reason
|
|
&pCallIncomingData->ConferenceID,
|
|
NULL, // alternate address
|
|
NULL); // non-standard data
|
|
return 1;
|
|
}
|
|
|
|
// Look for wConferenceID in conference list
|
|
status = LockConferenceID(&pCallIncomingData->ConferenceID, &pConference);
|
|
if (status == CC_OK) {
|
|
// We found a matching conference ID
|
|
if ((pConference->bDeferredDelete) &&
|
|
((pConference->bAutoAccept == FALSE) ||
|
|
((pConference->tsMultipointController == TS_TRUE) &&
|
|
(pCallIncomingData->bCallerIsMC == TRUE)))) {
|
|
UnlockListen(pListen);
|
|
UnlockConference(pConference);
|
|
Q931RejectCall(hQ931Call, // Q931 call handle
|
|
CC_REJECT_UNDEFINED_REASON, // reject reason
|
|
&pCallIncomingData->ConferenceID,
|
|
NULL, // alternate address
|
|
NULL); // non-standard data
|
|
return 1;
|
|
} else {
|
|
if (pConference->tsMultipointController == TS_TRUE) {
|
|
if ((pCallIncomingData->pCalleeDestAddr == NULL) ||
|
|
((pCallIncomingData->pCalleeDestAddr != NULL) &&
|
|
(EqualAddrs(pCallIncomingData->pLocalAddr,
|
|
pCallIncomingData->pCalleeDestAddr)))) {
|
|
switch (pCallIncomingData->wGoal) {
|
|
case CSG_CREATE:
|
|
UnlockListen(pListen);
|
|
UnlockConference(pConference);
|
|
Q931RejectCall(hQ931Call, // Q931 call handle
|
|
CC_REJECT_UNDEFINED_REASON, // reject reason
|
|
&pCallIncomingData->ConferenceID,
|
|
NULL, // alternate address
|
|
NULL); // non-standard data
|
|
return 1;
|
|
case CSG_JOIN:
|
|
if ((pConference->bDeferredDelete) &&
|
|
(pConference->bAutoAccept == TRUE)) {
|
|
// Auto accept
|
|
status = AllocAndLockCall(
|
|
&hCall, // pointer to call handle
|
|
pConference->hConference, // conference handle
|
|
hQ931Call, // Q931 call handle
|
|
CC_INVALID_HANDLE, // Q931 call handle for third party invitor
|
|
pCallIncomingData->pCalleeAliasList,
|
|
pCallIncomingData->pCallerAliasList,
|
|
NULL, // pPeerExtraAliasNames
|
|
NULL, // pPeerExtension
|
|
NULL, // local non-standard data
|
|
pCallIncomingData->pNonStandardData, // remote non-standard data
|
|
NULL, // local display value
|
|
pCallIncomingData->pszDisplay, // remote display value
|
|
pCallIncomingData->pSourceEndpointType->pVendorInfo,// remote vendor info
|
|
pCallIncomingData->pLocalAddr, // local address
|
|
pCallIncomingData->pCallerAddr, // connect address
|
|
NULL, // destination address
|
|
pCallIncomingData->pSourceAddr, // source call signal address
|
|
CALLEE, // call type
|
|
pCallIncomingData->bCallerIsMC,
|
|
0, // user token; user will specify in AcceptRejectCall
|
|
INCOMING, // initial call state
|
|
&pCallIncomingData->CallIdentifier, // h225 CallIdentifier
|
|
&pCallIncomingData->ConferenceID, // conference ID
|
|
&pCall); // pointer to call object
|
|
|
|
if (status != CC_OK) {
|
|
UnlockListen(pListen);
|
|
UnlockConference(pConference);
|
|
Q931RejectCall(hQ931Call, // Q931 call handle
|
|
CC_REJECT_UNDEFINED_REASON, // reject reason
|
|
&pCallIncomingData->ConferenceID,
|
|
NULL, // alternate address
|
|
NULL); // non-standard data
|
|
return 1;
|
|
}
|
|
|
|
AcceptCall(pCall, pConference);
|
|
return 1; // Don't send back a RINGING indication
|
|
} else {
|
|
UnlockConference(pConference);
|
|
return _GenerateListenCallback(pListen,
|
|
hQ931Call,
|
|
pCallIncomingData);
|
|
}
|
|
case CSG_INVITE:
|
|
UnlockListen(pListen);
|
|
UnlockConference(pConference);
|
|
Q931RejectCall(hQ931Call, // Q931 call handle
|
|
CC_REJECT_IN_CONF, // reject reason
|
|
&pCallIncomingData->ConferenceID,
|
|
NULL, // alternate address
|
|
NULL); // non-standard data
|
|
return 1;
|
|
} // switch (wGoal)
|
|
} else { // connect addr != destination addr
|
|
switch (pCallIncomingData->wGoal) {
|
|
case CSG_CREATE:
|
|
case CSG_JOIN:
|
|
UnlockListen(pListen);
|
|
UnlockConference(pConference);
|
|
Q931RejectCall(hQ931Call, // Q931 call handle
|
|
CC_REJECT_UNDEFINED_REASON, // reject reason
|
|
&pCallIncomingData->ConferenceID,
|
|
NULL, // alternate address
|
|
NULL); // non-standard data
|
|
return 1;
|
|
case CSG_INVITE:
|
|
// 3rd party invite
|
|
if (pCallIncomingData->bCallerIsMC == TRUE) {
|
|
UnlockListen(pListen);
|
|
UnlockConference(pConference);
|
|
Q931RejectCall(hQ931Call, // Q931 call handle
|
|
CC_REJECT_UNDEFINED_REASON, // reject reason
|
|
&pCallIncomingData->ConferenceID,
|
|
NULL, // alternate address
|
|
NULL); // non-standard data
|
|
return 1;
|
|
}
|
|
status = AllocAndLockCall(
|
|
&hCall, // pointer to call handle
|
|
pConference->hConference, // conference handle
|
|
CC_INVALID_HANDLE, // Q931 call handle
|
|
hQ931Call, // Q931 call handle for third party invitor
|
|
pCallIncomingData->pCallerAliasList, // local alias names
|
|
pCallIncomingData->pCalleeAliasList, // remote alias names
|
|
NULL, // pPeerExtraAliasNames
|
|
NULL, // pPeerExtension
|
|
pCallIncomingData->pNonStandardData, // local non-standard data
|
|
NULL, // remote non-standard data
|
|
pCallIncomingData->pszDisplay, // local display value
|
|
NULL, // remote display value
|
|
NULL, // remote vendor info
|
|
NULL, // local address
|
|
pCallIncomingData->pCalleeDestAddr, // connect address
|
|
pCallIncomingData->pCalleeDestAddr, // destination address
|
|
pCallIncomingData->pSourceAddr, // source call signal address
|
|
THIRD_PARTY_INTERMEDIARY, // call type
|
|
TRUE, // caller (this endpoint) is MC
|
|
0, // user token; user will specify in AcceptRejectCall
|
|
PLACED, // initial call state
|
|
&pCallIncomingData->CallIdentifier, // h225 CallIdentifier
|
|
&pCallIncomingData->ConferenceID, // conference ID
|
|
&pCall); // pointer to call object
|
|
|
|
if (status != CC_OK) {
|
|
UnlockListen(pListen);
|
|
UnlockConference(pConference);
|
|
Q931RejectCall(hQ931Call, // Q931 call handle
|
|
CC_REJECT_UNDEFINED_REASON, // reject reason
|
|
&pCallIncomingData->ConferenceID,
|
|
NULL, // alternate address
|
|
NULL); // non-standard data
|
|
return 1;
|
|
}
|
|
PlaceCall(pCall, pConference);
|
|
UnlockCall(pCall);
|
|
UnlockConference(pConference);
|
|
return 1; // Don't send back a RINGING indication
|
|
} // switch (wGoal)
|
|
}
|
|
} else { // pConference->tsMultipointController != TS_TRUE
|
|
if ((pCallIncomingData->pCalleeDestAddr == NULL) ||
|
|
((pCallIncomingData->pCalleeDestAddr != NULL) &&
|
|
(EqualAddrs(pCallIncomingData->pLocalAddr,
|
|
pCallIncomingData->pCalleeDestAddr)))) {
|
|
switch (pCallIncomingData->wGoal) {
|
|
case CSG_CREATE:
|
|
UnlockListen(pListen);
|
|
UnlockConference(pConference);
|
|
Q931RejectCall(hQ931Call, // Q931 call handle
|
|
CC_REJECT_UNDEFINED_REASON, // reject reason
|
|
&pCallIncomingData->ConferenceID,
|
|
NULL, // alternate address
|
|
NULL); // non-standard data
|
|
return 1;
|
|
case CSG_JOIN:
|
|
case CSG_INVITE:
|
|
UnlockConference(pConference);
|
|
return _GenerateListenCallback(pListen,
|
|
hQ931Call,
|
|
pCallIncomingData);
|
|
} // switch (wGoal)
|
|
} else { // connect addr != destination addr
|
|
UnlockListen(pListen);
|
|
UnlockConference(pConference);
|
|
Q931RejectCall(hQ931Call, // Q931 call handle
|
|
CC_REJECT_UNDEFINED_REASON, // reject reason
|
|
&pCallIncomingData->ConferenceID,
|
|
NULL, // alternate address
|
|
NULL); // non-standard data
|
|
return 1;
|
|
} // connect addr != destination addr
|
|
} // pConference->tsMultipointController != TS_TRUE
|
|
} // Matching conference ID
|
|
} else if (status == CC_BAD_PARAM) {
|
|
// This is OK; it simply means that we did not find a matching conference ID
|
|
if (((pCallIncomingData->pCalleeDestAddr != NULL) &&
|
|
(EqualAddrs(pCallIncomingData->pLocalAddr,
|
|
pCallIncomingData->pCalleeDestAddr))) ||
|
|
(pCallIncomingData->pCalleeDestAddr == NULL)) {
|
|
return _GenerateListenCallback(pListen,
|
|
hQ931Call,
|
|
pCallIncomingData);
|
|
} else { // connect addr != destination addr
|
|
UnlockListen(pListen);
|
|
Q931RejectCall(hQ931Call, // Q931 call handle
|
|
CC_REJECT_UNDEFINED_REASON, // reject reason
|
|
&pCallIncomingData->ConferenceID,
|
|
NULL, // alternate address
|
|
NULL); // non-standard data
|
|
return 1;
|
|
}
|
|
} else { // fatal error in LockConference
|
|
UnlockListen(pListen);
|
|
Q931RejectCall(hQ931Call, // Q931 call handle
|
|
CC_REJECT_UNDEFINED_REASON, // reject reason
|
|
&pCallIncomingData->ConferenceID,
|
|
NULL, // alternate address
|
|
NULL); // non-standard data
|
|
return 1;
|
|
}
|
|
|
|
// We should never reach this point
|
|
ASSERT(0);
|
|
return 1;
|
|
}
|
|
|
|
|
|
|
|
DWORD _Q931CallRemoteHangup( HQ931CALL hQ931Call,
|
|
CC_HLISTEN hListen,
|
|
CC_HCALL hCall)
|
|
{
|
|
CC_LISTEN_CALLBACK_PARAMS ListenCallbackParams;
|
|
PCALL pCall;
|
|
PLISTEN pListen;
|
|
|
|
if (hCall == CC_INVALID_HANDLE) {
|
|
// Either we've already informed the user of the hangup,
|
|
// or the user has not yet accepted or rejected the incoming
|
|
// call request
|
|
ASSERT(hListen != CC_INVALID_HANDLE);
|
|
|
|
if (LockQ931Call(hCall, hQ931Call, &pCall) != CC_OK)
|
|
return 0;
|
|
|
|
hCall = pCall->hCall;
|
|
|
|
if (pCall->hConference != CC_INVALID_HANDLE) {
|
|
UnlockCall(pCall);
|
|
// XXX -- need bHangupReason
|
|
ProcessRemoteHangup(hCall, hQ931Call, CC_REJECT_NORMAL_CALL_CLEARING);
|
|
return 0;
|
|
}
|
|
|
|
if (LockListen(hListen, &pListen) != CC_OK) {
|
|
FreeCall(pCall);
|
|
return 0;
|
|
}
|
|
|
|
MarkCallForDeletion(pCall);
|
|
|
|
ListenCallbackParams.hCall = pCall->hCall;
|
|
ListenCallbackParams.pCallerAliasNames = pCall->pPeerAliasNames;
|
|
ListenCallbackParams.pCalleeAliasNames = pCall->pLocalAliasNames;
|
|
ListenCallbackParams.pNonStandardData = pCall->pPeerNonStandardData;
|
|
ListenCallbackParams.pszDisplay = pCall->pszPeerDisplay;
|
|
ListenCallbackParams.pVendorInfo = pCall->pPeerVendorInfo;
|
|
ListenCallbackParams.wGoal = CC_GOAL_CREATE; // igonred in this callback
|
|
ListenCallbackParams.ConferenceID = pCall->ConferenceID;
|
|
ListenCallbackParams.pCallerAddr = pCall->pQ931PeerConnectAddr;
|
|
ListenCallbackParams.pCalleeAddr = pCall->pQ931LocalConnectAddr;
|
|
ListenCallbackParams.dwListenToken = pListen->dwListenToken;
|
|
|
|
InvokeUserListenCallback(pListen,
|
|
CC_PEER_CANCEL,
|
|
&ListenCallbackParams);
|
|
|
|
// Need to validate the listen and call handles; the associated objects may
|
|
// have been deleted during the user callback by this thread
|
|
if (ValidateListen(hListen) == CC_OK)
|
|
UnlockListen(pListen);
|
|
if (ValidateCallMarkedForDeletion(hCall) == CC_OK)
|
|
FreeCall(pCall);
|
|
} else
|
|
// XXX -- need bHangupReason
|
|
ProcessRemoteHangup(hCall, hQ931Call, CC_REJECT_NORMAL_CALL_CLEARING);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
DWORD _Q931CallRejected( HQ931CALL hQ931Call,
|
|
CC_HCALL hCall,
|
|
PCSS_CALL_REJECTED pCallRejectedData)
|
|
{
|
|
PCALL pCall;
|
|
CC_HCONFERENCE hConference;
|
|
PCONFERENCE pConference;
|
|
HRESULT status;
|
|
CC_CONNECT_CALLBACK_PARAMS ConnectCallbackParams;
|
|
HQ931CALL hQ931CallInvitor;
|
|
CC_ENDPOINTTYPE SourceEndpointType;
|
|
CALLTYPE CallType;
|
|
CC_CONFERENCEID ConferenceID;
|
|
CC_ADDR SourceAddr;
|
|
WORD wNumCalls;
|
|
WORD wQ931Goal;
|
|
WORD wQ931CallType;
|
|
|
|
status = LockCall(hCall, &pCall);
|
|
if (status != CC_OK)
|
|
return 0;
|
|
|
|
CallType = pCall->CallType;
|
|
ConferenceID = pCall->ConferenceID;
|
|
|
|
if ((pCall->hQ931Call != hQ931Call) ||
|
|
((pCall->CallState != PLACED) && (pCall->CallState != RINGING))) {
|
|
// The peer must be in a bad state; we don't expect to receive this message now
|
|
UnlockCall(pCall);
|
|
return 0;
|
|
}
|
|
|
|
if (CallType == THIRD_PARTY_INTERMEDIARY) {
|
|
hQ931CallInvitor = pCall->hQ931CallInvitor;
|
|
FreeCall(pCall);
|
|
if (hQ931CallInvitor != CC_INVALID_HANDLE)
|
|
Q931RejectCall(hQ931CallInvitor,
|
|
pCallRejectedData->bRejectReason,
|
|
&ConferenceID,
|
|
NULL, // alternate address
|
|
NULL); // non-standard data
|
|
return 0;
|
|
}
|
|
|
|
if (pCall->hConference == CC_INVALID_HANDLE) {
|
|
// Call is not attached to a conference
|
|
FreeCall(pCall);
|
|
return 0;
|
|
}
|
|
|
|
UnlockCall(pCall);
|
|
|
|
status = LockCallAndConference(hCall, &pCall, &pConference);
|
|
if (status != CC_OK)
|
|
return 0;
|
|
|
|
ConnectCallbackParams.pNonStandardData = pCallRejectedData->pNonStandardData;
|
|
ConnectCallbackParams.pszPeerDisplay = NULL;
|
|
ConnectCallbackParams.bRejectReason = pCallRejectedData->bRejectReason;
|
|
ConnectCallbackParams.pTermCapList = NULL;
|
|
ConnectCallbackParams.pH2250MuxCapability = NULL;
|
|
ConnectCallbackParams.pTermCapDescriptors = NULL;
|
|
ConnectCallbackParams.pLocalAddr = pCall->pQ931LocalConnectAddr;
|
|
if (pCall->pQ931DestinationAddr == NULL)
|
|
ConnectCallbackParams.pPeerAddr = pCall->pQ931PeerConnectAddr;
|
|
else
|
|
ConnectCallbackParams.pPeerAddr = pCall->pQ931DestinationAddr;
|
|
ConnectCallbackParams.pVendorInfo = pCall->pPeerVendorInfo;
|
|
|
|
if (pCallRejectedData->bRejectReason == CC_REJECT_ROUTE_TO_MC)
|
|
{
|
|
ConnectCallbackParams.bMultipointConference = TRUE;
|
|
wQ931Goal = CSG_JOIN;
|
|
wQ931CallType = CC_CALLTYPE_N_N;
|
|
}
|
|
else
|
|
{
|
|
// Goal and CallType need to be changed for multipoint support.
|
|
ConnectCallbackParams.bMultipointConference = FALSE;
|
|
wQ931Goal = CSG_CREATE;
|
|
wQ931CallType = CC_CALLTYPE_PT_PT;
|
|
}
|
|
ConnectCallbackParams.pConferenceID = &pCallRejectedData->ConferenceID;
|
|
if (pCallRejectedData->bRejectReason == CC_REJECT_ROUTE_TO_MC)
|
|
ConnectCallbackParams.pMCAddress = pCallRejectedData->pAlternateAddr;
|
|
else
|
|
ConnectCallbackParams.pMCAddress = NULL;
|
|
ConnectCallbackParams.pAlternateAddress = pCallRejectedData->pAlternateAddr;
|
|
ConnectCallbackParams.dwUserToken = pCall->dwUserToken;
|
|
|
|
// save a copy of the conference handle; we'll need it to validate
|
|
// the conference object after returning from the user callback
|
|
hConference = pConference->hConference;
|
|
|
|
if (((pCallRejectedData->bRejectReason == CC_REJECT_ROUTE_TO_MC) ||
|
|
(pCallRejectedData->bRejectReason == CC_REJECT_CALL_FORWARDED) ||
|
|
(pCallRejectedData->bRejectReason == CC_REJECT_ROUTE_TO_GATEKEEPER)) &&
|
|
(EqualConferenceIDs(&pCallRejectedData->ConferenceID, &pCall->ConferenceID)) &&
|
|
(pCallRejectedData->pAlternateAddr != NULL)) {
|
|
// XXX - In order to be H.323 compliant here, we need to re-permission this call
|
|
// through the gatekeeper because:
|
|
// 1. The rerouted call may be going to another gatekeeper zone.
|
|
// 2. The alternate address may be NULL, and we may have to resolve the
|
|
// alternate alias name list through the gatekeeper
|
|
SourceEndpointType.pVendorInfo = pConference->pVendorInfo;
|
|
SourceEndpointType.bIsTerminal = TRUE;
|
|
SourceEndpointType.bIsGateway = FALSE;
|
|
|
|
// Cause our local Q.931 connect address to be placed in the
|
|
// Q.931 setup-UUIE sourceAddress field
|
|
SourceAddr.nAddrType = CC_IP_BINARY;
|
|
SourceAddr.bMulticast = FALSE;
|
|
SourceAddr.Addr.IP_Binary.dwAddr = 0;
|
|
SourceAddr.Addr.IP_Binary.wPort = 0;
|
|
|
|
status = Q931PlaceCall(&pCall->hQ931Call, // Q931 call handle
|
|
pCall->pszLocalDisplay,
|
|
pCall->pLocalAliasNames,
|
|
pCall->pPeerAliasNames,
|
|
pCall->pPeerExtraAliasNames, // pExtraAliasList
|
|
pCall->pPeerExtension, // pExtensionAliasItem
|
|
pCall->pLocalNonStandardData,// non-standard data
|
|
&SourceEndpointType,
|
|
NULL, // pszCalledPartyNumber
|
|
pCallRejectedData->pAlternateAddr, // connect address
|
|
pCall->pQ931DestinationAddr, // destination address
|
|
NULL, // source address
|
|
FALSE, // bIsMC
|
|
&pCall->ConferenceID, // conference ID
|
|
wQ931Goal, // goal
|
|
wQ931CallType, // call type
|
|
hCall, // user token
|
|
(Q931_CALLBACK)Q931Callback, // callback
|
|
#ifdef GATEKEEPER
|
|
pCall->GkiCall.usCRV, // CRV
|
|
&pCall->CallIdentifier); // H.225 CallIdentifier
|
|
#else
|
|
0, // CRV
|
|
&pCall->CallIdentifier); // H.225 CallIdentifier
|
|
#endif GATEKEEPER
|
|
if (status != CS_OK) {
|
|
MarkCallForDeletion(pCall);
|
|
InvokeUserConferenceCallback(pConference,
|
|
CC_CONNECT_INDICATION,
|
|
status,
|
|
&ConnectCallbackParams);
|
|
|
|
if (ValidateCallMarkedForDeletion(hCall) == CC_OK)
|
|
FreeCall(pCall);
|
|
|
|
if (ValidateConference(hConference) != CC_OK)
|
|
return 0;
|
|
|
|
for ( ; ; ) {
|
|
// Start up an enqueued call, if one exists
|
|
status = RemoveEnqueuedCallFromConference(pConference, &hCall);
|
|
if ((status != CC_OK) || (hCall == CC_INVALID_HANDLE))
|
|
break;
|
|
|
|
status = LockCall(hCall, &pCall);
|
|
if (status == CC_OK) {
|
|
pCall->CallState = PLACED;
|
|
|
|
status = PlaceCall(pCall, pConference);
|
|
UnlockCall(pCall);
|
|
if (status == CC_OK)
|
|
break;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
UnlockCall(pCall);
|
|
UnlockConference(pConference);
|
|
return 0;
|
|
}
|
|
|
|
MarkCallForDeletion(pCall);
|
|
|
|
if ((CallType == CALLER) || (CallType == THIRD_PARTY_INVITOR) ||
|
|
((CallType == CALLEE) && (pConference->LocalEndpointAttached == NEVER_ATTACHED))) {
|
|
InvokeUserConferenceCallback(pConference,
|
|
CC_CONNECT_INDICATION,
|
|
CC_PEER_REJECT,
|
|
&ConnectCallbackParams);
|
|
}
|
|
|
|
if (ValidateCallMarkedForDeletion(hCall) == CC_OK)
|
|
FreeCall(pCall);
|
|
|
|
// Need to validate conference handle; the associated object may
|
|
// have been deleted during the user callback in this thread
|
|
if (ValidateConference(hConference) != CC_OK)
|
|
return 0;
|
|
|
|
for ( ; ; ) {
|
|
// Start up an enqueued call, if one exists
|
|
status = RemoveEnqueuedCallFromConference(pConference, &hCall);
|
|
if ((status != CC_OK) || (hCall == CC_INVALID_HANDLE))
|
|
break;
|
|
|
|
status = LockCall(hCall, &pCall);
|
|
if (status == CC_OK) {
|
|
pCall->CallState = PLACED;
|
|
|
|
status = PlaceCall(pCall, pConference);
|
|
UnlockCall(pCall);
|
|
if (status == CC_OK)
|
|
break;
|
|
}
|
|
}
|
|
|
|
EnumerateCallsInConference(&wNumCalls, NULL, pConference, REAL_CALLS);
|
|
|
|
if (wNumCalls == 0) {
|
|
if (pConference->bDeferredDelete) {
|
|
ASSERT(pConference->LocalEndpointAttached == DETACHED);
|
|
FreeConference(pConference);
|
|
} else {
|
|
if ((pConference->ConferenceMode != MULTIPOINT_MODE) ||
|
|
(pConference->tsMultipointController != TS_TRUE))
|
|
ReInitializeConference(pConference);
|
|
UnlockConference(pConference);
|
|
}
|
|
} else {
|
|
UnlockConference(pConference);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
DWORD _Q931CallAccepted( HQ931CALL hQ931Call,
|
|
CC_HCALL hCall,
|
|
PCSS_CALL_ACCEPTED pCallAcceptedData)
|
|
{
|
|
HRESULT status;
|
|
PCALL pCall;
|
|
CC_HCONFERENCE hConference;
|
|
PCONFERENCE pConference;
|
|
CC_CONNECT_CALLBACK_PARAMS ConnectCallbackParams;
|
|
BYTE bTerminalType;
|
|
BOOL bMultipointConference;
|
|
CALLTYPE CallType;
|
|
HQ931CALL hQ931CallInvitor;
|
|
H245_INST_T H245Instance;
|
|
DWORD dwLinkLayerPhysicalId;
|
|
|
|
status = LockCallAndConference(hCall, &pCall, &pConference);
|
|
if (status != CC_OK)
|
|
return 0;
|
|
|
|
CallType = pCall->CallType;
|
|
hConference = pConference->hConference;
|
|
hQ931Call = pCall->hQ931Call;
|
|
hQ931CallInvitor = pCall->hQ931CallInvitor;
|
|
|
|
ASSERT((pCall->hQ931Call == hQ931Call) || (pCall->hQ931CallInvitor == hQ931Call));
|
|
|
|
if ((pConference->ConferenceMode == POINT_TO_POINT_MODE) ||
|
|
(pConference->ConferenceMode == MULTIPOINT_MODE))
|
|
bMultipointConference = TRUE;
|
|
else
|
|
bMultipointConference = FALSE;
|
|
|
|
// Initialize ConnectCallbackParams
|
|
ConnectCallbackParams.pNonStandardData = pCallAcceptedData->pNonStandardData;
|
|
ConnectCallbackParams.pszPeerDisplay = pCallAcceptedData->pszDisplay;
|
|
ConnectCallbackParams.bRejectReason = CC_REJECT_UNDEFINED_REASON; // field ignored
|
|
ConnectCallbackParams.pTermCapList = NULL;
|
|
ConnectCallbackParams.pH2250MuxCapability = NULL;
|
|
ConnectCallbackParams.pTermCapDescriptors = NULL;
|
|
ConnectCallbackParams.pLocalAddr = pCall->pQ931LocalConnectAddr;
|
|
ConnectCallbackParams.pPeerAddr = pCallAcceptedData->pCalleeAddr;
|
|
ConnectCallbackParams.pVendorInfo = pCall->pPeerVendorInfo;
|
|
ConnectCallbackParams.bMultipointConference = bMultipointConference;
|
|
ConnectCallbackParams.pConferenceID = &pConference->ConferenceID;
|
|
ConnectCallbackParams.pMCAddress = pConference->pMultipointControllerAddr;
|
|
ConnectCallbackParams.pAlternateAddress = NULL;
|
|
ConnectCallbackParams.dwUserToken = pCall->dwUserToken;
|
|
|
|
if (pCallAcceptedData->pCalleeAddr) {
|
|
// Set pCall->pQ931DestinationAddr to the destination address that we got from Q931.
|
|
// Note that we may not current have a destination address (if the client didn't
|
|
// specify one), or we may currently have a destination address in domain name format
|
|
// which we need to change to binary format
|
|
if (pCall->pQ931DestinationAddr == NULL)
|
|
pCall->pQ931DestinationAddr = (PCC_ADDR)MemAlloc(sizeof(CC_ADDR));
|
|
if (pCall->pQ931DestinationAddr != NULL)
|
|
*pCall->pQ931DestinationAddr = *pCallAcceptedData->pCalleeAddr;
|
|
}
|
|
|
|
if ((!EqualConferenceIDs(&pConference->ConferenceID, &InvalidConferenceID)) &&
|
|
(!EqualConferenceIDs(&pConference->ConferenceID, &pCallAcceptedData->ConferenceID))) {
|
|
|
|
MarkCallForDeletion(pCall);
|
|
|
|
if (CallType == THIRD_PARTY_INTERMEDIARY) {
|
|
if (hQ931CallInvitor != CC_INVALID_HANDLE)
|
|
Q931RejectCall(hQ931CallInvitor,
|
|
CC_REJECT_UNDEFINED_REASON,
|
|
&pCallAcceptedData->ConferenceID,
|
|
NULL, // alternate address
|
|
pCallAcceptedData->pNonStandardData);
|
|
} else {
|
|
if ((CallType == CALLER) || (CallType == THIRD_PARTY_INVITOR) ||
|
|
((CallType == CALLEE) && (pConference->LocalEndpointAttached == NEVER_ATTACHED)))
|
|
InvokeUserConferenceCallback(pConference,
|
|
CC_CONNECT_INDICATION,
|
|
CC_INTERNAL_ERROR,
|
|
&ConnectCallbackParams);
|
|
}
|
|
if (ValidateCallMarkedForDeletion(hCall) == CC_OK)
|
|
FreeCall(pCall);
|
|
if (ValidateConference(hConference) == CC_OK)
|
|
UnlockConference(pConference);
|
|
Q931Hangup(hQ931Call, CC_REJECT_UNDEFINED_REASON);
|
|
return 0;
|
|
}
|
|
|
|
pConference->ConferenceID = pCallAcceptedData->ConferenceID;
|
|
pCall->ConferenceID = pCallAcceptedData->ConferenceID;
|
|
// Copy the newly-supplied peer address into the call object.
|
|
// This is preferable if the original peer address was in IP dot
|
|
// or domain name format
|
|
if (CallType != THIRD_PARTY_INVITOR) {
|
|
if (pCallAcceptedData->pCalleeAddr != NULL) {
|
|
if (pCall->pQ931DestinationAddr == NULL)
|
|
pCall->pQ931DestinationAddr = (PCC_ADDR)MemAlloc(sizeof(CC_ADDR));
|
|
if (pCall->pQ931DestinationAddr != NULL)
|
|
*pCall->pQ931DestinationAddr = *pCallAcceptedData->pCalleeAddr;
|
|
}
|
|
|
|
if (pCallAcceptedData->pLocalAddr != NULL) {
|
|
if (pCall->pQ931LocalConnectAddr == NULL)
|
|
pCall->pQ931LocalConnectAddr = (PCC_ADDR)MemAlloc(sizeof(CC_ADDR));
|
|
if (pCall->pQ931LocalConnectAddr != NULL)
|
|
*pCall->pQ931LocalConnectAddr = *pCallAcceptedData->pLocalAddr;
|
|
}
|
|
}
|
|
|
|
ASSERT(pCall->pPeerNonStandardData == NULL);
|
|
CopyNonStandardData(&pCall->pPeerNonStandardData,
|
|
pCallAcceptedData->pNonStandardData);
|
|
|
|
ASSERT(pCall->pszPeerDisplay == NULL);
|
|
CopyDisplay(&pCall->pszPeerDisplay,
|
|
pCallAcceptedData->pszDisplay);
|
|
|
|
ASSERT(pCall->pPeerVendorInfo == NULL);
|
|
CopyVendorInfo(&pCall->pPeerVendorInfo,
|
|
pCallAcceptedData->pDestinationEndpointType->pVendorInfo);
|
|
|
|
if (CallType == THIRD_PARTY_INVITOR) {
|
|
pCall->CallState = CALL_COMPLETE;
|
|
ConnectCallbackParams.pPeerAddr = pCall->pQ931DestinationAddr;
|
|
MarkCallForDeletion(pCall);
|
|
InvokeUserConferenceCallback(pConference,
|
|
CC_CONNECT_INDICATION,
|
|
CC_OK,
|
|
&ConnectCallbackParams);
|
|
if (ValidateCallMarkedForDeletion(hCall) == CC_OK)
|
|
FreeCall(pCall);
|
|
if (ValidateConference(hConference) == CC_OK)
|
|
UnlockConference(pConference);
|
|
return 0;
|
|
}
|
|
|
|
pCall->CallState = TERMCAP;
|
|
|
|
status = MakeH245PhysicalID(&pCall->dwH245PhysicalID);
|
|
if (status != CC_OK) {
|
|
|
|
MarkCallForDeletion(pCall);
|
|
|
|
if (CallType == THIRD_PARTY_INTERMEDIARY) {
|
|
if (hQ931CallInvitor != CC_INVALID_HANDLE)
|
|
Q931RejectCall(hQ931CallInvitor,
|
|
CC_REJECT_UNDEFINED_REASON,
|
|
&pCallAcceptedData->ConferenceID,
|
|
NULL, // alternate address
|
|
pCallAcceptedData->pNonStandardData);
|
|
} else {
|
|
if ((CallType == CALLER) || (CallType == THIRD_PARTY_INVITOR) ||
|
|
((CallType == CALLEE) && (pConference->LocalEndpointAttached == NEVER_ATTACHED)))
|
|
InvokeUserConferenceCallback(pConference,
|
|
CC_CONNECT_INDICATION,
|
|
status,
|
|
&ConnectCallbackParams);
|
|
}
|
|
Q931Hangup(hQ931Call, CC_REJECT_UNDEFINED_REASON);
|
|
if (ValidateCallMarkedForDeletion(hCall) == CC_OK)
|
|
FreeCall(pCall);
|
|
if (ValidateConference(hConference) == CC_OK)
|
|
UnlockConference(pConference);
|
|
return 0;
|
|
}
|
|
|
|
//MULTITHREAD
|
|
//Use a tmp ID so we don't clobber the chosen H245Id.
|
|
// H245Id=>
|
|
// <= linkLayerId
|
|
dwLinkLayerPhysicalId = INVALID_PHYS_ID;
|
|
|
|
SetTerminalType(pConference->tsMultipointController, &bTerminalType);
|
|
pCall->H245Instance = H245Init(H245_CONF_H323,
|
|
pCall->dwH245PhysicalID,
|
|
&dwLinkLayerPhysicalId,
|
|
hCall,
|
|
(H245_CONF_IND_CALLBACK_T)H245Callback,
|
|
bTerminalType);
|
|
if (pCall->H245Instance == H245_INVALID_ID) {
|
|
MarkCallForDeletion(pCall);
|
|
if (CallType == THIRD_PARTY_INTERMEDIARY) {
|
|
if (hQ931CallInvitor != CC_INVALID_HANDLE)
|
|
Q931RejectCall(hQ931CallInvitor,
|
|
CC_REJECT_UNDEFINED_REASON,
|
|
&pCallAcceptedData->ConferenceID,
|
|
NULL, // alternate address
|
|
pCallAcceptedData->pNonStandardData);
|
|
} else {
|
|
if ((CallType == CALLER) || (CallType == THIRD_PARTY_INVITOR) ||
|
|
((CallType == CALLEE) && (pConference->LocalEndpointAttached == NEVER_ATTACHED)))
|
|
InvokeUserConferenceCallback(pConference,
|
|
CC_CONNECT_INDICATION,
|
|
CC_INTERNAL_ERROR,
|
|
&ConnectCallbackParams);
|
|
}
|
|
Q931Hangup(hQ931Call, CC_REJECT_UNDEFINED_REASON);
|
|
if (ValidateCallMarkedForDeletion(hCall) == CC_OK)
|
|
FreeCall(pCall);
|
|
if (ValidateConference(hConference) == CC_OK)
|
|
UnlockConference(pConference);
|
|
return 0;
|
|
}
|
|
|
|
H245Instance = pCall->H245Instance;
|
|
|
|
// XXX -- need to define connect callback routine
|
|
// Send in the Id we got back from H245Init.
|
|
status = linkLayerConnect(dwLinkLayerPhysicalId,
|
|
pCallAcceptedData->pH245Addr,
|
|
NULL);
|
|
if (status != NOERROR) {
|
|
|
|
MarkCallForDeletion(pCall);
|
|
|
|
if (CallType == THIRD_PARTY_INTERMEDIARY) {
|
|
if (hQ931CallInvitor != CC_INVALID_HANDLE)
|
|
Q931RejectCall(hQ931CallInvitor,
|
|
CC_REJECT_UNDEFINED_REASON,
|
|
&pCallAcceptedData->ConferenceID,
|
|
NULL, // alternate address
|
|
pCallAcceptedData->pNonStandardData);
|
|
} else {
|
|
if ((CallType == CALLER) || (CallType == THIRD_PARTY_INVITOR) ||
|
|
((CallType == CALLEE) && (pConference->LocalEndpointAttached == NEVER_ATTACHED)))
|
|
InvokeUserConferenceCallback(pConference,
|
|
CC_CONNECT_INDICATION,
|
|
status,
|
|
&ConnectCallbackParams);
|
|
}
|
|
H245ShutDown(H245Instance);
|
|
Q931Hangup(hQ931Call, CC_REJECT_UNDEFINED_REASON);
|
|
if (ValidateCallMarkedForDeletion(hCall) == CC_OK)
|
|
FreeCall(pCall);
|
|
if (ValidateConference(hConference) == CC_OK)
|
|
UnlockConference(pConference);
|
|
return 0;
|
|
}
|
|
|
|
pCall->bLinkEstablished = TRUE;
|
|
|
|
status = SendTermCaps(pCall, pConference);
|
|
if (status != CC_OK) {
|
|
|
|
MarkCallForDeletion(pCall);
|
|
|
|
if (CallType == THIRD_PARTY_INTERMEDIARY) {
|
|
if (hQ931CallInvitor != CC_INVALID_HANDLE)
|
|
Q931RejectCall(hQ931CallInvitor,
|
|
CC_REJECT_UNDEFINED_REASON,
|
|
&pCallAcceptedData->ConferenceID,
|
|
NULL, // alternate address
|
|
pCallAcceptedData->pNonStandardData);
|
|
} else {
|
|
if ((CallType == CALLER) || (CallType == THIRD_PARTY_INVITOR) ||
|
|
((CallType == CALLEE) && (pConference->LocalEndpointAttached == NEVER_ATTACHED)))
|
|
InvokeUserConferenceCallback(pConference,
|
|
CC_CONNECT_INDICATION,
|
|
CC_NO_MEMORY,
|
|
&ConnectCallbackParams);
|
|
}
|
|
H245ShutDown(H245Instance);
|
|
Q931Hangup(hQ931Call, CC_REJECT_UNDEFINED_REASON);
|
|
if (ValidateCallMarkedForDeletion(hCall) == CC_OK)
|
|
FreeCall(pCall);
|
|
if (ValidateConference(hConference) == CC_OK)
|
|
UnlockConference(pConference);
|
|
return 0;
|
|
}
|
|
|
|
pCall->OutgoingTermCapState = AWAITING_ACK;
|
|
|
|
if (pCall->MasterSlaveState == MASTER_SLAVE_NOT_STARTED) {
|
|
status = H245InitMasterSlave(pCall->H245Instance,
|
|
pCall->H245Instance); // returned as dwTransId in the callback
|
|
if (status != H245_ERROR_OK) {
|
|
|
|
MarkCallForDeletion(pCall);
|
|
|
|
if (CallType == THIRD_PARTY_INTERMEDIARY) {
|
|
if (hQ931CallInvitor != CC_INVALID_HANDLE)
|
|
Q931RejectCall(hQ931CallInvitor,
|
|
CC_REJECT_UNDEFINED_REASON,
|
|
&pCallAcceptedData->ConferenceID,
|
|
NULL, // alternate address
|
|
pCallAcceptedData->pNonStandardData);
|
|
} else {
|
|
if ((CallType == CALLER) || (CallType == THIRD_PARTY_INVITOR) ||
|
|
((CallType == CALLEE) && (pConference->LocalEndpointAttached == NEVER_ATTACHED)))
|
|
InvokeUserConferenceCallback(pConference,
|
|
CC_CONNECT_INDICATION,
|
|
status,
|
|
&ConnectCallbackParams);
|
|
}
|
|
H245ShutDown(H245Instance);
|
|
Q931Hangup(hQ931Call, CC_REJECT_UNDEFINED_REASON);
|
|
if (ValidateCallMarkedForDeletion(hCall) == CC_OK)
|
|
FreeCall(pCall);
|
|
if (ValidateConference(hConference) == CC_OK)
|
|
UnlockConference(pConference);
|
|
return 0;
|
|
}
|
|
pCall->MasterSlaveState = MASTER_SLAVE_IN_PROGRESS;
|
|
}
|
|
|
|
UnlockConference(pConference);
|
|
UnlockCall(pCall);
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
DWORD _Q931CallRinging( HQ931CALL hQ931Call,
|
|
CC_HCALL hCall)
|
|
{
|
|
PCALL pCall;
|
|
CC_HCONFERENCE hConference;
|
|
PCONFERENCE pConference;
|
|
HRESULT status;
|
|
CC_RINGING_CALLBACK_PARAMS RingingCallbackParams;
|
|
CC_CONFERENCEID ConferenceID;
|
|
|
|
status = LockCallAndConference(hCall, &pCall, &pConference);
|
|
if (status != CC_OK) {
|
|
Q931RejectCall(hQ931Call, // Q931 call handle
|
|
CC_REJECT_UNDEFINED_REASON, // reject reason
|
|
NULL, // conference ID
|
|
NULL, // alternate address
|
|
NULL); // non-standard data
|
|
return 0;
|
|
}
|
|
|
|
ConferenceID = pCall->ConferenceID;
|
|
|
|
if ((pCall->hQ931Call != hQ931Call) || (pCall->CallState != PLACED)) {
|
|
// The peer must be in a bad state; we don't expect to receive this message now
|
|
UnlockCall(pCall);
|
|
return 0;
|
|
}
|
|
|
|
pCall->CallState = RINGING;
|
|
|
|
if (pCall->CallType == THIRD_PARTY_INTERMEDIARY) {
|
|
// Send "ringing" indication to pCall->hQ931CallInvitor
|
|
Q931Ringing(pCall->hQ931CallInvitor,
|
|
NULL); // pCRV
|
|
UnlockConference(pConference);
|
|
UnlockCall(pCall);
|
|
return 0;
|
|
}
|
|
|
|
RingingCallbackParams.pNonStandardData = NULL;
|
|
RingingCallbackParams.dwUserToken = pCall->dwUserToken;
|
|
|
|
// save a copy of the conference handle; we'll need it to validate
|
|
// the conference object after returning from the user callback
|
|
hConference = pConference->hConference;
|
|
|
|
InvokeUserConferenceCallback(pConference,
|
|
CC_RINGING_INDICATION,
|
|
CC_OK,
|
|
&RingingCallbackParams);
|
|
|
|
// Need to validate conference and call handles; the associated objects may
|
|
// have been deleted during the user callback in this thread
|
|
if (ValidateConference(hConference) == CC_OK)
|
|
UnlockConference(pConference);
|
|
if (ValidateCall(hCall) == CC_OK)
|
|
UnlockCall(pCall);
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
DWORD _Q931CallFailed( HQ931CALL hQ931Call,
|
|
CC_HCALL hCall,
|
|
PCSS_CALL_FAILED pCallFailedData)
|
|
{
|
|
PCALL pCall;
|
|
CC_HCONFERENCE hConference;
|
|
PCONFERENCE pConference;
|
|
HQ931CALL hQ931CallInvitor;
|
|
HRESULT status;
|
|
CC_CONNECT_CALLBACK_PARAMS ConnectCallbackParams;
|
|
CALLTYPE CallType;
|
|
CC_CONFERENCEID ConferenceID;
|
|
WORD wNumCalls;
|
|
|
|
status = LockCallAndConference(hCall, &pCall, &pConference);
|
|
if (status != CC_OK)
|
|
return 0;
|
|
|
|
CallType = pCall->CallType;
|
|
ConferenceID = pCall->ConferenceID;
|
|
|
|
if (pCall->hQ931Call != hQ931Call) {
|
|
UnlockConference(pConference);
|
|
UnlockCall(pCall);
|
|
return 0;
|
|
}
|
|
|
|
if (CallType == THIRD_PARTY_INTERMEDIARY) {
|
|
hQ931CallInvitor = pCall->hQ931CallInvitor;
|
|
FreeCall(pCall);
|
|
UnlockConference(pConference);
|
|
if (hQ931CallInvitor != CC_INVALID_HANDLE)
|
|
Q931RejectCall(hQ931CallInvitor,
|
|
CC_REJECT_UNREACHABLE_DESTINATION,
|
|
&ConferenceID,
|
|
NULL, // alternate address
|
|
NULL); // non-standard data
|
|
return 0;
|
|
}
|
|
|
|
ConnectCallbackParams.pNonStandardData = NULL;
|
|
ConnectCallbackParams.pszPeerDisplay = NULL;
|
|
ConnectCallbackParams.bRejectReason = CC_REJECT_UNREACHABLE_DESTINATION;
|
|
ConnectCallbackParams.pTermCapList = NULL;
|
|
ConnectCallbackParams.pH2250MuxCapability = NULL;
|
|
ConnectCallbackParams.pTermCapDescriptors = NULL;
|
|
ConnectCallbackParams.pLocalAddr = pCall->pQ931LocalConnectAddr;
|
|
if (pCall->pQ931DestinationAddr == NULL)
|
|
ConnectCallbackParams.pPeerAddr = pCall->pQ931PeerConnectAddr;
|
|
else
|
|
ConnectCallbackParams.pPeerAddr = pCall->pQ931DestinationAddr;
|
|
ConnectCallbackParams.pVendorInfo = pCall->pPeerVendorInfo;
|
|
ConnectCallbackParams.bMultipointConference = FALSE;
|
|
ConnectCallbackParams.pConferenceID = &pConference->ConferenceID;
|
|
ConnectCallbackParams.pMCAddress = NULL;
|
|
ConnectCallbackParams.pAlternateAddress = NULL;
|
|
ConnectCallbackParams.dwUserToken = pCall->dwUserToken;
|
|
|
|
// save a copy of the conference handle; we'll need it to validate
|
|
// the conference object after returning from the user callback
|
|
hConference = pConference->hConference;
|
|
|
|
MarkCallForDeletion(pCall);
|
|
|
|
if ((CallType == CALLER) || (CallType == THIRD_PARTY_INVITOR) ||
|
|
((CallType == CALLEE) && (pConference->LocalEndpointAttached == NEVER_ATTACHED))) {
|
|
InvokeUserConferenceCallback(pConference,
|
|
CC_CONNECT_INDICATION,
|
|
pCallFailedData->error,
|
|
&ConnectCallbackParams);
|
|
}
|
|
if (ValidateCallMarkedForDeletion(hCall) == CC_OK)
|
|
FreeCall(pCall);
|
|
// Need to validate conference handle; the associated object may
|
|
// have been deleted during the user callback in this thread
|
|
if (ValidateConference(hConference) != CC_OK)
|
|
return 0;
|
|
|
|
for ( ; ; ) {
|
|
// Start up an enqueued call, if one exists
|
|
status = RemoveEnqueuedCallFromConference(pConference, &hCall);
|
|
if ((status != CC_OK) || (hCall == CC_INVALID_HANDLE))
|
|
break;
|
|
|
|
status = LockCall(hCall, &pCall);
|
|
if (status == CC_OK) {
|
|
pCall->CallState = PLACED;
|
|
|
|
status = PlaceCall(pCall, pConference);
|
|
UnlockCall(pCall);
|
|
if (status == CC_OK)
|
|
break;
|
|
}
|
|
}
|
|
|
|
EnumerateCallsInConference(&wNumCalls, NULL, pConference, REAL_CALLS);
|
|
|
|
if (wNumCalls == 0) {
|
|
if (pConference->bDeferredDelete) {
|
|
ASSERT(pConference->LocalEndpointAttached == DETACHED);
|
|
FreeConference(pConference);
|
|
} else {
|
|
if ((pConference->ConferenceMode != MULTIPOINT_MODE) ||
|
|
(pConference->tsMultipointController != TS_TRUE))
|
|
ReInitializeConference(pConference);
|
|
UnlockConference(pConference);
|
|
}
|
|
} else {
|
|
UnlockConference(pConference);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
DWORD _Q931CallConnectionClosed( HQ931CALL hQ931Call,
|
|
CC_HCALL hCall)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
DWORD Q931Callback( BYTE bEvent,
|
|
HQ931CALL hQ931Call,
|
|
DWORD_PTR dwListenToken,
|
|
DWORD_PTR dwUserToken,
|
|
void * pEventData)
|
|
{
|
|
DWORD dwStatus;
|
|
|
|
EnterCallControl();
|
|
|
|
if (CallControlState != OPERATIONAL_STATE)
|
|
DWLeaveCallControl(0);
|
|
|
|
switch (bEvent) {
|
|
case Q931_CALL_INCOMING:
|
|
dwStatus = _Q931CallIncoming(hQ931Call, (CC_HLISTEN)dwListenToken,
|
|
(PCSS_CALL_INCOMING)pEventData);
|
|
break;
|
|
|
|
case Q931_CALL_REMOTE_HANGUP:
|
|
dwStatus = _Q931CallRemoteHangup(hQ931Call, (CC_HLISTEN)dwListenToken,
|
|
(CC_HCALL)dwUserToken);
|
|
break;
|
|
|
|
case Q931_CALL_REJECTED:
|
|
dwStatus = _Q931CallRejected(hQ931Call, (CC_HCALL)dwUserToken,
|
|
(PCSS_CALL_REJECTED)pEventData);
|
|
break;
|
|
|
|
case Q931_CALL_ACCEPTED:
|
|
dwStatus = _Q931CallAccepted(hQ931Call, (CC_HCALL)dwUserToken,
|
|
(PCSS_CALL_ACCEPTED)pEventData);
|
|
break;
|
|
|
|
case Q931_CALL_RINGING:
|
|
dwStatus = _Q931CallRinging(hQ931Call, (CC_HCALL)dwUserToken);
|
|
break;
|
|
|
|
case Q931_CALL_FAILED:
|
|
dwStatus = _Q931CallFailed(hQ931Call, (CC_HCALL)dwUserToken,
|
|
(PCSS_CALL_FAILED)pEventData);
|
|
break;
|
|
|
|
case Q931_CALL_CONNECTION_CLOSED:
|
|
dwStatus = _Q931CallConnectionClosed(hQ931Call, (CC_HCALL)dwUserToken);
|
|
break;
|
|
|
|
default:
|
|
ASSERT(0);
|
|
dwStatus = 0;
|
|
break;
|
|
}
|
|
DWLeaveCallControl(dwStatus);
|
|
}
|
|
|