mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1624 lines
41 KiB
1624 lines
41 KiB
/*++
|
|
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
sdpsp.cpp
|
|
|
|
Abstract:
|
|
|
|
This module contains a multicast conference service provider for TAPI3.0.
|
|
It is first designed and implemented in c. Later, in order to use the SDP
|
|
parser, which is written in C++, this file is changed to cpp. It still
|
|
uses only c features except the lines that uses the parser.
|
|
|
|
Author:
|
|
|
|
Mu Han (muhan) 26-March-1997
|
|
|
|
--*/
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// Include files //
|
|
// //
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "stdafx.h"
|
|
|
|
#include <initguid.h>
|
|
#include <confpdu.h>
|
|
#include "resource.h"
|
|
#include "conftsp.h"
|
|
#include "confdbg.h"
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// Global Variables //
|
|
// //
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
static WCHAR gszUIDLLName[] = L"IPCONF.TSP";
|
|
|
|
//
|
|
// Some data used in talking with TAPI.
|
|
//
|
|
HPROVIDER ghProvider;
|
|
DWORD gdwPermanentProviderID;
|
|
DWORD gdwLineDeviceIDBase;
|
|
|
|
// The handle of this dll.
|
|
extern "C"
|
|
{
|
|
HINSTANCE g_hInstance;
|
|
}
|
|
|
|
//
|
|
// This function is called if the completion of the process will be sent
|
|
// as an asynchrous event. Set in TSPI_ProviderInit.
|
|
//
|
|
ASYNC_COMPLETION glpfnCompletionProc;
|
|
|
|
//
|
|
// Notify tapi about events in the provider. Set in TSPI_LineOpen.
|
|
//
|
|
LINEEVENT glpfnLineEventProc;
|
|
|
|
// This service provider has only one line.
|
|
LINE gLine;
|
|
|
|
// Calls are stored in an array of structures. The array will grow as needed.
|
|
CCallList gpCallList;
|
|
DWORD gdwNumCallsInUse = 0;
|
|
|
|
// The critical section the protects the global variables.
|
|
CRITICAL_SECTION gCritSec;
|
|
|
|
#if 0 // we dont' need the user name anymore.
|
|
// The name of the user.
|
|
CHAR gszUserName[MAXUSERNAMELEN + 1];
|
|
#endif
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// Functiion definitions for the call object. //
|
|
// //
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
DWORD CALL::Init(
|
|
HTAPICALL htCall,
|
|
LPLINECALLPARAMS const lpCallParams
|
|
)
|
|
{
|
|
m_htCall = htCall;
|
|
m_dwState = LINECALLSTATE_IDLE;
|
|
m_dwStateMode = 0;
|
|
m_dwMediaMode = IPCONF_MEDIAMODES;
|
|
m_dwAudioQOSLevel = LINEQOSSERVICELEVEL_IFAVAILABLE;
|
|
m_dwVideoQOSLevel = LINEQOSSERVICELEVEL_IFAVAILABLE;
|
|
// m_dwAudioQOSLevel = LINEQOSSERVICELEVEL_BESTEFFORT;
|
|
// m_dwVideoQOSLevel = LINEQOSSERVICELEVEL_BESTEFFORT;
|
|
|
|
if (!lpCallParams)
|
|
{
|
|
return NOERROR;
|
|
}
|
|
|
|
// set my media modes.
|
|
m_dwMediaMode = lpCallParams->dwMediaMode;
|
|
|
|
if (lpCallParams->dwReceivingFlowspecOffset == 0)
|
|
{
|
|
// No QOS policy specified.
|
|
DBGOUT((WARN, "no qos level request."));
|
|
return NOERROR;
|
|
}
|
|
|
|
// get the QOS policy requirements.
|
|
LPLINECALLQOSINFO pQOSInfo = (LPLINECALLQOSINFO)
|
|
(((LPBYTE)lpCallParams) + lpCallParams->dwReceivingFlowspecOffset);
|
|
|
|
ASSERT(pQOSInfo->dwKey == LINEQOSSTRUCT_KEY);
|
|
|
|
// find out if this is a QOS level request.
|
|
if (pQOSInfo->dwQOSRequestType != LINEQOSREQUESTTYPE_SERVICELEVEL)
|
|
{
|
|
// It is not a request for qos service level.
|
|
DBGOUT((WARN, "wrong qos request type."));
|
|
return NOERROR;
|
|
}
|
|
|
|
DWORD dwCount = pQOSInfo->SetQOSServiceLevel.dwNumServiceLevelEntries;
|
|
for (DWORD i = 0; i < dwCount; i ++)
|
|
{
|
|
LINEQOSSERVICELEVEL &QOSLevel =
|
|
pQOSInfo->SetQOSServiceLevel.LineQOSServiceLevel[i];
|
|
|
|
switch (QOSLevel.dwMediaMode)
|
|
{
|
|
case LINEMEDIAMODE_VIDEO:
|
|
m_dwVideoQOSLevel = QOSLevel.dwQOSServiceLevel;
|
|
break;
|
|
|
|
case LINEMEDIAMODE_INTERACTIVEVOICE:
|
|
case LINEMEDIAMODE_AUTOMATEDVOICE:
|
|
m_dwAudioQOSLevel = QOSLevel.dwQOSServiceLevel;
|
|
break;
|
|
|
|
default:
|
|
DBGOUT((WARN, "Unknown mediamode for QOS, %x", dwMediaMode));
|
|
break;
|
|
}
|
|
}
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
void CALL::SetCallState(
|
|
DWORD dwCallState,
|
|
DWORD dwCallStateMode
|
|
)
|
|
{
|
|
if (m_dwState != dwCallState)
|
|
{
|
|
m_dwState = dwCallState;
|
|
m_dwStateMode = dwCallStateMode;
|
|
|
|
(*glpfnLineEventProc)(
|
|
gLine.htLine,
|
|
m_htCall,
|
|
LINE_CALLSTATE,
|
|
m_dwState,
|
|
m_dwStateMode,
|
|
m_dwMediaMode
|
|
);
|
|
DBGOUT((INFO, "sending event to htCall: %x", m_htCall));
|
|
}
|
|
}
|
|
|
|
DWORD CALL::SendMSPStartMessage(LPCWSTR lpszDestAddress)
|
|
{
|
|
DWORD dwStrLen = lstrlenW(lpszDestAddress);
|
|
DWORD dwSize = sizeof(MSG_TSPMSPDATA) + dwStrLen * sizeof(WCHAR);
|
|
|
|
MSG_TSPMSPDATA *pData = (MSG_TSPMSPDATA *)MemAlloc(dwSize);
|
|
|
|
if (pData == NULL)
|
|
{
|
|
DBGOUT((FAIL, "No memory for the TSPMSP data, size: %d", dwSize));
|
|
return LINEERR_NOMEM;
|
|
}
|
|
|
|
pData->command = CALL_START;
|
|
|
|
pData->CallStart.dwAudioQOSLevel = m_dwAudioQOSLevel;
|
|
pData->CallStart.dwVideoQOSLevel = m_dwVideoQOSLevel;
|
|
pData->CallStart.dwSDPLen = dwStrLen;
|
|
lstrcpyW(pData->CallStart.szSDP, lpszDestAddress);
|
|
|
|
DBGOUT((INFO, "Send MSP call Start message"));
|
|
(*glpfnLineEventProc)(
|
|
gLine.htLine,
|
|
m_htCall,
|
|
LINE_SENDMSPDATA,
|
|
0,
|
|
PtrToUlong(pData),
|
|
dwSize
|
|
);
|
|
|
|
MemFree(pData);
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
DWORD CALL::SendMSPStopMessage()
|
|
{
|
|
MSG_TSPMSPDATA Data;
|
|
|
|
Data.command = CALL_STOP;
|
|
|
|
DBGOUT((INFO, "Send MSP call Stop message"));
|
|
(*glpfnLineEventProc)(
|
|
gLine.htLine,
|
|
m_htCall,
|
|
LINE_SENDMSPDATA,
|
|
0,
|
|
PtrToUlong(&Data),
|
|
sizeof(MSG_TSPMSPDATA)
|
|
);
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// Private Functiion definitions //
|
|
// //
|
|
// Note: none of these functions uses critical sections operations inside. //
|
|
// The caller is responsible for critical sections. //
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
LONG
|
|
CheckCallParams(
|
|
LPLINECALLPARAMS const lpCallParams
|
|
)
|
|
{
|
|
// validate pointer
|
|
if (lpCallParams == NULL)
|
|
{
|
|
return NOERROR;
|
|
}
|
|
|
|
// see if the address type is right
|
|
if (lpCallParams->dwAddressType != LINEADDRESSTYPE_SDP)
|
|
{
|
|
DBGOUT((FAIL,
|
|
"wrong address type 0x%08lx.\n", lpCallParams->dwAddressType
|
|
));
|
|
return LINEERR_INVALADDRESSTYPE;
|
|
}
|
|
|
|
// see if we support call parameters
|
|
if (lpCallParams->dwCallParamFlags != 0)
|
|
{
|
|
DBGOUT((FAIL,
|
|
"do not support call parameters 0x%08lx.\n",
|
|
lpCallParams->dwCallParamFlags
|
|
));
|
|
return LINEERR_INVALCALLPARAMS;
|
|
}
|
|
|
|
// see if we support media modes specified
|
|
if (lpCallParams->dwMediaMode & ~IPCONF_MEDIAMODES)
|
|
{
|
|
DBGOUT((FAIL,
|
|
"do not support media modes 0x%08lx.\n",
|
|
lpCallParams->dwMediaMode
|
|
));
|
|
return LINEERR_INVALMEDIAMODE;
|
|
}
|
|
|
|
// see if we support bearer modes
|
|
if (lpCallParams->dwBearerMode & ~IPCONF_BEARERMODES)
|
|
{
|
|
DBGOUT((FAIL,
|
|
"do not support bearer mode 0x%08lx.\n",
|
|
lpCallParams->dwBearerMode
|
|
));
|
|
return LINEERR_INVALBEARERMODE;
|
|
}
|
|
|
|
// see if we support address modes
|
|
if (lpCallParams->dwAddressMode & ~IPCONF_ADDRESSMODES)
|
|
{
|
|
DBGOUT((FAIL,
|
|
"do not support address mode 0x%08lx.\n",
|
|
lpCallParams->dwAddressMode
|
|
));
|
|
return LINEERR_INVALADDRESSMODE;
|
|
}
|
|
|
|
// validate address id specified There is only one address per line
|
|
if (lpCallParams->dwAddressID != 0)
|
|
{
|
|
DBGOUT((FAIL,
|
|
"address id 0x%08lx invalid.\n",
|
|
lpCallParams->dwAddressID
|
|
));
|
|
return LINEERR_INVALADDRESSID;
|
|
}
|
|
return NOERROR;
|
|
}
|
|
|
|
DWORD
|
|
FreeCall(DWORD hdCall)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Decrement the ref count on the call and release the call if the ref
|
|
count gets 0.
|
|
|
|
Arguments:
|
|
|
|
hdCall - The handle of the call.
|
|
|
|
Return Value:
|
|
|
|
NOERROR
|
|
--*/
|
|
{
|
|
if (gpCallList[hdCall] == NULL)
|
|
{
|
|
return NOERROR;
|
|
}
|
|
|
|
DWORD dwLine = (DWORD)gpCallList[hdCall]->hdLine();
|
|
|
|
MemFree(gpCallList[hdCall]);
|
|
gpCallList[hdCall] = NULL;
|
|
|
|
gdwNumCallsInUse --;
|
|
gLine.dwNumCalls --;
|
|
|
|
DBGOUT((INFO, "No.%d call was deleted.", hdCall));
|
|
return NOERROR;
|
|
}
|
|
|
|
long FindFreeCallSlot(DWORD &hdCall)
|
|
{
|
|
if (gdwNumCallsInUse < gpCallList.size())
|
|
{
|
|
for (DWORD i = 0; i < gpCallList.size(); i++)
|
|
{
|
|
if (gpCallList[i] == NULL)
|
|
{
|
|
hdCall = i;
|
|
return TRUE;;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!gpCallList.add())
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
hdCall = gpCallList.size() - 1;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// DllMain definition //
|
|
// //
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
BOOL
|
|
WINAPI
|
|
DllMain(
|
|
HINSTANCE hDLL,
|
|
DWORD dwReason,
|
|
LPVOID lpReserved
|
|
)
|
|
{
|
|
DWORD i;
|
|
DWORD dwUserNameLen = MAXUSERNAMELEN;
|
|
|
|
HRESULT hr;
|
|
|
|
switch (dwReason)
|
|
{
|
|
case DLL_PROCESS_ATTACH:
|
|
DBGOUT((TRCE, "DLL_PROCESS_ATTACH"));
|
|
|
|
DisableThreadLibraryCalls(hDLL);
|
|
g_hInstance = hDLL;
|
|
|
|
#if 0 // we dont' need the user name anymore.
|
|
// switch in user's context
|
|
RpcImpersonateClient(0);
|
|
|
|
// determine name of current user
|
|
GetUserNameA(gszUserName, &dwUserNameLen);
|
|
|
|
// switch back
|
|
RpcRevertToSelf();
|
|
|
|
#endif
|
|
// Initialize critical sections.
|
|
__try
|
|
{
|
|
InitializeCriticalSection(&gCritSec);
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return FALSE;
|
|
}
|
|
break;
|
|
|
|
case DLL_PROCESS_DETACH:
|
|
DBGOUT((TRCE, "DLL_PROCESS_DETACH"));
|
|
|
|
DeleteCriticalSection(&gCritSec);
|
|
|
|
break;
|
|
|
|
} // switch
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// We get a slough of C4047 (different levels of indrection) warnings down
|
|
// below in the initialization of FUNC_PARAM structs as a result of the
|
|
// real func prototypes having params that are types other than DWORDs,
|
|
// so since these are known non-interesting warnings just turn them off
|
|
//
|
|
|
|
#pragma warning (disable:4047)
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// TSPI_lineXxx functions //
|
|
// //
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineClose(
|
|
HDRVLINE hdLine
|
|
)
|
|
{
|
|
DBGOUT((TRCE, "TSPI_lineClose, hdLine %p", hdLine));
|
|
|
|
DWORD dwLine = HandleToUlong(hdLine);
|
|
|
|
if (dwLine != IPCONF_LINE_HANDLE)
|
|
{
|
|
DBGOUT((FAIL, "invalide line handle, hdLine %p", hdLine));
|
|
return LINEERR_INVALLINEHANDLE;
|
|
}
|
|
|
|
EnterCriticalSection(&gCritSec);
|
|
|
|
// Clean up all the open calls when this line is closed.
|
|
for (DWORD i = 0; i < gpCallList.size(); i++)
|
|
{
|
|
if ((gpCallList[i] != NULL))
|
|
{
|
|
FreeCall(i);
|
|
}
|
|
}
|
|
|
|
gLine.bOpened = FALSE;
|
|
|
|
LeaveCriticalSection(&gCritSec);
|
|
|
|
DBGOUT((TRCE, "TSPI_lineClose succeeded."));
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineCloseCall(
|
|
HDRVCALL hdCall
|
|
)
|
|
{
|
|
DBGOUT((TRCE, "TSPI_lineCloseCall, hdCall %p", hdCall));
|
|
|
|
DWORD dwCall = HandleToUlong(hdCall);
|
|
|
|
EnterCriticalSection(&gCritSec);
|
|
|
|
if (dwCall >= gpCallList.size())
|
|
{
|
|
LeaveCriticalSection(&gCritSec);
|
|
DBGOUT((FAIL, "TSPI_lineCloseCall invalid call handle: %p", hdCall));
|
|
return LINEERR_INVALCALLHANDLE;
|
|
}
|
|
|
|
FreeCall(dwCall);
|
|
|
|
LeaveCriticalSection(&gCritSec);
|
|
|
|
DBGOUT((TRCE, "TSPI_lineCloseCall succeeded"));
|
|
return NOERROR;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineCreateMSPInstance(
|
|
HDRVLINE hdLine,
|
|
DWORD dwAddressID,
|
|
HTAPIMSPLINE htMSPLine,
|
|
LPHDRVMSPLINE phdMSPLine
|
|
)
|
|
{
|
|
DBGOUT((TRCE, "TSPI_lineCreateMSPInstance"));
|
|
|
|
if (IsBadWritePtr(phdMSPLine, sizeof (HDRVMSPLINE)))
|
|
{
|
|
DBGOUT((FAIL, "TSPI_lineCreateMSPInstance bad pointer"));
|
|
return LINEERR_INVALPOINTER;
|
|
}
|
|
|
|
if (HandleToUlong(hdLine) != IPCONF_LINE_HANDLE)
|
|
{
|
|
DBGOUT((FAIL, "TSPI_lineCreateMSPInstance, bad line handle:%p", hdLine));
|
|
return LINEERR_INVALLINEHANDLE;
|
|
}
|
|
|
|
EnterCriticalSection(&gCritSec);
|
|
|
|
// We are not keeping the msp handles. Just fake a handle here.
|
|
*phdMSPLine = (HDRVMSPLINE)(gLine.dwNextMSPHandle ++);
|
|
|
|
LeaveCriticalSection(&gCritSec);
|
|
|
|
DBGOUT((TRCE, "TSPI_lineCloseCall succeeded"));
|
|
return (NOERROR);
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineCloseMSPInstance(
|
|
HDRVMSPLINE hdMSPLine
|
|
)
|
|
{
|
|
DBGOUT((TRCE, "TSPI_lineCloseMSPInstance, hdMSPLine %p", hdMSPLine));
|
|
DBGOUT((TRCE, "TSPI_lineCloseCall succeeded"));
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineDrop(
|
|
DRV_REQUESTID dwRequestID,
|
|
HDRVCALL hdCall,
|
|
LPCSTR lpsUserUserInfo,
|
|
DWORD dwSize
|
|
)
|
|
{
|
|
DBGOUT((TRCE, "TSPI_lineDrop, hdCall %p", hdCall));
|
|
|
|
DWORD dwCall = HandleToUlong(hdCall);
|
|
|
|
EnterCriticalSection(&gCritSec);
|
|
|
|
// check the call handle.
|
|
if (dwCall >= gpCallList.size())
|
|
{
|
|
LeaveCriticalSection(&gCritSec);
|
|
(*glpfnCompletionProc)(dwRequestID, LINEERR_INVALCALLHANDLE);
|
|
|
|
DBGOUT((FAIL, "TSPI_lineDrop invalid call handle %p", hdCall));
|
|
return dwRequestID;
|
|
}
|
|
|
|
CALL *pCall = gpCallList[dwCall];
|
|
if (pCall != NULL)
|
|
{
|
|
pCall->SetCallState(LINECALLSTATE_IDLE, 0);
|
|
pCall->SendMSPStopMessage();
|
|
|
|
DBGOUT((INFO, "call %d state changed to idle", dwCall));
|
|
}
|
|
|
|
LeaveCriticalSection(&gCritSec);
|
|
|
|
(*glpfnCompletionProc)(dwRequestID, 0);
|
|
|
|
DBGOUT((TRCE, "TSPI_lineDrop succeeded"));
|
|
return dwRequestID;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetAddressCaps(
|
|
DWORD dwDeviceID,
|
|
DWORD dwAddressID,
|
|
DWORD dwTSPIVersion,
|
|
DWORD dwExtVersion,
|
|
LPLINEADDRESSCAPS lpAddressCaps
|
|
)
|
|
{
|
|
DBGOUT((TRCE, "TSPI_lineGetAddressCaps"));
|
|
|
|
if (dwDeviceID != gdwLineDeviceIDBase)
|
|
{
|
|
DBGOUT((TRCE, "TSPI_lineGetAddressCaps bad device id: %d", dwDeviceID));
|
|
return LINEERR_BADDEVICEID;
|
|
}
|
|
|
|
// Check the address ID.
|
|
if (dwAddressID != 0)
|
|
{
|
|
DBGOUT((TRCE, "TSPI_lineGetAddressCaps bad address id: %d", dwAddressID));
|
|
return LINEERR_INVALADDRESSID;
|
|
}
|
|
|
|
// load the address name from the string table.
|
|
WCHAR szAddressName[IPCONF_BUFSIZE + 1];
|
|
if (0 == LoadStringW(g_hInstance, IDS_IPCONFADDRESSNAME, szAddressName, IPCONF_BUFSIZE))
|
|
{
|
|
szAddressName[0] = L'\0';
|
|
}
|
|
|
|
DWORD dwAddressSize = (lstrlenW(szAddressName) + 1) * (sizeof WCHAR);
|
|
|
|
lpAddressCaps->dwNeededSize = sizeof(LINEADDRESSCAPS) + dwAddressSize;
|
|
|
|
if (lpAddressCaps->dwTotalSize >= lpAddressCaps->dwNeededSize)
|
|
{
|
|
// Copy the IP address to the end of the structure.
|
|
lpAddressCaps->dwUsedSize = lpAddressCaps->dwNeededSize;
|
|
|
|
lpAddressCaps->dwAddressSize = dwAddressSize;
|
|
lpAddressCaps->dwAddressOffset = sizeof(LINEADDRESSCAPS);
|
|
lstrcpyW ((WCHAR *)(lpAddressCaps + 1), szAddressName);
|
|
}
|
|
else
|
|
{
|
|
lpAddressCaps->dwUsedSize = sizeof(LINEADDRESSCAPS);
|
|
}
|
|
lpAddressCaps->dwLineDeviceID = dwDeviceID;
|
|
lpAddressCaps->dwAddressSharing = LINEADDRESSSHARING_PRIVATE;
|
|
lpAddressCaps->dwCallInfoStates = LINECALLINFOSTATE_MEDIAMODE;
|
|
lpAddressCaps->dwCallerIDFlags =
|
|
lpAddressCaps->dwCalledIDFlags =
|
|
lpAddressCaps->dwConnectedIDFlags =
|
|
lpAddressCaps->dwRedirectionIDFlags =
|
|
lpAddressCaps->dwRedirectingIDFlags = LINECALLPARTYID_UNAVAIL;
|
|
lpAddressCaps->dwCallStates = LINECALLSTATE_IDLE |
|
|
LINECALLSTATE_DIALING |
|
|
LINECALLSTATE_CONNECTED;
|
|
lpAddressCaps->dwDialToneModes = 0;
|
|
lpAddressCaps->dwBusyModes = 0;
|
|
lpAddressCaps->dwSpecialInfo = 0;
|
|
lpAddressCaps->dwDisconnectModes = LINEDISCONNECTMODE_NORMAL |
|
|
LINEDISCONNECTMODE_UNAVAIL;
|
|
lpAddressCaps->dwMaxNumActiveCalls = MAXCALLSPERADDRESS;
|
|
lpAddressCaps->dwAddrCapFlags = LINEADDRCAPFLAGS_DIALED |
|
|
LINEADDRCAPFLAGS_ORIGOFFHOOK;
|
|
|
|
lpAddressCaps->dwCallFeatures = LINECALLFEATURE_DROP |
|
|
LINECALLFEATURE_SETQOS;
|
|
|
|
lpAddressCaps->dwAddressFeatures = LINEADDRFEATURE_MAKECALL;
|
|
|
|
DBGOUT((TRCE, "TSPI_lineGetAddressCaps succeeded."));
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetAddressID(
|
|
HDRVLINE hdLine,
|
|
LPDWORD lpdwAddressID,
|
|
DWORD dwAddressMode,
|
|
LPCWSTR lpsAddress,
|
|
DWORD dwSize
|
|
)
|
|
{
|
|
DBGOUT((TRCE, "TSPI_lineGetAddressID htLine:%p", hdLine));
|
|
*lpdwAddressID = 0;
|
|
DBGOUT((TRCE, "TSPI_lineGetAddressID succeeded."));
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetAddressStatus(
|
|
HDRVLINE hdLine,
|
|
DWORD dwAddressID,
|
|
LPLINEADDRESSSTATUS lpAddressStatus
|
|
)
|
|
{
|
|
DBGOUT((TRCE, "TSPI_lineGetAddressStatus htLine:%p", hdLine));
|
|
|
|
if (HandleToUlong(hdLine) != IPCONF_LINE_HANDLE)
|
|
{
|
|
DBGOUT((FAIL, "TSPI_lineGetAddressStatus htLine:%p", hdLine));
|
|
return LINEERR_INVALLINEHANDLE;
|
|
}
|
|
|
|
lpAddressStatus->dwNeededSize =
|
|
lpAddressStatus->dwUsedSize = sizeof(LINEADDRESSSTATUS);
|
|
|
|
EnterCriticalSection(&gCritSec);
|
|
|
|
lpAddressStatus->dwNumActiveCalls = gLine.dwNumCalls;
|
|
|
|
LeaveCriticalSection(&gCritSec);
|
|
|
|
lpAddressStatus->dwAddressFeatures = LINEADDRFEATURE_MAKECALL;
|
|
|
|
DBGOUT((TRCE, "TSPI_lineGetAddressStatus succeeded."));
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetCallAddressID(
|
|
HDRVCALL hdCall,
|
|
LPDWORD lpdwAddressID
|
|
)
|
|
{
|
|
DBGOUT((TRCE, "TSPI_lineGetCallAddressID hdCall %p", hdCall));
|
|
//
|
|
// We only support 1 address (id=0) per line
|
|
//
|
|
*lpdwAddressID = 0;
|
|
|
|
DBGOUT((TRCE, "TSPI_lineGetCallAddressID succeeded."));
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetCallInfo(
|
|
HDRVCALL hdCall,
|
|
LPLINECALLINFO lpLineInfo
|
|
)
|
|
{
|
|
DBGOUT((TRCE, "TSPI_lineGetCallInfo hdCall %p", hdCall));
|
|
|
|
DWORD dwCall = HandleToUlong(hdCall);
|
|
|
|
EnterCriticalSection(&gCritSec);
|
|
|
|
if (dwCall >= gpCallList.size())
|
|
{
|
|
LeaveCriticalSection(&gCritSec);
|
|
|
|
DBGOUT((FAIL, "TSPI_lineGetCallInfo bad call handle %p", hdCall));
|
|
return LINEERR_INVALCALLHANDLE;
|
|
}
|
|
|
|
// get the call object.
|
|
CALL *pCall = gpCallList[dwCall];
|
|
if (pCall == NULL)
|
|
{
|
|
LeaveCriticalSection(&gCritSec);
|
|
DBGOUT((FAIL, "TSPI_lineGetCallInfo bad call handle %p", hdCall));
|
|
return LINEERR_INVALCALLHANDLE;
|
|
}
|
|
|
|
lpLineInfo->dwMediaMode = pCall->dwMediaMode();
|
|
LeaveCriticalSection(&gCritSec);
|
|
|
|
lpLineInfo->dwLineDeviceID = gLine.dwDeviceID;
|
|
lpLineInfo->dwAddressID = 0; // There is only on address per line.
|
|
|
|
lpLineInfo->dwBearerMode = IPCONF_BEARERMODES;
|
|
lpLineInfo->dwCallStates = LINECALLSTATE_IDLE |
|
|
LINECALLSTATE_DIALING |
|
|
LINECALLSTATE_CONNECTED;
|
|
lpLineInfo->dwOrigin = LINECALLORIGIN_OUTBOUND;
|
|
lpLineInfo->dwReason = LINECALLREASON_DIRECT;
|
|
|
|
lpLineInfo->dwCallerIDFlags =
|
|
lpLineInfo->dwCalledIDFlags =
|
|
lpLineInfo->dwConnectedIDFlags =
|
|
lpLineInfo->dwRedirectionIDFlags =
|
|
lpLineInfo->dwRedirectingIDFlags = LINECALLPARTYID_UNAVAIL;
|
|
|
|
DBGOUT((TRCE, "TSPI_lineGetCallInfo succeeded."));
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetCallStatus(
|
|
HDRVCALL hdCall,
|
|
LPLINECALLSTATUS lpLineStatus
|
|
)
|
|
{
|
|
DBGOUT((TRCE, "TSPI_lineGetCallStatus hdCall %p", hdCall));
|
|
|
|
DWORD dwCall = HandleToUlong(hdCall);
|
|
|
|
EnterCriticalSection(&gCritSec);
|
|
|
|
// check the call handle.
|
|
if (dwCall >= gpCallList.size())
|
|
{
|
|
LeaveCriticalSection(&gCritSec);
|
|
DBGOUT((TRCE, "TSPI_lineGetCallStatus bad call handle %p", hdCall));
|
|
return LINEERR_INVALCALLHANDLE;
|
|
}
|
|
|
|
lpLineStatus->dwNeededSize =
|
|
lpLineStatus->dwUsedSize = sizeof(LINECALLSTATUS);
|
|
|
|
lpLineStatus->dwCallState = gpCallList[dwCall]->dwState();
|
|
if (lpLineStatus->dwCallState != LINECALLSTATE_IDLE)
|
|
{
|
|
lpLineStatus->dwCallFeatures = LINECALLFEATURE_DROP |
|
|
LINECALLFEATURE_SETQOS;
|
|
}
|
|
LeaveCriticalSection(&gCritSec);
|
|
|
|
DBGOUT((TRCE, "TSPI_lineGetCallStatus succeeded."));
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetDevCaps(
|
|
DWORD dwDeviceID,
|
|
DWORD dwTSPIVersion,
|
|
DWORD dwExtVersion,
|
|
LPLINEDEVCAPS lpLineDevCaps
|
|
)
|
|
{
|
|
DBGOUT((TRCE, "TSPI_lineGetDevCaps"));
|
|
|
|
if (dwDeviceID != gdwLineDeviceIDBase)
|
|
{
|
|
DBGOUT((FAIL, "TSPI_lineGetDevCaps bad device id %d", dwDeviceID));
|
|
return LINEERR_BADDEVICEID;
|
|
}
|
|
|
|
DWORD dwProviderInfoSize;
|
|
DWORD dwLineNameSize;
|
|
DWORD dwDevSpecificSize;
|
|
DWORD dwOffset;
|
|
|
|
// load the name of the service provider from the string table.
|
|
WCHAR szProviderInfo[IPCONF_BUFSIZE + 1];
|
|
if (0 == LoadStringW(g_hInstance, IDS_IPCONFPROVIDERNAME, szProviderInfo, IPCONF_BUFSIZE))
|
|
{
|
|
szProviderInfo[0] = L'\0';
|
|
}
|
|
|
|
dwProviderInfoSize = (lstrlenW(szProviderInfo) + 1) * sizeof(WCHAR);
|
|
|
|
// load the line name format from the string table and print the line name.
|
|
WCHAR szLineName[IPCONF_BUFSIZE + 1];
|
|
if (0 == LoadStringW(g_hInstance, IDS_IPCONFLINENAME, szLineName, IPCONF_BUFSIZE))
|
|
{
|
|
szLineName[0] = L'\0';
|
|
}
|
|
|
|
dwLineNameSize = (lstrlenW(szLineName) + 1) * (sizeof WCHAR);
|
|
|
|
lpLineDevCaps->dwNeededSize = sizeof (LINEDEVCAPS)
|
|
+ dwProviderInfoSize
|
|
+ dwLineNameSize;
|
|
|
|
if (lpLineDevCaps->dwTotalSize >= lpLineDevCaps->dwNeededSize)
|
|
{
|
|
lpLineDevCaps->dwUsedSize = lpLineDevCaps->dwNeededSize;
|
|
|
|
CHAR *pChar;
|
|
|
|
pChar = (CHAR *)(lpLineDevCaps + 1);
|
|
dwOffset = sizeof(LINEDEVCAPS);
|
|
|
|
// fill in the provider info.
|
|
lpLineDevCaps->dwProviderInfoSize = dwProviderInfoSize;
|
|
lpLineDevCaps->dwProviderInfoOffset = dwOffset;
|
|
lstrcpyW ((WCHAR *)pChar, szProviderInfo);
|
|
|
|
pChar += dwProviderInfoSize;
|
|
dwOffset += dwProviderInfoSize;
|
|
|
|
// fill in the name of the line.
|
|
lpLineDevCaps->dwLineNameSize = dwLineNameSize;
|
|
lpLineDevCaps->dwLineNameOffset = dwOffset;
|
|
lstrcpyW ((WCHAR *)pChar, szLineName);
|
|
}
|
|
else
|
|
{
|
|
lpLineDevCaps->dwUsedSize = sizeof(LINEDEVCAPS);
|
|
}
|
|
|
|
// We don't have really "Permanent" line ids. So just fake one here.
|
|
lpLineDevCaps->dwPermanentLineID =
|
|
((gdwPermanentProviderID & 0xffff) << 16) |
|
|
((dwDeviceID - gdwLineDeviceIDBase) & 0xffff);
|
|
|
|
CopyMemory(
|
|
&(lpLineDevCaps->PermanentLineGuid),
|
|
&GUID_LINE,
|
|
sizeof(GUID)
|
|
);
|
|
|
|
lpLineDevCaps->PermanentLineGuid.Data1 += dwDeviceID - gdwLineDeviceIDBase;
|
|
|
|
lpLineDevCaps->dwStringFormat = STRINGFORMAT_UNICODE;
|
|
lpLineDevCaps->dwAddressModes = IPCONF_ADDRESSMODES;
|
|
lpLineDevCaps->dwNumAddresses = IPCONF_NUMADDRESSESPERLINE;
|
|
lpLineDevCaps->dwBearerModes = IPCONF_BEARERMODES;
|
|
lpLineDevCaps->dwMediaModes = IPCONF_MEDIAMODES;
|
|
lpLineDevCaps->dwMaxRate = (1 << 20);
|
|
lpLineDevCaps->dwAddressTypes = LINEADDRESSTYPE_SDP;
|
|
lpLineDevCaps->dwDevCapFlags =
|
|
LINEDEVCAPFLAGS_CLOSEDROP
|
|
| LINEDEVCAPFLAGS_MSP;
|
|
|
|
lpLineDevCaps->dwMaxNumActiveCalls =
|
|
MAXCALLSPERADDRESS * IPCONF_NUMADDRESSESPERLINE;
|
|
lpLineDevCaps->dwRingModes = 0;
|
|
lpLineDevCaps->dwLineFeatures = LINEFEATURE_MAKECALL;
|
|
|
|
CopyMemory(
|
|
&(lpLineDevCaps->ProtocolGuid),
|
|
&TAPIPROTOCOL_Multicast,
|
|
sizeof(GUID)
|
|
);
|
|
|
|
DBGOUT((TRCE, "TSPI_lineGetDevCaps succeeded."));
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetIcon(
|
|
DWORD dwDeviceID,
|
|
LPCWSTR lpgszDeviceClass,
|
|
LPHICON lphIcon
|
|
)
|
|
{
|
|
DBGOUT((TRCE, "TSPI_lineGetIcon:"));
|
|
return LINEERR_OPERATIONUNAVAIL;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetID(
|
|
HDRVLINE hdLine,
|
|
DWORD dwAddressID,
|
|
HDRVCALL hdCall,
|
|
DWORD dwSelect,
|
|
LPVARSTRING lpDeviceID,
|
|
LPCWSTR lpgszDeviceClass,
|
|
HANDLE hTargetProcess
|
|
)
|
|
{
|
|
DBGOUT((TRCE, "TSPI_lineGetID:"));
|
|
return LINEERR_OPERATIONUNAVAIL;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetLineDevStatus(
|
|
HDRVLINE hdLine,
|
|
LPLINEDEVSTATUS lpLineDevStatus
|
|
)
|
|
{
|
|
DBGOUT((TRCE, "TSPI_lineGetLineDevStatus %p", hdLine));
|
|
|
|
if (HandleToUlong(hdLine) != IPCONF_LINE_HANDLE)
|
|
{
|
|
DBGOUT((FAIL, "TSPI_lineGetLineDevStatus bad line handle %p", hdLine));
|
|
return LINEERR_INVALLINEHANDLE;
|
|
}
|
|
|
|
lpLineDevStatus->dwUsedSize =
|
|
lpLineDevStatus->dwNeededSize = sizeof (LINEDEVSTATUS);
|
|
|
|
EnterCriticalSection(&gCritSec);
|
|
lpLineDevStatus->dwNumActiveCalls = gLine.dwNumCalls;
|
|
LeaveCriticalSection(&gCritSec);
|
|
|
|
lpLineDevStatus->dwLineFeatures = LINEFEATURE_MAKECALL;
|
|
lpLineDevStatus->dwDevStatusFlags = LINEDEVSTATUSFLAGS_CONNECTED |
|
|
LINEDEVSTATUSFLAGS_INSERVICE;
|
|
|
|
DBGOUT((TRCE, "TSPI_lineGetLineDevStatus succeeded"));
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetNumAddressIDs(
|
|
HDRVLINE hdLine,
|
|
LPDWORD lpdwNumAddressIDs
|
|
)
|
|
{
|
|
DBGOUT((TRCE, "TSPI_lineGetNumAddressIDs"));
|
|
|
|
*lpdwNumAddressIDs = IPCONF_NUMADDRESSESPERLINE;
|
|
|
|
DBGOUT((TRCE, "TSPI_lineGetNumAddressIDs succeeded."));
|
|
return NOERROR;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineMakeCall(
|
|
DRV_REQUESTID dwRequestID,
|
|
HDRVLINE hdLine,
|
|
HTAPICALL htCall,
|
|
LPHDRVCALL lphdCall,
|
|
LPCWSTR lpszDestAddress,
|
|
DWORD dwCountryCode,
|
|
LPLINECALLPARAMS const lpCallParams
|
|
)
|
|
{
|
|
DBGOUT((TRCE, "TSPI_lineMakeCall hdLine %p, htCall %p",
|
|
hdLine, htCall));
|
|
|
|
// check the line handle.
|
|
if (HandleToUlong(hdLine) != IPCONF_LINE_HANDLE)
|
|
{
|
|
DBGOUT((FAIL, "TSPI_lineMakeCall Bad line handle %p", hdLine));
|
|
return LINEERR_INVALLINEHANDLE;
|
|
}
|
|
|
|
LONG lResult;
|
|
if ((lResult = CheckCallParams(lpCallParams)) != NOERROR)
|
|
{
|
|
DBGOUT((FAIL, "TSPI_lineMakeCall Bad call params"));
|
|
return lResult;
|
|
}
|
|
|
|
// check the destination address.
|
|
if (lpszDestAddress == NULL || lstrlenW(lpszDestAddress) == 0)
|
|
{
|
|
DBGOUT((FAIL, "TSPI_lineMakeCall invalid address."));
|
|
return LINEERR_INVALADDRESS;
|
|
}
|
|
|
|
DBGOUT((TRCE, "TSPI_lineMakeCall making call to %ws", lpszDestAddress));
|
|
|
|
// check the line handle.
|
|
EnterCriticalSection(&gCritSec);
|
|
|
|
// create a call object.
|
|
CALL * pCall = (CALL *)MemAlloc(sizeof(CALL));
|
|
|
|
if (pCall == NULL)
|
|
{
|
|
LeaveCriticalSection(&gCritSec);
|
|
|
|
DBGOUT((FAIL, "out of memory for a new call"));
|
|
return LINEERR_NOMEM;
|
|
}
|
|
|
|
if (pCall->Init(
|
|
htCall,
|
|
lpCallParams
|
|
) != NOERROR)
|
|
{
|
|
MemFree(pCall);
|
|
LeaveCriticalSection(&gCritSec);
|
|
|
|
DBGOUT((FAIL, "out of memory in init a new call"));
|
|
return LINEERR_NOMEM;
|
|
}
|
|
|
|
// add the call into the call list.
|
|
DWORD hdCall;
|
|
if (!FindFreeCallSlot(hdCall))
|
|
{
|
|
LeaveCriticalSection(&gCritSec);
|
|
MemFree(pCall);
|
|
|
|
DBGOUT((FAIL, "out of memory finding a new slot"));
|
|
return LINEERR_NOMEM;
|
|
}
|
|
|
|
gpCallList[hdCall] = pCall;
|
|
|
|
// Increament the call count for the line and the provider.
|
|
gLine.dwNumCalls ++;
|
|
|
|
gdwNumCallsInUse ++;
|
|
|
|
// Complete the request and set the initial call state.
|
|
(*glpfnCompletionProc)(dwRequestID, lResult);
|
|
|
|
*lphdCall = (HDRVCALL)(hdCall);
|
|
|
|
// Send the MSP a message about this call. It has the SDP in it.
|
|
lResult = pCall->SendMSPStartMessage(lpszDestAddress);
|
|
|
|
if (lResult == NOERROR)
|
|
{
|
|
// Set the call state to dialing.
|
|
pCall->SetCallState(
|
|
LINECALLSTATE_DIALING,
|
|
0
|
|
);
|
|
DBGOUT((INFO, "call %d state changed to dialing", hdCall));
|
|
}
|
|
else
|
|
{
|
|
DBGOUT((FAIL, "send MSP message failed, err:%x", lResult));
|
|
|
|
// Set the call state to idel.
|
|
pCall->SetCallState(
|
|
LINECALLSTATE_DISCONNECTED,
|
|
LINEDISCONNECTMODE_UNREACHABLE
|
|
);
|
|
DBGOUT((INFO, "call %d state changed to disconnected", hdCall));
|
|
}
|
|
|
|
LeaveCriticalSection(&gCritSec);
|
|
|
|
DBGOUT((TRCE, "TSPI_lineMakeCall succeeded."));
|
|
return dwRequestID;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineMSPIdentify(
|
|
DWORD dwDeviceID,
|
|
GUID * pCLSID
|
|
)
|
|
{
|
|
DBGOUT((TRCE, "TSPI_lineMSPIdentify dwDeviceID %d", dwDeviceID));
|
|
|
|
*pCLSID = CLSID_CONFMSP;
|
|
|
|
DBGOUT((TRCE, "TSPI_lineMSPIdentify succeeded."));
|
|
return NOERROR;
|
|
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineNegotiateTSPIVersion(
|
|
DWORD dwDeviceID,
|
|
DWORD dwLowVersion,
|
|
DWORD dwHighVersion,
|
|
LPDWORD lpdwTSPIVersion
|
|
)
|
|
{
|
|
DBGOUT((TRCE, "TSPI_lineNegotiateTSPIVersion dwDeviceID %d", dwDeviceID));
|
|
|
|
LONG lResult = 0;
|
|
|
|
if (TAPI_CURRENT_VERSION <= dwHighVersion
|
|
&& TAPI_CURRENT_VERSION >= dwLowVersion)
|
|
{
|
|
*lpdwTSPIVersion = TAPI_CURRENT_VERSION;
|
|
}
|
|
else
|
|
{
|
|
DBGOUT((FAIL, "TSPI_lineNegotiateTSPIVersion failed."));
|
|
|
|
return LINEERR_INCOMPATIBLEAPIVERSION;
|
|
}
|
|
|
|
DBGOUT((TRCE, "TSPI_lineNegotiateTSPIVersion succeeded. version %x",
|
|
TAPI_CURRENT_VERSION));
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineOpen(
|
|
DWORD dwDeviceID,
|
|
HTAPILINE htLine,
|
|
LPHDRVLINE lphdLine,
|
|
DWORD dwTSPIVersion,
|
|
LINEEVENT lpfnEventProc
|
|
)
|
|
{
|
|
DBGOUT((TRCE, "TSPI_lineOpen dwDiviceID %d", dwDeviceID));
|
|
|
|
LONG lResult;
|
|
|
|
if (dwDeviceID != gdwLineDeviceIDBase)
|
|
{
|
|
DBGOUT((FAIL, "TSPI_lineOpen bad DiviceID %d", dwDeviceID));
|
|
return LINEERR_BADDEVICEID;
|
|
}
|
|
|
|
EnterCriticalSection(&gCritSec);
|
|
|
|
lResult = LINEERR_RESOURCEUNAVAIL;
|
|
|
|
if (!gLine.bOpened)
|
|
{
|
|
*lphdLine = (HDRVLINE)IPCONF_LINE_HANDLE;
|
|
gLine.bOpened = TRUE;
|
|
gLine.htLine = htLine;
|
|
gLine.dwNumCalls = 0;
|
|
lResult = 0;
|
|
}
|
|
LeaveCriticalSection(&gCritSec);
|
|
|
|
DBGOUT((TRCE, "TSPI_lineOpen returns:%d", lResult));
|
|
|
|
return lResult;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineReceiveMSPData(
|
|
HDRVLINE hdLine,
|
|
HDRVCALL hdCall, // can be NULL
|
|
HDRVMSPLINE hdMSPLine, // from lineCreateMSPInstance
|
|
LPBYTE pBuffer,
|
|
DWORD dwSize
|
|
)
|
|
{
|
|
DBGOUT((TRCE, "TSPI_lineReceiveMSPData hdLine %p", hdLine));
|
|
|
|
if ((dwSize == 0) || IsBadReadPtr(pBuffer, dwSize))
|
|
{
|
|
DBGOUT((FAIL, "TSPI_lineReceiveMSPData bad puffer"));
|
|
return LINEERR_INVALPOINTER;
|
|
}
|
|
|
|
DWORD dwCall = HandleToUlong(hdCall);
|
|
|
|
EnterCriticalSection(&gCritSec);
|
|
|
|
// check the call handle.
|
|
if (dwCall >= gpCallList.size() || gpCallList[dwCall] == NULL)
|
|
{
|
|
LeaveCriticalSection(&gCritSec);
|
|
|
|
DBGOUT((FAIL, "TSPI_lineReceiveMSPData invalide call handle: %x",
|
|
dwCall));
|
|
|
|
return LINEERR_INVALCALLHANDLE;
|
|
}
|
|
|
|
MSG_TSPMSPDATA *pData = (MSG_TSPMSPDATA *)pBuffer;
|
|
|
|
long lResult = NOERROR;
|
|
|
|
switch (pData->command)
|
|
{
|
|
case CALL_CONNECTED:
|
|
// Set the call state to connected.
|
|
gpCallList[dwCall]->SetCallState(
|
|
LINECALLSTATE_CONNECTED,
|
|
LINECONNECTEDMODE_ACTIVE
|
|
);
|
|
DBGOUT((INFO, "call %d state changed to connected", dwCall));
|
|
break;
|
|
|
|
case CALL_DISCONNECTED:
|
|
// Set the call state to idel.
|
|
gpCallList[dwCall]->SetCallState(
|
|
LINECALLSTATE_DISCONNECTED,
|
|
LINEDISCONNECTMODE_UNREACHABLE
|
|
);
|
|
DBGOUT((INFO, "call %d state changed to disconnected", dwCall));
|
|
break;
|
|
|
|
case CALL_QOS_EVENT:
|
|
(*glpfnLineEventProc)(
|
|
gLine.htLine,
|
|
gpCallList[dwCall]->htCall(),
|
|
LINE_QOSINFO,
|
|
pData->QosEvent.dwEvent,
|
|
pData->QosEvent.dwMediaMode,
|
|
0
|
|
);
|
|
break;
|
|
|
|
default:
|
|
DBGOUT((FAIL, "invalide command: %x", pData->command));
|
|
lResult = LINEERR_OPERATIONFAILED;
|
|
}
|
|
|
|
LeaveCriticalSection(&gCritSec);
|
|
|
|
DBGOUT((TRCE, "TSPI_lineReceiveMSPData returns:%d", lResult));
|
|
return lResult;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineSetDefaultMediaDetection(
|
|
HDRVLINE hdLine,
|
|
DWORD dwMediaModes
|
|
)
|
|
{
|
|
DBGOUT((TRCE, "TSPI_lineSetDefaultMediaDetection:"));
|
|
return LINEERR_OPERATIONUNAVAIL;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineSetMediaMode(
|
|
HDRVCALL hdCall,
|
|
DWORD dwMediaMode
|
|
)
|
|
{
|
|
DBGOUT((TRCE, "TSPI_lineSetMediaMode:"));
|
|
return LINEERR_OPERATIONUNAVAIL;
|
|
}
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// TSPI_providerXxx functions //
|
|
// //
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
#if 0 // we dont' need the user name anymore.
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_providerCheckForNewUser(
|
|
IN DWORD dwPermanentProviderID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Once a line is opened, it will never be opened twice, even when the user
|
|
logs off and logs on. So we need a way to find out when the user changes.
|
|
That's why this function is added. It only work for single user.
|
|
|
|
Everytime a new app starts using tapi, tapisrv will call this function.
|
|
We need to check to see if the user has changed and register the new user
|
|
in the ILS server.
|
|
|
|
Arguments:
|
|
|
|
NONE.
|
|
|
|
Return Values:
|
|
|
|
NOERROR always.
|
|
|
|
--*/
|
|
{
|
|
DBGOUT((TRCE, "TSPI_providerCheckForNewUser"));
|
|
|
|
DWORD dwUserNameLen = MAXUSERNAMELEN;
|
|
CHAR szNewUserName[MAXUSERNAMELEN + 1];
|
|
|
|
UNREFERENCED_PARAMETER(dwPermanentProviderID ); // It is me.
|
|
|
|
// switch in user's context
|
|
RpcImpersonateClient(0);
|
|
|
|
// determine name of current user
|
|
GetUserNameA(szNewUserName, &dwUserNameLen);
|
|
|
|
// switch back
|
|
RpcRevertToSelf();
|
|
|
|
EnterCriticalSection(&gCritSec);
|
|
|
|
lstrcpy(gszUserName, szNewUserName);
|
|
|
|
LeaveCriticalSection(&gCritSec);
|
|
|
|
DBGOUT((TRCE, "TSPI_providerCheckForNewUser succeeded, new user :%ws",
|
|
gszUserName ));
|
|
|
|
return NOERROR;
|
|
}
|
|
#endif
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_providerEnumDevices(
|
|
DWORD dwPermanentProviderID,
|
|
LPDWORD lpdwNumLines,
|
|
LPDWORD lpdwNumPhones,
|
|
HPROVIDER hProvider,
|
|
LINEEVENT lpfnLineCreateProc,
|
|
PHONEEVENT lpfnPhoneCreateProc
|
|
)
|
|
{
|
|
DBGOUT((TRCE, "TSPI_providerEnumDevices"));
|
|
|
|
EnterCriticalSection(&gCritSec);
|
|
|
|
*lpdwNumLines = IPCONF_NUMLINES;
|
|
*lpdwNumPhones = IPCONF_NUMPHONES;
|
|
|
|
// save provider handle
|
|
ghProvider = hProvider;
|
|
|
|
// save the callback used in creating new lines.
|
|
glpfnLineEventProc = lpfnLineCreateProc;
|
|
|
|
LeaveCriticalSection(&gCritSec);
|
|
|
|
DBGOUT((TRCE, "TSPI_providerEnumDevices succeeded."));
|
|
return NOERROR;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_providerInit(
|
|
DWORD dwTSPIVersion,
|
|
DWORD dwPermanentProviderID,
|
|
DWORD dwLineDeviceIDBase,
|
|
DWORD dwPhoneDeviceIDBase,
|
|
DWORD dwNumLines,
|
|
DWORD dwNumPhones,
|
|
ASYNC_COMPLETION lpfnCompletionProc,
|
|
LPDWORD lpdwTSPIOptions
|
|
)
|
|
{
|
|
DBGOUT((TRCE, "TSPI_providerInit"));
|
|
|
|
LONG hr = LINEERR_OPERATIONFAILED;
|
|
|
|
EnterCriticalSection(&gCritSec);
|
|
|
|
glpfnCompletionProc = lpfnCompletionProc;
|
|
gdwLineDeviceIDBase = dwLineDeviceIDBase;
|
|
gdwPermanentProviderID = dwPermanentProviderID;
|
|
|
|
gLine.dwDeviceID = gdwLineDeviceIDBase;
|
|
gLine.bOpened = FALSE;
|
|
|
|
LeaveCriticalSection(&gCritSec);
|
|
|
|
DBGOUT((TRCE, "TSPI_providerInit succeeded."));
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_providerInstall(
|
|
HWND hwndOwner,
|
|
DWORD dwPermanentProviderID
|
|
)
|
|
{
|
|
DBGOUT((TRCE, "TSPI_providerInstall:"));
|
|
//
|
|
// Although this func is never called by TAPI v2.0, we export
|
|
// it so that the Telephony Control Panel Applet knows that it
|
|
// can add this provider via lineAddProvider(), otherwise
|
|
// Telephon.cpl will not consider it installable
|
|
//
|
|
//
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_providerRemove(
|
|
HWND hwndOwner,
|
|
DWORD dwPermanentProviderID
|
|
)
|
|
{
|
|
//
|
|
// Although this func is never called by TAPI v2.0, we export
|
|
// it so that the Telephony Control Panel Applet knows that it
|
|
// can configure this provider via lineConfigProvider(),
|
|
// otherwise Telephon.cpl will not consider it configurable
|
|
//
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_providerShutdown(
|
|
DWORD dwTSPIVersion,
|
|
DWORD dwPermanentProviderID
|
|
)
|
|
{
|
|
DBGOUT((TRCE, "TSPI_providerShutdown."));
|
|
|
|
EnterCriticalSection(&gCritSec);
|
|
|
|
// Clean up all the open calls when this provider is shutted down.
|
|
for (DWORD i = 0; i < gpCallList.size(); i++)
|
|
{
|
|
FreeCall(i);
|
|
}
|
|
|
|
LeaveCriticalSection(&gCritSec);
|
|
|
|
DBGOUT((TRCE, "TSPI_providerShutdown succeeded."));
|
|
return NOERROR;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_providerUIIdentify(
|
|
LPWSTR lpszUIDLLName
|
|
)
|
|
{
|
|
lstrcpyW(lpszUIDLLName, gszUIDLLName);
|
|
return NOERROR;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TUISPI_providerRemove(
|
|
TUISPIDLLCALLBACK lpfnUIDLLCallback,
|
|
HWND hwndOwner,
|
|
DWORD dwPermanentProviderID
|
|
)
|
|
{
|
|
DBGOUT((TRCE, "TUISPI_providerInstall"));
|
|
return NOERROR;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TUISPI_providerInstall(
|
|
TUISPIDLLCALLBACK lpfnUIDLLCallback,
|
|
HWND hwndOwner,
|
|
DWORD dwPermanentProviderID
|
|
)
|
|
{
|
|
DBGOUT((TRCE, "TUISPI_providerInstall"));
|
|
|
|
const CHAR szKey[] =
|
|
"Software\\Microsoft\\Windows\\CurrentVersion\\Telephony\\Providers";
|
|
|
|
HKEY hKey;
|
|
DWORD dwDataSize, dwDataType;
|
|
DWORD dwNumProviders;
|
|
|
|
CHAR szName[IPCONF_BUFSIZE + 1], szPath[IPCONF_BUFSIZE + 1];
|
|
|
|
// open the providers key
|
|
if (RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
szKey,
|
|
0,
|
|
KEY_READ,
|
|
&hKey
|
|
) == ERROR_SUCCESS)
|
|
{
|
|
// first get the number of providers installed.
|
|
dwDataSize = sizeof(DWORD);
|
|
if (RegQueryValueEx(
|
|
hKey,
|
|
"NumProviders",
|
|
0,
|
|
&dwDataType,
|
|
(LPBYTE) &dwNumProviders,
|
|
&dwDataSize
|
|
) != ERROR_SUCCESS)
|
|
{
|
|
RegCloseKey (hKey);
|
|
return LINEERR_UNINITIALIZED;
|
|
}
|
|
|
|
// then go through the list of providers to see if
|
|
// we are already installed.
|
|
for (DWORD i = 0; i < dwNumProviders; i ++)
|
|
{
|
|
wsprintf(szName, "ProviderFileName%d", i);
|
|
dwDataSize = sizeof(szPath);
|
|
if (RegQueryValueEx(
|
|
hKey,
|
|
szName,
|
|
0,
|
|
&dwDataType,
|
|
(LPBYTE) &szPath,
|
|
&dwDataSize
|
|
) != ERROR_SUCCESS)
|
|
{
|
|
RegCloseKey (hKey);
|
|
return LINEERR_UNINITIALIZED;
|
|
}
|
|
|
|
_strupr(szPath);
|
|
|
|
if (strstr(szPath, "IPCONF") != NULL)
|
|
{
|
|
RegCloseKey (hKey);
|
|
|
|
// found, we don't want to be installed twice.
|
|
return LINEERR_NOMULTIPLEINSTANCE;
|
|
}
|
|
}
|
|
RegCloseKey (hKey);
|
|
return NOERROR;
|
|
}
|
|
|
|
return LINEERR_UNINITIALIZED;
|
|
}
|
|
|