1625 lines
41 KiB
C++
1625 lines
41 KiB
C++
/*++
|
||
|
||
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;
|
||
}
|
||
|