3945 lines
97 KiB
C
3945 lines
97 KiB
C
/*++
|
||
|
||
Copyright (c) 1997 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
call.c
|
||
|
||
Abstract:
|
||
|
||
TAPI Service Provider functions related to manipulating calls.
|
||
|
||
TSPI_lineAnswer
|
||
TSPI_lineCloseCall
|
||
TSPI_lineDrop
|
||
TSPI_lineGetCallAddressID
|
||
TSPI_lineGetCallInfo
|
||
TSPI_lineGetCallStatus
|
||
TSPI_lineMakeCallMSP
|
||
|
||
Environment:
|
||
|
||
User Mode - Win32
|
||
|
||
--*/
|
||
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
// //
|
||
// Include files //
|
||
// //
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
|
||
#include "globals.h"
|
||
#include "provider.h"
|
||
#include "registry.h"
|
||
#include "termcaps.h"
|
||
#include "callback.h"
|
||
#include "line.h"
|
||
#include <h323tsp.h>
|
||
#include <h323pdu.h>
|
||
#include <iphlpapi.h>
|
||
|
||
WCHAR g_strAlias[MAX_ALIAS_LENGTH+1];
|
||
DWORD g_dwAliasLength = 0;
|
||
|
||
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
// //
|
||
// Private procedures //
|
||
// //
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
|
||
BOOL
|
||
H323CloseCallCommand(
|
||
PH323_CALL pCall
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Sends CLOSE_CALL_COMMAND from TSP to MSP.
|
||
|
||
Arguments:
|
||
|
||
pCall - Specifies a pointer to the associated call object.
|
||
|
||
Return Values:
|
||
|
||
Returns true if successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
H323TSP_MESSAGE Message;
|
||
|
||
// set the appropriate message type
|
||
Message.Type = H323TSP_CLOSE_CALL_COMMAND;
|
||
|
||
// send msp message
|
||
(*g_pfnLineEventProc)(
|
||
pCall->pLine->htLine,
|
||
pCall->htCall,
|
||
LINE_SENDMSPDATA,
|
||
MSP_HANDLE_UNKNOWN,
|
||
(DWORD_PTR)&Message,
|
||
sizeof(Message)
|
||
);
|
||
|
||
// success
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
BOOL
|
||
H323AddU2U(
|
||
PLIST_ENTRY pListHead,
|
||
DWORD dwDataSize,
|
||
PBYTE pData
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Create user user structure and adds to list.
|
||
|
||
Arguments:
|
||
|
||
pListHead - Pointer to list in which to add user user info.
|
||
|
||
dwDataSize - Size of buffer pointed to by pData.
|
||
|
||
pData - Pointer to user user info.
|
||
|
||
Return Values:
|
||
|
||
Returns true if successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
PH323_U2ULE pU2ULE;
|
||
|
||
// validate data buffer pointer and size
|
||
if ((pData != NULL) && (dwDataSize > 0)) {
|
||
|
||
// allocate memory for user user info
|
||
pU2ULE = H323HeapAlloc(dwDataSize + sizeof(H323_U2ULE));
|
||
|
||
// validate pointer
|
||
if (pU2ULE == NULL) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"could not allocate user user info.\n"
|
||
));
|
||
|
||
// failure
|
||
return FALSE;
|
||
}
|
||
|
||
// aim pointer at the end of the buffer by default
|
||
pU2ULE->pU2U = (LPBYTE)pU2ULE + sizeof(H323_U2ULE);
|
||
pU2ULE->dwU2USize = dwDataSize;
|
||
|
||
// transfer user user info into list entry
|
||
memcpy(pU2ULE->pU2U, pData, pU2ULE->dwU2USize);
|
||
|
||
// add list entry to back of list
|
||
InsertTailList(pListHead, &pU2ULE->Link);
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_VERBOSE,
|
||
"added user user info 0x%08lx (%d bytes).\n",
|
||
pU2ULE->pU2U,
|
||
pU2ULE->dwU2USize
|
||
));
|
||
}
|
||
|
||
// success
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
BOOL
|
||
H323RemoveU2U(
|
||
PLIST_ENTRY pListHead,
|
||
PH323_U2ULE * ppU2ULE
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Removes user user info structure from list.
|
||
|
||
Arguments:
|
||
|
||
pListHead - Pointer to list in which to remove user user info.
|
||
|
||
ppU2ULE - Pointer to pointer to list entry.
|
||
|
||
Return Values:
|
||
|
||
Returns true if successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
PLIST_ENTRY pLE;
|
||
|
||
// process list until empty
|
||
if (!IsListEmpty(pListHead)) {
|
||
|
||
// retrieve first entry
|
||
pLE = RemoveHeadList(pListHead);
|
||
|
||
// convert list entry to structure pointer
|
||
*ppU2ULE = CONTAINING_RECORD(pLE, H323_U2ULE, Link);
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_VERBOSE,
|
||
"removed user user info 0x%08lx (%d bytes).\n",
|
||
(*ppU2ULE)->pU2U,
|
||
(*ppU2ULE)->dwU2USize
|
||
));
|
||
|
||
// success
|
||
return TRUE;
|
||
}
|
||
|
||
// failure
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
BOOL
|
||
H323FreeU2U(
|
||
PLIST_ENTRY pListHead
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Releases memory for user user list.
|
||
|
||
Arguments:
|
||
|
||
pListHead - Pointer to list in which to free user user info.
|
||
|
||
Return Values:
|
||
|
||
Returns true if successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
PLIST_ENTRY pLE;
|
||
PH323_U2ULE pU2ULE;
|
||
|
||
// process list until empty
|
||
while (!IsListEmpty(pListHead)) {
|
||
|
||
// retrieve first entry
|
||
pLE = RemoveHeadList(pListHead);
|
||
|
||
// convert list entry to structure pointer
|
||
pU2ULE = CONTAINING_RECORD(pLE, H323_U2ULE, Link);
|
||
|
||
// release memory
|
||
H323HeapFree(pU2ULE);
|
||
}
|
||
|
||
// success
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
BOOL
|
||
H323ResetCall(
|
||
PH323_CALL pCall
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Resets call object to original state for re-use.
|
||
|
||
Arguments:
|
||
|
||
pCall - Specifies a pointer to the call object to be reset.
|
||
|
||
Return Values:
|
||
|
||
Returns true if successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
// reset state of call object
|
||
pCall->nState = H323_CALLSTATE_ALLOCATED;
|
||
|
||
// reset tapi info
|
||
pCall->dwCallState = LINECALLSTATE_UNKNOWN;
|
||
pCall->dwCallStateMode = 0;
|
||
pCall->dwOrigin = LINECALLORIGIN_UNKNOWN;
|
||
pCall->dwAddressType = 0;
|
||
pCall->dwIncomingModes = 0;
|
||
pCall->dwOutgoingModes = 0;
|
||
pCall->dwRequestedModes = 0;
|
||
pCall->fMonitoringDigits = FALSE;
|
||
|
||
pCall->dwAppSpecific = 0;
|
||
|
||
// reset tapi handles
|
||
pCall->hdCall = (HDRVCALL)NULL;
|
||
pCall->htCall = (HTAPICALL)NULL;
|
||
|
||
// reset intelcc handles
|
||
pCall->hccCall = UNINITIALIZED;
|
||
pCall->hccConf = UNINITIALIZED;
|
||
|
||
// reset link speeds
|
||
pCall->dwLinkSpeed = UNINITIALIZED;
|
||
|
||
// reset addresses
|
||
memset(&pCall->ccCalleeAddr,0,sizeof(CC_ADDR));
|
||
memset(&pCall->ccCallerAddr,0,sizeof(CC_ADDR));
|
||
|
||
// release alias strings
|
||
H323HeapFree(pCall->ccCalleeAlias.pData);
|
||
H323HeapFree(pCall->ccCallerAlias.pData);
|
||
|
||
// reset aliases
|
||
memset(&pCall->ccCalleeAlias,0,sizeof(CC_ALIASITEM));
|
||
memset(&pCall->ccCallerAlias,0,sizeof(CC_ALIASITEM));
|
||
|
||
// reset remote caps
|
||
memset(&pCall->ccRemoteAudioCaps,0,sizeof(CC_TERMCAP));
|
||
memset(&pCall->ccRemoteVideoCaps,0,sizeof(CC_TERMCAP));
|
||
|
||
// release user user information
|
||
H323FreeU2U(&pCall->IncomingU2U);
|
||
H323FreeU2U(&pCall->OutgoingU2U);
|
||
|
||
// success
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
BOOL
|
||
H323AllocCall(
|
||
PH323_CALL * ppCall
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Allocates call object and channel table.
|
||
|
||
Arguments:
|
||
|
||
ppCall - Specifies a pointer to a DWORD-sized value which the service
|
||
provider fills in with the newly allocated call object.
|
||
|
||
Return Values:
|
||
|
||
Returns true if successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
HRESULT hr;
|
||
PH323_CALL pCall;
|
||
|
||
// allocate call from heap
|
||
pCall = H323HeapAlloc(sizeof(H323_CALL));
|
||
|
||
// validate pointer
|
||
if (pCall == NULL) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"could not allocate call object.\n"
|
||
));
|
||
|
||
// failure
|
||
return FALSE;
|
||
}
|
||
|
||
// allocate default channel objects
|
||
if (!H323AllocChannelTable(&pCall->pChannelTable)) {
|
||
|
||
// release call
|
||
H323HeapFree(pCall);
|
||
|
||
// failure
|
||
return FALSE;
|
||
}
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_VERBOSE,
|
||
"call 0x%08lx allocated.\n",
|
||
pCall
|
||
));
|
||
|
||
// initialize user user information
|
||
InitializeListHead(&pCall->IncomingU2U);
|
||
InitializeListHead(&pCall->OutgoingU2U);
|
||
|
||
// reset call object
|
||
H323ResetCall(pCall);
|
||
|
||
// transfer
|
||
*ppCall = pCall;
|
||
|
||
// success
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
BOOL
|
||
H323FreeCall(
|
||
PH323_CALL pCall
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Deallocates call object and channel table.
|
||
|
||
Arguments:
|
||
|
||
pCall - Specifies a pointer to the call object to release.
|
||
|
||
Return Values:
|
||
|
||
Returns true if successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
// validate pointer
|
||
if (pCall != NULL) {
|
||
|
||
// release memory for channel table
|
||
H323FreeChannelTable(pCall->pChannelTable);
|
||
|
||
// reset call
|
||
H323ResetCall(pCall);
|
||
|
||
// release call
|
||
H323HeapFree(pCall);
|
||
}
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_VERBOSE,
|
||
"call 0x%08lx released.\n",
|
||
pCall
|
||
));
|
||
|
||
// success
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
DWORD
|
||
H323DetermineLinkSpeed(
|
||
DWORD dwHostAddr
|
||
)
|
||
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Determines speed of specified link.
|
||
|
||
Arguments:
|
||
|
||
dwHostAddr - interface address given in host order.
|
||
|
||
Return Values:
|
||
|
||
Returns link speed (defaults to 28.8kbps).
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
#define DEFAULT_IPADDRROW 10
|
||
#define DEFAULT_LINKSPEED (MAXIMUM_BITRATE_28800 * 100)
|
||
|
||
DWORD dwSize;
|
||
DWORD dwIndex;
|
||
DWORD dwStatus;
|
||
DWORD dwIPAddr;
|
||
DWORD dwIfIndex = UNINITIALIZED;
|
||
PMIB_IPADDRTABLE pIPAddrTable = NULL;
|
||
MIB_IFROW IfRow;
|
||
|
||
// convert to network order
|
||
dwIPAddr = htonl(dwHostAddr);
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_VERBOSE,
|
||
"determining link speed for %s\n",
|
||
H323AddrToString(dwIPAddr)
|
||
));
|
||
|
||
// default to reasonable size
|
||
dwSize = sizeof(MIB_IPADDRTABLE) +
|
||
sizeof(MIB_IPADDRROW) * DEFAULT_IPADDRROW
|
||
;
|
||
|
||
do {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_VERBOSE,
|
||
"allocating IP address table (%d bytes)\n",
|
||
dwSize
|
||
));
|
||
|
||
// release buffer
|
||
H323HeapFree(pIPAddrTable);
|
||
|
||
// allocate default table
|
||
pIPAddrTable = H323HeapAlloc(dwSize);
|
||
|
||
// validate pointer
|
||
if (pIPAddrTable == NULL) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"could not allocate IP address table\n"
|
||
));
|
||
|
||
// failure
|
||
return DEFAULT_LINKSPEED;
|
||
}
|
||
|
||
// attempt to get table
|
||
dwStatus = GetIpAddrTable(
|
||
pIPAddrTable,
|
||
&dwSize,
|
||
FALSE // sort table
|
||
);
|
||
|
||
} while (dwStatus == ERROR_INSUFFICIENT_BUFFER);
|
||
|
||
// validate status
|
||
if (dwStatus != NOERROR) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"error 0x%08lx calling GetIpAddrTable\n",
|
||
dwStatus
|
||
));
|
||
|
||
// release buffer
|
||
H323HeapFree(pIPAddrTable);
|
||
|
||
// failure
|
||
return DEFAULT_LINKSPEED;
|
||
}
|
||
|
||
// find the correct row in the table
|
||
for (dwIndex = 0; dwIndex < pIPAddrTable->dwNumEntries; dwIndex++) {
|
||
|
||
// compare given address to interface address
|
||
if (dwIPAddr == pIPAddrTable->table[dwIndex].dwAddr) {
|
||
|
||
// save index into interface table
|
||
dwIfIndex = pIPAddrTable->table[dwIndex].dwIndex;
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_TRACE,
|
||
"address %s maps to interface %d\n",
|
||
H323AddrToString(dwIPAddr),
|
||
dwIfIndex
|
||
));
|
||
|
||
// done
|
||
break;
|
||
}
|
||
}
|
||
|
||
// release buffer
|
||
H323HeapFree(pIPAddrTable);
|
||
|
||
// validate row pointer
|
||
if (dwIfIndex == UNINITIALIZED) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"could not locate %s in IP address table\n",
|
||
H323AddrToString(dwIPAddr)
|
||
));
|
||
|
||
// failure
|
||
return DEFAULT_LINKSPEED;
|
||
}
|
||
|
||
// initialize structure
|
||
memset(&IfRow,0,sizeof(IfRow));
|
||
|
||
// set interface index
|
||
IfRow.dwIndex = dwIfIndex;
|
||
|
||
// retrieve interface info
|
||
dwStatus = GetIfEntry(&IfRow);
|
||
|
||
// validate status
|
||
if (dwStatus != NOERROR) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"error 0x%08lx calling GetIfEntry(%d)\n",
|
||
dwStatus,
|
||
dwIfIndex
|
||
));
|
||
|
||
// failure
|
||
return DEFAULT_LINKSPEED;
|
||
}
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_TRACE,
|
||
"interface %d has link speed of %d bps\n",
|
||
dwIfIndex,
|
||
IfRow.dwSpeed
|
||
));
|
||
|
||
// return link speed
|
||
return IfRow.dwSpeed;
|
||
}
|
||
|
||
|
||
BOOL
|
||
H323ResolveCallerAddress(
|
||
PH323_CALL pCall
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Resolves caller address from callee address.
|
||
|
||
Arguments:
|
||
|
||
pCall - Specifies a pointer to the call object of interest.
|
||
|
||
Return Values:
|
||
|
||
Returns true if successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
INT nStatus;
|
||
SOCKET hCtrlSocket;
|
||
SOCKADDR CalleeSockAddr;
|
||
SOCKADDR CallerSockAddr;
|
||
DWORD dwNumBytesReturned = 0;
|
||
|
||
// allocate control socket
|
||
hCtrlSocket = WSASocket(
|
||
AF_INET, // af
|
||
SOCK_DGRAM, // type
|
||
IPPROTO_IP, // protocol
|
||
NULL, // lpProtocolInfo
|
||
0, // g
|
||
WSA_FLAG_OVERLAPPED // dwFlags
|
||
);
|
||
|
||
// validate control socket
|
||
if (hCtrlSocket == INVALID_SOCKET) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"error %d creating control socket.\n",
|
||
WSAGetLastError()
|
||
));
|
||
|
||
// failure
|
||
return FALSE;
|
||
}
|
||
|
||
// initialize ioctl parameters
|
||
memset(&CalleeSockAddr,0,sizeof(SOCKADDR));
|
||
memset(&CallerSockAddr,0,sizeof(SOCKADDR));
|
||
|
||
// initialize address family
|
||
CalleeSockAddr.sa_family = AF_INET;
|
||
|
||
// transfer callee information
|
||
((SOCKADDR_IN*)&CalleeSockAddr)->sin_addr.s_addr =
|
||
htonl(pCall->ccCalleeAddr.Addr.IP_Binary.dwAddr);
|
||
|
||
// query stack
|
||
nStatus = WSAIoctl(
|
||
hCtrlSocket,
|
||
SIO_ROUTING_INTERFACE_QUERY,
|
||
&CalleeSockAddr,
|
||
sizeof(SOCKADDR),
|
||
&CallerSockAddr,
|
||
sizeof(SOCKADDR),
|
||
&dwNumBytesReturned,
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
// release handle
|
||
closesocket(hCtrlSocket);
|
||
|
||
// validate return code
|
||
if (nStatus == SOCKET_ERROR) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"error 0x%08lx calling SIO_ROUTING_INTERFACE_QUERY.\n",
|
||
WSAGetLastError()
|
||
));
|
||
|
||
// failure
|
||
return FALSE;
|
||
}
|
||
|
||
// save interface address of best route
|
||
pCall->ccCallerAddr.nAddrType = CC_IP_BINARY;
|
||
pCall->ccCallerAddr.Addr.IP_Binary.dwAddr =
|
||
ntohl(((SOCKADDR_IN*)&CallerSockAddr)->sin_addr.s_addr);
|
||
pCall->ccCallerAddr.Addr.IP_Binary.wPort =
|
||
LOWORD(g_RegistrySettings.dwQ931CallSignallingPort);
|
||
pCall->ccCallerAddr.bMulticast =
|
||
IN_MULTICAST(pCall->ccCallerAddr.Addr.IP_Binary.dwAddr);
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_TRACE,
|
||
"caller address resolved to %s.\n",
|
||
H323AddrToString(((SOCKADDR_IN*)&CallerSockAddr)->sin_addr.s_addr)
|
||
));
|
||
|
||
// determine link speed for local interface
|
||
pCall->dwLinkSpeed = H323DetermineLinkSpeed(
|
||
pCall->ccCallerAddr.Addr.IP_Binary.dwAddr
|
||
);
|
||
|
||
// success
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
BOOL
|
||
H323ResolveE164Address(
|
||
PH323_CALL pCall,
|
||
LPCWSTR pwszDialableAddr
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Resolves E.164 address ("4259367111").
|
||
|
||
Arguments:
|
||
|
||
pCall - Specifies a pointer to the call object of interest.
|
||
|
||
pwszDialableAddr - Specifies a pointer to the dialable address specified
|
||
by the TAPI application.
|
||
|
||
Return Values:
|
||
|
||
Returns true if successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
WCHAR * pwszValidE164Chars;
|
||
WCHAR wszAddr[H323_MAXDESTNAMELEN+1];
|
||
|
||
DWORD dwE164AddrSize = 0;
|
||
WCHAR wszValidE164Chars[] = { CC_ALIAS_H323_PHONE_CHARS L"\0" };
|
||
|
||
// make sure pstn gateway has been specified
|
||
if ((g_RegistrySettings.fIsGatewayEnabled == FALSE) ||
|
||
(g_RegistrySettings.ccGatewayAddr.nAddrType == 0)) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"pstn gateway not specified.\n"
|
||
));
|
||
|
||
// failure
|
||
return FALSE;
|
||
}
|
||
|
||
// save gateway address as callee address
|
||
pCall->ccCalleeAddr = g_RegistrySettings.ccGatewayAddr;
|
||
|
||
// process until termination char
|
||
while (*pwszDialableAddr != L'\0') {
|
||
|
||
// reset pointer to valid characters
|
||
pwszValidE164Chars = wszValidE164Chars;
|
||
|
||
// process until termination char
|
||
while (*pwszValidE164Chars != L'\0') {
|
||
|
||
// see if valid E.164 character specified
|
||
if (*pwszDialableAddr == *pwszValidE164Chars) {
|
||
|
||
// save valid character in temp buffer
|
||
wszAddr[dwE164AddrSize++] = *pwszDialableAddr;
|
||
|
||
break;
|
||
}
|
||
|
||
// next valid char
|
||
++pwszValidE164Chars;
|
||
}
|
||
|
||
// next input char
|
||
++pwszDialableAddr;
|
||
}
|
||
|
||
// validate string
|
||
if (dwE164AddrSize == 0) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"no valid E.164 characters in string.\n"
|
||
));
|
||
|
||
// failure
|
||
return FALSE;
|
||
}
|
||
|
||
// terminate string
|
||
wszAddr[dwE164AddrSize++] = '\0';
|
||
|
||
// allocate callee alias from e164 address
|
||
pCall->ccCalleeAlias.pData = H323HeapAlloc(
|
||
dwE164AddrSize * sizeof(WCHAR)
|
||
);
|
||
|
||
// validate pointer
|
||
if (pCall->ccCalleeAlias.pData == NULL) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"could not allocate E.164 number.\n"
|
||
));
|
||
|
||
// failure
|
||
return FALSE;
|
||
}
|
||
|
||
// transfer callee alias
|
||
memcpy(pCall->ccCalleeAlias.pData,
|
||
wszAddr,
|
||
dwE164AddrSize * sizeof(WCHAR)
|
||
);
|
||
|
||
// complete alias
|
||
pCall->ccCalleeAlias.wType = CC_ALIAS_H323_PHONE;
|
||
pCall->ccCalleeAlias.wPrefixLength = 0;
|
||
pCall->ccCalleeAlias.pPrefix = NULL;
|
||
pCall->ccCalleeAlias.wDataLength = LOWORD(dwE164AddrSize - 1);
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_TRACE,
|
||
"callee alias resolved to E.164 number %S.\n",
|
||
pCall->ccCalleeAlias.pData
|
||
));
|
||
|
||
// determine caller address
|
||
return H323ResolveCallerAddress(pCall);
|
||
}
|
||
|
||
|
||
BOOL
|
||
H323ResolveIPAddress(
|
||
PH323_CALL pCall,
|
||
LPSTR pszDialableAddr
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Resolves IP address ("172.31.255.231") or DNS entry ("DONRYAN1").
|
||
|
||
Arguments:
|
||
|
||
pCall - Specifies a pointer to the call object of interest.
|
||
|
||
pszDialableAddr - Specifies a pointer to the dialable address specified
|
||
by the TAPI application.
|
||
|
||
Return Values:
|
||
|
||
Returns true if successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD dwIPAddr;
|
||
struct hostent * pHost;
|
||
|
||
// attempt to convert ip address
|
||
dwIPAddr = inet_addr(pszDialableAddr);
|
||
|
||
// see if address converted
|
||
if (dwIPAddr == UNINITIALIZED) {
|
||
|
||
// attempt to lookup hostname
|
||
pHost = gethostbyname(pszDialableAddr);
|
||
|
||
// validate pointer
|
||
if (pHost != NULL) {
|
||
|
||
// retrieve host address from structure
|
||
dwIPAddr = *(unsigned long *)pHost->h_addr;
|
||
}
|
||
}
|
||
|
||
// see if address converted
|
||
if (dwIPAddr == UNINITIALIZED) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"error 0x%08lx resolving IP address.\n",
|
||
WSAGetLastError()
|
||
));
|
||
|
||
// failure
|
||
return FALSE;
|
||
}
|
||
|
||
// save converted address
|
||
pCall->ccCalleeAddr.nAddrType = CC_IP_BINARY;
|
||
pCall->ccCalleeAddr.Addr.IP_Binary.dwAddr = ntohl(dwIPAddr);
|
||
pCall->ccCalleeAddr.Addr.IP_Binary.wPort =
|
||
LOWORD(g_RegistrySettings.dwQ931CallSignallingPort);
|
||
pCall->ccCalleeAddr.bMulticast =
|
||
IN_MULTICAST(pCall->ccCalleeAddr.Addr.IP_Binary.dwAddr);
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_TRACE,
|
||
"callee address resolved to %s:%d.\n",
|
||
H323AddrToString(dwIPAddr),
|
||
pCall->ccCalleeAddr.Addr.IP_Binary.wPort
|
||
));
|
||
|
||
// determine caller address
|
||
return H323ResolveCallerAddress(pCall);
|
||
}
|
||
|
||
|
||
BOOL
|
||
H323ResolveEmailAddress(
|
||
PH323_CALL pCall,
|
||
LPCWSTR pwszDialableAddr,
|
||
LPSTR pszUser,
|
||
LPSTR pszDomain
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Resolves e-mail address ("donryan@microsoft.com").
|
||
|
||
Arguments:
|
||
|
||
pCall - Specifies a pointer to the call object of interest.
|
||
|
||
pwszDialableAddr - Specifies a pointer to the dialable address specified
|
||
by the TAPI application.
|
||
|
||
pszUser - Specifies a pointer to the user component of e-mail name.
|
||
|
||
pszDomain - Specified a pointer to the domain component of e-mail name.
|
||
|
||
Return Values:
|
||
|
||
Returns true if successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD dwAddrSize;
|
||
|
||
// attempt to resolve domain locally
|
||
if (H323ResolveIPAddress(pCall, pszDomain)) {
|
||
|
||
// success
|
||
return TRUE;
|
||
}
|
||
|
||
// make sure proxy has been specified
|
||
if ((g_RegistrySettings.fIsProxyEnabled == FALSE) ||
|
||
(g_RegistrySettings.ccProxyAddr.nAddrType == 0)) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"proxy not specified.\n"
|
||
));
|
||
|
||
// failure
|
||
return FALSE;
|
||
}
|
||
|
||
// save proxy address as callee address
|
||
pCall->ccCalleeAddr = g_RegistrySettings.ccProxyAddr;
|
||
|
||
// size destination address string
|
||
dwAddrSize = wcslen(pwszDialableAddr) + 1;
|
||
|
||
// allocate callee alias from e164 address
|
||
pCall->ccCalleeAlias.pData = H323HeapAlloc(
|
||
dwAddrSize * sizeof(WCHAR)
|
||
);
|
||
|
||
// validate pointer
|
||
if (pCall->ccCalleeAlias.pData == NULL) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"could not allocate H.323 alias.\n"
|
||
));
|
||
|
||
// failure
|
||
return FALSE;
|
||
}
|
||
|
||
// transfer callee alias
|
||
memcpy(pCall->ccCalleeAlias.pData,
|
||
pwszDialableAddr,
|
||
dwAddrSize * sizeof(WCHAR)
|
||
);
|
||
|
||
// complete alias
|
||
pCall->ccCalleeAlias.wType = CC_ALIAS_H323_ID;
|
||
pCall->ccCalleeAlias.wPrefixLength = 0;
|
||
pCall->ccCalleeAlias.pPrefix = NULL;
|
||
pCall->ccCalleeAlias.wDataLength = LOWORD(dwAddrSize - 1);
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_TRACE,
|
||
"callee alias resolved to H.323 alias %S.\n",
|
||
pCall->ccCalleeAlias.pData
|
||
));
|
||
|
||
// determine caller address
|
||
return H323ResolveCallerAddress(pCall);
|
||
}
|
||
|
||
|
||
BOOL
|
||
H323ResolveAddress(
|
||
PH323_CALL pCall,
|
||
LPCWSTR pwszDialableAddr
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Resolves remote address and determines the correct local address
|
||
to use in order to reach remote address.
|
||
|
||
Arguments:
|
||
|
||
pCall - Specifies a pointer to the call object of interest.
|
||
|
||
pwszDialableAddr - Specifies a pointer to the dialable address specified
|
||
by the TAPI application.
|
||
|
||
Return Values:
|
||
|
||
Returns true if successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD dwIPAddr;
|
||
CHAR szDelimiters[] = "@ \t\n";
|
||
CHAR szAddr[H323_MAXDESTNAMELEN+1];
|
||
LPSTR pszUser = NULL;
|
||
LPSTR pszDomain = NULL;
|
||
|
||
// validate pointerr
|
||
if (pwszDialableAddr == NULL) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"null destination address.\n"
|
||
));
|
||
|
||
// failure
|
||
return FALSE;
|
||
}
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_TRACE,
|
||
"resolving %s %S.\n",
|
||
H323AddressTypeToString(pCall->dwAddressType),
|
||
pwszDialableAddr
|
||
));
|
||
|
||
// check whether phone number has been specified
|
||
if (pCall->dwAddressType == LINEADDRESSTYPE_PHONENUMBER) {
|
||
|
||
// need to direct call to pstn gateway
|
||
return H323ResolveE164Address(pCall, pwszDialableAddr);
|
||
}
|
||
|
||
// convert address from unicode
|
||
if (WideCharToMultiByte(
|
||
CP_ACP,
|
||
0,
|
||
pwszDialableAddr,
|
||
-1,
|
||
szAddr,
|
||
sizeof(szAddr),
|
||
NULL,
|
||
NULL
|
||
) == 0) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"could not convert address from unicode.\n"
|
||
));
|
||
|
||
// failure
|
||
return FALSE;
|
||
}
|
||
|
||
// parse user name
|
||
pszUser = strtok(szAddr, szDelimiters);
|
||
|
||
// parse domain name
|
||
pszDomain = strtok(NULL, szDelimiters);
|
||
|
||
// validate pointer
|
||
if (pszUser == NULL) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"could not parse destination address.\n"
|
||
));
|
||
|
||
// failure
|
||
return FALSE;
|
||
}
|
||
|
||
// validate pointer
|
||
if (pszDomain == NULL) {
|
||
|
||
// switch pointers
|
||
pszDomain = pszUser;
|
||
|
||
// re-initialize
|
||
pszUser = NULL;
|
||
}
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_VERBOSE,
|
||
"resolving user %s domain %s.\n",
|
||
pszUser,
|
||
pszDomain
|
||
));
|
||
|
||
// process e-mail and domain names
|
||
return H323ResolveEmailAddress(
|
||
pCall,
|
||
pwszDialableAddr,
|
||
pszUser,
|
||
pszDomain
|
||
);
|
||
}
|
||
|
||
|
||
BOOL
|
||
H323ValidateCallParams(
|
||
PH323_CALL pCall,
|
||
LPLINECALLPARAMS pCallParams,
|
||
LPCWSTR pwszDialableAddr,
|
||
PDWORD pdwStatus
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Validate optional call parameters specified by user.
|
||
|
||
Arguments:
|
||
|
||
pCall - Pointer to call object of interest.
|
||
|
||
pCallParams - Pointer to specified call parameters to be
|
||
validated.
|
||
|
||
pwszDialableAddr - Pointer to the dialable address specified
|
||
by the TAPI application.
|
||
|
||
pdwStatus - Pointer to DWORD containing error code if this
|
||
routine fails for any reason.
|
||
|
||
Return Values:
|
||
|
||
Returns true if successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD dwMediaModes = H323_LINE_DEFMEDIAMODES;
|
||
|
||
// validate pointer
|
||
if (pCallParams != NULL) {
|
||
|
||
// retrieve media modes specified
|
||
dwMediaModes = pCallParams->dwMediaMode;
|
||
|
||
// retrieve address type specified
|
||
pCall->dwAddressType = pCallParams->dwAddressType;
|
||
|
||
// see if we support call parameters
|
||
if (pCallParams->dwCallParamFlags != 0) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"do not support call parameters 0x%08lx.\n",
|
||
pCallParams->dwCallParamFlags
|
||
));
|
||
|
||
// do not support param flags
|
||
*pdwStatus = LINEERR_INVALCALLPARAMS;
|
||
|
||
// failure
|
||
return FALSE;
|
||
}
|
||
|
||
// see if unknown bit is specified
|
||
if (dwMediaModes & LINEMEDIAMODE_UNKNOWN) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_VERBOSE,
|
||
"clearing unknown media mode.\n"
|
||
));
|
||
|
||
// clear unknown bit from modes
|
||
dwMediaModes &= ~LINEMEDIAMODE_UNKNOWN;
|
||
}
|
||
|
||
// see if both audio bits are specified
|
||
if ((dwMediaModes & LINEMEDIAMODE_AUTOMATEDVOICE) &&
|
||
(dwMediaModes & LINEMEDIAMODE_INTERACTIVEVOICE)) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_VERBOSE,
|
||
"clearing automated voice media mode.\n"
|
||
));
|
||
|
||
// clear extra audio bit from modes
|
||
dwMediaModes &= ~LINEMEDIAMODE_INTERACTIVEVOICE;
|
||
}
|
||
|
||
// see if we support media modes specified
|
||
if (dwMediaModes & ~H323_LINE_MEDIAMODES) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"do not support media modes 0x%08lx.\n",
|
||
pCallParams->dwMediaMode
|
||
));
|
||
|
||
// do not support media mode
|
||
*pdwStatus = LINEERR_INVALMEDIAMODE;
|
||
|
||
// failure
|
||
return FALSE;
|
||
}
|
||
|
||
// see if we support bearer modes
|
||
if (pCallParams->dwBearerMode & ~H323_LINE_BEARERMODES) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"do not support bearer mode 0x%08lx.\n",
|
||
pCallParams->dwBearerMode
|
||
));
|
||
|
||
// do not support bearer mode
|
||
*pdwStatus = LINEERR_INVALBEARERMODE;
|
||
|
||
// failure
|
||
return FALSE;
|
||
}
|
||
|
||
// see if we support address modes
|
||
if (pCallParams->dwAddressMode & ~H323_LINE_ADDRESSMODES) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"do not support address mode 0x%08lx.\n",
|
||
pCallParams->dwAddressMode
|
||
));
|
||
|
||
// do not support address mode
|
||
*pdwStatus = LINEERR_INVALADDRESSMODE;
|
||
|
||
// failure
|
||
return FALSE;
|
||
}
|
||
|
||
// validate address id specified
|
||
if (!H323IsValidAddressID(pCallParams->dwAddressID)) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"address id 0x%08lx invalid.\n",
|
||
pCallParams->dwAddressID
|
||
));
|
||
|
||
// invalid address id
|
||
*pdwStatus = LINEERR_INVALADDRESSID;
|
||
|
||
// failure
|
||
return FALSE;
|
||
}
|
||
|
||
// validate destination address type specified
|
||
if (pCall->dwAddressType & ~H323_LINE_ADDRESSTYPES) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"address type 0x%08lx invalid.\n",
|
||
pCallParams->dwAddressType
|
||
));
|
||
|
||
// invalid address type
|
||
*pdwStatus = LINEERR_INVALADDRESSTYPE;
|
||
|
||
// failure
|
||
return FALSE;
|
||
}
|
||
|
||
// see if callee alias specified
|
||
if ((pCallParams->dwCalledPartySize > 0) &&
|
||
(pCall->dwAddressType != LINEADDRESSTYPE_PHONENUMBER)) {
|
||
|
||
// allocate memory for callee string
|
||
pCall->ccCalleeAlias.pData = H323HeapAlloc(
|
||
pCallParams->dwCalledPartySize
|
||
);
|
||
|
||
// validate pointer
|
||
if (pCall->ccCalleeAlias.pData == NULL) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"could not allocate callee name.\n"
|
||
));
|
||
|
||
// no memory available
|
||
*pdwStatus = LINEERR_NOMEM;
|
||
|
||
// failure
|
||
return FALSE;
|
||
}
|
||
|
||
// transfer memory
|
||
memcpy(pCall->ccCalleeAlias.pData,
|
||
(LPBYTE)pCallParams +
|
||
pCallParams->dwCalledPartyOffset,
|
||
pCallParams->dwCalledPartySize
|
||
);
|
||
|
||
// complete alias
|
||
pCall->ccCalleeAlias.wType = CC_ALIAS_H323_ID;
|
||
pCall->ccCalleeAlias.wPrefixLength = 0;
|
||
pCall->ccCalleeAlias.pPrefix = NULL;
|
||
pCall->ccCalleeAlias.wDataLength =
|
||
(WORD)wcslen(pCall->ccCalleeAlias.pData);
|
||
}
|
||
|
||
// see if caller name specified
|
||
if (pCallParams->dwCallingPartyIDSize > 0) {
|
||
|
||
// allocate memory for callee string
|
||
pCall->ccCallerAlias.pData = H323HeapAlloc(
|
||
pCallParams->dwCallingPartyIDSize
|
||
);
|
||
|
||
// validate pointer
|
||
if (pCall->ccCallerAlias.pData == NULL) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"could not allocate caller name.\n"
|
||
));
|
||
|
||
// no memory available
|
||
*pdwStatus = LINEERR_NOMEM;
|
||
|
||
// failure
|
||
return FALSE;
|
||
}
|
||
|
||
// transfer memory
|
||
memcpy(pCall->ccCallerAlias.pData,
|
||
(LPBYTE)pCallParams +
|
||
pCallParams->dwCallingPartyIDOffset,
|
||
pCallParams->dwCallingPartyIDSize
|
||
);
|
||
|
||
// complete alias
|
||
pCall->ccCallerAlias.wType = CC_ALIAS_H323_ID;
|
||
pCall->ccCallerAlias.wPrefixLength = 0;
|
||
pCall->ccCallerAlias.pPrefix = NULL;
|
||
pCall->ccCallerAlias.wDataLength =
|
||
(WORD)wcslen(pCall->ccCallerAlias.pData);
|
||
}
|
||
|
||
// check for user user information
|
||
if (pCallParams->dwUserUserInfoSize > 0) {
|
||
|
||
// save user user info
|
||
if (!H323AddU2U(
|
||
&pCall->OutgoingU2U,
|
||
pCallParams->dwUserUserInfoSize,
|
||
(LPBYTE)pCallParams +
|
||
pCallParams->dwUserUserInfoOffset
|
||
)) {
|
||
|
||
// invalid address id
|
||
*pdwStatus = LINEERR_NOMEM;
|
||
|
||
// failure
|
||
return FALSE;
|
||
}
|
||
}
|
||
}
|
||
|
||
// clear incoming modes
|
||
pCall->dwIncomingModes = 0;
|
||
|
||
// outgoing modes will be finalized during H.245 stage
|
||
pCall->dwOutgoingModes = dwMediaModes | LINEMEDIAMODE_UNKNOWN;
|
||
|
||
// save media modes specified
|
||
pCall->dwRequestedModes = dwMediaModes;
|
||
|
||
// resolve dialable into local and remote address
|
||
if (!H323ResolveAddress(pCall, pwszDialableAddr)) {
|
||
|
||
// invalid destination addr
|
||
*pdwStatus = LINEERR_INVALADDRESS;
|
||
|
||
// failure
|
||
return FALSE;
|
||
}
|
||
|
||
// success
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
// //
|
||
// Public procedures //
|
||
// //
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
|
||
BOOL
|
||
H323BindCall(
|
||
PH323_CALL pCall,
|
||
PCC_CONFERENCEID pConferenceID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Associates call object with the specified conference id.
|
||
|
||
Arguments:
|
||
|
||
pCall - Specifies a pointer to the call object to bind.
|
||
|
||
pConferenceID - Pointer to conference id to be associated with call object.
|
||
|
||
Return Values:
|
||
|
||
Returns true if successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
HRESULT hr;
|
||
CC_TERMCAPLIST TermCapList;
|
||
CC_TERMCAPDESCRIPTORS TermCapDescriptors;
|
||
|
||
// determine term caps from link speed
|
||
H323GetTermCapList(pCall,&TermCapList,&TermCapDescriptors);
|
||
|
||
// create conference
|
||
hr = CC_CreateConference(
|
||
&pCall->hccConf, // phConference
|
||
pConferenceID, // pConferenceID
|
||
0, // dwConferenceConfiguration
|
||
&TermCapList, // pTermCapList
|
||
&TermCapDescriptors, // pTermCapDescriptors
|
||
&g_VendorInfo, // pVendorInfo
|
||
NULL, // pTerminalID
|
||
PtrToUlong(pCall->hdCall), // dwConferenceToken
|
||
NULL, // TermCapConstructor
|
||
NULL, // SessionTableConstructor
|
||
H323ConferenceCallback // ConferenceCallback
|
||
);
|
||
|
||
// validate
|
||
if (hr != S_OK) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"error %s (0x%08lx) binding call 0x%08lx.\n",
|
||
H323StatusToString(hr), hr,
|
||
pCall
|
||
));
|
||
|
||
// failure
|
||
return FALSE;
|
||
}
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_VERBOSE,
|
||
"call 0x%08lx bound to conference 0x%08lx.\n",
|
||
pCall,
|
||
pCall->hccConf
|
||
));
|
||
|
||
// success
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
BOOL
|
||
H323UnbindCall(
|
||
PH323_CALL pCall
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Removes association between call object and conference object.
|
||
|
||
Arguments:
|
||
|
||
pCall - Specifies a pointer to the call object to unbind.
|
||
|
||
Return Values:
|
||
|
||
Returns true if successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
HRESULT hr;
|
||
|
||
// validate conference handle
|
||
if (pCall->hccConf != UNINITIALIZED) {
|
||
|
||
// destroy conference object used for call
|
||
hr = CC_DestroyConference(pCall->hccConf, FALSE);
|
||
|
||
// validate
|
||
if (hr != S_OK) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"error 0x%08lx destroying conference 0x%08lx.\n",
|
||
hr,
|
||
pCall->hccConf
|
||
));
|
||
|
||
// failure
|
||
return FALSE;
|
||
}
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_VERBOSE,
|
||
"call 0x%08lx unbound from conference 0x%08lx.\n",
|
||
pCall,
|
||
pCall->hccConf
|
||
));
|
||
|
||
// invalidate conference handle
|
||
pCall->hccConf = UNINITIALIZED;
|
||
}
|
||
|
||
// success
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
BOOL
|
||
H323PlaceCall(
|
||
PH323_CALL pCall
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Initiates outbound call to specified destination.
|
||
|
||
Arguments:
|
||
|
||
pCall - Specifies the pointer to the call object.
|
||
|
||
Return Values:
|
||
|
||
Returns true if successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
HRESULT hr;
|
||
CC_ALIASITEM LocalAlias;
|
||
CC_ALIASITEM CalleeAlias;
|
||
CC_ALIASNAMES LocalAliasNames;
|
||
CC_ALIASNAMES CalleeAliasNames;
|
||
PCC_ALIASNAMES pLocalAliasNames = NULL;
|
||
PCC_ALIASNAMES pCalleeAliasNames = NULL;
|
||
CC_NONSTANDARDDATA NonStandardData;
|
||
PCC_NONSTANDARDDATA pNonStandardData = NULL;
|
||
PH323_U2ULE pU2ULE = NULL;
|
||
PWSTR pwszDisplay = NULL;
|
||
|
||
// see if user user information specified
|
||
if (H323RemoveU2U(&pCall->OutgoingU2U,&pU2ULE)) {
|
||
|
||
// transfer header information
|
||
NonStandardData.bCountryCode = H221_COUNTRY_CODE_USA;
|
||
NonStandardData.bExtension = H221_COUNTRY_EXT_USA;
|
||
NonStandardData.wManufacturerCode = H221_MFG_CODE_MICROSOFT;
|
||
|
||
// initialize octet string containing data
|
||
NonStandardData.sData.wOctetStringLength = LOWORD(pU2ULE->dwU2USize);
|
||
NonStandardData.sData.pOctetString = pU2ULE->pU2U;
|
||
|
||
// point to stack based structure
|
||
pNonStandardData = &NonStandardData;
|
||
}
|
||
|
||
// see if caller alias specified
|
||
if (g_dwAliasLength > 0)
|
||
{
|
||
// send caller name as display
|
||
pwszDisplay = g_strAlias;
|
||
}
|
||
else if ((pCall->ccCallerAlias.wType == CC_ALIAS_H323_ID) ||
|
||
(pCall->ccCallerAlias.wType == CC_ALIAS_H323_PHONE)) {
|
||
|
||
// fill in local alias list
|
||
LocalAliasNames.wCount = 1;
|
||
LocalAliasNames.pItems = &pCall->ccCallerAlias;
|
||
|
||
// initialize pointer
|
||
pLocalAliasNames = &LocalAliasNames;
|
||
|
||
// send caller name as display
|
||
pwszDisplay = pCall->ccCallerAlias.pData;
|
||
}
|
||
|
||
// see if callee alias specified
|
||
if ((pCall->ccCalleeAlias.wType == CC_ALIAS_H323_ID) ||
|
||
(pCall->ccCalleeAlias.wType == CC_ALIAS_H323_PHONE)) {
|
||
|
||
// fill in callee alias list
|
||
CalleeAliasNames.wCount = 1;
|
||
CalleeAliasNames.pItems = &pCall->ccCalleeAlias;
|
||
|
||
// initialize pointer
|
||
pCalleeAliasNames = &CalleeAliasNames;
|
||
}
|
||
|
||
// place call
|
||
hr = CC_PlaceCall(
|
||
pCall->hccConf, // hConference
|
||
&pCall->hccCall, // phCall
|
||
pLocalAliasNames, // pLocalAliasNames
|
||
pCalleeAliasNames, // pCalleeAliasNames
|
||
NULL, // pExtraCalleeAliasNames
|
||
NULL, // pCalleeExtension
|
||
pNonStandardData, // pNonStandardData
|
||
pwszDisplay, // pwszDisplay
|
||
&pCall->ccCalleeAddr, // pDestinationAddr
|
||
NULL, // pConnectAddr
|
||
0, // dwBandwidth
|
||
PtrToUlong(pCall->hdCall) // dwUserToken
|
||
);
|
||
|
||
// validate
|
||
if (hr == S_OK) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_VERBOSE,
|
||
"call 0x%08lx placed.\n",
|
||
pCall
|
||
));
|
||
|
||
} else {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"error 0x%08lx calling CC_PlaceCall.\n", hr
|
||
));
|
||
}
|
||
|
||
// release memory
|
||
H323HeapFree(pU2ULE);
|
||
|
||
// return status
|
||
return (hr == S_OK);
|
||
}
|
||
|
||
|
||
BOOL
|
||
H323DropCall(
|
||
PH323_CALL pCall,
|
||
DWORD dwDisconnectMode
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Hangs up call (if necessary) and changes state to idle.
|
||
|
||
Arguments:
|
||
|
||
pCall - Specifies a pointer to the call object to drop.
|
||
|
||
dwDisconnectMode - Status code for disconnect.
|
||
|
||
Return Values:
|
||
|
||
Returns true if successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
HRESULT hr;
|
||
PH323_U2ULE pU2ULE = NULL;
|
||
CC_NONSTANDARDDATA NonStandardData;
|
||
PCC_NONSTANDARDDATA pNonStandardData = NULL;
|
||
|
||
// determine call state
|
||
switch (pCall->dwCallState) {
|
||
|
||
case LINECALLSTATE_CONNECTED:
|
||
|
||
// hangup call (this will invoke async indication)
|
||
hr = CC_Hangup(pCall->hccConf, FALSE, PtrToUlong(pCall->hdCall));
|
||
|
||
// validate
|
||
if (hr == CC_OK) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_VERBOSE,
|
||
"call 0x%08lx hung up.\n",
|
||
pCall
|
||
));
|
||
|
||
} else {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"error %s (0x%08lx) hanging up call 0x%08lx.\n",
|
||
H323StatusToString((DWORD)hr), hr,
|
||
pCall
|
||
));
|
||
}
|
||
|
||
// change call state to disconnected
|
||
H323ChangeCallState(pCall, LINECALLSTATE_DISCONNECTED, dwDisconnectMode);
|
||
|
||
break;
|
||
|
||
case LINECALLSTATE_OFFERING:
|
||
|
||
// see if user user information specified
|
||
if (H323RemoveU2U(&pCall->OutgoingU2U,&pU2ULE)) {
|
||
|
||
// transfer header information
|
||
NonStandardData.bCountryCode = H221_COUNTRY_CODE_USA;
|
||
NonStandardData.bExtension = H221_COUNTRY_EXT_USA;
|
||
NonStandardData.wManufacturerCode = H221_MFG_CODE_MICROSOFT;
|
||
|
||
// initialize octet string containing data
|
||
NonStandardData.sData.wOctetStringLength = LOWORD(pU2ULE->dwU2USize);
|
||
NonStandardData.sData.pOctetString = pU2ULE->pU2U;
|
||
|
||
// point to stack based structure
|
||
pNonStandardData = &NonStandardData;
|
||
}
|
||
|
||
// reject call
|
||
hr = CC_RejectCall(
|
||
CC_REJECT_DESTINATION_REJECTION,
|
||
pNonStandardData,
|
||
pCall->hccCall
|
||
);
|
||
|
||
// validate
|
||
if (hr == CC_OK) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_VERBOSE,
|
||
"call 0x%08lx rejected.\n",
|
||
pCall
|
||
));
|
||
|
||
} else {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"error %s (0x%08lx) reject call 0x%08lx.\n",
|
||
H323StatusToString((DWORD)hr), hr,
|
||
pCall
|
||
));
|
||
}
|
||
|
||
// release memory
|
||
H323HeapFree(pU2ULE);
|
||
|
||
// change call state to disconnected
|
||
H323ChangeCallState(pCall, LINECALLSTATE_DISCONNECTED, dwDisconnectMode);
|
||
|
||
break;
|
||
|
||
case LINECALLSTATE_DIALING:
|
||
case LINECALLSTATE_RINGBACK:
|
||
case LINECALLSTATE_ACCEPTED:
|
||
|
||
// cancel outbound call
|
||
hr = CC_CancelCall(pCall->hccCall);
|
||
|
||
// validate
|
||
if (hr == CC_OK) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_VERBOSE,
|
||
"call 0x%08lx cancelled.\n",
|
||
pCall
|
||
));
|
||
|
||
} else {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"error %s (0x%08lx) cancelling call 0x%08lx.\n",
|
||
H323StatusToString((DWORD)hr), hr,
|
||
pCall
|
||
));
|
||
}
|
||
|
||
// change call state to disconnected
|
||
H323ChangeCallState(pCall, LINECALLSTATE_DISCONNECTED, dwDisconnectMode);
|
||
|
||
break;
|
||
|
||
case LINECALLSTATE_DISCONNECTED:
|
||
|
||
//
|
||
// disconnected but still need to clean up
|
||
//
|
||
|
||
break;
|
||
|
||
case LINECALLSTATE_IDLE:
|
||
|
||
//
|
||
// call object already idle
|
||
//
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
// Tell the MSP to stop streaming.
|
||
H323CloseCallCommand(pCall);
|
||
|
||
// close logical channels
|
||
H323CloseChannelTable(pCall->pChannelTable);
|
||
|
||
// change call state to idle
|
||
H323ChangeCallState(pCall, LINECALLSTATE_IDLE, 0);
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_VERBOSE,
|
||
"call 0x%08lx dropped.\n",
|
||
pCall
|
||
));
|
||
|
||
// success
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
BOOL
|
||
H323CloseCall(
|
||
PH323_CALL pCall
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Hangs up call (if necessary) and closes call object.
|
||
|
||
Arguments:
|
||
|
||
pCall - Specifies a pointer to the call object to release.
|
||
|
||
Return Values:
|
||
|
||
Returns true if successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
// drop call using normal disconnect code
|
||
H323DropCall(pCall,LINEDISCONNECTMODE_NORMAL);
|
||
|
||
// unbind conference
|
||
H323UnbindCall(pCall);
|
||
|
||
// mark entry as allocated
|
||
H323FreeCallFromTable(pCall,pCall->pLine->pCallTable);
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_VERBOSE,
|
||
"call 0x%08lx closed.\n",
|
||
pCall
|
||
));
|
||
|
||
// success
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
BOOL
|
||
H323GetCallAndLock(
|
||
PH323_CALL * ppCall,
|
||
HDRVCALL hdCall
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Retrieves pointer to call object given call handle.
|
||
|
||
Arguments:
|
||
|
||
ppCall - Specifies a pointer to a DWORD-sized memory location
|
||
into which the service provider must write the call object pointer
|
||
associated with the given call handle.
|
||
|
||
hdCall - Specifies the Service Provider's opaque handle to the call.
|
||
|
||
Return Values:
|
||
|
||
Returns true if successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD i;
|
||
HDRVLINE hdLine;
|
||
PH323_LINE pLine = NULL;
|
||
PH323_CALL pCall = NULL;
|
||
|
||
// retrieve line handle from call
|
||
hdLine = H323GetLineHandle(PtrToUlong(hdCall));
|
||
|
||
// retrieve line pointer
|
||
if (!H323GetLineAndLock(&pLine, hdLine)) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"call handle 0x%08lx invalid line.\n",
|
||
PtrToUlong(hdCall)
|
||
));
|
||
|
||
// unlock line device
|
||
H323UnlockLine(pLine);
|
||
|
||
// failure
|
||
return FALSE;
|
||
}
|
||
|
||
// retrieve call table index
|
||
i = H323GetCallTableIndex(PtrToUlong(hdCall));
|
||
|
||
// validate call table index
|
||
if (i >= pLine->pCallTable->dwNumSlots) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"call handle 0x%08lx invalid index.\n",
|
||
PtrToUlong(hdCall)
|
||
));
|
||
|
||
// unlock line device
|
||
H323UnlockLine(pLine);
|
||
|
||
// failure
|
||
return FALSE;
|
||
}
|
||
|
||
// retrieve call pointer from table
|
||
pCall = pLine->pCallTable->pCalls[i];
|
||
|
||
// validate call information
|
||
if (!H323IsCallEqual(pCall,hdCall)) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"call handle 0x%08lx mismatch.\n",
|
||
PtrToUlong(hdCall)
|
||
));
|
||
|
||
// unlock line device
|
||
H323UnlockLine(pLine);
|
||
|
||
// failure
|
||
return FALSE;
|
||
}
|
||
|
||
// transfer
|
||
*ppCall = pCall;
|
||
|
||
// success
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
BOOL
|
||
H323GetCallByHCall(
|
||
PH323_CALL * ppCall,
|
||
struct _H323_LINE * pLine,
|
||
CC_HCALL hccCall
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Retrieves pointer to call object given callcont call handle.
|
||
|
||
Arguments:
|
||
|
||
ppCall - Specifies a pointer to a DWORD-sized memory location
|
||
into which the service provider must write the call object pointer
|
||
associated with the given call handle.
|
||
|
||
pLine - Specifies a pointer to associated line object.
|
||
|
||
hccCall - Specifies the call control module handle to the call.
|
||
|
||
Return Values:
|
||
|
||
Returns true if successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD i;
|
||
PH323_CALL_TABLE pCallTable = pLine->pCallTable;
|
||
|
||
// loop through each object in table
|
||
for (i = 0; i < pCallTable->dwNumSlots; i++) {
|
||
|
||
// validate object has been allocated
|
||
if (H323IsCallInUse(pCallTable->pCalls[i])) {
|
||
|
||
// check for given call control handle
|
||
if (pCallTable->pCalls[i]->hccCall == hccCall) {
|
||
|
||
// transfer pointer
|
||
*ppCall = pCallTable->pCalls[i];
|
||
|
||
// success
|
||
return TRUE;
|
||
}
|
||
}
|
||
}
|
||
|
||
// failure
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
BOOL
|
||
H323ChangeCallState(
|
||
PH323_CALL pCall,
|
||
DWORD dwCallState,
|
||
DWORD dwCallStateMode
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Reports call state of specified call object.
|
||
|
||
Arguments:
|
||
|
||
pCall - Specifies a pointer to call object.
|
||
|
||
dwCallState - Specifies new state of call object.
|
||
|
||
dwCallStateMode - Specifies new state mode of call object.
|
||
|
||
Return Values:
|
||
|
||
Returns true if successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
H323DBG((
|
||
DEBUG_LEVEL_VERBOSE,
|
||
"call 0x%08lx %s. state mode: 0x%08lx\n",
|
||
pCall,
|
||
H323CallStateToString(dwCallState),
|
||
dwCallStateMode
|
||
));
|
||
|
||
// save new call state
|
||
pCall->dwCallState = dwCallState;
|
||
pCall->dwCallStateMode = dwCallStateMode;
|
||
|
||
// report call status
|
||
(*g_pfnLineEventProc)(
|
||
pCall->pLine->htLine,
|
||
pCall->htCall,
|
||
LINE_CALLSTATE,
|
||
pCall->dwCallState,
|
||
pCall->dwCallStateMode,
|
||
pCall->dwIncomingModes | pCall->dwOutgoingModes
|
||
);
|
||
|
||
// success
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
BOOL
|
||
H323AllocCallTable(
|
||
PH323_CALL_TABLE * ppCallTable
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Allocates table of call objects.
|
||
|
||
Arguments:
|
||
|
||
ppCallTable - Pointer to DWORD-sized value which service
|
||
provider must fill in with newly allocated table.
|
||
|
||
Return Values:
|
||
|
||
Returns true if successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
PH323_CALL_TABLE pCallTable;
|
||
|
||
// allocate table from heap
|
||
pCallTable = H323HeapAlloc(
|
||
sizeof(H323_CALL_TABLE) +
|
||
sizeof(PH323_CALL) * H323_DEFCALLSPERLINE
|
||
);
|
||
|
||
// validate table pointer
|
||
if (pCallTable == NULL) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"could not allocate call table.\n"
|
||
));
|
||
|
||
// failure
|
||
return FALSE;
|
||
}
|
||
|
||
// initialize number of entries in table
|
||
pCallTable->dwNumSlots = H323_DEFCALLSPERLINE;
|
||
|
||
// transfer pointer to caller
|
||
*ppCallTable = pCallTable;
|
||
|
||
// success
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
BOOL
|
||
H323FreeCallTable(
|
||
PH323_CALL_TABLE pCallTable
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Deallocates table of call objects.
|
||
|
||
Arguments:
|
||
|
||
pCallTable - Pointer to call table to release.
|
||
|
||
Return Values:
|
||
|
||
Returns true if successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD i;
|
||
|
||
// loop through each object in table
|
||
for (i = 0; i < pCallTable->dwNumSlots; i++) {
|
||
|
||
// validate object has been allocated
|
||
if (H323IsCallAllocated(pCallTable->pCalls[i])) {
|
||
|
||
// release memory for object
|
||
H323FreeCall(pCallTable->pCalls[i]);
|
||
}
|
||
}
|
||
|
||
// release memory for table
|
||
H323HeapFree(pCallTable);
|
||
|
||
// success
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
BOOL
|
||
H323CloseCallTable(
|
||
PH323_CALL_TABLE pCallTable
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Closes table of call objects.
|
||
|
||
Arguments:
|
||
|
||
pCallTable - Pointer to table to close.
|
||
|
||
Return Values:
|
||
|
||
Returns true if successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD i;
|
||
|
||
// loop through each objectin table
|
||
for (i = 0; i < pCallTable->dwNumSlots; i++) {
|
||
|
||
// validate object is in use
|
||
if (H323IsCallInUse(pCallTable->pCalls[i])) {
|
||
|
||
// close previously opened object
|
||
H323PostCloseCallMessage(pCallTable->pCalls[i]->hdCall);
|
||
}
|
||
}
|
||
|
||
// success
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
BOOL
|
||
H323AllocCallFromTable(
|
||
PH323_CALL * ppCall,
|
||
PH323_CALL_TABLE * ppCallTable,
|
||
PH323_LINE pLine
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Allocates call object in table.
|
||
|
||
Arguments:
|
||
|
||
ppCall - Specifies a pointer to a DWORD-sized value in which the
|
||
service provider must write the allocated call object.
|
||
|
||
ppCallTable - Pointer to pointer to call table in which to
|
||
allocate call from (expands table if necessary).
|
||
|
||
pLine - Pointer to containing line object.
|
||
|
||
Return Values:
|
||
|
||
Returns true if successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD i;
|
||
PH323_CALL pCall = NULL;
|
||
PH323_CALL_TABLE pCallTable = *ppCallTable;
|
||
|
||
// retrieve index to next entry
|
||
i = pCallTable->dwNextAvailable;
|
||
|
||
// see if previously allocated entries available
|
||
if (pCallTable->dwNumAllocated > pCallTable->dwNumInUse) {
|
||
|
||
// search table looking for available entry
|
||
while (H323IsCallInUse(pCallTable->pCalls[i]) ||
|
||
!H323IsCallAllocated(pCallTable->pCalls[i])) {
|
||
|
||
// increment index and adjust to wrap
|
||
i = H323GetNextIndex(i, pCallTable->dwNumSlots);
|
||
}
|
||
|
||
// retrieve pointer to object
|
||
pCall = pCallTable->pCalls[i];
|
||
|
||
// mark entry as being in use
|
||
pCall->nState = H323_CALLSTATE_IN_USE;
|
||
|
||
// initialize call handle with index
|
||
pCall->hdCall = H323CreateCallHandle(PtrToUlong(pLine->hdLine),i);
|
||
|
||
// increment number in use
|
||
pCallTable->dwNumInUse++;
|
||
|
||
// adjust next available index
|
||
pCallTable->dwNextAvailable =
|
||
H323GetNextIndex(i, pCallTable->dwNumSlots);
|
||
|
||
// transfer pointer
|
||
*ppCall = pCall;
|
||
|
||
// success
|
||
return TRUE;
|
||
}
|
||
|
||
// see if table is full and more slots need to be allocated
|
||
if (pCallTable->dwNumAllocated == pCallTable->dwNumSlots) {
|
||
|
||
// attempt to double table
|
||
pCallTable = H323HeapReAlloc(
|
||
pCallTable,
|
||
sizeof(H323_CALL_TABLE) +
|
||
pCallTable->dwNumSlots * 2 * sizeof(PH323_CALL)
|
||
);
|
||
|
||
// validate pointer
|
||
if (pCallTable == NULL) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"could not expand channel table.\n"
|
||
));
|
||
|
||
// failure
|
||
return FALSE;
|
||
}
|
||
|
||
// adjust index into table
|
||
i = pCallTable->dwNumSlots;
|
||
|
||
// adjust number of slots
|
||
pCallTable->dwNumSlots *= 2;
|
||
|
||
// transfer pointer to caller
|
||
*ppCallTable = pCallTable;
|
||
}
|
||
|
||
// allocate new object
|
||
if (!H323AllocCall(&pCall)) {
|
||
|
||
// failure
|
||
return FALSE;
|
||
}
|
||
|
||
// search table looking for slot with no object allocated
|
||
while (H323IsCallAllocated(pCallTable->pCalls[i])) {
|
||
|
||
// increment index and adjust to wrap
|
||
i = H323GetNextIndex(i, pCallTable->dwNumSlots);
|
||
}
|
||
|
||
// store pointer to object
|
||
pCallTable->pCalls[i] = pCall;
|
||
|
||
// mark entry as being in use
|
||
pCall->nState = H323_CALLSTATE_IN_USE;
|
||
|
||
// initialize call handle with index
|
||
pCall->hdCall = H323CreateCallHandle(PtrToUlong(pLine->hdLine),i);
|
||
|
||
// increment number in use
|
||
pCallTable->dwNumInUse++;
|
||
|
||
// increment number allocated
|
||
pCallTable->dwNumAllocated++;
|
||
|
||
// adjust next available index
|
||
pCallTable->dwNextAvailable =
|
||
H323GetNextIndex(i, pCallTable->dwNumSlots);
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_VERBOSE,
|
||
"call 0x%08lx stored in slot %d (hdCall=0x%08lx).\n",
|
||
pCall, i,
|
||
pCall->hdCall
|
||
));
|
||
|
||
// transfer pointer
|
||
*ppCall = pCall;
|
||
|
||
// success
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
BOOL
|
||
H323FreeCallFromTable(
|
||
PH323_CALL pCall,
|
||
PH323_CALL_TABLE pCallTable
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Deallocates call object in table.
|
||
|
||
Arguments:
|
||
|
||
pCall - Pointer to object to deallocate.
|
||
|
||
pCallTable - Pointer to table containing object.
|
||
|
||
Return Values:
|
||
|
||
Returns true if successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
// reset call object
|
||
H323ResetCall(pCall);
|
||
|
||
// decrement entries in use
|
||
pCallTable->dwNumInUse--;
|
||
|
||
// success
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
BOOL
|
||
H323AcceptCall(
|
||
PH323_CALL pCall
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Accepts incoming call.
|
||
|
||
Arguments:
|
||
|
||
pCall - Pointer to object to accept.
|
||
|
||
Return Values:
|
||
|
||
Returns true if successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
HRESULT hr;
|
||
PH323_U2ULE pU2ULE = NULL;
|
||
CC_NONSTANDARDDATA NonStandardData;
|
||
PCC_NONSTANDARDDATA pNonStandardData = NULL;
|
||
PWSTR pwszDisplay = NULL;
|
||
|
||
// see if user user information specified
|
||
if (H323RemoveU2U(&pCall->OutgoingU2U,&pU2ULE)) {
|
||
|
||
// transfer header information
|
||
NonStandardData.bCountryCode = H221_COUNTRY_CODE_USA;
|
||
NonStandardData.bExtension = H221_COUNTRY_EXT_USA;
|
||
NonStandardData.wManufacturerCode = H221_MFG_CODE_MICROSOFT;
|
||
|
||
// initialize octet string containing data
|
||
NonStandardData.sData.wOctetStringLength = LOWORD(pU2ULE->dwU2USize);
|
||
NonStandardData.sData.pOctetString = pU2ULE->pU2U;
|
||
|
||
// point to stack based structure
|
||
pNonStandardData = &NonStandardData;
|
||
}
|
||
|
||
// see if callee alias specified
|
||
if (g_dwAliasLength > 0)
|
||
{
|
||
pwszDisplay = g_strAlias;
|
||
}
|
||
else if ((pCall->ccCalleeAlias.wType == CC_ALIAS_H323_ID) ||
|
||
(pCall->ccCalleeAlias.wType == CC_ALIAS_H323_PHONE)) {
|
||
|
||
// send caller name as display
|
||
pwszDisplay = pCall->ccCalleeAlias.pData;
|
||
}
|
||
|
||
// accept call
|
||
hr = CC_AcceptCall(
|
||
pCall->hccConf, // hConference
|
||
pNonStandardData, // pNonStandardData
|
||
pwszDisplay, // pwszDisplay
|
||
pCall->hccCall, // hCall
|
||
0, // dwBandwidth
|
||
PtrToUlong(pCall->hdCall) // dwUserToken
|
||
);
|
||
|
||
// validate status
|
||
if (hr != CC_OK) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"error %s (0x%08lx) answering call 0x%08lx.\n",
|
||
H323StatusToString((DWORD)hr), hr,
|
||
pCall
|
||
));
|
||
|
||
// release memory
|
||
H323HeapFree(pU2ULE);
|
||
|
||
// drop call using disconnect mode
|
||
H323DropCall(pCall, LINEDISCONNECTMODE_TEMPFAILURE);
|
||
|
||
// failure
|
||
return FALSE;
|
||
}
|
||
|
||
// release memory
|
||
H323HeapFree(pU2ULE);
|
||
|
||
// change call state to accepted from offering
|
||
H323ChangeCallState(pCall, LINECALLSTATE_ACCEPTED, 0);
|
||
|
||
// success
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
// //
|
||
// TSPI procedures //
|
||
// //
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
|
||
LONG
|
||
TSPIAPI
|
||
TSPI_lineAnswer(
|
||
DRV_REQUESTID dwRequestID,
|
||
HDRVCALL hdCall,
|
||
LPCSTR pUserUserInfo,
|
||
DWORD dwSize
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function answers the specified offering call.
|
||
|
||
When a new call arrives, the Service Provider sends the TAPI DLL a
|
||
LINE_NEWCALL event to exchange opaque handles for the call. The Service
|
||
Provider follows this with a LINE_CALLSTATE message inform the TAPI DLL
|
||
and its client applications of the call's call state. The TAPI DLL
|
||
typically answers this call (on behalf of an application) using
|
||
TSPI_lineAnswer. After the call has been successfully answered, the call
|
||
will typically transition to the connected state.
|
||
|
||
In some telephony environments (like ISDN) where user alerting is separate
|
||
from call offering, the TAPI DLL and its client apps may have the option to
|
||
first accept a call prior to answering, or instead to reject or redirect
|
||
the offering call.
|
||
|
||
If a call comes in (is offered) at the time another call is already active,
|
||
then the new call is connected to by invoking TSPI_lineAnswer. The effect
|
||
this has on the existing active call depends on the line's device
|
||
capabilities. The first call may be unaffected, it may automatically be
|
||
dropped, or it may automatically be placed on hold. The appropriate
|
||
LINE_CALLSTATE messages will report state transitions to the TAPI DLL about
|
||
both calls.
|
||
|
||
The TAPI DLL has the option to send user-to-user information at the time of
|
||
the answer. Even if user-to-user information can be sent, often no
|
||
guarantees are made that the network will deliver this information to the
|
||
calling party. The TAPI DLL can consult a line's device capabilities to
|
||
determine whether or not sending user-to-user information on answer is
|
||
available.
|
||
|
||
Arguments:
|
||
|
||
dwRequestID - Specifies the identifier of the asynchronous request.
|
||
The Service Provider returns this value if the function completes
|
||
asynchronously.
|
||
|
||
hdCall - Specifies the Service Provider's opaque handle to the call to be
|
||
answered. Valid call states: offering, accepted.
|
||
|
||
pUserUserInfo - Specifies a far pointer to a string containing
|
||
user-to-user information to be sent to the remote party at the time of
|
||
answering the call. If this pointer is NULL, it indicates that no
|
||
user-to-user information is to be sent. User-to-user information is
|
||
only sent if supported by the underlying network (see LINEDEVCAPS).
|
||
|
||
dwSize - Specifies the size in bytes of the user-to-user information in
|
||
pUserUserInfo. If pUserUserInfo is NULL, no user-to-user
|
||
information is sent to the calling party and dwSize is ignored.
|
||
|
||
Return Values:
|
||
|
||
Returns zero if the function is successful, the (positive) dwRequestID
|
||
value if the function will be completed asynchronously, or a negative
|
||
error number if an error has occurred. Possible error returns are:
|
||
|
||
LINEERR_INVALCALLHANDLE - The specified call handle is invalid.
|
||
|
||
LINEERR_INVALCALLSTATE - The call is not in a valid state for the
|
||
requested operation.
|
||
|
||
LINEERR_OPERATIONFAILED - The specified operation failed for
|
||
unspecified reason.
|
||
|
||
--*/
|
||
|
||
{
|
||
PH323_CALL pCall = NULL;
|
||
CC_NONSTANDARDDATA NonStandardData;
|
||
PCC_NONSTANDARDDATA pNonStandardData = NULL;
|
||
|
||
// retrieve call pointer from handle
|
||
if (!H323GetCallAndLock(&pCall, hdCall)) {
|
||
|
||
// invalid call handle
|
||
return LINEERR_INVALCALLHANDLE;
|
||
}
|
||
|
||
// see if call in offering state
|
||
if (!H323IsCallOffering(pCall)) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"call 0x%08lx cannot be accepted state 0x%08lx.\n",
|
||
pCall,
|
||
pCall->dwCallState
|
||
));
|
||
|
||
// release line device
|
||
H323UnlockLine(pCall->pLine);
|
||
|
||
// invalid call state
|
||
return LINEERR_INVALCALLSTATE;
|
||
}
|
||
|
||
// save outgoing user user information (if specified)
|
||
if (!H323AddU2U(&pCall->OutgoingU2U,dwSize,(PBYTE)pUserUserInfo)) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"could not save user user info.\n"
|
||
));
|
||
|
||
// release line device
|
||
H323UnlockLine(pCall->pLine);
|
||
|
||
// no memory available
|
||
return LINEERR_NOMEM;
|
||
}
|
||
|
||
// post place request to callback thread
|
||
if (!H323PostAcceptCallMessage(pCall->hdCall)) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"could not accept place call message.\n"
|
||
));
|
||
|
||
// drop call using disconnect mode
|
||
H323PostDropCallMessage(pCall->hdCall, LINEDISCONNECTMODE_TEMPFAILURE);
|
||
|
||
// release line device
|
||
H323UnlockLine(pCall->pLine);
|
||
|
||
// could not complete operation
|
||
return LINEERR_OPERATIONFAILED;
|
||
}
|
||
|
||
// complete the async accept operation now
|
||
(*g_pfnCompletionProc)(dwRequestID, NOERROR);
|
||
|
||
// release line device
|
||
H323UnlockLine(pCall->pLine);
|
||
|
||
// async success
|
||
return dwRequestID;
|
||
}
|
||
|
||
|
||
LONG
|
||
TSPIAPI
|
||
TSPI_lineCloseCall(
|
||
HDRVCALL hdCall
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function deletes the call after completing or aborting all outstanding
|
||
asynchronous operations on the call.
|
||
|
||
The Service Provider has the responsibility to (eventually) report
|
||
completion for every operation it decides to execute asynchronously.
|
||
If this procedure is called for a call on which there are outstanding
|
||
asynchronous operations, the operations should be reported complete with an
|
||
appropriate result or error code before this procedure returns. If there
|
||
is an active call on the line at the time of TSPI_lineCloseCall, the call
|
||
must be dropped. Generally the TAPI DLL would wait for calls to be
|
||
finished and asynchronous operations to complete in an orderly fashion.
|
||
However, the Service Provider should be prepared to handle an early call to
|
||
TSPI_lineCloseCall in "abort" or "emergency shutdown" situations.
|
||
|
||
After this procedure returns the Service Provider must report no further
|
||
events on the call. The Service Provider's opaque handle for the call
|
||
becomes "invalid".
|
||
|
||
This function is presumed to complete successfully and synchronously.
|
||
|
||
Arguments:
|
||
|
||
hdCall - Specifies the Service Provider's opaque handle to the call to be
|
||
deleted. After the call has been successfully deleted, this handle is
|
||
no longer valid. Valid call states: any.
|
||
|
||
Return Values:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PH323_CALL pCall = NULL;
|
||
|
||
// retrieve call pointer from handle
|
||
if (!H323GetCallAndLock(&pCall, hdCall)) {
|
||
|
||
// invalid call handle
|
||
return LINEERR_INVALCALLHANDLE;
|
||
}
|
||
|
||
// close call asynchronously
|
||
if (!H323PostCloseCallMessage(pCall->hdCall)) {
|
||
|
||
// could not close call
|
||
return LINEERR_OPERATIONFAILED;
|
||
}
|
||
|
||
// release line device
|
||
H323UnlockLine(pCall->pLine);
|
||
|
||
// success
|
||
return NOERROR;
|
||
}
|
||
|
||
|
||
LONG
|
||
TSPIAPI
|
||
TSPI_lineDrop(
|
||
DRV_REQUESTID dwRequestID,
|
||
HDRVCALL hdCall,
|
||
LPCSTR pUserUserInfo,
|
||
DWORD dwSize
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This functions drops or disconnects the specified call. The TAPI DLL has
|
||
the option to specify user-to-user information to be transmitted as part
|
||
of the call disconnect.
|
||
|
||
When invoking TSPI_lineDrop related calls may sometimes be affected as
|
||
well. For example, dropping a conference call may drop all individual
|
||
participating calls. LINE_CALLSTATE messages are sent to the TAPI DLL for
|
||
all calls whose call state is affected. A dropped call will typically
|
||
transition to the idle state.
|
||
|
||
Invoking TSPI_lineDrop on a call in the offering state rejects the call.
|
||
Not all telephone networks provide this capability.
|
||
|
||
Invoking TSPI_lineDrop on a consultation call that was set up using either
|
||
TSPI_lineSetupTransfer or TSPI_lineSetupConference, will cancel the
|
||
consultation call. Some switches automatically unhold the other call.
|
||
|
||
The TAPI DLL has the option to send user-to-user information at the time
|
||
of the drop. Even if user-to-user information can be sent, often no
|
||
guarantees are made that the network will deliver this information to the
|
||
remote party.
|
||
|
||
Note that in various bridged or party line configurations when multiple
|
||
parties are on the call, TSPI_lineDrop by the application may not actually
|
||
clear the call.
|
||
|
||
Arguments:
|
||
|
||
dwRequestID - Specifies the identifier of the asynchronous request.
|
||
The Service Provider returns this value if the function completes
|
||
asynchronously.
|
||
|
||
hdCall - Specifies the Service Provider's opaque handle to the call to
|
||
be dropped. Valid call states: any.
|
||
|
||
psUserUserInfo - Specifies a far pointer to a string containing
|
||
user-to-user information to be sent to the remote party as part of
|
||
the call disconnect. This pointer is unused if dwUserUserInfoSize
|
||
is zero and no user-to-user information is to be sent. User-to-user
|
||
information is only sent if supported by the underlying network
|
||
(see LINEDEVCAPS).
|
||
|
||
dwSize - Specifies the size in bytes of the user-to-user information in
|
||
psUserUserInfo. If zero, then psUserUserInfo can be left NULL, and
|
||
no user-to-user information will be sent to the remote party.
|
||
|
||
Return Values:
|
||
|
||
Returns zero if the function is successful, the (positive) dwRequestID
|
||
value if the function will be completed asynchronously, or a negative error
|
||
number if an error has occurred. Possible error returns are:
|
||
|
||
LINEERR_INVALCALLHANDLE - The specified call handle is invalid.
|
||
|
||
LINEERR_INVALPOINTER - The specified pointer parameter is invalid.
|
||
|
||
LINEERR_INVALCALLSTATE - The current state of the call does not allow
|
||
the call to be dropped.
|
||
|
||
LINEERR_OPERATIONUNAVAIL - The specified operation is not available.
|
||
|
||
LINEERR_OPERATIONFAILED - The specified operation failed for
|
||
unspecified reasons.
|
||
|
||
--*/
|
||
|
||
{
|
||
PH323_CALL pCall = NULL;
|
||
|
||
// retrieve call pointer from handle
|
||
if (!H323GetCallAndLock(&pCall, hdCall)) {
|
||
|
||
// invalid call handle
|
||
return LINEERR_INVALCALLHANDLE;
|
||
}
|
||
|
||
// save outgoing user user information (if specified)
|
||
if (!H323AddU2U(&pCall->OutgoingU2U,dwSize,(PBYTE)pUserUserInfo)) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"could not save user user info.\n"
|
||
));
|
||
|
||
// release line device
|
||
H323UnlockLine(pCall->pLine);
|
||
|
||
// no memory available
|
||
return LINEERR_NOMEM;
|
||
}
|
||
|
||
// drop specified call
|
||
if (!H323PostDropCallMessage(pCall->hdCall,LINEDISCONNECTMODE_NORMAL)) {
|
||
|
||
// release line device
|
||
H323UnlockLine(pCall->pLine);
|
||
|
||
// could not drop call
|
||
return LINEERR_OPERATIONFAILED;
|
||
}
|
||
|
||
// complete the async accept operation now
|
||
(*g_pfnCompletionProc)(dwRequestID, NOERROR);
|
||
|
||
// release line device
|
||
H323UnlockLine(pCall->pLine);
|
||
|
||
// async success
|
||
return dwRequestID;
|
||
}
|
||
|
||
|
||
LONG
|
||
TSPIAPI
|
||
TSPI_lineGetCallAddressID(
|
||
HDRVCALL hdCall,
|
||
LPDWORD pdwAddressID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This operation allows the TAPI DLL to retrieve the address ID for the
|
||
indicated call.
|
||
|
||
This operation must be executed synchronously by the Service Provider,
|
||
with presumed success. This operation may be called from within the
|
||
context of the ASYNC_LINE_COMPLETION or LINEEVENT callbacks (i.e., from
|
||
within an interrupt context). This function would typically be called
|
||
at the start of the call life cycle.
|
||
|
||
If the Service Provider models lines as "pools" of channel resources
|
||
and does "inverse multiplexing" of a call over several address IDs it
|
||
should consistently choose one of these address IDs as the primary
|
||
identifier reported by this function and in the LINE_CALLINFO data
|
||
structure.
|
||
|
||
Arguments:
|
||
|
||
hdCall - Specifies the Service Provider's opaque handle to the call
|
||
whose address ID is to be retrieved. Valid call states: any.
|
||
|
||
pdwAddressID - Specifies a far pointer to a DWORD into which the
|
||
Service Provider writes the call's address ID.
|
||
|
||
Return Values:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
// only one addr
|
||
*pdwAddressID = 0;
|
||
|
||
// success
|
||
return NOERROR;
|
||
}
|
||
|
||
|
||
LONG
|
||
TSPIAPI
|
||
TSPI_lineGetCallInfo(
|
||
HDRVCALL hdCall,
|
||
LPLINECALLINFO pCallInfo
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This operation enables the TAPI DLL to obtain fixed information about
|
||
the specified call.
|
||
|
||
A separate LINECALLINFO structure exists for every (inbound or outbound)
|
||
call. The structure contains primarily fixed information about the call.
|
||
An application would typically be interested in checking this information
|
||
when it receives its handle for a call via the LINE_CALLSTATE message, or
|
||
each time it receives notification via a LINE_CALLINFO message that parts
|
||
of the call information structure have changed. These messages supply the
|
||
handle for the call as a parameter.
|
||
|
||
If the Service Provider models lines as "pools" of channel resources and
|
||
does "inverse multiplexing" of a call over several address IDs it should
|
||
consistently choose one of these address IDs as the primary identifier
|
||
reported by this function in the LINE_CALLINFO data structure.
|
||
|
||
Arguments:
|
||
|
||
hdCall - Specifies the Service Provider's opaque handle to the call
|
||
whose call information is to be retrieved.
|
||
|
||
pCallInfo - Specifies a far pointer to a variable sized data structure
|
||
of type LINECALLINFO. Upon successful completion of the request, this
|
||
structure is filled with call related information.
|
||
|
||
Return Values:
|
||
|
||
Returns zero if the function is successful or a negative error
|
||
number if an error has occurred. Possible error returns are:
|
||
|
||
LINEERR_INVALCALLHANDLE - The specified call handle is invalid.
|
||
|
||
LINEERR_STRUCTURETOOSMALL - The dwTotalSize member of a structure does
|
||
not specify enough memory to contain the fixed portion of the
|
||
structure. The dwNeededSize field has been set to the amount
|
||
required.
|
||
|
||
--*/
|
||
|
||
{
|
||
PH323_CALL pCall = NULL;
|
||
DWORD dwCalleeNameSize = 0;
|
||
DWORD dwCallerNameSize = 0;
|
||
DWORD dwCallerNumberSize = 0;
|
||
DWORD dwNextOffset = sizeof(LINECALLINFO);
|
||
DWORD dwU2USize = 0;
|
||
WCHAR IPAddress[20];
|
||
PBYTE pU2U = NULL;
|
||
|
||
// retrieve call pointer from handle
|
||
if (!H323GetCallAndLock(&pCall, hdCall)) {
|
||
|
||
// invalid call handle
|
||
return LINEERR_INVALCALLHANDLE;
|
||
}
|
||
|
||
// see if user user info available
|
||
if (!IsListEmpty(&pCall->IncomingU2U)) {
|
||
|
||
PLIST_ENTRY pLE;
|
||
PH323_U2ULE pU2ULE;
|
||
|
||
// get first list entry
|
||
pLE = pCall->IncomingU2U.Flink;
|
||
|
||
// convert to user user structure
|
||
pU2ULE = CONTAINING_RECORD(pLE, H323_U2ULE, Link);
|
||
|
||
// transfer info
|
||
dwU2USize = pU2ULE->dwU2USize;
|
||
pU2U = pU2ULE->pU2U;
|
||
}
|
||
|
||
// initialize caller and callee id flags now
|
||
pCallInfo->dwCalledIDFlags = LINECALLPARTYID_UNAVAIL;
|
||
pCallInfo->dwCallerIDFlags = LINECALLPARTYID_UNAVAIL;
|
||
|
||
// calculate memory necessary for strings
|
||
dwCalleeNameSize = H323SizeOfWSZ(pCall->ccCalleeAlias.pData);
|
||
dwCallerNameSize = H323SizeOfWSZ(pCall->ccCallerAlias.pData);
|
||
|
||
// convert the IP address to string. It is in host order.
|
||
wsprintfW(IPAddress, L"%d.%d.%d.%d",
|
||
(pCall->ccCallerAddr.Addr.IP_Binary.dwAddr >> 24) & 0xff,
|
||
(pCall->ccCallerAddr.Addr.IP_Binary.dwAddr >> 16) & 0xff,
|
||
(pCall->ccCallerAddr.Addr.IP_Binary.dwAddr >> 8) & 0xff,
|
||
(pCall->ccCallerAddr.Addr.IP_Binary.dwAddr) & 0xff
|
||
);
|
||
|
||
dwCallerNumberSize = H323SizeOfWSZ(IPAddress);
|
||
|
||
// determine number of bytes needed
|
||
pCallInfo->dwNeededSize = sizeof(LINECALLINFO) +
|
||
dwCalleeNameSize +
|
||
dwCallerNameSize +
|
||
dwCallerNumberSize +
|
||
dwU2USize
|
||
;
|
||
|
||
// see if structure size is large enough
|
||
if (pCallInfo->dwTotalSize >= pCallInfo->dwNeededSize) {
|
||
|
||
// record number of bytes used
|
||
pCallInfo->dwUsedSize = pCallInfo->dwNeededSize;
|
||
|
||
// validate string size
|
||
if (dwCalleeNameSize > 0) {
|
||
|
||
// callee name was specified
|
||
pCallInfo->dwCalledIDFlags = LINECALLPARTYID_NAME;
|
||
|
||
// determine size and offset for callee name
|
||
pCallInfo->dwCalledIDNameSize = dwCalleeNameSize;
|
||
pCallInfo->dwCalledIDNameOffset = dwNextOffset;
|
||
|
||
// copy call info after fixed portion
|
||
memcpy((LPBYTE)pCallInfo + pCallInfo->dwCalledIDNameOffset,
|
||
(LPBYTE)pCall->ccCalleeAlias.pData,
|
||
pCallInfo->dwCalledIDNameSize
|
||
);
|
||
|
||
// adjust offset to include string
|
||
dwNextOffset += pCallInfo->dwCalledIDNameSize;
|
||
}
|
||
|
||
// validate string size
|
||
if (dwCallerNameSize > 0) {
|
||
|
||
// caller name was specified
|
||
pCallInfo->dwCallerIDFlags = LINECALLPARTYID_NAME;
|
||
|
||
// determine size and offset for caller name
|
||
pCallInfo->dwCallerIDNameSize = dwCallerNameSize;
|
||
pCallInfo->dwCallerIDNameOffset = dwNextOffset;
|
||
|
||
// copy call info after fixed portion
|
||
memcpy((LPBYTE)pCallInfo + pCallInfo->dwCallerIDNameOffset,
|
||
(LPBYTE)pCall->ccCallerAlias.pData,
|
||
pCallInfo->dwCallerIDNameSize
|
||
);
|
||
|
||
// adjust offset to include string
|
||
dwNextOffset += pCallInfo->dwCallerIDNameSize;
|
||
}
|
||
|
||
// validate string size
|
||
if (dwCallerNumberSize > 0) {
|
||
|
||
// caller name was specified
|
||
pCallInfo->dwCallerIDFlags |= LINECALLPARTYID_ADDRESS;
|
||
|
||
// determine size and offset for caller name
|
||
pCallInfo->dwCallerIDSize = dwCallerNumberSize;
|
||
pCallInfo->dwCallerIDOffset = dwNextOffset;
|
||
|
||
// copy call info after fixed portion
|
||
memcpy((LPBYTE)pCallInfo + pCallInfo->dwCallerIDOffset,
|
||
(LPBYTE)IPAddress,
|
||
pCallInfo->dwCallerIDSize
|
||
);
|
||
|
||
// adjust offset to include string
|
||
dwNextOffset += pCallInfo->dwCallerIDSize;
|
||
}
|
||
|
||
// validate buffer
|
||
if (dwU2USize > 0) {
|
||
|
||
// determine size and offset of info
|
||
pCallInfo->dwUserUserInfoSize = dwU2USize;
|
||
pCallInfo->dwUserUserInfoOffset = dwNextOffset;
|
||
|
||
// copy user user info after fixed portion
|
||
memcpy((LPBYTE)pCallInfo + pCallInfo->dwUserUserInfoOffset,
|
||
(LPBYTE)pU2U,
|
||
pCallInfo->dwUserUserInfoSize
|
||
);
|
||
|
||
// adjust offset to include string
|
||
dwNextOffset += pCallInfo->dwUserUserInfoSize;
|
||
}
|
||
|
||
} else if (pCallInfo->dwTotalSize >= sizeof(LINECALLINFO)) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_WARNING,
|
||
"linecallinfo structure too small for strings.\n"
|
||
));
|
||
|
||
// structure only contains fixed portion
|
||
pCallInfo->dwUsedSize = sizeof(LINECALLINFO);
|
||
|
||
} else {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_WARNING,
|
||
"linecallinfo structure too small.\n"
|
||
));
|
||
|
||
// release line device
|
||
H323UnlockLine(pCall->pLine);
|
||
|
||
// structure is too small
|
||
return LINEERR_STRUCTURETOOSMALL;
|
||
}
|
||
|
||
// initialize call line device and address info
|
||
pCallInfo->dwLineDeviceID = pCall->pLine->dwDeviceID;
|
||
pCallInfo->dwAddressID = 0;
|
||
|
||
// initialize variable call parameters
|
||
pCallInfo->dwOrigin = pCall->dwOrigin;
|
||
pCallInfo->dwMediaMode = pCall->dwIncomingModes | pCall->dwOutgoingModes;
|
||
pCallInfo->dwReason = H323IsCallInbound(pCall)
|
||
? LINECALLREASON_UNAVAIL
|
||
: LINECALLREASON_DIRECT
|
||
;
|
||
pCallInfo->dwCallStates = H323IsCallInbound(pCall)
|
||
? H323_CALL_INBOUNDSTATES
|
||
: H323_CALL_OUTBOUNDSTATES
|
||
;
|
||
|
||
// initialize constant call parameters
|
||
pCallInfo->dwBearerMode = H323_LINE_BEARERMODES;
|
||
pCallInfo->dwRate = H323_LINE_MAXRATE;
|
||
|
||
// initialize unsupported call capabilities
|
||
pCallInfo->dwConnectedIDFlags = LINECALLPARTYID_UNAVAIL;
|
||
pCallInfo->dwRedirectionIDFlags = LINECALLPARTYID_UNAVAIL;
|
||
pCallInfo->dwRedirectingIDFlags = LINECALLPARTYID_UNAVAIL;
|
||
|
||
//pass on the dwAppSpecific info
|
||
pCallInfo->dwAppSpecific = pCall->dwAppSpecific;
|
||
|
||
// release line device
|
||
H323UnlockLine(pCall->pLine);
|
||
|
||
// success
|
||
return NOERROR;
|
||
}
|
||
|
||
/*++
|
||
Parameters
|
||
|
||
hdCall - The handle to the call whose application-specific field is to be
|
||
set. The call state of hdCall can be any state.
|
||
|
||
dwAppSpecific - The new content of the dwAppSpecific member for the call's
|
||
LINECALLINFO structure. This value is uninterpreted by the service
|
||
provider. This parameter is not validated by TAPI when this function is called.
|
||
|
||
|
||
Return Values
|
||
Returns zero if the function succeeds, or an error number if an error
|
||
occurs. Possible return values are as follows:
|
||
|
||
LINEERR_INVALCALLHANDLE,
|
||
LINEERR_OPERATIONFAILED,
|
||
LINEERR_NOMEM,
|
||
LINEERR_RESOURCEUNAVAIL,
|
||
LINEERR_OPERATIONUNAVAIL.
|
||
|
||
Routine Description:
|
||
The application-specific field in the LINECALLINFO data structure that
|
||
exists for each call is uninterpreted by the Telephony API or any of its
|
||
service providers. Its usage is entirely defined by the applications. The
|
||
field can be read from the LINECALLINFO record returned by
|
||
TSPI_lineGetCallInfo. However, TSPI_lineSetAppSpecific must be used to set
|
||
the field so that changes become visible to other applications. When this
|
||
field is changed, the service provider sends a LINE_CALLINFO message with
|
||
an indication that the AppSpecific field has changed.
|
||
|
||
++*/
|
||
|
||
LONG
|
||
TSPIAPI
|
||
TSPI_lineSetAppSpecific(
|
||
HDRVCALL hdCall,
|
||
DWORD dwAppSpecific
|
||
)
|
||
{
|
||
PH323_CALL pCall = NULL;
|
||
|
||
// retrieve call pointer from handle
|
||
if (!H323GetCallAndLock(&pCall, hdCall)) {
|
||
|
||
// invalid call handle
|
||
return LINEERR_INVALCALLHANDLE;
|
||
}
|
||
|
||
pCall->dwAppSpecific = dwAppSpecific;
|
||
|
||
(*g_pfnLineEventProc)(
|
||
pCall->pLine->htLine,
|
||
pCall->htCall,
|
||
LINE_CALLINFO,
|
||
LINECALLINFOSTATE_APPSPECIFIC,
|
||
0,
|
||
0
|
||
);
|
||
|
||
// release line device
|
||
H323UnlockLine( pCall->pLine );
|
||
|
||
// success
|
||
return ERROR_SUCCESS;
|
||
}
|
||
|
||
|
||
LONG
|
||
TSPIAPI
|
||
TSPI_lineGetCallStatus(
|
||
HDRVCALL hdCall,
|
||
LPLINECALLSTATUS pCallStatus
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This operation returns the current status of the specified call.
|
||
|
||
TSPI_lineCallStatus returns the dynamic status of a call, whereas
|
||
TSPI_lineGetCallInfo returns primarily static information about a call.
|
||
Call status information includes the current call state, detailed mode
|
||
information related to the call while in this state (if any), as well
|
||
as a list of the available TSPI functions the TAPI DLL can invoke on the
|
||
call while the call is in this state. An application would typically be
|
||
interested in requesting this information when it receives notification
|
||
about a call state change via the LINE_CALLSTATE message.
|
||
|
||
Arguments:
|
||
|
||
hdCall - Specifies the Service Provider's opaque handle to the call
|
||
to be queried for its status. Valid call states: any.
|
||
|
||
pCallStatus - Specifies a far pointer to a variable sized data structure
|
||
of type LINECALLSTATUS. Upon successful completion of the request,
|
||
this structure is filled with call status information.
|
||
|
||
Return Values:
|
||
|
||
Returns zero if the function is successful or a negative error
|
||
number if an error has occurred. Possible error returns are:
|
||
|
||
LINEERR_INVALCALLHANDLE - The specified call handle is invalid.
|
||
|
||
LINEERR_STRUCTURETOOSMALL - The dwTotalSize member of a structure does
|
||
not specify enough memory to contain the fixed portion of the
|
||
structure. The dwNeededSize field has been set to the amount
|
||
required.
|
||
|
||
--*/
|
||
|
||
{
|
||
PH323_CALL pCall = NULL;
|
||
|
||
// retrieve call pointer from handle
|
||
if (!H323GetCallAndLock(&pCall, hdCall)) {
|
||
|
||
// invalid call handle
|
||
return LINEERR_INVALCALLHANDLE;
|
||
}
|
||
|
||
// determine number of bytes needed
|
||
pCallStatus->dwNeededSize = sizeof(LINECALLSTATUS);
|
||
|
||
// see if structure size is large enough
|
||
if (pCallStatus->dwTotalSize < pCallStatus->dwNeededSize) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"linecallstatus structure too small.\n"
|
||
));
|
||
|
||
// release line device
|
||
H323UnlockLine(pCall->pLine);
|
||
|
||
// allocated structure too small
|
||
return LINEERR_STRUCTURETOOSMALL;
|
||
}
|
||
|
||
// record amount of memory used
|
||
pCallStatus->dwUsedSize = pCallStatus->dwNeededSize;
|
||
|
||
// transer call state information
|
||
pCallStatus->dwCallState = pCall->dwCallState;
|
||
pCallStatus->dwCallStateMode = pCall->dwCallStateMode;
|
||
|
||
// determine call feature based on state
|
||
pCallStatus->dwCallFeatures = H323GetCallFeatures(pCall);
|
||
|
||
// release line device
|
||
H323UnlockLine(pCall->pLine);
|
||
|
||
// success
|
||
return NOERROR;
|
||
}
|
||
|
||
|
||
LONG
|
||
TSPIAPI
|
||
TSPI_lineMakeCall(
|
||
DRV_REQUESTID dwRequestID,
|
||
HDRVLINE hdLine,
|
||
HTAPICALL htCall,
|
||
LPHDRVCALL phdCall,
|
||
LPCWSTR pwszDialableAddr,
|
||
DWORD dwCountryCode,
|
||
LPLINECALLPARAMS const pCallParams
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function places a call on the specified line to the specified
|
||
destination address, exchanging opaque handles for the new call
|
||
between the TAPI DLL and Service Provider. Optionally, call parameters
|
||
can be specified if anything but default call setup parameters are
|
||
requested.
|
||
|
||
After dialing has completed, several LINE_CALLSTATE messages will
|
||
typically be sent to the TAPI DLL to notify it about the progress of the
|
||
call. No generally valid sequence of call state transitions is specified
|
||
as no single fixed sequence of transitions can be guaranteed in practice.
|
||
A typical sequence may cause a call to transition from dialtone, dialing,
|
||
proceeding, ringback, to connected. With non-dialed lines, the call may
|
||
typically transition directly to connected state.
|
||
|
||
The TAPI DLL has the option to specify an originating address on the
|
||
specified line device. A service provider that models all stations on a
|
||
switch as addresses on a single line device allows the TAPI DLL to
|
||
originate calls from any of these stations using TSPI_lineMakeCall.
|
||
|
||
The call parameters allow the TAPI DLL to make non voice calls or request
|
||
special call setup options that are not available by default.
|
||
|
||
The TAPI DLL can partially dial using TSPI_lineMakeCall and continue
|
||
dialing using TSPI_lineDial. To abandon a call attempt, use TSPI_lineDrop.
|
||
|
||
The Service Provider initially does media monitoring on the new call for
|
||
at least the set of media modes that were monitored for on the line.
|
||
|
||
Arguments:
|
||
|
||
dwRequestID - Specifies the identifier of the asynchronous request.
|
||
The Service Provider returns this value if the function completes
|
||
asynchronously.
|
||
|
||
hdLine - Specifies the Service Provider's opaque handle to the line on
|
||
which the new call is to be originated.
|
||
|
||
htCall - Specifies the TAPI DLL's opaque handle to the new call. The
|
||
Service Provider must save this and use it in all subsequent calls to
|
||
the LINEEVENT procedure reporting events on the call.
|
||
|
||
phdCall - Specifies a far pointer to an opaque HDRVCALL representing the
|
||
Service Provider's identifier for the call. The Service Provider must
|
||
fill this location with its opaque handle for the call before this
|
||
procedure returns, whether it decides to execute the request
|
||
sychronously or asynchronously. This handle is invalid if the function
|
||
results in an error (either synchronously or asynchronously).
|
||
|
||
pwszDialableAddr - Specifies a far pointer to the destination address. This
|
||
follows the standard dialable number format. This pointer may be
|
||
specified as NULL for non-dialed addresses (i.e., a hot phone) or when
|
||
all dialing will be performed using TSPI_lineDial. In the latter case,
|
||
TSPI_lineMakeCall will allocate an available call appearance which
|
||
would typically remain in the dialtone state until dialing begins.
|
||
Service providers that have inverse multiplexing capabilities may allow
|
||
an application to specify multiple addresses at once.
|
||
|
||
dwCountryCode - Specifies the country code of the called party. If a value
|
||
of zero is specified, then a default will be used by the
|
||
implementation.
|
||
|
||
pCallParams - Specifies a far pointer to a LINECALLPARAMS structure. This
|
||
structure allows the TAPI DLL to specify how it wants the call to be
|
||
set up. If NULL is specified, then a default 3.1kHz voice call is
|
||
established, and an arbitrary origination address on the line is
|
||
selected. This structure allows the TAPI DLL to select such elements
|
||
as the call's bearer mode, data rate, expected media mode, origination
|
||
address, blocking of caller ID information, dialing parameters, etc.
|
||
|
||
Return Values:
|
||
|
||
Returns zero if the function is successful, the (positive) dwRequestID
|
||
value if the function will be completed asynchronously, or a negative error
|
||
number if an error has occurred. Possible error returns are:
|
||
|
||
LINEERR_CALLUNAVAIL - All call appearances on the specified address are
|
||
currently in use.
|
||
|
||
LINEERR_INVALADDRESSID - The specified address ID is out of range.
|
||
|
||
LINEERR_INVALADDRESSMODE - The address mode is invalid.
|
||
|
||
LINEERR_INVALBEARERMODE - The bearer mode is invalid.
|
||
|
||
LINEERR_INVALCALLPARAMS - The specified call parameter structure is
|
||
invalid.
|
||
|
||
LINEERR_INVALLINEHANDLE - The specified line handle is invalid.
|
||
|
||
LINEERR_INVALLINESTATE - The line is currently not in a state in
|
||
which this operation can be performed.
|
||
|
||
LINEERR_INVALMEDIAMODE - One or more media modes specified as a
|
||
parameter or in a list is invalid or not supported by the the
|
||
service provider.
|
||
|
||
LINEERR_OPERATIONFAILED - The operation failed for unspecified reasons.
|
||
|
||
LINEERR_RESOURCEUNAVAIL - The specified operation cannot be completed
|
||
because of resource overcommitment.
|
||
|
||
--*/
|
||
|
||
{
|
||
PH323_CALL pCall = NULL;
|
||
PH323_LINE pLine = NULL;
|
||
DWORD dwStatus = dwRequestID;
|
||
|
||
UNREFERENCED_PARAMETER(dwCountryCode);
|
||
|
||
// retrieve line device pointer from handle
|
||
if (!H323GetLineAndLock(&pLine, hdLine)) {
|
||
|
||
// invalid line device handle
|
||
return LINEERR_INVALLINEHANDLE;
|
||
}
|
||
|
||
// validate line state
|
||
if (!H323IsLineOpen(pLine)) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"line %d is not currently opened.\n",
|
||
pLine->dwDeviceID
|
||
));
|
||
|
||
// release line device
|
||
H323UnlockLine(pLine);
|
||
|
||
// line needs to be opened
|
||
return LINEERR_INVALLINESTATE;
|
||
}
|
||
|
||
// see if line is available
|
||
if (!H323IsLineAvailable(pLine)) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"line %d is currently at maximum capacity.\n",
|
||
pLine->dwDeviceID
|
||
));
|
||
|
||
// release line device
|
||
H323UnlockLine(pLine);
|
||
|
||
// line is currenty maxed
|
||
return LINEERR_RESOURCEUNAVAIL;
|
||
}
|
||
|
||
// allocate outgoing call from line call table
|
||
if (!H323AllocCallFromTable(&pCall,&pLine->pCallTable,pLine)) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"could not allocate outgoing call.\n"
|
||
));
|
||
|
||
// release line device
|
||
H323UnlockLine(pLine);
|
||
|
||
// no memory available
|
||
return LINEERR_NOMEM;
|
||
}
|
||
|
||
// save tapi handle
|
||
pCall->htCall = htCall;
|
||
|
||
// save back pointer
|
||
pCall->pLine = pLine;
|
||
|
||
// specify outgoing call direction
|
||
pCall->dwOrigin = LINECALLORIGIN_OUTBOUND;
|
||
|
||
// validate call parameters
|
||
if (!H323ValidateCallParams(
|
||
pCall,
|
||
pCallParams,
|
||
pwszDialableAddr,
|
||
&dwStatus)) {
|
||
|
||
// failure
|
||
goto cleanup;
|
||
}
|
||
|
||
// bind outgoing call
|
||
if (!H323BindCall(pCall,NULL)) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"could not bind call.\n"
|
||
));
|
||
|
||
// no memory available
|
||
dwStatus = LINEERR_NOMEM;
|
||
|
||
// failure
|
||
goto cleanup;
|
||
}
|
||
|
||
// post place request to callback thread
|
||
if (!H323PostPlaceCallMessage(pCall->hdCall)) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"could not post place call message.\n"
|
||
));
|
||
|
||
// could not complete operation
|
||
dwStatus = LINEERR_OPERATIONFAILED;
|
||
|
||
// failure
|
||
goto cleanup;
|
||
}
|
||
|
||
// complete the async accept operation now
|
||
(*g_pfnCompletionProc)(dwRequestID, NOERROR);
|
||
|
||
// change call state to accepted from offering
|
||
H323ChangeCallState(pCall, LINECALLSTATE_DIALING, 0);
|
||
|
||
// transfer handle
|
||
*phdCall = pCall->hdCall;
|
||
|
||
// release line device
|
||
H323UnlockLine(pLine);
|
||
|
||
// success
|
||
return dwStatus;
|
||
|
||
cleanup:
|
||
|
||
// unbind call
|
||
H323UnbindCall(pCall);
|
||
|
||
// release outgoing call from line call table
|
||
H323FreeCallFromTable(pCall,pLine->pCallTable);
|
||
|
||
// release line device
|
||
H323UnlockLine(pLine);
|
||
|
||
// failure
|
||
return dwStatus;
|
||
}
|
||
|
||
|
||
LONG
|
||
TSPIAPI
|
||
TSPI_lineReleaseUserUserInfo(
|
||
DRV_REQUESTID dwRequestID,
|
||
HDRVCALL hdCall
|
||
)
|
||
{
|
||
PLIST_ENTRY pLE;
|
||
PH323_U2ULE pU2ULE;
|
||
PH323_CALL pCall = NULL;
|
||
|
||
// retrieve call pointer from handle
|
||
if (!H323GetCallAndLock(&pCall, hdCall)) {
|
||
|
||
// invalid call handle
|
||
return LINEERR_INVALCALLHANDLE;
|
||
}
|
||
|
||
// see if list is empty
|
||
if (!IsListEmpty(&pCall->IncomingU2U)) {
|
||
|
||
// remove first entry from list
|
||
pLE = RemoveHeadList(&pCall->IncomingU2U);
|
||
|
||
// convert to user user structure
|
||
pU2ULE = CONTAINING_RECORD(pLE, H323_U2ULE, Link);
|
||
|
||
// release memory
|
||
H323HeapFree(pU2ULE);
|
||
}
|
||
|
||
// see if list contains pending data
|
||
if (!IsListEmpty(&pCall->IncomingU2U)) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_VERBOSE,
|
||
"more user user info available.\n"
|
||
));
|
||
|
||
// signal incoming
|
||
(*g_pfnLineEventProc)(
|
||
pCall->pLine->htLine,
|
||
pCall->htCall,
|
||
LINE_CALLINFO,
|
||
LINECALLINFOSTATE_USERUSERINFO,
|
||
0,
|
||
0
|
||
);
|
||
}
|
||
|
||
// complete the async accept operation now
|
||
(*g_pfnCompletionProc)(dwRequestID, NOERROR);
|
||
|
||
// release line device
|
||
H323UnlockLine(pCall->pLine);
|
||
|
||
// async success
|
||
return dwRequestID;
|
||
}
|
||
|
||
|
||
LONG
|
||
TSPIAPI
|
||
TSPI_lineSendUserUserInfo(
|
||
DRV_REQUESTID dwRequestID,
|
||
HDRVCALL hdCall,
|
||
LPCSTR pUserUserInfo,
|
||
DWORD dwSize
|
||
)
|
||
{
|
||
HRESULT hr;
|
||
PH323_CALL pCall = NULL;
|
||
CC_NONSTANDARDDATA NonStandardData;
|
||
PCC_NONSTANDARDDATA pNonStandardData = NULL;
|
||
|
||
// retrieve call pointer from handle
|
||
if (!H323GetCallAndLock(&pCall, hdCall)) {
|
||
|
||
// invalid call handle
|
||
return LINEERR_INVALCALLHANDLE;
|
||
}
|
||
|
||
// check for user user info
|
||
if (pUserUserInfo != NULL) {
|
||
|
||
// transfer header information
|
||
NonStandardData.bCountryCode = H221_COUNTRY_CODE_USA;
|
||
NonStandardData.bExtension = H221_COUNTRY_EXT_USA;
|
||
NonStandardData.wManufacturerCode = H221_MFG_CODE_MICROSOFT;
|
||
|
||
// initialize octet string containing data
|
||
NonStandardData.sData.wOctetStringLength = LOWORD(dwSize);
|
||
NonStandardData.sData.pOctetString = (PBYTE)pUserUserInfo;
|
||
|
||
// point to stack based structure
|
||
pNonStandardData = &NonStandardData;
|
||
}
|
||
|
||
// send user user data
|
||
hr = CC_SendNonStandardMessage(
|
||
pCall->hccCall,
|
||
CC_H245_MESSAGE_COMMAND,
|
||
pNonStandardData
|
||
);
|
||
|
||
// validate status
|
||
if (hr != CC_OK) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"error %s (0x%08lx) sending non-standard message.\n",
|
||
H323StatusToString((DWORD)hr), hr
|
||
));
|
||
|
||
// release line device
|
||
H323UnlockLine(pCall->pLine);
|
||
|
||
// unable to answer call
|
||
return LINEERR_OPERATIONFAILED;
|
||
}
|
||
|
||
// complete the async accept operation now
|
||
(*g_pfnCompletionProc)(dwRequestID, NOERROR);
|
||
|
||
// release line device
|
||
H323UnlockLine(pCall->pLine);
|
||
|
||
// async success
|
||
return dwRequestID;
|
||
}
|
||
|
||
|
||
LONG
|
||
TSPIAPI
|
||
TSPI_lineMonitorDigits(
|
||
HDRVCALL hdCall,
|
||
DWORD dwDigitModes
|
||
)
|
||
{
|
||
PH323_CALL pCall = NULL;
|
||
|
||
// retrieve call pointer from handle
|
||
if (!H323GetCallAndLock(&pCall, hdCall)) {
|
||
|
||
// invalid call handle
|
||
return LINEERR_INVALCALLHANDLE;
|
||
}
|
||
|
||
// see if mode empty
|
||
if (dwDigitModes == 0) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_VERBOSE,
|
||
"disabling dtmf detection.\n"
|
||
));
|
||
|
||
// enable monitoring digits
|
||
pCall->fMonitoringDigits = FALSE;
|
||
|
||
// release line device
|
||
H323UnlockLine(pCall->pLine);
|
||
|
||
// success
|
||
return NOERROR;
|
||
|
||
} else if (dwDigitModes != LINEDIGITMODE_DTMF) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"invalid digit modes 0x%08lx.\n",
|
||
dwDigitModes
|
||
));
|
||
|
||
// release line device
|
||
H323UnlockLine(pCall->pLine);
|
||
|
||
// invalid call handle
|
||
return LINEERR_INVALDIGITMODE;
|
||
}
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_VERBOSE,
|
||
"enabling dtmf detection.\n"
|
||
));
|
||
|
||
// enable monitoring digits
|
||
pCall->fMonitoringDigits = TRUE;
|
||
|
||
// release line device
|
||
H323UnlockLine(pCall->pLine);
|
||
|
||
// success
|
||
return NOERROR;
|
||
}
|
||
|
||
|
||
LONG
|
||
TSPIAPI
|
||
TSPI_lineGenerateDigits(
|
||
HDRVCALL hdCall,
|
||
DWORD dwEndToEndID,
|
||
DWORD dwDigitMode,
|
||
LPCWSTR pwszDigits,
|
||
DWORD dwDuration
|
||
)
|
||
{
|
||
HRESULT hr;
|
||
PH323_CALL pCall = NULL;
|
||
|
||
UNREFERENCED_PARAMETER(dwDuration);
|
||
|
||
// retrieve call pointer from handle
|
||
if (!H323GetCallAndLock(&pCall, hdCall)) {
|
||
|
||
// invalid call handle
|
||
return LINEERR_INVALCALLHANDLE;
|
||
}
|
||
|
||
// verify that the call was connected
|
||
if (!H323IsCallConnected(pCall)) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"call 0x%08lx not connected.\n",
|
||
pCall
|
||
));
|
||
|
||
// release line device
|
||
H323UnlockLine(pCall->pLine);
|
||
|
||
return LINEERR_INVALCALLSTATE;
|
||
}
|
||
|
||
// verify monitor modes
|
||
if (dwDigitMode != LINEDIGITMODE_DTMF) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"invalid digit mode 0x%08lx.\n",
|
||
dwDigitMode
|
||
));
|
||
|
||
// release line device
|
||
H323UnlockLine(pCall->pLine);
|
||
|
||
// invalid call handle
|
||
return LINEERR_INVALDIGITMODE;
|
||
}
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_VERBOSE,
|
||
"sending user input %S.\n",
|
||
pwszDigits
|
||
));
|
||
|
||
// send user input message
|
||
hr = CC_UserInput(pCall->hccCall, (PWSTR)pwszDigits);
|
||
|
||
// validate
|
||
if (hr != CC_OK) {
|
||
|
||
H323DBG((
|
||
DEBUG_LEVEL_ERROR,
|
||
"error 0x%08lx sending user input message.\n",
|
||
hr
|
||
));
|
||
|
||
// signal completion
|
||
(*g_pfnLineEventProc)(
|
||
pCall->pLine->htLine,
|
||
pCall->htCall,
|
||
LINE_GENERATE,
|
||
LINEGENERATETERM_CANCEL,
|
||
dwEndToEndID,
|
||
GetTickCount()
|
||
);
|
||
|
||
// release line device
|
||
H323UnlockLine(pCall->pLine);
|
||
|
||
// failure
|
||
return LINEERR_INVALDIGITS;
|
||
}
|
||
|
||
// signal completion
|
||
(*g_pfnLineEventProc)(
|
||
pCall->pLine->htLine,
|
||
pCall->htCall,
|
||
LINE_GENERATE,
|
||
LINEGENERATETERM_DONE,
|
||
dwEndToEndID,
|
||
GetTickCount()
|
||
);
|
||
|
||
// release line device
|
||
H323UnlockLine(pCall->pLine);
|
||
|
||
// success
|
||
return NOERROR;
|
||
}
|