|
|
/*++ BUILD Version: 0000 // Increment this if a change has global effects
Copyright (c) 1995-1998 Microsoft Corporation
Module Name:
phone.c
Abstract:
Src module for tapi server phone funcs
Author:
Dan Knudson (DanKn) 01-Apr-1995
Revision History:
--*/
#include "windows.h"
#include "assert.h"
#include "tapi.h"
#include "tspi.h"
#include "utils.h"
#include "client.h"
#include "server.h"
#include "phone.h"
#include "tapihndl.h"
#include "private.h"
#include "string.h"
extern TAPIGLOBALS TapiGlobals;
extern PTPROVIDER pRemoteSP;
extern CRITICAL_SECTION gSafeMutexCritSec;
extern HANDLE ghHandleTable;
extern BOOL gbQueueSPEvents; extern BOOL gbNTServer; extern BOOL gbServerInited;
#if DBG
char * PASCAL MapResultCodeToText( LONG lResult, char *pszResult ); #endif
void DestroytPhoneClient( HPHONE hPhone );
BOOL IsAPIVersionInRange( DWORD dwAPIVersion, DWORD dwSPIVersion );
LONG InitTapiStruct( LPVOID pTapiStruct, DWORD dwTotalSize, DWORD dwFixedSize, BOOL bZeroInit );
void PASCAL SendMsgToPhoneClients( PTPHONE ptPhone, PTPHONECLIENT ptPhoneClienttoExclude, DWORD Msg, DWORD Param1, DWORD Param2, DWORD Param3 );
BOOL PASCAL WaitForExclusivetPhoneAccess( PTPHONE ptPhone, HANDLE *phMutex, BOOL *pbDupedMutex, DWORD dwTimeout );
void PASCAL SendReinitMsgToAllXxxApps( void );
PTCLIENT PASCAL WaitForExclusiveClientAccess( PTCLIENT ptClient );
void CALLBACK CompletionProcSP( DWORD dwRequestID, LONG lResult );
void PASCAL SendAMsgToAllPhoneApps( DWORD dwWantVersion, DWORD dwMsg, DWORD Param1, DWORD Param2, DWORD Param3 ); BOOL GetPhonePermanentIdFromDeviceID( PTCLIENT ptClient, DWORD dwDeviceID, LPTAPIPERMANENTID pID );
LONG InitializeClient( PTCLIENT ptClient );
LONG PASCAL GetPhoneClientListFromPhone( PTPHONE ptPhone, PTPOINTERLIST *ppList );
BOOL IsBadStructParam( DWORD dwParamsBufferSize, LPBYTE pDataBuf, DWORD dwXxxOffset );
void CALLBACK PhoneEventProcSP( HTAPIPHONE htPhone, DWORD dwMsg, ULONG_PTR Param1, ULONG_PTR Param2, ULONG_PTR Param3 );
LONG GetPermPhoneIDAndInsertInTable( PTPROVIDER ptProvider, DWORD dwDeviceID, DWORD dwSPIVersion );
LONG AppendNewDeviceInfo ( BOOL bLine, DWORD dwDeviceID );
LONG RemoveDeviceInfoEntry ( BOOL bLine, DWORD dwDeviceID );
LONG PASCAL GetClientList( BOOL bAdminOnly, PTPOINTERLIST *ppList );
PTPHONELOOKUPENTRY GetPhoneLookupEntry( DWORD dwDeviceID ) { DWORD dwDeviceIDBase = 0; PTPHONELOOKUPTABLE pLookupTable = TapiGlobals.pPhoneLookup;
if (dwDeviceID >= TapiGlobals.dwNumPhones) { return ((PTPHONELOOKUPENTRY) NULL); }
while (pLookupTable) { if (dwDeviceID < pLookupTable->dwNumTotalEntries) { return (pLookupTable->aEntries + dwDeviceID); }
dwDeviceID -= pLookupTable->dwNumTotalEntries;
pLookupTable = pLookupTable->pNext; }
return ((PTPHONELOOKUPENTRY) NULL); }
LONG GetPhoneVersions( HPHONE hPhone, LPDWORD lpdwAPIVersion, LPDWORD lpdwSPIVersion ) { LONG lResult; PTPHONECLIENT ptPhoneClient;
if ((ptPhoneClient = ReferenceObject( ghHandleTable, hPhone, TPHONECLIENT_KEY ))) { *lpdwAPIVersion = ptPhoneClient->dwAPIVersion;
try { *lpdwSPIVersion = ptPhoneClient->ptPhone->dwSPIVersion;
lResult = (ptPhoneClient->dwKey == TPHONECLIENT_KEY ? 0 : PHONEERR_INVALPHONEHANDLE); } myexcept { lResult = PHONEERR_INVALPHONEHANDLE; }
DereferenceObject (ghHandleTable, hPhone, 1); } else { lResult = PHONEERR_INVALPHONEHANDLE; }
return lResult; }
BOOL PASCAL IsValidPhoneExtVersion( DWORD dwDeviceID, DWORD dwExtVersion ) { BOOL bResult; PTPHONE ptPhone; PTPROVIDER ptProvider; PTPHONELOOKUPENTRY pLookupEntry;
if (dwExtVersion == 0) { return TRUE; }
if (!(pLookupEntry = GetPhoneLookupEntry (dwDeviceID))) { return FALSE; }
ptPhone = pLookupEntry->ptPhone;
if (ptPhone) { try { if (ptPhone->dwExtVersionCount) { bResult = (dwExtVersion == ptPhone->dwExtVersion ? TRUE : FALSE);
if (ptPhone->dwKey == TPHONE_KEY) { goto IsValidPhoneExtVersion_return; } }
} myexcept { //
// if here the phone was closed, just drop thru to the code below
//
} }
ptProvider = pLookupEntry->ptProvider;
if (ptProvider->apfn[SP_PHONENEGOTIATEEXTVERSION]) { LONG lResult; DWORD dwNegotiatedExtVersion;
lResult = CallSP5( ptProvider->apfn[SP_PHONENEGOTIATEEXTVERSION], "phoneNegotiateExtVersion", SP_FUNC_SYNC, (DWORD) dwDeviceID, (DWORD) pLookupEntry->dwSPIVersion, (DWORD) dwExtVersion, (DWORD) dwExtVersion, (ULONG_PTR) &dwNegotiatedExtVersion );
bResult = ((lResult || !dwNegotiatedExtVersion) ? FALSE : TRUE); } else { bResult = FALSE; }
IsValidPhoneExtVersion_return:
return bResult; }
PTPHONEAPP PASCAL IsValidPhoneApp( HPHONEAPP hPhoneApp, PTCLIENT ptClient ) { PTPHONEAPP ptPhoneApp;
if ((ptPhoneApp = ReferenceObject( ghHandleTable, hPhoneApp, TPHONEAPP_KEY ))) { if (ptPhoneApp->ptClient != ptClient) { ptPhoneApp = NULL; }
DereferenceObject (ghHandleTable, hPhoneApp, 1); }
return ptPhoneApp; }
LONG PASCAL ValidateButtonInfo( LPPHONEBUTTONINFO pButtonInfoApp, LPPHONEBUTTONINFO *ppButtonInfoSP, DWORD dwAPIVersion, DWORD dwSPIVersion ) { //
// This routine checks the fields in a PHONEBUTTONINFO struct,
// looking for invalid bit flags and making sure that the
// various size/offset pairs only reference data within the
// variable-data portion of the structure. Also, if the
// specified SPI version is greater than the API version and
// the fixed structure size differs between the two versions,
// a larger buffer is allocated, the var data is relocated,
// and the sizeof/offset pairs are patched.
//
char szFunc[] = "ValidateButtonInfo";
DWORD dwTotalSize = pButtonInfoApp->dwTotalSize, dwFixedSizeApp, dwFixedSizeSP;
switch (dwAPIVersion) { case TAPI_VERSION1_0:
dwFixedSizeApp = 36; // 9 * sizeof (DWORD)
break;
case TAPI_VERSION1_4: case TAPI_VERSION2_0: case TAPI_VERSION2_1: case TAPI_VERSION2_2: case TAPI_VERSION3_0: case TAPI_VERSION_CURRENT:
dwFixedSizeApp = sizeof (PHONEBUTTONINFO); break;
default:
return PHONEERR_INVALPHONEHANDLE; }
switch (dwSPIVersion) { case TAPI_VERSION1_0:
dwFixedSizeSP = 36; // 9 * sizeof (DWORD)
break;
case TAPI_VERSION1_4: case TAPI_VERSION2_0: case TAPI_VERSION2_1: case TAPI_VERSION2_2: case TAPI_VERSION3_0: case TAPI_VERSION_CURRENT:
dwFixedSizeSP = sizeof (PHONEBUTTONINFO); break;
default:
return PHONEERR_INVALPHONEHANDLE; }
if (dwTotalSize < dwFixedSizeApp) { LOG((TL_TRACE, "%sbad dwTotalSize, x%x (minimum valid size=x%x)", szFunc, dwTotalSize, dwFixedSizeApp ));
return PHONEERR_STRUCTURETOOSMALL; }
if (ISBADSIZEOFFSET( dwTotalSize, dwFixedSizeApp, pButtonInfoApp->dwButtonTextSize, pButtonInfoApp->dwButtonTextOffset, 0, szFunc, "ButtonText" ) ||
ISBADSIZEOFFSET( dwTotalSize, dwFixedSizeApp, pButtonInfoApp->dwDevSpecificSize, pButtonInfoApp->dwDevSpecificOffset, 0, szFunc, "DevSpecific" )) { return PHONEERR_OPERATIONFAILED; }
if (dwAPIVersion < TAPI_VERSION1_4) { goto ValidateButtonInfo_checkFixedSizes; }
ValidateButtonInfo_checkFixedSizes:
if (dwFixedSizeApp < dwFixedSizeSP) { DWORD dwFixedSizeDiff = dwFixedSizeSP - dwFixedSizeApp; LPPHONEBUTTONINFO pButtonInfoSP;
if (!(pButtonInfoSP = ServerAlloc (dwTotalSize + dwFixedSizeDiff))) { return PHONEERR_NOMEM; }
CopyMemory (pButtonInfoSP, pButtonInfoApp, dwFixedSizeApp);
pButtonInfoSP->dwTotalSize = dwTotalSize + dwFixedSizeDiff;
CopyMemory( ((LPBYTE) pButtonInfoSP) + dwFixedSizeSP, ((LPBYTE) pButtonInfoApp) + dwFixedSizeApp, dwTotalSize - dwFixedSizeApp );
pButtonInfoSP->dwButtonTextOffset += dwFixedSizeDiff; pButtonInfoSP->dwDevSpecificOffset += dwFixedSizeDiff;
*ppButtonInfoSP = pButtonInfoSP; } else { *ppButtonInfoSP = pButtonInfoApp; }
//bjm 03/19 - not used - ValidateButtonInfo_return:
return 0; // success
}
BOOL PASCAL WaitForExclusivePhoneClientAccess( PTPHONECLIENT ptPhoneClient ) { //
// Assumes ptXxxClient->hXxx has already been referenced,
// so we can safely access ptXxxClient
//
LOCKTPHONECLIENT (ptPhoneClient);
if (ptPhoneClient->dwKey == TPHONECLIENT_KEY) { return TRUE; }
UNLOCKTPHONECLIENT (ptPhoneClient);
return FALSE; }
void DestroytPhone( PTPHONE ptPhone, BOOL bUnconditional ) { BOOL bCloseMutex; HANDLE hMutex;
LOG((TL_ERROR, "DestroytPhone: enter, ptPhone=x%p", ptPhone));
if (WaitForExclusivetPhoneAccess( ptPhone, &hMutex, &bCloseMutex, INFINITE )) { //
// If the key is bad another thread is in the process of
// destroying this widget, so just release the mutex &
// return. Otherwise, if this is a conditional destroy
// & there are existing clients (which can happen when
// one app is closing the last client just as another app
// is creating one) just release the mutex & return.
// Otherwise, mark the widget as bad and proceed with
// the destroy; also, send CLOSE msgs to all the clients
// (note that we have to do this manually rather than via
// SendMsgToPhoneClients since 1) we don't want to hold the
// mutex when sending msgs [deadlock], and 2) we mark the
// dwKey as invalid)
//
{ BOOL bExit; TPOINTERLIST fastClientList, *pClientList = &fastClientList;
if (ptPhone->dwKey == TPHONE_KEY && (bUnconditional == TRUE || ptPhone->ptPhoneClients == NULL)) { if (GetPhoneClientListFromPhone (ptPhone, &pClientList) != 0) { //
// If here we know there's at least a few entries
// in the fastClientList (DEF_NUM_PTR_LIST_ENTRIES
// to be exact), so we'll just work with that list
// and at least get msgs out to a few clients
//
pClientList = &fastClientList;
fastClientList.dwNumUsedEntries = DEF_NUM_PTR_LIST_ENTRIES; }
ptPhone->dwKey = INVAL_KEY; bExit = FALSE; } else { bExit = TRUE; }
MyReleaseMutex (hMutex, bCloseMutex);
if (bExit) { return; }
if (pClientList->dwNumUsedEntries) { DWORD i; PTCLIENT ptClient; PTPHONECLIENT ptPhoneClient; ASYNCEVENTMSG msg;
ZeroMemory (&msg, sizeof (msg));
msg.TotalSize = sizeof (ASYNCEVENTMSG); msg.Msg = PHONE_CLOSE;
for (i = 0; i < pClientList->dwNumUsedEntries; i++) { ptPhoneClient = (PTPHONECLIENT) pClientList->aEntries[i];
try { msg.InitContext = ptPhoneClient->ptPhoneApp->InitContext; msg.hDevice = ptPhoneClient->hRemotePhone; msg.OpenContext = ptPhoneClient->OpenContext;
ptClient = ptPhoneClient->ptClient;
if (ptPhoneClient->dwKey == TPHONECLIENT_KEY && !FMsgDisabled( ptPhoneClient->ptPhoneApp->dwAPIVersion, ptPhoneClient->adwEventSubMasks, PHONE_CLOSE, 0 )) { WriteEventBuffer (ptClient, &msg); } } myexcept { // do nothing
} } }
if (pClientList != &fastClientList) { ServerFree (pClientList); } }
//
// Destroy all the widget's clients. Note that we want to
// grab the mutex (and we don't have to dup it, since this
// thread will be the one to close it) each time we reference
// the list of clients, since another thread might be
// destroying a client too.
//
{ HPHONE hPhone;
hMutex = ptPhone->hMutex;
destroy_tPhoneClients:
WaitForSingleObject (hMutex, INFINITE);
hPhone = (ptPhone->ptPhoneClients ? ptPhone->ptPhoneClients->hPhone : (HPHONE) 0);
ReleaseMutex (hMutex);
if (hPhone) { DestroytPhoneClient (hPhone); goto destroy_tPhoneClients; } }
//
// Tell the provider to close the widget
//
{ PTPROVIDER ptProvider = ptPhone->ptProvider; PTPHONELOOKUPENTRY pEntry;
pEntry = GetPhoneLookupEntry (ptPhone->dwDeviceID);
if (ptProvider->dwTSPIOptions & LINETSPIOPTION_NONREENTRANT) { WaitForSingleObject (ptProvider->hMutex, INFINITE); }
if (ptProvider->apfn[SP_PHONECLOSE] && pEntry && !pEntry->bRemoved ) { CallSP1( ptProvider->apfn[SP_PHONECLOSE], "phoneClose", SP_FUNC_SYNC, (ULONG_PTR) ptPhone->hdPhone ); }
if (ptProvider->dwTSPIOptions & LINETSPIOPTION_NONREENTRANT) { ReleaseMutex (ptProvider->hMutex); } }
//
// NULLify the ptPhone field in the lookup entry, so POpen will
// know it has to open the SP's phone on the next open request
//
{ PTPHONELOOKUPENTRY pEntry;
pEntry = GetPhoneLookupEntry (ptPhone->dwDeviceID); if (NULL != pEntry) { pEntry->ptPhone = NULL; } }
DereferenceObject (ghHandleTable, ptPhone->hPhone, 1); } }
void DestroytPhoneClient( HPHONE hPhone ) { BOOL bExit = TRUE, bUnlock = FALSE; HANDLE hMutex; PTPHONE ptPhone; PTPHONECLIENT ptPhoneClient;
LOG((TL_TRACE, "DestroytPhoneClient: enter, hPhone=x%x", hPhone));
if (!(ptPhoneClient = ReferenceObject( ghHandleTable, hPhone, TPHONECLIENT_KEY ))) { return; }
//
// If we can get exclusive access to this tPhoneClient then mark
// it (the dwKey) as bad & continue with teardown. Else, another
// thread is already in the process of destroying this tPhoneClient
//
//
if (WaitForExclusivePhoneClientAccess (ptPhoneClient)) { BOOL bSendDevStateMsg = FALSE; DWORD dwParam1, dwParam2;
ptPhoneClient->dwKey = INVAL_KEY;
UNLOCKTPHONECLIENT (ptPhoneClient);
//
// Remove tPhoneClient from tPhoneApp's list. Note that we don't
// have to worry validating the tPhoneApp here, since we know
// it's valid (another thread trying to destroy the tPhoneApp
// will be spinning until the tPhoneClient we're destroying here
// is removed from the tPhoneApp's list)
//
{ PTPHONEAPP ptPhoneApp = (PTPHONEAPP) ptPhoneClient->ptPhoneApp;
LOCKTPHONEAPP (ptPhoneApp);
if (ptPhoneClient->pNextSametPhoneApp) { ptPhoneClient->pNextSametPhoneApp->pPrevSametPhoneApp = ptPhoneClient->pPrevSametPhoneApp; }
if (ptPhoneClient->pPrevSametPhoneApp) { ptPhoneClient->pPrevSametPhoneApp->pNextSametPhoneApp = ptPhoneClient->pNextSametPhoneApp; } else { ptPhoneApp->ptPhoneClients = ptPhoneClient->pNextSametPhoneApp; }
UNLOCKTPHONEAPP (ptPhoneApp); }
//
// Remove tPhoneClient from tPhone's list. Note that we don't
// have to worry about dup-ing the mutex here because we know
// it's valid & won't get closed before we release it.
//
ptPhone = ptPhoneClient->ptPhone;
hMutex = ptPhone->hMutex;
WaitForSingleObject (hMutex, INFINITE);
{ //
// Also check for ext ver stuff
//
if (ptPhoneClient->dwExtVersion) { if ((--ptPhone->dwExtVersionCount) == 0 && ptPhone->ptProvider->apfn[SP_PHONESELECTEXTVERSION]) { CallSP2( ptPhone->ptProvider->apfn[SP_PHONESELECTEXTVERSION], "phoneSelectExtVersion", SP_FUNC_SYNC, (ULONG_PTR) ptPhone->hdPhone, (DWORD) 0 );
ptPhone->dwExtVersion = 0; } } }
if (ptPhoneClient->pNextSametPhone) { ptPhoneClient->pNextSametPhone->pPrevSametPhone = ptPhoneClient->pPrevSametPhone; }
if (ptPhoneClient->pPrevSametPhone) { ptPhoneClient->pPrevSametPhone->pNextSametPhone = ptPhoneClient->pNextSametPhone; } else { ptPhone->ptPhoneClients = ptPhoneClient->pNextSametPhone; }
//
// Decrement tPhone's NumOwners/Monitors as appropriate
//
if (ptPhoneClient->dwPrivilege == PHONEPRIVILEGE_OWNER) { ptPhone->dwNumOwners--; } else { ptPhone->dwNumMonitors--; }
//
//
//
if (ptPhone->dwKey == TPHONE_KEY) { if (ptPhone->ptPhoneClients) { bSendDevStateMsg = TRUE;
dwParam1 = (ptPhoneClient->dwPrivilege == PHONEPRIVILEGE_OWNER ? PHONESTATE_OWNER : PHONESTATE_MONITORS);
dwParam2 = (ptPhoneClient->dwPrivilege == PHONEPRIVILEGE_OWNER ? 0 : ptPhone->dwNumMonitors);
//
// See if we need to reset the status msgs (if so, make
// sure to check/set the busy flag & not to hold the
// mutex while calling down to provider - see comments
// in LSetStatusMessages)
//
if ((ptPhoneClient->dwPhoneStates & ~PHONESTATE_REINIT) || ptPhoneClient->dwButtonModes || ptPhoneClient->dwButtonStates) { DWORD dwUnionPhoneStates = 0, dwUnionButtonModes = 0, dwUnionButtonStates = 0; PTPHONECLIENT ptPC;
while (ptPhone->dwBusy) { BOOL bClosed = TRUE;
ReleaseMutex (hMutex); Sleep (50); WaitForSingleObject (hMutex, INFINITE);
try { if (ptPhone->dwKey == TPHONE_KEY) { bClosed = FALSE; } } myexcept { // do nothing
}
if (bClosed) { goto releasMutex; } }
for( ptPC = ptPhone->ptPhoneClients; ptPC; ptPC = ptPC->pNextSametPhone ) { if (ptPC != ptPhoneClient) { dwUnionPhoneStates |= ptPC->dwPhoneStates; dwUnionButtonModes |= ptPC->dwButtonModes; dwUnionButtonStates |= ptPC->dwButtonStates; } }
if ((dwUnionPhoneStates != ptPhone->dwUnionPhoneStates) || (dwUnionButtonModes != ptPhone->dwUnionButtonModes) || (dwUnionButtonStates != ptPhone->dwUnionButtonStates)) { if (ptPhone->ptProvider->apfn [SP_PHONESETSTATUSMESSAGES]) { LONG lResult; TSPIPROC pfn; HDRVPHONE hdPhone = ptPhone->hdPhone;
pfn = ptPhone->ptProvider-> apfn[SP_PHONESETSTATUSMESSAGES];
ptPhone->dwBusy = 1;
ReleaseMutex (hMutex);
lResult = CallSP4( pfn, "phoneSetStatusMessages", SP_FUNC_SYNC, (ULONG_PTR) hdPhone, (DWORD) dwUnionPhoneStates, (DWORD) dwUnionButtonModes, (DWORD) dwUnionButtonStates );
WaitForSingleObject (hMutex, INFINITE);
try { if (ptPhone->dwKey == TPHONE_KEY) { ptPhone->dwBusy = 0;
if (lResult == 0) { ptPhone->dwUnionPhoneStates = dwUnionPhoneStates; ptPhone->dwUnionButtonModes = dwUnionButtonModes; ptPhone->dwUnionButtonStates = dwUnionButtonStates; } } } myexcept { // do nothing
} } } } } else { //
// This was the last client so destroy the tPhone too
//
ReleaseMutex (hMutex); hMutex = NULL; DestroytPhone (ptPhone, FALSE); // conditional destroy
} }
releasMutex:
if (hMutex) { ReleaseMutex (hMutex); }
//
// Now that the mutex is released send any necessary msgs
//
if (bSendDevStateMsg) { SendMsgToPhoneClients( ptPhone, NULL, PHONE_STATE, dwParam1, dwParam2, 0 ); }
//
// Decrement reference count by two to remove the initial
// reference & the reference above
//
DereferenceObject (ghHandleTable, hPhone, 2); } else { DereferenceObject (ghHandleTable, hPhone, 1); } }
LONG DestroytPhoneApp( HPHONEAPP hPhoneApp ) { BOOL bExit = TRUE, bUnlock = FALSE; PTPHONEAPP ptPhoneApp;
LOG((TL_TRACE, "DestroytPhoneApp: enter, hPhoneApp=x%x", hPhoneApp));
if (!(ptPhoneApp = ReferenceObject (ghHandleTable, hPhoneApp, 0))) { return (TapiGlobals.dwNumPhoneInits ? PHONEERR_INVALAPPHANDLE : PHONEERR_UNINITIALIZED); }
//
// Check to make sure that this is a valid tPhoneClient object,
// then grab the lock and (recheck and) mark object as invalid.
//
LOCKTPHONEAPP (ptPhoneApp);
if (ptPhoneApp->dwKey != TPHONEAPP_KEY) { UNLOCKTPHONEAPP (ptPhoneApp); DereferenceObject (ghHandleTable, hPhoneApp, 1); return (TapiGlobals.dwNumPhoneInits ? PHONEERR_INVALAPPHANDLE : PHONEERR_UNINITIALIZED); }
ptPhoneApp->dwKey = INVAL_KEY;
//
// Destroy all the tPhoneClients. Note that we want to grab the
// lock each time we reference the list of tPhoneClient's, since
// another thread might be destroying a tPhoneClient too.
//
{ HPHONE hPhone;
destroy_tPhoneClients:
hPhone = (ptPhoneApp->ptPhoneClients ? ptPhoneApp->ptPhoneClients->hPhone : (HPHONE) 0);
UNLOCKTPHONEAPP (ptPhoneApp);
if (hPhone) { DestroytPhoneClient (hPhone); LOCKTPHONEAPP (ptPhoneApp); goto destroy_tPhoneClients; } }
//
// Remove ptPhoneApp from tClient's list. Note that we don't
// have to worry about dup-ing the mutex here because we know
// it's valid & won't get closed before we release it.
//
{ PTCLIENT ptClient = (PTCLIENT) ptPhoneApp->ptClient;
LOCKTCLIENT (ptClient);
if (ptPhoneApp->pNext) { ptPhoneApp->pNext->pPrev = ptPhoneApp->pPrev; }
if (ptPhoneApp->pPrev) { ptPhoneApp->pPrev->pNext = ptPhoneApp->pNext; } else { ptClient->ptPhoneApps = ptPhoneApp->pNext; }
UNLOCKTCLIENT (ptClient); }
//
// Decrement total num inits & see if we need to go thru shutdown
//
TapiEnterCriticalSection (&TapiGlobals.CritSec);
//assert(TapiGlobals.dwNumLineInits != 0);
TapiGlobals.dwNumPhoneInits--;
if ((TapiGlobals.dwNumLineInits == 0) && (TapiGlobals.dwNumPhoneInits == 0) && !(TapiGlobals.dwFlags & TAPIGLOBALS_SERVER)) { ServerShutdown(); gbServerInited = FALSE; }
TapiLeaveCriticalSection (&TapiGlobals.CritSec);
//
// Decrement reference count by two to remove the initial
// reference & the reference above
//
DereferenceObject (ghHandleTable, hPhoneApp, 2);
return 0; }
LONG PASCAL PhoneProlog( PTCLIENT ptClient, DWORD dwArgType, DWORD dwArg, LPVOID phdXxx, LPDWORD pdwPrivilege, HANDLE *phMutex, BOOL *pbDupedMutex, DWORD dwTSPIFuncIndex, TSPIPROC *ppfnTSPI_phoneXxx, PASYNCREQUESTINFO *ppAsyncRequestInfo, DWORD dwRemoteRequestID #if DBG
,char *pszFuncName #endif
) { LONG lResult = 0; DWORD initContext; DWORD openContext; ULONG_PTR htXxx; PTPROVIDER ptProvider;
#if DBG
LOG((TL_TRACE, "PhoneProlog: (phone%s) enter", pszFuncName)); #else
LOG((TL_TRACE, "PhoneProlog: -- enter")); #endif
*phMutex = NULL; *pbDupedMutex = FALSE;
if (ppAsyncRequestInfo) { *ppAsyncRequestInfo = (PASYNCREQUESTINFO) NULL; }
if (TapiGlobals.dwNumPhoneInits == 0) { lResult = PHONEERR_UNINITIALIZED; goto PhoneProlog_return; }
if (ptClient->phContext == (HANDLE) -1) { lResult = PHONEERR_REINIT; goto PhoneProlog_return; }
switch (dwArgType) { case ANY_RT_HPHONE: { PTPHONECLIENT ptPhoneClient;
if ((ptPhoneClient = ReferenceObject( ghHandleTable, dwArg, TPHONECLIENT_KEY ))) { if (ptPhoneClient->ptClient != ptClient) { lResult = PHONEERR_INVALPHONEHANDLE; } else if (ptPhoneClient->dwPrivilege < *pdwPrivilege) { lResult = PHONEERR_NOTOWNER; } else { try { ptProvider = ptPhoneClient->ptPhone->ptProvider; *((HDRVPHONE *) phdXxx) = ptPhoneClient->ptPhone->hdPhone;
if (ppAsyncRequestInfo) { initContext = ptPhoneClient->ptPhoneApp->InitContext; openContext = ptPhoneClient->OpenContext; htXxx = (ULONG_PTR)ptPhoneClient->ptPhone; } } myexcept { lResult = PHONEERR_INVALPHONEHANDLE; }
if (lResult || ptPhoneClient->dwKey != TPHONECLIENT_KEY) { lResult = PHONEERR_INVALPHONEHANDLE; } else if (ptProvider->dwTSPIOptions & LINETSPIOPTION_NONREENTRANT) { if (!WaitForMutex( ptProvider->hMutex, phMutex, pbDupedMutex, ptProvider, TPROVIDER_KEY, INFINITE )) { lResult = PHONEERR_OPERATIONFAILED; } } }
DereferenceObject (ghHandleTable, dwArg, 1); } else { lResult = PHONEERR_INVALPHONEHANDLE; }
break; } case DEVICE_ID: { PTPHONELOOKUPENTRY pPhoneLookupEntry;
#if TELE_SERVER
//
// Ff it's a server, map the device id
//
if ((TapiGlobals.dwFlags & TAPIGLOBALS_SERVER) && !IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR)) { try { if (*pdwPrivilege >= ptClient->dwPhoneDevices) { lResult = PHONEERR_BADDEVICEID; goto PhoneProlog_return; }
*pdwPrivilege = (ptClient->pPhoneDevices)[*pdwPrivilege]; } myexcept { lResult = PHONEERR_INVALPHONEHANDLE; goto PhoneProlog_return; } } #endif
if (dwArg && !IsValidPhoneApp ((HPHONEAPP) dwArg, ptClient)) { lResult = PHONEERR_INVALAPPHANDLE; } else if (!(pPhoneLookupEntry = GetPhoneLookupEntry (*pdwPrivilege))) { lResult = PHONEERR_BADDEVICEID; } else if (pPhoneLookupEntry->bRemoved) { lResult = PHONEERR_NODEVICE; } else if (!(ptProvider = pPhoneLookupEntry->ptProvider)) { lResult = PHONEERR_NODRIVER; } else if (ptProvider->dwTSPIOptions & LINETSPIOPTION_NONREENTRANT) { if (!WaitForMutex( ptProvider->hMutex, phMutex, pbDupedMutex, ptProvider, TPROVIDER_KEY, INFINITE )) { lResult = PHONEERR_OPERATIONFAILED; } }
break; } } // switch
if (lResult) { goto PhoneProlog_return; }
//
// Make sure that if caller wants a pointer to a TSPI proc that the
// func is exported by the provider
//
if (ppfnTSPI_phoneXxx && !(*ppfnTSPI_phoneXxx = ptProvider->apfn[dwTSPIFuncIndex])) { lResult = PHONEERR_OPERATIONUNAVAIL; goto PhoneProlog_return; }
//
// See if we need to alloc & init an ASYNCREQUESTINFO struct
//
if (ppAsyncRequestInfo) { PASYNCREQUESTINFO pAsyncRequestInfo;
if (!(pAsyncRequestInfo = ServerAlloc (sizeof(ASYNCREQUESTINFO)))) { lResult = PHONEERR_NOMEM; goto PhoneProlog_return; }
pAsyncRequestInfo->dwLocalRequestID = (DWORD) NewObject (ghHandleTable, pAsyncRequestInfo, NULL);
if (pAsyncRequestInfo->dwLocalRequestID == 0) { ServerFree (pAsyncRequestInfo); lResult = LINEERR_NOMEM; goto PhoneProlog_return; }
pAsyncRequestInfo->dwKey = TASYNC_KEY; pAsyncRequestInfo->ptClient = ptClient; pAsyncRequestInfo->InitContext = initContext; pAsyncRequestInfo->OpenContext = openContext; pAsyncRequestInfo->htXxx = htXxx; pAsyncRequestInfo->dwLineFlags = 0;
if (dwRemoteRequestID) { lResult = pAsyncRequestInfo->dwRemoteRequestID = dwRemoteRequestID; } else { lResult = pAsyncRequestInfo->dwRemoteRequestID = pAsyncRequestInfo->dwLocalRequestID; }
*ppAsyncRequestInfo = pAsyncRequestInfo; }
PhoneProlog_return:
#if DBG
{ char szResult[32];
LOG((TL_TRACE, "PhoneProlog: (phone%s) exit, result=%s", pszFuncName, MapResultCodeToText (lResult, szResult) )); } #else
LOG((TL_TRACE, "PhoneProlog: exit, result=x%x", lResult )); #endif
return lResult; }
void PASCAL PhoneEpilogSync( LONG *plResult, HANDLE hMutex, BOOL bCloseMutex #if DBG
,char *pszFuncName #endif
) { MyReleaseMutex (hMutex, bCloseMutex);
#if DBG
{ char szResult[32];
LOG((TL_TRACE, "PhoneEpilogSync: (phone%s) exit, result=%s", pszFuncName, MapResultCodeToText (*plResult, szResult) )); } #else
LOG((TL_TRACE, "PhoneEpilogSync: -- exit, result=x%x", *plResult )); #endif
}
void PASCAL PhoneEpilogAsync( LONG *plResult, LONG lRequestID, HANDLE hMutex, BOOL bCloseMutex, PASYNCREQUESTINFO pAsyncRequestInfo #if DBG
,char *pszFuncName #endif
) { MyReleaseMutex (hMutex, bCloseMutex);
if (lRequestID > 0) { if (*plResult <= 0) { if (*plResult == 0) { LOG((TL_ERROR, "Error: SP returned 0, not request ID")); }
//
// If here the service provider returned an error (or 0,
// which it never should for async requests), so call
// CompletionProcSP like the service provider normally
// would, & the worker thread will take care of sending
// the client a REPLY msg with the request result (we'll
// return an async request id)
//
CompletionProcSP( pAsyncRequestInfo->dwLocalRequestID, *plResult ); } } else if (pAsyncRequestInfo != NULL) { //
// If here an error occured before we even called the service
// provider, so just free the async request (the error will
// be returned to the client synchronously)
//
DereferenceObject( ghHandleTable, pAsyncRequestInfo->dwLocalRequestID, 1 ); }
*plResult = lRequestID;
#if DBG
{ char szResult[32];
LOG((TL_TRACE, "PhoneEpilogSync: (phone%s) exit, result=%s", pszFuncName, MapResultCodeToText (lRequestID, szResult) )); } #else
LOG((TL_TRACE, "PhoneEpilogSync: -- exit, result=x%x", lRequestID )); #endif
}
BOOL PASCAL WaitForExclusivetPhoneAccess( PTPHONE ptPhone, HANDLE *phMutex, BOOL *pbDupedMutex, DWORD dwTimeout ) { try { if (ptPhone->dwKey == TPHONE_KEY &&
WaitForMutex( ptPhone->hMutex, phMutex, pbDupedMutex, (LPVOID) ptPhone, TPHONE_KEY, INFINITE )) { if (ptPhone->dwKey == TPHONE_KEY) { return TRUE; }
MyReleaseMutex (*phMutex, *pbDupedMutex); }
} myexcept { // do nothing
}
return FALSE; }
PTPHONEAPP PASCAL WaitForExclusivePhoneAppAccess( HPHONEAPP hPhoneApp, PTCLIENT ptClient ) { PTPHONEAPP ptPhoneApp;
if (!(ptPhoneApp = ReferenceObject( ghHandleTable, hPhoneApp, TPHONEAPP_KEY ))) { return NULL; }
LOCKTPHONEAPP (ptPhoneApp);
if ((ptPhoneApp->dwKey != TPHONEAPP_KEY) || (ptPhoneApp->ptClient != ptClient)) { UNLOCKTPHONEAPP (ptPhoneApp);
ptPhoneApp = NULL; }
DereferenceObject (ghHandleTable, hPhoneApp, 1);
return ptPhoneApp; }
LONG PASCAL GetPhoneAppListFromClient( PTCLIENT ptClient, PTPOINTERLIST *ppList ) { if (WaitForExclusiveClientAccess (ptClient)) { DWORD dwNumTotalEntries = DEF_NUM_PTR_LIST_ENTRIES, dwNumUsedEntries = 0; PTPHONEAPP ptPhoneApp = ptClient->ptPhoneApps; PTPOINTERLIST pList = *ppList;
while (ptPhoneApp) { if (dwNumUsedEntries == dwNumTotalEntries) { //
// We need a larger list, so alloc a new one, copy the
// contents of the current one, and the free the current
// one iff we previously alloc'd it
//
PTPOINTERLIST pNewList;
dwNumTotalEntries <<= 1;
if (!(pNewList = ServerAlloc( sizeof (TPOINTERLIST) + sizeof (LPVOID) * (dwNumTotalEntries - DEF_NUM_PTR_LIST_ENTRIES) ))) { UNLOCKTCLIENT (ptClient); return PHONEERR_NOMEM; }
CopyMemory( pNewList->aEntries, pList->aEntries, dwNumUsedEntries * sizeof (LPVOID) );
if (pList != *ppList) { ServerFree (pList); }
pList = pNewList; }
pList->aEntries[dwNumUsedEntries++] = ptPhoneApp;
ptPhoneApp = ptPhoneApp->pNext; }
UNLOCKTCLIENT (ptClient);
pList->dwNumUsedEntries = dwNumUsedEntries;
*ppList = pList; } else { return PHONEERR_OPERATIONFAILED; }
return 0; }
LONG PASCAL GetPhoneClientListFromPhone( PTPHONE ptPhone, PTPOINTERLIST *ppList ) { BOOL bDupedMutex; HANDLE hMutex;
if (WaitForExclusivetPhoneAccess( ptPhone, &hMutex, &bDupedMutex, INFINITE )) { DWORD dwNumTotalEntries = DEF_NUM_PTR_LIST_ENTRIES, dwNumUsedEntries = 0; PTPOINTERLIST pList = *ppList; PTPHONECLIENT ptPhoneClient = ptPhone->ptPhoneClients;
while (ptPhoneClient) { if (dwNumUsedEntries == dwNumTotalEntries) { //
// We need a larger list, so alloc a new one, copy the
// contents of the current one, and the free the current
// one iff we previously alloc'd it
//
PTPOINTERLIST pNewList;
dwNumTotalEntries <<= 1;
if (!(pNewList = ServerAlloc( sizeof (TPOINTERLIST) + sizeof (LPVOID) * (dwNumTotalEntries - DEF_NUM_PTR_LIST_ENTRIES) ))) { MyReleaseMutex (hMutex, bDupedMutex); return PHONEERR_NOMEM; }
CopyMemory( pNewList->aEntries, pList->aEntries, dwNumUsedEntries * sizeof (LPVOID) );
if (pList != *ppList) { ServerFree (pList); }
pList = pNewList; }
pList->aEntries[dwNumUsedEntries++] = ptPhoneClient;
ptPhoneClient = ptPhoneClient->pNextSametPhone; }
MyReleaseMutex (hMutex, bDupedMutex);
pList->dwNumUsedEntries = dwNumUsedEntries;
*ppList = pList; } else { return PHONEERR_INVALPHONEHANDLE; }
return 0; }
void PASCAL SendMsgToPhoneClients( PTPHONE ptPhone, PTPHONECLIENT ptPhoneClientToExclude, DWORD Msg, DWORD Param1, DWORD Param2, DWORD Param3 ) { DWORD i; TPOINTERLIST clientList, *pClientList = &clientList; ASYNCEVENTMSG msg;
if (Msg == PHONE_STATE && Param1 & PHONESTATE_REINIT) { SendReinitMsgToAllXxxApps();
if (Param1 == PHONESTATE_REINIT) { return; } else { Param1 &= ~PHONESTATE_REINIT; } }
if (GetPhoneClientListFromPhone (ptPhone, &pClientList) != 0) { return; }
msg.TotalSize = sizeof (ASYNCEVENTMSG); msg.fnPostProcessProcHandle = 0; msg.Msg = Msg; msg.Param1 = Param1; msg.Param2 = Param2; msg.Param3 = Param3;
for (i = 0; i < pClientList->dwNumUsedEntries; i++) { try { PTCLIENT ptClient; PTPHONECLIENT ptPhoneClient = pClientList->aEntries[i];
if (ptPhoneClient == ptPhoneClientToExclude) { continue; }
if (FMsgDisabled ( ptPhoneClient->ptPhoneApp->dwAPIVersion, ptPhoneClient->adwEventSubMasks, (DWORD) Msg, (DWORD) Param1 )) { continue; }
if (Msg == PHONE_STATE) { DWORD phoneStates = Param1;
//
// Munge the state flags so we don't pass
// unexpected flags to old apps
//
switch (ptPhoneClient->dwAPIVersion) { case TAPI_VERSION1_0:
phoneStates &= AllPhoneStates1_0; break;
default: // case TAPI_VERSION1_4:
// case TAPI_VERSION_CURRENT:
phoneStates &= AllPhoneStates1_4; break; }
if (Param1 & PHONESTATE_CAPSCHANGE) { }
if (ptPhoneClient->dwPhoneStates & (DWORD) phoneStates) { msg.Param1 = phoneStates; } else { continue; } } else if (Msg == PHONE_BUTTON) { DWORD buttonModes = Param2, buttonStates = Param3;
//
// Munge the state flags so we don't pass
// unexpected flags to old apps
//
switch (ptPhoneClient->dwAPIVersion) { case TAPI_VERSION1_0:
buttonStates &= AllButtonStates1_0; break;
default: // case TAPI_VERSION1_4:
// case TAPI_VERSION_CURRENT:
buttonStates &= AllButtonStates1_4; break; }
if (((DWORD) buttonModes & ptPhoneClient->dwButtonModes) && ((DWORD) buttonStates & ptPhoneClient->dwButtonStates)) { msg.Param2 = buttonModes; msg.Param3 = buttonStates; } else { continue; } }
msg.InitContext = ((PTPHONEAPP) ptPhoneClient->ptPhoneApp)->InitContext; msg.hDevice = ptPhoneClient->hRemotePhone; msg.OpenContext = ptPhoneClient->OpenContext;
ptClient = ptPhoneClient->ptClient;
if (ptPhoneClient->dwKey == TPHONECLIENT_KEY) { WriteEventBuffer (ptClient, &msg); } } myexcept { // just continue
} }
if (pClientList != &clientList) { ServerFree (pClientList); } }
void PASCAL PhoneEventProc( HTAPIPHONE htPhone, DWORD dwMsg, ULONG_PTR Param1, ULONG_PTR Param2, ULONG_PTR Param3 ) { PTPHONE ptPhone = (PTPHONE)htPhone;
switch (dwMsg) { case PHONE_CLOSE: { if (NULL == ptPhone) { break; }
if (ptPhone->dwKey == TINCOMPLETEPHONE_KEY) { //
// The device is in the process of getting opened but
// the key has not been set & the Open() func still owns
// the mutex and has stuff to do, so repost the msg
// and try again later. (Set Param3 to special value
// to indicate this repost, so EventProcSP doesn't recurse)
//
PhoneEventProcSP (htPhone, PHONE_CLOSE, 0, 0, 0xdeadbeef); } else if (ptPhone->dwKey == TPHONE_KEY) { DestroytPhone (ptPhone, TRUE); // unconditional destroy
}
break; } case PHONE_DEVSPECIFIC: case PHONE_STATE: case PHONE_BUTTON: { if (dwMsg == PHONE_STATE && ptPhone == NULL && Param1 & PHONESTATE_REINIT) { SendReinitMsgToAllXxxApps(); } else { SendMsgToPhoneClients( ptPhone, NULL, dwMsg, DWORD_CAST(Param1,__FILE__,__LINE__), DWORD_CAST(Param2,__FILE__,__LINE__), DWORD_CAST(Param3,__FILE__,__LINE__) ); }
break; } case PHONE_CREATE: { LONG lResult; DWORD dwDeviceID; TSPIPROC pfnTSPI_providerCreatePhoneDevice; PTPROVIDER ptProvider = (PTPROVIDER) Param1; PTPHONELOOKUPTABLE pTable, pPrevTable; PTPHONELOOKUPENTRY pEntry; PTPROVIDER ptProvider2;
pfnTSPI_providerCreatePhoneDevice = ptProvider->apfn[SP_PROVIDERCREATEPHONEDEVICE];
assert (pfnTSPI_providerCreatePhoneDevice != NULL);
//
// Search for a table entry (create a new table if we can't find
// a free entry in an existing table)
//
TapiEnterCriticalSection (&TapiGlobals.CritSec);
// Check to make sure provider is still loaded
ptProvider2 = TapiGlobals.ptProviders; while (ptProvider2 && ptProvider2 != ptProvider) { ptProvider2 = ptProvider2->pNext; }
if (ptProvider2 != ptProvider) { TapiLeaveCriticalSection (&TapiGlobals.CritSec); return; } if (!gbQueueSPEvents) { //
// We're shutting down, so bail out
//
TapiLeaveCriticalSection (&TapiGlobals.CritSec);
return; }
pTable = pPrevTable = TapiGlobals.pPhoneLookup;
while (pTable && !(pTable->dwNumUsedEntries < pTable->dwNumTotalEntries)) { pPrevTable = pTable;
pTable = pTable->pNext; }
if (!pTable) { if (!(pTable = ServerAlloc( sizeof (TPHONELOOKUPTABLE) + (2 * pPrevTable->dwNumTotalEntries - 1) * sizeof (TPHONELOOKUPENTRY) ))) { TapiLeaveCriticalSection (&TapiGlobals.CritSec); break; }
pPrevTable->pNext = pTable;
pTable->dwNumTotalEntries = 2 * pPrevTable->dwNumTotalEntries; }
//
// Initialize the table entry
//
pEntry = pTable->aEntries + pTable->dwNumUsedEntries;
dwDeviceID = TapiGlobals.dwNumPhones;
if ((pEntry->hMutex = MyCreateMutex())) { pEntry->ptProvider = (PTPROVIDER) Param1;
//
// Now call the creation & negotiation entrypoints, and if all
// goes well increment the counts & send msgs to the clients
//
if ((lResult = CallSP2( pfnTSPI_providerCreatePhoneDevice, "providerCreatePhoneDevice", SP_FUNC_SYNC, (ULONG_PTR) Param2, (DWORD) dwDeviceID
)) == 0) { TSPIPROC pfnTSPI_phoneNegotiateTSPIVersion = ptProvider->apfn[SP_PHONENEGOTIATETSPIVERSION]; TPOINTERLIST clientList, *pClientList = &clientList;
if (pfnTSPI_phoneNegotiateTSPIVersion && (lResult = CallSP4( pfnTSPI_phoneNegotiateTSPIVersion, "", SP_FUNC_SYNC, (DWORD) dwDeviceID, (DWORD) TAPI_VERSION1_0, (DWORD) TAPI_VERSION_CURRENT, (ULONG_PTR) &pEntry->dwSPIVersion
)) == 0) { PTCLIENT ptClient; ASYNCEVENTMSG msg;
GetPermPhoneIDAndInsertInTable( ptProvider, dwDeviceID, pEntry->dwSPIVersion );
pTable->dwNumUsedEntries++;
TapiGlobals.dwNumPhones++;
TapiLeaveCriticalSection (&TapiGlobals.CritSec); AppendNewDeviceInfo (FALSE, dwDeviceID); TapiEnterCriticalSection (&TapiGlobals.CritSec); msg.TotalSize = sizeof (ASYNCEVENTMSG); msg.fnPostProcessProcHandle = 0; msg.hDevice = 0; msg.OpenContext = 0; msg.Param2 = 0; msg.Param3 = 0;
// only send the message if the client is an
// admin or we're not a telephony server
// we don't want to send the message to non-admin
// clients, because their phones have not changed.
if (TapiGlobals.dwFlags & TAPIGLOBALS_SERVER) { lResult = GetClientList (TRUE, &pClientList); } else { lResult = GetClientList (FALSE, &pClientList); } if (lResult == S_OK) { DWORD i; PTPHONEAPP ptPhoneApp; for (i = 0; i < pClientList->dwNumUsedEntries; ++i) { ptClient = (PTCLIENT) pClientList->aEntries[i]; if (!WaitForExclusiveClientAccess (ptClient)) { continue; } ptPhoneApp = ptClient->ptPhoneApps;
while (ptPhoneApp) { if (ptPhoneApp->dwAPIVersion == TAPI_VERSION1_0) { msg.Msg = PHONE_STATE; msg.Param1 = PHONESTATE_REINIT; } else { msg.Msg = PHONE_CREATE; msg.Param1 = dwDeviceID; }
if (!FMsgDisabled( ptPhoneApp->dwAPIVersion, ptPhoneApp->adwEventSubMasks, (DWORD) msg.Msg, (DWORD) msg.Param1 )) { msg.InitContext = ptPhoneApp->InitContext;
WriteEventBuffer (ptClient, &msg); }
ptPhoneApp = ptPhoneApp->pNext; }
UNLOCKTCLIENT (ptClient); } } } if (pClientList != &clientList) { ServerFree (pClientList); } }
if (lResult) { MyCloseMutex (pEntry->hMutex); } }
TapiLeaveCriticalSection (&TapiGlobals.CritSec); break; } case PHONE_REMOVE: { PTPHONELOOKUPENTRY pLookupEntry; HANDLE hLookupEntryMutex = NULL; BOOL bOK = FALSE;
TapiEnterCriticalSection (&TapiGlobals.CritSec); if (!(pLookupEntry = GetPhoneLookupEntry ((DWORD) Param1)) || pLookupEntry->bRemoved) { TapiLeaveCriticalSection (&TapiGlobals.CritSec); return; }
if ( pLookupEntry->hMutex ) { bOK = DuplicateHandle( TapiGlobals.hProcess, pLookupEntry->hMutex, TapiGlobals.hProcess, &hLookupEntryMutex, 0, FALSE, DUPLICATE_SAME_ACCESS ); }
TapiLeaveCriticalSection(&TapiGlobals.CritSec);
if ( !bOK ) { return; }
//
// Wait for the LookupEntry's mutex on the duplicate handle
//
if (WaitForSingleObject (hLookupEntryMutex, INFINITE) != WAIT_OBJECT_0) { return; }
//
// Mark the lookup table entry as removed
//
pLookupEntry->bRemoved = 1;
//
// Release the mutex and close the duplicate handle
//
ReleaseMutex (hLookupEntryMutex); CloseHandle (hLookupEntryMutex); hLookupEntryMutex = NULL;
if (pLookupEntry->ptPhone) { DestroytPhone (pLookupEntry->ptPhone, TRUE); // unconditional destroy
}
TapiEnterCriticalSection (&TapiGlobals.CritSec);
//
// Close the mutex to reduce overall handle count
//
MyCloseMutex (pLookupEntry->hMutex); pLookupEntry->hMutex = NULL;
RemoveDeviceInfoEntry (FALSE, DWORD_CAST(Param1,__FILE__,__LINE__)); TapiLeaveCriticalSection(&TapiGlobals.CritSec);
SendAMsgToAllPhoneApps( TAPI_VERSION2_0 | 0x80000000, PHONE_REMOVE, DWORD_CAST(Param1,__FILE__,__LINE__), 0, 0 );
break; } default:
LOG((TL_ERROR, "PhoneEventProc: unknown msg, dwMsg=%ld", dwMsg)); break; } }
void CALLBACK PhoneEventProcSP( HTAPIPHONE htPhone, DWORD dwMsg, ULONG_PTR Param1, ULONG_PTR Param2, ULONG_PTR Param3 ) { PSPEVENT pSPEvent;
LOG((TL_TRACE, "PhoneEventProc: enter\n\thtPhone=x%lx, Msg=x%lx\n" \ "\tP1=x%lx, P2=x%lx, P3=x%lx", htPhone, dwMsg, Param1, Param2, Param3 ));
if ((pSPEvent = (PSPEVENT) ServerAlloc (sizeof (SPEVENT)))) { pSPEvent->dwType = SP_PHONE_EVENT; pSPEvent->htPhone = htPhone; pSPEvent->dwMsg = dwMsg; pSPEvent->dwParam1 = Param1; pSPEvent->dwParam2 = Param2; pSPEvent->dwParam3 = Param3;
if (!QueueSPEvent (pSPEvent)) { ServerFree (pSPEvent); } } else if (dwMsg != PHONE_CLOSE || Param3 != 0xdeadbeef) { //
// Alloc failed, so call the event proc within the SP's context
// (but not if it's CLOSE msg and Param3 == 0xdeadbeef,
// which means the real EventProc() is calling us directly &
// we don't want to recurse)
//
PhoneEventProc (htPhone, dwMsg, Param1, Param2, Param3); } }
void WINAPI PClose( PTCLIENT ptClient, PPHONECLOSE_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVPHONE hdPhone; DWORD dwPrivilege = PHONEPRIVILEGE_MONITOR;
if ((pParams->lResult = PHONEPROLOG( ptClient, // tClient
ANY_RT_HPHONE, // widget type
(DWORD) pParams->hPhone, // client widget handle
(LPVOID) &hdPhone, // provider widget handle
&dwPrivilege, // privileges or device ID
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
0, // provider func index
NULL, // provider func pointer
NULL, // async request info
0, // client async request ID
"Close" // func name
)) == 0) { PTPHONECLIENT ptPhoneClient; if ((ptPhoneClient = ReferenceObject( ghHandleTable, pParams->hPhone, TPHONECLIENT_KEY ))) { pParams->dwCallbackInstance = ptPhoneClient->OpenContext; DereferenceObject (ghHandleTable, pParams->hPhone, 1); } DestroytPhoneClient ((HPHONE) pParams->hPhone); }
PHONEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "Close" ); }
void PDevSpecific_PostProcess( PASYNCREQUESTINFO pAsyncRequestInfo, PASYNCEVENTMSG pAsyncEventMsg, LPVOID *ppBuf ) { PASYNCEVENTMSG pNewAsyncEventMsg = (PASYNCEVENTMSG) pAsyncRequestInfo->dwParam3;
CopyMemory (pNewAsyncEventMsg, pAsyncEventMsg, sizeof (ASYNCEVENTMSG));
*ppBuf = pNewAsyncEventMsg;
if (pAsyncEventMsg->Param2 == 0) // success
{ //
// Make sure to keep the total size 64-bit aligned
//
pNewAsyncEventMsg->TotalSize += (DWORD_CAST(pAsyncRequestInfo->dwParam2,__FILE__,__LINE__) + 7) & 0xfffffff8;
pNewAsyncEventMsg->Param3 = DWORD_CAST(pAsyncRequestInfo->dwParam1,__FILE__,__LINE__); // lpParams
pNewAsyncEventMsg->Param4 = DWORD_CAST(pAsyncRequestInfo->dwParam2,__FILE__,__LINE__); // dwSize
} }
void WINAPI PDevSpecific( PTCLIENT ptClient, PPHONEDEVSPECIFIC_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVPHONE hdPhone; PASYNCREQUESTINFO pAsyncRequestInfo; TSPIPROC pfnTSPI_phoneDevSpecific; DWORD dwPrivilege = PHONEPRIVILEGE_MONITOR;
//
// Verify size/offset/string params given our input buffer/size
//
if (ISBADSIZEOFFSET( dwParamsBufferSize, 0, pParams->dwParamsSize, pParams->dwParamsOffset, sizeof(DWORD), "PDevSpecific", "pParams->Params" )) { pParams->lResult = PHONEERR_OPERATIONFAILED; return; }
if ((lRequestID = PHONEPROLOG( ptClient, // tClient
ANY_RT_HPHONE, // widget type
(DWORD) pParams->hPhone, // client widget handle
(LPVOID) &hdPhone, // provider widget handle
&dwPrivilege, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_PHONEDEVSPECIFIC, // provider func index
&pfnTSPI_phoneDevSpecific, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
"DevSpecific" // func name
)) > 0) { LPBYTE pBuf;
//
// Alloc a shadow buf that the SP can use until it completes this
// request. Make sure there's enough extra space in the buf for
// an ASYNCEVENTMSG header so we don't have to alloc yet another
// buf in the post processing proc when preparing the completion
// msg to send to the client, and that the msg is 64-bit aligned.
//
if (!(pBuf = ServerAlloc( ((pParams->dwParamsSize + 7) & 0xfffffff8) + sizeof (ASYNCEVENTMSG) ))) { lRequestID = PHONEERR_NOMEM; goto PDevSpecific_epilog; }
CopyMemory( pBuf + sizeof (ASYNCEVENTMSG), pDataBuf + pParams->dwParamsOffset, pParams->dwParamsSize );
pAsyncRequestInfo->pfnPostProcess = PDevSpecific_PostProcess; pAsyncRequestInfo->dwParam1 = pParams->hpParams; pAsyncRequestInfo->dwParam2 = pParams->dwParamsSize; pAsyncRequestInfo->dwParam3 = (ULONG_PTR) pBuf;
pAsyncRequestInfo->hfnClientPostProcessProc = pParams->hfnPostProcessProc;
pParams->lResult = CallSP4( pfnTSPI_phoneDevSpecific, "phoneDevSpecific", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdPhone, (ULONG_PTR) (pParams->dwParamsSize ? pBuf + sizeof (ASYNCEVENTMSG) : NULL), (DWORD) pParams->dwParamsSize ); }
PDevSpecific_epilog:
PHONEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, "DevSpecific" ); }
void WINAPI PGetButtonInfo( PTCLIENT ptClient, PPHONEGETBUTTONINFO_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVPHONE hdPhone; TSPIPROC pfnTSPI_phoneGetButtonInfo; DWORD dwPrivilege = PHONEPRIVILEGE_MONITOR;
//
// Verify size/offset/string params given our input buffer/size
//
if (pParams->dwButtonInfoTotalSize > dwParamsBufferSize) { pParams->lResult = PHONEERR_OPERATIONFAILED; return; }
if ((pParams->lResult = PHONEPROLOG( ptClient, // tClient
ANY_RT_HPHONE, // widget type
(DWORD) pParams->hPhone, // client widget handle
(LPVOID) &hdPhone, // provider widget handle
&dwPrivilege, // privileges or device ID
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_PHONEGETBUTTONINFO, // provider func index
&pfnTSPI_phoneGetButtonInfo,// provider func pointer
NULL, // async request info
0, // client async request ID
"GetButtonInfo" // func name
)) == 0) { DWORD dwAPIVersion, dwSPIVersion, dwTotalSize, dwFixedSizeClient, dwFixedSizeSP; LPPHONEBUTTONINFO pButtonInfo = (LPPHONEBUTTONINFO) pDataBuf, pButtonInfo2 = (LPPHONEBUTTONINFO) NULL;
//
// Safely retrieve the API & SPI versions
//
if (GetPhoneVersions( pParams->hPhone, &dwAPIVersion, &dwSPIVersion
) != 0) { pParams->lResult = PHONEERR_INVALPHONEHANDLE; goto PGetButtonInfo_epilog; }
//
// Determine the fixed size of the structure for the specified API
// version, verify client's buffer is big enough
//
dwTotalSize = pParams->dwButtonInfoTotalSize;
switch (dwAPIVersion) { case TAPI_VERSION1_0:
dwFixedSizeClient = 0x24; break;
default: // case TAPI_VERSION_CURRENT:
dwFixedSizeClient = sizeof (PHONEBUTTONINFO); break; }
if (dwTotalSize < dwFixedSizeClient) { pParams->lResult = PHONEERR_STRUCTURETOOSMALL; goto PGetButtonInfo_epilog; }
//
// Determine the fixed size of the structure expected by the SP
//
switch (dwSPIVersion) { case TAPI_VERSION1_0:
dwFixedSizeSP = 0x24; break;
default: // case TAPI_VERSION_CURRENT:
dwFixedSizeSP = sizeof (PHONEBUTTONINFO); break; }
//
// If the client's buffer is < the fixed size of that expected by
// the SP (client is lower version than SP) then allocate an
// intermediate buffer
//
if (dwTotalSize < dwFixedSizeSP) { if (!(pButtonInfo2 = ServerAlloc (dwFixedSizeSP))) { pParams->lResult = PHONEERR_NOMEM; goto PGetButtonInfo_epilog; }
pButtonInfo = pButtonInfo2; dwTotalSize = dwFixedSizeSP; }
InitTapiStruct( pButtonInfo, dwTotalSize, dwFixedSizeSP, (pButtonInfo2 == NULL ? TRUE : FALSE) );
if ((pParams->lResult = CallSP3( pfnTSPI_phoneGetButtonInfo, "phoneGetButtonInfo", SP_FUNC_SYNC, (ULONG_PTR) hdPhone, (DWORD) pParams->dwButtonLampID, (ULONG_PTR) pButtonInfo
)) == 0) { #if DBG
//
// Verify the info returned by the provider
//
#endif
//
// Add the fields we're responsible for
//
//
// Munge fields where appropriate for old apps (don't want to
// pass back flags that they won't understand)
//
//
// If an intermediate buffer was used then copy the bits back
// to the the original buffer, & free the intermediate buffer.
// Also reset the dwUsedSize field to the fixed size of the
// structure for the specifed version, since any data in the
// variable portion is garbage as far as the client is concerned.
//
if (pButtonInfo == pButtonInfo2) { pButtonInfo = (LPPHONEBUTTONINFO) pDataBuf;
CopyMemory (pButtonInfo, pButtonInfo2, dwFixedSizeClient);
ServerFree (pButtonInfo2);
pButtonInfo->dwTotalSize = pParams->dwButtonInfoTotalSize; pButtonInfo->dwUsedSize = dwFixedSizeClient; }
//
// Indicate the offset & how many bytes of data we're passing back
//
pParams->dwButtonInfoOffset = 0;
*pdwNumBytesReturned = sizeof (TAPI32_MSG) + pButtonInfo->dwUsedSize; } }
PGetButtonInfo_epilog:
PHONEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "GetButtonInfo" ); }
void WINAPI PGetData( PTCLIENT ptClient, PPHONEGETDATA_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVPHONE hdPhone; TSPIPROC pfnTSPI_phoneGetData; DWORD dwPrivilege = PHONEPRIVILEGE_MONITOR;
//
// Verify size/offset/string params given our input buffer/size
//
if (pParams->dwSize > dwParamsBufferSize) { pParams->lResult = PHONEERR_OPERATIONFAILED; return; }
if ((pParams->lResult = PHONEPROLOG( ptClient, // tClient
ANY_RT_HPHONE, // widget type
(DWORD) pParams->hPhone, // client widget handle
(LPVOID) &hdPhone, // provider widget handle
&dwPrivilege, // privileges or device ID
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_PHONEGETDATA, // provider func index
&pfnTSPI_phoneGetData, // provider func pointer
NULL, // async request info
0, // client async request ID
"GetData" // func name
)) == 0) { if ((pParams->lResult = CallSP4( pfnTSPI_phoneGetData, "phoneGetData", SP_FUNC_SYNC, (ULONG_PTR) hdPhone, (DWORD) pParams->dwDataID, (ULONG_PTR) pDataBuf, (DWORD) pParams->dwSize
)) == 0) { //
// Indicate offset & how many bytes of data we're passing back
//
pParams->dwDataOffset = 0;
*pdwNumBytesReturned = sizeof (TAPI32_MSG) + pParams->dwSize; } }
PHONEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "GetData" ); }
void WINAPI PGetDevCaps( PTCLIENT ptClient, PPHONEGETDEVCAPS_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; DWORD dwDeviceID = pParams->dwDeviceID; HANDLE hMutex; TSPIPROC pfnTSPI_phoneGetDevCaps;
//
// Verify size/offset/string params given our input buffer/size
//
if (pParams->dwPhoneCapsTotalSize > dwParamsBufferSize) { pParams->lResult = PHONEERR_OPERATIONFAILED; return; }
if ((pParams->lResult = PHONEPROLOG( ptClient, // tClient
DEVICE_ID, // widget type
(DWORD) pParams->hPhoneApp, // client widget handle
NULL, // provider widget handle
&dwDeviceID, // privileges or device ID
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_PHONEGETDEVCAPS, // provider func index
&pfnTSPI_phoneGetDevCaps, // provider func pointer
NULL, // async request info
0, // client async request ID
"GetDevCaps" // func name
)) == 0) { DWORD dwAPIVersion, dwSPIVersion, dwTotalSize, dwFixedSizeClient, dwFixedSizeSP; LPPHONECAPS pCaps = (LPPHONECAPS) pDataBuf, pCaps2 = (LPPHONECAPS) NULL;
//
// Verify API & SPI version compatibility
//
dwAPIVersion = pParams->dwAPIVersion;
dwSPIVersion = (GetPhoneLookupEntry (dwDeviceID))->dwSPIVersion;
if (!IsAPIVersionInRange (dwAPIVersion, dwSPIVersion)) { pParams->lResult = PHONEERR_INCOMPATIBLEAPIVERSION; goto PGetDevCaps_epilog; }
//
// Verify Ext version compatibility
//
if (!IsValidPhoneExtVersion (dwDeviceID, pParams->dwExtVersion)) { pParams->lResult = PHONEERR_INCOMPATIBLEEXTVERSION; goto PGetDevCaps_epilog; }
//
// Determine the fixed size of the structure for the specified API
// version, verify client's buffer is big enough
//
dwTotalSize = pParams->dwPhoneCapsTotalSize;
switch (dwAPIVersion) { case TAPI_VERSION1_0: case TAPI_VERSION1_4:
dwFixedSizeClient = 144; // 36 * sizeof (DWORD)
break;
case TAPI_VERSION2_0: case TAPI_VERSION2_1:
dwFixedSizeClient = 180; // 45 * sizeof (DWORD)
break;
// case TAPI_VERSION2_2:
default: // (fix ppc build wrn) case TAPI_VERSION_CURRENT:
dwFixedSizeClient = sizeof (PHONECAPS); break; }
if (dwTotalSize < dwFixedSizeClient) { pParams->lResult = PHONEERR_STRUCTURETOOSMALL; goto PGetDevCaps_epilog; }
//
// Determine the fixed size of the structure expected by the SP
//
switch (dwSPIVersion) { case TAPI_VERSION1_0: case TAPI_VERSION1_4:
dwFixedSizeSP = 144; // 36 * sizeof (DWORD)
break;
case TAPI_VERSION2_0: case TAPI_VERSION2_1:
dwFixedSizeSP = 180; // 45 * sizeof (DWORD)
break;
// case TAPI_VERSION2_2:
default: // (fix ppc build wrn) case TAPI_VERSION_CURRENT:
dwFixedSizeSP = sizeof (PHONECAPS); break; }
//
// If the client's buffer is < the fixed size of that expected by
// the SP (client is lower version than SP) then allocate an
// intermediate buffer
//
if (dwTotalSize < dwFixedSizeSP) { if (!(pCaps2 = ServerAlloc (dwFixedSizeSP))) { pParams->lResult = PHONEERR_NOMEM; goto PGetDevCaps_epilog; }
pCaps = pCaps2; dwTotalSize = dwFixedSizeSP; }
InitTapiStruct( pCaps, dwTotalSize, dwFixedSizeSP, (pCaps2 == NULL ? TRUE : FALSE) );
if ((pParams->lResult = CallSP4( pfnTSPI_phoneGetDevCaps, "phoneGetDevCaps", SP_FUNC_SYNC, (DWORD) dwDeviceID, (DWORD) dwSPIVersion, (DWORD) pParams->dwExtVersion, (ULONG_PTR) pCaps
)) == 0) { #if DBG
//
// Verify the info returned by the provider
//
#endif
//
// Add the fields we're responsible for
//
pCaps->dwPhoneStates |= PHONESTATE_OWNER | PHONESTATE_MONITORS | PHONESTATE_REINIT;
//
// Munge fields where appropriate for old apps (don't want to
// pass back flags that they won't understand)
//
//
// If an intermediate buffer was used then copy the bits back
// to the the original buffer, & free the intermediate buffer.
// Also reset the dwUsedSize field to the fixed size of the
// structure for the specifed version, since any data in the
// variable portion is garbage as far as the client is concerned.
//
if (pCaps == pCaps2) { pCaps = (LPPHONECAPS) pDataBuf;
CopyMemory (pCaps, pCaps2, dwFixedSizeClient);
ServerFree (pCaps2);
pCaps->dwTotalSize = pParams->dwPhoneCapsTotalSize; pCaps->dwUsedSize = dwFixedSizeClient; }
//
// Indicate the offset & how many bytes of data we're passing back
//
pParams->dwPhoneCapsOffset = 0;
*pdwNumBytesReturned = sizeof (TAPI32_MSG) + pCaps->dwUsedSize; } }
PGetDevCaps_epilog:
PHONEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "GetDevCaps" ); }
void WINAPI PGetDisplay( PTCLIENT ptClient, PPHONEGETDISPLAY_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVPHONE hdPhone; TSPIPROC pfnTSPI_phoneGetDisplay; DWORD dwPrivilege = PHONEPRIVILEGE_MONITOR;
//
// Verify size/offset/string params given our input buffer/size
//
if (pParams->dwDisplayTotalSize > dwParamsBufferSize) { pParams->lResult = PHONEERR_OPERATIONFAILED; return; }
if ((pParams->lResult = PHONEPROLOG( ptClient, // tClient
ANY_RT_HPHONE, // widget type
(DWORD) pParams->hPhone, // client widget handle
(LPVOID) &hdPhone, // provider widget handle
&dwPrivilege, // privileges or device ID
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_PHONEGETDISPLAY, // provider func index
&pfnTSPI_phoneGetDisplay, // provider func pointer
NULL, // async request info
0, // client async request ID
"GetDisplay" // func name
)) == 0) { LPVARSTRING pDisplay = (LPVARSTRING) pDataBuf;
if (!InitTapiStruct( pDisplay, pParams->dwDisplayTotalSize, sizeof (VARSTRING), TRUE )) { pParams->lResult = PHONEERR_STRUCTURETOOSMALL; goto PGetDisplay_epilog; }
if ((pParams->lResult = CallSP2( pfnTSPI_phoneGetDisplay, "phoneGetDisplay", SP_FUNC_SYNC, (ULONG_PTR) hdPhone, (ULONG_PTR) pDisplay
)) == 0) { #if DBG
//
// Verify the info returned by the provider
//
#endif
//
// Indicate how many bytes of data we're passing back
//
pParams->dwDisplayOffset = 0;
*pdwNumBytesReturned = sizeof (TAPI32_MSG) + pDisplay->dwUsedSize; } }
PGetDisplay_epilog:
PHONEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "GetDisplay" ); }
void WINAPI PGetGain( PTCLIENT ptClient, PPHONEGETGAIN_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVPHONE hdPhone; TSPIPROC pfnTSPI_phoneGetGain; DWORD dwPrivilege = PHONEPRIVILEGE_MONITOR;
if ((pParams->lResult = PHONEPROLOG( ptClient, // tClient
ANY_RT_HPHONE, // widget type
(DWORD) pParams->hPhone, // client widget handle
(LPVOID) &hdPhone, // provider widget handle
&dwPrivilege, // privileges or device ID
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_PHONEGETGAIN, // provider func index
&pfnTSPI_phoneGetGain, // provider func pointer
NULL, // async request info
0, // client async request ID
"GetGain" // func name
)) == 0) { if (!IsOnlyOneBitSetInDWORD (pParams->dwHookSwitchDev) || (pParams->dwHookSwitchDev & ~AllHookSwitchDevs)) { pParams->lResult = PHONEERR_INVALHOOKSWITCHDEV; } else { if ((pParams->lResult = CallSP3( pfnTSPI_phoneGetGain, "phoneGetGain", SP_FUNC_SYNC, (ULONG_PTR) hdPhone, (DWORD) pParams->dwHookSwitchDev, (ULONG_PTR) &pParams->dwGain
)) == 0) { *pdwNumBytesReturned = sizeof (PHONEGETGAIN_PARAMS); } } }
PHONEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "GetGain" ); }
void WINAPI PGetHookSwitch( PTCLIENT ptClient, PPHONEGETHOOKSWITCH_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVPHONE hdPhone; TSPIPROC pfnTSPI_phoneGetHookSwitch; DWORD dwPrivilege = PHONEPRIVILEGE_MONITOR;
if ((pParams->lResult = PHONEPROLOG( ptClient, // tClient
ANY_RT_HPHONE, // widget type
(DWORD) pParams->hPhone, // client widget handle
(LPVOID) &hdPhone, // provider widget handle
&dwPrivilege, // privileges or device ID
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_PHONEGETHOOKSWITCH, // provider func index
&pfnTSPI_phoneGetHookSwitch,// provider func pointer
NULL, // async request info
0, // client async request ID
"GetHookSwitch" // func name
)) == 0) { if ((pParams->lResult = CallSP2( pfnTSPI_phoneGetHookSwitch, "phoneGetHookSwitch", SP_FUNC_SYNC, (ULONG_PTR) hdPhone, (ULONG_PTR) &pParams->dwHookSwitchDevs
)) == 0) { *pdwNumBytesReturned = sizeof (PHONEGETHOOKSWITCH_PARAMS); } }
PHONEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "GetHookSwitch" ); }
void WINAPI PGetIcon( PTCLIENT ptClient, PPHONEGETICON_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { WCHAR *pszDeviceClass; BOOL bCloseMutex; HANDLE hMutex; TSPIPROC pfnTSPI_phoneGetIcon;
//
// Verify size/offset/string params given our input buffer/size
//
if ((pParams->dwDeviceClassOffset != TAPI_NO_DATA) &&
IsBadStringParam( dwParamsBufferSize, pDataBuf, pParams->dwDeviceClassOffset )) { pParams->lResult = PHONEERR_OPERATIONFAILED; return; }
pszDeviceClass = (WCHAR *) (pParams->dwDeviceClassOffset == TAPI_NO_DATA ? NULL : pDataBuf + pParams->dwDeviceClassOffset);
if ((pParams->lResult = PHONEPROLOG( ptClient, // tClient
DEVICE_ID, // widget type
0, // client widget handle
NULL, // provider widget handle
&(pParams->dwDeviceID), // privileges or device ID
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_PHONEGETICON, // provider func index
&pfnTSPI_phoneGetIcon, // provider func pointer
NULL, // async request info
0, // client async request ID
"GetIcon" // func name
)) == 0) {
if ((pParams->lResult = CallSP3( pfnTSPI_phoneGetIcon, "phoneGetIcon", SP_FUNC_SYNC, (DWORD) pParams->dwDeviceID, (ULONG_PTR) pszDeviceClass, (ULONG_PTR) &pParams->hIcon
)) == 0) { *pdwNumBytesReturned = sizeof (PHONEGETICON_PARAMS); } } else if (pParams->lResult == PHONEERR_OPERATIONUNAVAIL) { if ((pszDeviceClass == NULL) || (_wcsicmp(pszDeviceClass, L"tapi/phone") == 0)) { pParams->hIcon = TapiGlobals.hPhoneIcon; pParams->lResult = 0; *pdwNumBytesReturned = sizeof (PHONEGETICON_PARAMS); } else { pParams->lResult = PHONEERR_INVALDEVICECLASS; } }
PHONEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "GetIcon" ); }
void WINAPI PGetIDEx( PTCLIENT ptClient, PPHONEGETID_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) {
LPBYTE pDeviceClass = pDataBuf + pParams->dwDeviceClassOffset; LPWSTR pDeviceClassCopy = NULL; LPWSTR szStringId1 = NULL; LPWSTR szStringId2 = NULL; LPVARSTRING pID = (LPVARSTRING) pDataBuf; DWORD dwAvailSize;
//
// Make a copy of the device class
//
pDeviceClassCopy = (LPWSTR) ServerAlloc( (1 + wcslen( (LPWSTR)pDeviceClass )) * sizeof(WCHAR)); if (!pDeviceClassCopy) { LOG((TL_ERROR, "PGetIDEx: failed to allocate DeviceClassCopy")); pParams->lResult = PHONEERR_NOMEM; }
wcscpy(pDeviceClassCopy, (LPWSTR)pDeviceClass);
//
// First call PGetID
//
PGetID( ptClient, pParams, dwParamsBufferSize, pDataBuf, pdwNumBytesReturned);
//
// if PGetID was successful and the request was for a wave device,
// translate the device ID into a string ID
//
if ( (pParams->lResult == 0) && !(pID->dwNeededSize > pID->dwTotalSize) ) { if (!_wcsicmp((LPWSTR)pDeviceClassCopy, L"wave/in") || !_wcsicmp((LPWSTR)pDeviceClassCopy, L"wave/out") || !_wcsicmp((LPWSTR)pDeviceClassCopy, L"midi/in") || !_wcsicmp((LPWSTR)pDeviceClassCopy, L"midi/out") ) { szStringId1 = WaveDeviceIdToStringId ( *(DWORD*)((LPBYTE)pID + pID->dwStringOffset), (LPWSTR)pDeviceClassCopy); if ( szStringId1 ) { dwAvailSize = pID->dwTotalSize - pID->dwUsedSize + sizeof(DWORD); if ( dwAvailSize >= (wcslen(szStringId1) + 1) * sizeof(WCHAR) ) { wcscpy( (LPWSTR)((LPBYTE)pID + pID->dwStringOffset), szStringId1 ); pID->dwStringSize = (wcslen(szStringId1) + 1) * sizeof(WCHAR); pID->dwUsedSize = pID->dwNeededSize = pID->dwUsedSize + pID->dwStringSize - sizeof(DWORD); *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pID->dwUsedSize; } else { pID->dwNeededSize = (wcslen(szStringId1) + 1) * sizeof(WCHAR); }
ServerFree(szStringId1); } else { LOG((TL_ERROR, "PGetIDEx: WaveDeviceIdToStringId failed")); pParams->lResult = PHONEERR_OPERATIONFAILED; } } else if (!_wcsicmp((LPWSTR)pDeviceClassCopy, L"wave/in/out")) { szStringId1 = WaveDeviceIdToStringId ( *(DWORD*)((LPBYTE)pID + pID->dwStringOffset), L"wave/in"); szStringId2 = WaveDeviceIdToStringId ( *( (DWORD*)((LPBYTE)pID + pID->dwStringOffset) + 1 ), L"wave/out"); if ( szStringId1 && szStringId2 ) { dwAvailSize = pID->dwTotalSize - pID->dwUsedSize + 2 * sizeof(DWORD); if ( dwAvailSize >= (wcslen(szStringId1) + wcslen(szStringId2) + 2) * sizeof(WCHAR) ) { wcscpy( (LPWSTR)((LPBYTE)pID + pID->dwStringOffset), szStringId1 ); wcscpy( (LPWSTR) ((LPBYTE)pID + pID->dwStringOffset + (wcslen(szStringId1) + 1) * sizeof(WCHAR)), szStringId2 ); pID->dwStringSize = (wcslen(szStringId1) + wcslen(szStringId2) + 2) * sizeof(WCHAR); pID->dwUsedSize = pID->dwNeededSize = pID->dwUsedSize + pID->dwStringSize - 2 * sizeof(DWORD); *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pID->dwUsedSize; } else { pID->dwNeededSize = (wcslen(szStringId1) + wcslen(szStringId2) + 2) * sizeof(WCHAR); }
} else { LOG((TL_ERROR, "PGetIDEx: WaveDeviceIdToStringId failed")); pParams->lResult = PHONEERR_OPERATIONFAILED; } ServerFree(szStringId1); ServerFree(szStringId2); } }
ServerFree(pDeviceClassCopy); }
void WINAPI PGetID( PTCLIENT ptClient, PPHONEGETID_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVPHONE hdPhone; TSPIPROC pfnTSPI_phoneGetID; DWORD dwPrivilege = PHONEPRIVILEGE_MONITOR;
//
// Verify size/offset/string params given our input buffer/size
//
if ((pParams->dwDeviceIDTotalSize > dwParamsBufferSize) ||
IsBadStringParam( dwParamsBufferSize, pDataBuf, pParams->dwDeviceClassOffset )) { pParams->lResult = PHONEERR_OPERATIONFAILED; return; }
if ((pParams->lResult = PHONEPROLOG( ptClient, // tClient
ANY_RT_HPHONE, // widget type
(DWORD) pParams->hPhone, // client widget handle
(LPVOID) &hdPhone, // provider widget handle
&dwPrivilege, // privileges or device ID
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_PHONEGETID, // provider func index
&pfnTSPI_phoneGetID, // provider func pointer
NULL, // async request info
0, // client async request ID
"GetID" // func name
)) == 0 || pParams->lResult == PHONEERR_OPERATIONUNAVAIL) { WCHAR *pszDeviceClass; LPVARSTRING pID = (LPVARSTRING) pDataBuf;
//
// We'll handle the "tapi/phone" class right here rather than
// burden every single driver with having to support it
//
if (_wcsicmp( (PWSTR)(pDataBuf + pParams->dwDeviceClassOffset), L"tapi/phone"
) == 0) { if (!InitTapiStruct( pID, pParams->dwDeviceIDTotalSize, sizeof (VARSTRING), TRUE )) { pParams->lResult = PHONEERR_STRUCTURETOOSMALL; goto PGetID_epilog; }
pID->dwNeededSize += sizeof (DWORD);
if (pID->dwTotalSize >= pID->dwNeededSize) { PTPHONECLIENT ptPhoneClient;
if (!(ptPhoneClient = ReferenceObject( ghHandleTable, pParams->hPhone, 0 ))) { pParams->lResult = PHONEERR_INVALPHONEHANDLE; goto PGetID_epilog; }
try { *((LPDWORD)(pID + 1)) = ptPhoneClient->ptPhone->dwDeviceID; } myexcept { pParams->lResult = PHONEERR_INVALPHONEHANDLE; }
DereferenceObject (ghHandleTable, pParams->hPhone, 1);
if (pParams->lResult == PHONEERR_INVALPHONEHANDLE) { goto PGetID_epilog; }
pID->dwUsedSize += sizeof (DWORD); pID->dwStringFormat = STRINGFORMAT_BINARY; pID->dwStringSize = sizeof (DWORD); pID->dwStringOffset = sizeof (VARSTRING); }
//
// Indicate offset & how many bytes of data we're passing back
//
pParams->lResult = 0; pParams->dwDeviceIDOffset = 0; *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pID->dwUsedSize; goto PGetID_epilog; } else if (pParams->lResult == PHONEERR_OPERATIONUNAVAIL) { goto PGetID_epilog; }
//
// Alloc a temporary buf for the dev class, since we'll be using
// the existing buffer for output
//
{ UINT nStringSize;
nStringSize = sizeof(WCHAR) * (1 + wcslen((PWSTR)(pDataBuf + pParams->dwDeviceClassOffset)));
if (0 == nStringSize) { pParams->lResult = PHONEERR_INVALPARAM; goto PGetID_epilog; }
if (!(pszDeviceClass = (WCHAR *) ServerAlloc(nStringSize) )) { pParams->lResult = PHONEERR_NOMEM; goto PGetID_epilog; }
}
wcscpy( pszDeviceClass, (PWSTR)(pDataBuf + pParams->dwDeviceClassOffset) );
if (!InitTapiStruct( pID, pParams->dwDeviceIDTotalSize, sizeof (VARSTRING), TRUE )) { ServerFree (pszDeviceClass); pParams->lResult = PHONEERR_STRUCTURETOOSMALL; goto PGetID_epilog; }
if ((pParams->lResult = CallSP4( pfnTSPI_phoneGetID, "phoneGetID", SP_FUNC_SYNC, (ULONG_PTR) hdPhone, (ULONG_PTR) pID, (ULONG_PTR) pszDeviceClass, (ULONG_PTR) (IS_REMOTE_CLIENT (ptClient) ? (HANDLE) -1 : ptClient->hProcess)
)) == 0) {
#if TELE_SERVER
//
// If
// this is a server &
// client doesn't have admin privileges &
// the specified device class == "tapi/line" &
// the dwUsedSize indicates that a line id was
// (likely) copied to the buffer
// then
// try to map the retrieved line device id back
// to one that makes sense to the client (and
// fail the request if there's no mapping)
//
if (IS_REMOTE_CLIENT(ptClient) && (_wcsicmp (pszDeviceClass, L"tapi/line") == 0) && !IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR) && (pID->dwUsedSize >= (sizeof (*pID) + sizeof (DWORD)))) { DWORD i; LPDWORD pdwLineID = (LPDWORD) (((LPBYTE) pID) + pID->dwStringOffset);
for (i = 0; i < ptClient->dwLineDevices; i++) { if (*pdwLineID == ptClient->pLineDevices[i]) { *pdwLineID = i; break; } }
if (i >= ptClient->dwLineDevices) { pParams->lResult = PHONEERR_OPERATIONFAILED; } } #endif
//
// Indicate offset & how many bytes of data we're passing back
//
pParams->dwDeviceIDOffset = 0;
*pdwNumBytesReturned = sizeof (TAPI32_MSG) + pID->dwUsedSize; }
ServerFree (pszDeviceClass); }
PGetID_epilog:
PHONEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "GetID" ); }
void WINAPI PGetLamp( PTCLIENT ptClient, PPHONEGETLAMP_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVPHONE hdPhone; TSPIPROC pfnTSPI_phoneGetLamp; DWORD dwPrivilege = PHONEPRIVILEGE_MONITOR;
if ((pParams->lResult = PHONEPROLOG( ptClient, // tClient
ANY_RT_HPHONE, // widget type
(DWORD) pParams->hPhone, // client widget handle
(LPVOID) &hdPhone, // provider widget handle
&dwPrivilege, // privileges or device ID
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_PHONEGETLAMP, // provider func index
&pfnTSPI_phoneGetLamp, // provider func pointer
NULL, // async request info
0, // client async request ID
"GetLamp" // func name
)) == 0) { if ((pParams->lResult = CallSP3( pfnTSPI_phoneGetLamp, "phoneGetLamp", SP_FUNC_SYNC, (ULONG_PTR) hdPhone, (DWORD) pParams->dwButtonLampID, (ULONG_PTR) &pParams->dwLampMode
)) == 0) { *pdwNumBytesReturned = sizeof (PHONEGETLAMP_PARAMS); } }
PHONEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "GetLamp" ); }
void WINAPI PGetRing( PTCLIENT ptClient, PPHONEGETRING_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVPHONE hdPhone; TSPIPROC pfnTSPI_phoneGetRing; DWORD dwPrivilege = PHONEPRIVILEGE_MONITOR;
if ((pParams->lResult = PHONEPROLOG( ptClient, // tClient
ANY_RT_HPHONE, // widget type
(DWORD) pParams->hPhone, // client widget handle
(LPVOID) &hdPhone, // provider widget handle
&dwPrivilege, // privileges or device ID
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_PHONEGETRING, // provider func index
&pfnTSPI_phoneGetRing, // provider func pointer
NULL, // async request info
0, // client async request ID
"GetRing" // func name
)) == 0) { if ((pParams->lResult = CallSP3( pfnTSPI_phoneGetRing, "phoneGetRing", SP_FUNC_SYNC, (ULONG_PTR) hdPhone, (ULONG_PTR) &pParams->dwRingMode, (ULONG_PTR) &pParams->dwVolume
)) == 0) { *pdwNumBytesReturned = sizeof (PHONEGETRING_PARAMS); } }
PHONEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "GetRing" ); }
void WINAPI PGetStatus( PTCLIENT ptClient, PPHONEGETSTATUS_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVPHONE hdPhone; TSPIPROC pfnTSPI_phoneGetStatus; DWORD dwPrivilege = PHONEPRIVILEGE_MONITOR; PTPHONECLIENT ptPhoneClient;
//
// Verify size/offset/string params given our input buffer/size
//
if (pParams->dwPhoneStatusTotalSize > dwParamsBufferSize) { pParams->lResult = PHONEERR_OPERATIONFAILED; return; }
if ((pParams->lResult = PHONEPROLOG( ptClient, // tClient
ANY_RT_HPHONE, // widget type
(DWORD) pParams->hPhone, // client widget handle
(LPVOID) &hdPhone, // provider widget handle
&dwPrivilege, // privileges or device ID
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_PHONEGETSTATUS, // provider func index
&pfnTSPI_phoneGetStatus, // provider func pointer
NULL, // async request info
0, // client async request ID
"GetStatus" // func name
)) == 0) { DWORD dwAPIVersion, dwSPIVersion, dwTotalSize, dwFixedSizeClient, dwFixedSizeSP; LPPHONESTATUS pStatus = (LPPHONESTATUS) pDataBuf, pStatus2 = (LPPHONESTATUS) NULL;
if (!(ptPhoneClient = ReferenceObject( ghHandleTable, pParams->hPhone, 0 ))) { pParams->lResult = (TapiGlobals.dwNumPhoneInits ? PHONEERR_INVALPHONEHANDLE : PHONEERR_UNINITIALIZED); // since ReferenceObject failed, no point
// in dereferencing.
goto PGetStatus_epilog; }
//
// Safely retrieve the API & SPI versions
//
if (GetPhoneVersions( pParams->hPhone, &dwAPIVersion, &dwSPIVersion
) != 0) { pParams->lResult = PHONEERR_INVALPHONEHANDLE; goto PGetStatus_dereference; }
//
// Determine the fixed size of the structure for the specified API
// version, verify client's buffer is big enough
//
dwTotalSize = pParams->dwPhoneStatusTotalSize;
switch (dwAPIVersion) { case TAPI_VERSION1_0: case TAPI_VERSION1_4:
dwFixedSizeClient = 100; // 25 * sizeof (DWORD)
break;
default: // (fix ppc build wrn) case TAPI_VERSION_CURRENT:
dwFixedSizeClient = sizeof (PHONESTATUS); break; }
if (dwTotalSize < dwFixedSizeClient) { pParams->lResult = PHONEERR_STRUCTURETOOSMALL; goto PGetStatus_dereference; }
//
// Determine the fixed size of the structure expected by the SP
//
switch (dwSPIVersion) { case TAPI_VERSION1_0: case TAPI_VERSION1_4:
dwFixedSizeSP = 100; // 25 * sizeof (DWORD)
break;
default: // (fix ppc build wrn) case TAPI_VERSION_CURRENT:
dwFixedSizeSP = sizeof (PHONESTATUS); break; }
//
// If the client's buffer is < the fixed size of that expected by
// the SP (client is lower version than SP) then allocate an
// intermediate buffer
//
if (dwTotalSize < dwFixedSizeSP) { if (!(pStatus2 = ServerAlloc (dwFixedSizeSP))) { pParams->lResult = PHONEERR_NOMEM; goto PGetStatus_dereference; }
pStatus = pStatus2; dwTotalSize = dwFixedSizeSP; }
InitTapiStruct( pStatus, dwTotalSize, dwFixedSizeSP, (pStatus2 == NULL ? TRUE : FALSE) );
if ((pParams->lResult = CallSP2( pfnTSPI_phoneGetStatus, "phoneGetStatus", SP_FUNC_SYNC, (ULONG_PTR) hdPhone, (ULONG_PTR) pStatus
)) == 0) { DWORD dwNeededSize = 0, dwAlign = 0; PTPHONEAPP ptPhoneApp; PTPHONE ptPhone; PTPHONECLIENT ptPhClnt; WCHAR *pAppName;
#if DBG
//
// Verify the info returned by the provider
//
#endif
//
// Add the fields we're responsible for
//
try { ptPhone = ptPhoneClient->ptPhone;
pStatus->dwNumOwners = ptPhone->dwNumOwners; pStatus->dwNumMonitors = ptPhone->dwNumMonitors;
if (0 != pStatus->dwUsedSize % 2) // 2 is sizeof(WCHAR)
{ // make sure that the owner name will always be aligned
// on a WCHAR boundary.
dwAlign = 1; }
// Initialize fields.
pStatus->dwOwnerNameSize = 0; pStatus->dwOwnerNameOffset = 0;
if (0 != ptPhone->dwNumOwners) { for (ptPhClnt = ptPhone->ptPhoneClients; NULL != ptPhClnt; ptPhClnt = ptPhClnt->pNextSametPhone) { if (PHONEPRIVILEGE_OWNER == ptPhClnt->dwPrivilege) { ptPhoneApp = ptPhClnt->ptPhoneApp; if (0 < ptPhoneApp->dwFriendlyNameSize && NULL != ptPhoneApp->pszFriendlyName) { dwNeededSize = ptPhoneApp->dwFriendlyNameSize + dwAlign; pAppName = ptPhoneApp->pszFriendlyName; } else if (0 < ptPhoneApp->dwModuleNameSize && NULL != ptPhoneApp->pszModuleName) { dwNeededSize = ptPhoneApp->dwFriendlyNameSize + dwAlign; pAppName = ptPhoneApp->pszFriendlyName; } else { break; }
pStatus->dwNeededSize += dwNeededSize;
if (dwNeededSize <= pStatus->dwTotalSize - pStatus->dwUsedSize) { pStatus->dwOwnerNameSize = dwNeededSize - dwAlign; pStatus->dwOwnerNameOffset = pStatus->dwUsedSize + dwAlign; CopyMemory( ((LPBYTE) pStatus) + pStatus->dwOwnerNameOffset, pAppName, dwNeededSize-dwAlign );
if (ptPhoneApp->dwKey == TPHONEAPP_KEY) { pStatus->dwUsedSize += dwNeededSize; } else { pStatus->dwOwnerNameSize = 0; pStatus->dwOwnerNameOffset = 0; } }
break; } } } } myexcept { pParams->lResult = PHONEERR_INVALPHONEHANDLE; goto PGetStatus_dereference; }
//
// Munge fields where appropriate for old apps (don't want to
// pass back flags that they won't understand)
//
//
// If an intermediate buffer was used then copy the bits back
// to the the original buffer, & free the intermediate buffer.
// Also reset the dwUsedSize field to the fixed size of the
// structure for the specifed version, since any data in the
// variable portion is garbage as far as the client is concerned.
//
if (pStatus == pStatus2) { pStatus = (LPPHONESTATUS) pDataBuf;
CopyMemory (pStatus, pStatus2, dwFixedSizeClient);
ServerFree (pStatus2);
pStatus->dwTotalSize = pParams->dwPhoneStatusTotalSize; pStatus->dwUsedSize = dwFixedSizeClient; }
//
// Indicate the offset & how many bytes of data we're passing back
//
pParams->dwPhoneStatusOffset = 0;
*pdwNumBytesReturned = sizeof (TAPI32_MSG) + pStatus->dwUsedSize; }
PGetStatus_dereference:
DereferenceObject (ghHandleTable, pParams->hPhone, 1); }
PGetStatus_epilog:
PHONEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "GetStatus" ); }
void WINAPI PGetStatusMessages( PTCLIENT ptClient, PPHONEGETSTATUSMESSAGES_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { PTPHONECLIENT ptPhoneClient;
if ((ptPhoneClient = ReferenceObject( ghHandleTable, pParams->hPhone, 0 ))) { if (ptPhoneClient->ptClient == ptClient) { pParams->dwPhoneStates = ptPhoneClient->dwPhoneStates; pParams->dwButtonModes = ptPhoneClient->dwButtonModes; pParams->dwButtonStates = ptPhoneClient->dwButtonStates;
*pdwNumBytesReturned = sizeof (PHONEGETSTATUSMESSAGES_PARAMS); } else { pParams->lResult = (TapiGlobals.dwNumPhoneInits ? PHONEERR_INVALPHONEHANDLE : PHONEERR_UNINITIALIZED); }
DereferenceObject (ghHandleTable, pParams->hPhone, 1); } else { pParams->lResult = (TapiGlobals.dwNumPhoneInits ? PHONEERR_INVALPHONEHANDLE : PHONEERR_UNINITIALIZED); }
#if DBG
{ char szResult[32];
LOG((TL_TRACE, "phoneGetStatusMessages: exit, result=%s", MapResultCodeToText (pParams->lResult, szResult) )); } #else
LOG((TL_TRACE, "phoneGetStatusMessages: exit, result=x%x", pParams->lResult )); #endif
}
void WINAPI PGetVolume( PTCLIENT ptClient, PPHONEGETVOLUME_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVPHONE hdPhone; TSPIPROC pfnTSPI_phoneGetVolume; DWORD dwPrivilege = PHONEPRIVILEGE_MONITOR;
if ((pParams->lResult = PHONEPROLOG( ptClient, // tClient
ANY_RT_HPHONE, // widget type
(DWORD) pParams->hPhone, // client widget handle
(LPVOID) &hdPhone, // provider widget handle
&dwPrivilege, // privileges or device ID
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_PHONEGETVOLUME, // provider func index
&pfnTSPI_phoneGetVolume, // provider func pointer
NULL, // async request info
0, // client async request ID
"GetVolume" // func name
)) == 0) { if (!IsOnlyOneBitSetInDWORD (pParams->dwHookSwitchDev) || (pParams->dwHookSwitchDev & ~AllHookSwitchDevs)) { pParams->lResult = PHONEERR_INVALHOOKSWITCHDEV; } else { if ((pParams->lResult = CallSP3( pfnTSPI_phoneGetVolume, "phoneGetVolume", SP_FUNC_SYNC, (ULONG_PTR) hdPhone, (DWORD) pParams->dwHookSwitchDev, (ULONG_PTR) &pParams->dwVolume
)) == 0) { *pdwNumBytesReturned = sizeof (PHONEGETVOLUME_PARAMS); } } }
PHONEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "GetVolume" ); }
void WINAPI PInitialize( PTCLIENT ptClient, PPHONEINITIALIZE_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { DWORD dwFriendlyNameSize, dwModuleNameSize; PTPHONEAPP ptPhoneApp; BOOL bInitClient = FALSE;
LOG((TL_TRACE, "PInitialize - enter. dwParamsBufferSize %lx, ptClient %p", dwParamsBufferSize, ptClient));
//
// Verify size/offset/string params given our input buffer/size
//
if (IsBadStringParam( dwParamsBufferSize, pDataBuf, pParams->dwFriendlyNameOffset ) ||
IsBadStringParam( dwParamsBufferSize, pDataBuf, pParams->dwModuleNameOffset )) { LOG((TL_ERROR, "PInitialize - error1.")); pParams->lResult = PHONEERR_OPERATIONFAILED; return; }
//
// Alloc & init a new tPhoneApp
//
dwFriendlyNameSize = sizeof(WCHAR) * (1 + lstrlenW( (PWSTR)(pDataBuf + pParams->dwFriendlyNameOffset)) );
dwModuleNameSize = sizeof(WCHAR) * (1 + lstrlenW( (PWSTR)(pDataBuf + pParams->dwModuleNameOffset)) );
if (!(ptPhoneApp = ServerAlloc( sizeof (TPHONEAPP) + dwFriendlyNameSize + dwModuleNameSize ))) { pParams->lResult = PHONEERR_NOMEM; goto PInitialize_return; }
if (!(ptPhoneApp->hPhoneApp = (HPHONEAPP) NewObject( ghHandleTable, ptPhoneApp, NULL ))) { pParams->lResult = PHONEERR_NOMEM; ServerFree (ptPhoneApp); goto PInitialize_return; }
ptPhoneApp->dwKey = TPHONEAPP_KEY; ptPhoneApp->ptClient = ptClient; ptPhoneApp->InitContext = pParams->InitContext; ptPhoneApp->dwAPIVersion = pParams->dwAPIVersion;
ptPhoneApp->pszFriendlyName = (WCHAR *) (ptPhoneApp + 1); ptPhoneApp->dwFriendlyNameSize = dwFriendlyNameSize;
wcscpy( ptPhoneApp->pszFriendlyName, (PWSTR)(pDataBuf + pParams->dwFriendlyNameOffset) );
ptPhoneApp->pszModuleName = (PWSTR)((BYTE *) (ptPhoneApp + 1) + dwFriendlyNameSize); ptPhoneApp->dwModuleNameSize = dwModuleNameSize;
wcscpy( ptPhoneApp->pszModuleName, (PWSTR)(pDataBuf + pParams->dwModuleNameOffset) );
//
// Safely insert new tPhoneApp at front of tClient's tPhoneApp list
//
if (ptClient->ptLineApps == NULL) { bInitClient = TRUE; }
if (WaitForExclusiveClientAccess (ptClient)) { if (ptPhoneApp->dwAPIVersion <= TAPI_VERSION3_0) { FillMemory ( ptPhoneApp->adwEventSubMasks, sizeof(DWORD) * EM_NUM_MASKS, (BYTE) 0xff ); } else { CopyMemory ( ptPhoneApp->adwEventSubMasks, ptClient->adwEventSubMasks, sizeof(DWORD) * EM_NUM_MASKS ); } if ((ptPhoneApp->pNext = ptClient->ptPhoneApps)) { ptPhoneApp->pNext->pPrev = ptPhoneApp; }
ptClient->ptPhoneApps = ptPhoneApp;
UNLOCKTCLIENT (ptClient); } else { LOG((TL_ERROR, "PInitialize - error2.")); pParams->lResult = PHONEERR_OPERATIONFAILED; goto PInitialize_error1; }
//
// Check if global reinit flag set
//
if (TapiGlobals.dwFlags & TAPIGLOBALS_REINIT) { pParams->lResult = PHONEERR_REINIT; goto PInitialize_error2; }
//
// See if we need to go thru init
//
TapiEnterCriticalSection (&TapiGlobals.CritSec);
if ((TapiGlobals.dwNumLineInits == 0) && (TapiGlobals.dwNumPhoneInits == 0) && !gbServerInited) { if ((pParams->lResult = ServerInit(FALSE)) != 0) { TapiLeaveCriticalSection (&TapiGlobals.CritSec); goto PInitialize_error2; } gbServerInited = TRUE; }
#if TELE_SERVER
if (bInitClient) { if (pParams->lResult = InitializeClient (ptClient)) { TapiLeaveCriticalSection (&TapiGlobals.CritSec); goto PInitialize_error2; } } #else
pParams->lResult = 0; // That's what happens if it's not a server...
#endif
//
// Fill in the return values
//
pParams->hPhoneApp = ptPhoneApp->hPhoneApp; pParams->dwNumDevs = TapiGlobals.dwNumPhones;
#if TELE_SERVER
if ((TapiGlobals.dwFlags & TAPIGLOBALS_SERVER) && !IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR)) { pParams->dwNumDevs = ptClient->dwPhoneDevices; } #endif
//
// Increment total num phone inits
//
TapiGlobals.dwNumPhoneInits++;
*pdwNumBytesReturned = sizeof (PHONEINITIALIZE_PARAMS);
TapiLeaveCriticalSection (&TapiGlobals.CritSec);
goto PInitialize_return;
PInitialize_error2:
if (WaitForExclusiveClientAccess (ptClient)) { if (ptPhoneApp->pNext) { ptPhoneApp->pNext->pPrev = ptPhoneApp->pPrev; }
if (ptPhoneApp->pPrev) { ptPhoneApp->pPrev->pNext = ptPhoneApp->pNext; } else { ptClient->ptPhoneApps = ptPhoneApp->pNext; }
UNLOCKTCLIENT (ptClient); }
PInitialize_error1:
DereferenceObject (ghHandleTable, ptPhoneApp->hPhoneApp, 1);
PInitialize_return:
#if DBG
{ char szResult[32];
LOG((TL_TRACE, "phoneInitialize: exit, result=%s", MapResultCodeToText (pParams->lResult, szResult) )); } #else
LOG((TL_TRACE, "phoneInitialize: exit, result=x%x", pParams->lResult )); #endif
return; }
void WINAPI PNegotiateAPIVersion( PTCLIENT ptClient, PPHONENEGOTIATEAPIVERSION_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { //
// Note: TAPI_VERSION1_0 <= dwNegotiatedAPIVersion <= dwSPIVersion
//
DWORD dwDeviceID = pParams->dwDeviceID;
//
// Verify size/offset/string params given our input buffer/size
//
if (dwParamsBufferSize < sizeof (PHONEEXTENSIONID)) { pParams->lResult = PHONEERR_OPERATIONFAILED; return; }
if (TapiGlobals.dwNumPhoneInits == 0) { pParams->lResult = PHONEERR_UNINITIALIZED; goto PNegotiateAPIVersion_exit; }
#if TELE_SERVER
if ((TapiGlobals.dwFlags & TAPIGLOBALS_SERVER) && !IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR)) { try { if (dwDeviceID >= ptClient->dwPhoneDevices) { pParams->lResult = PHONEERR_BADDEVICEID; goto PNegotiateAPIVersion_exit; } dwDeviceID = ptClient->pPhoneDevices[dwDeviceID]; } myexcept { LOG((TL_ERROR, "ptClient excepted in PhoneNegotiateAPIVersion")); pParams->lResult = PHONEERR_INVALPHONEHANDLE; goto PNegotiateAPIVersion_exit; } }
#endif
if (dwDeviceID < TapiGlobals.dwNumPhones) { DWORD dwAPIHighVersion = pParams->dwAPIHighVersion, dwAPILowVersion = pParams->dwAPILowVersion, dwHighestValidAPIVersion; PTPHONEAPP ptPhoneApp;
if (!(ptPhoneApp = ReferenceObject( ghHandleTable, pParams->hPhoneApp, TPHONEAPP_KEY ))) { pParams->lResult = (TapiGlobals.dwNumPhoneInits ? PHONEERR_INVALAPPHANDLE : PHONEERR_UNINITIALIZED);
goto PNegotiateAPIVersion_exit; }
//
// Do a minimax test on the specified lo/hi values
//
if ((dwAPILowVersion > dwAPIHighVersion) || (dwAPILowVersion > TAPI_VERSION_CURRENT) || (dwAPIHighVersion < TAPI_VERSION1_0)) { pParams->lResult = PHONEERR_INCOMPATIBLEAPIVERSION; goto PNegotiateAPIVersion_dereference; }
//
// Find the highest valid API version given the lo/hi values.
// Since valid vers aren't consecutive we need to check for
// errors that our minimax test missed.
//
if (dwAPIHighVersion < TAPI_VERSION_CURRENT) { if ((dwAPIHighVersion >= TAPI_VERSION3_0) && (dwAPILowVersion <= TAPI_VERSION3_0)) { dwHighestValidAPIVersion = TAPI_VERSION3_0; } else if ((dwAPIHighVersion >= TAPI_VERSION2_2) && (dwAPILowVersion <= TAPI_VERSION2_2)) { dwHighestValidAPIVersion = TAPI_VERSION2_2; } else if ((dwAPIHighVersion >= TAPI_VERSION2_1) && (dwAPILowVersion <= TAPI_VERSION2_1)) { dwHighestValidAPIVersion = TAPI_VERSION2_1; } else if ((dwAPIHighVersion >= TAPI_VERSION2_0) && (dwAPILowVersion <= TAPI_VERSION2_0)) { dwHighestValidAPIVersion = TAPI_VERSION2_0; } else if ((dwAPIHighVersion >= TAPI_VERSION1_4) && (dwAPILowVersion <= TAPI_VERSION1_4)) { dwHighestValidAPIVersion = TAPI_VERSION1_4; } else if ((dwAPIHighVersion >= TAPI_VERSION1_0) && (dwAPILowVersion <= TAPI_VERSION1_0)) { dwHighestValidAPIVersion = TAPI_VERSION1_0; } else { LOG((TL_ERROR, " Incompatible version")); pParams->lResult = PHONEERR_INCOMPATIBLEAPIVERSION; goto PNegotiateAPIVersion_dereference; } } else { dwHighestValidAPIVersion = TAPI_VERSION_CURRENT; }
//
// WARNING!!! WARNING!!! WARNING!!! WARNING!!!
// This code overwrites ptPhoneApp and later invalidates it.
// Do NOT use ptPhoneApp after the UNLOCKTPHONEAPP call.
//
if (WaitForExclusivePhoneAppAccess( pParams->hPhoneApp, ptClient )) {
//
// Is this app trying to negotiate something valid?
//
// If an app has called phoneInitalize (as opposed to
// phoneInitializeEx), we'll clamp the max APIVersion they can
// negotiate to 1.4.
//
if ( ptPhoneApp->dwAPIVersion < TAPI_VERSION2_0 ) { dwHighestValidAPIVersion = (dwHighestValidAPIVersion >= TAPI_VERSION1_4) ? TAPI_VERSION1_4 : TAPI_VERSION1_0; }
//
// Save the highest valid API version the client says it supports
// (we need this for determining which msgs to send to it)
//
if (dwHighestValidAPIVersion > ptPhoneApp->dwAPIVersion) { ptPhoneApp->dwAPIVersion = dwHighestValidAPIVersion; }
UNLOCKTPHONEAPP(ptPhoneApp); } else { pParams->lResult = PHONEERR_INVALAPPHANDLE; goto PNegotiateAPIVersion_dereference; }
//
// See if there's a valid match with the SPI ver
//
{ DWORD dwSPIVersion; PTPHONELOOKUPENTRY pLookupEntry;
pLookupEntry = GetPhoneLookupEntry (dwDeviceID); dwSPIVersion = pLookupEntry->dwSPIVersion;
if (pLookupEntry->bRemoved) { LOG((TL_ERROR, " phone removed...")); pParams->lResult = PHONEERR_NODEVICE; goto PNegotiateAPIVersion_dereference; }
if (pLookupEntry->ptProvider == NULL) { LOG((TL_ERROR, " Provider == NULL")); pParams->lResult = PHONEERR_NODRIVER; goto PNegotiateAPIVersion_dereference; }
if (dwAPILowVersion <= dwSPIVersion) { pParams->dwAPIVersion = (dwHighestValidAPIVersion > dwSPIVersion ? dwSPIVersion : dwHighestValidAPIVersion);
//
// Retrieve ext id (indicate no exts if GetExtID not exported)
//
if (pLookupEntry->ptProvider->apfn[SP_PHONEGETEXTENSIONID]) { if ((pParams->lResult = CallSP3( pLookupEntry->ptProvider-> apfn[SP_PHONEGETEXTENSIONID], "phoneGetExtensionID", SP_FUNC_SYNC, (DWORD) dwDeviceID, (DWORD) dwSPIVersion, (ULONG_PTR) pDataBuf
)) != 0) { goto PNegotiateAPIVersion_dereference; } } else { FillMemory (pDataBuf, sizeof (PHONEEXTENSIONID), 0); } } else { LOG((TL_ERROR, " API version too high")); pParams->lResult = PHONEERR_INCOMPATIBLEAPIVERSION; goto PNegotiateAPIVersion_dereference; } }
pParams->dwExtensionIDOffset = 0; pParams->dwSize = sizeof (PHONEEXTENSIONID);
LOG((TL_INFO, " ExtensionID0=x%08lx", *(LPDWORD)(pDataBuf+0) )); LOG((TL_INFO, " ExtensionID1=x%08lx", *(LPDWORD)(pDataBuf+4) )); LOG((TL_INFO, " ExtensionID2=x%08lx", *(LPDWORD)(pDataBuf+8) )); LOG((TL_INFO, " ExtensionID3=x%08lx", *(LPDWORD)(pDataBuf+12) ));
*pdwNumBytesReturned = sizeof (PHONEEXTENSIONID) + sizeof (TAPI32_MSG);
PNegotiateAPIVersion_dereference:
DereferenceObject (ghHandleTable, pParams->hPhoneApp, 1); } else { pParams->lResult = PHONEERR_BADDEVICEID; }
PNegotiateAPIVersion_exit:
#if DBG
{ char szResult[32];
LOG((TL_TRACE, "phoneNegotiateAPIVersion: exit, result=%s", MapResultCodeToText (pParams->lResult, szResult) )); } #else
LOG((TL_TRACE, "phoneNegotiateAPIVersion: exit, result=x%x", pParams->lResult )); #endif
return; }
void WINAPI PNegotiateExtVersion( PTCLIENT ptClient, PPHONENEGOTIATEEXTVERSION_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; DWORD dwDeviceID = pParams->dwDeviceID; HANDLE hMutex; TSPIPROC pfnTSPI_phoneNegotiateExtVersion;
if ((pParams->lResult = PHONEPROLOG( ptClient, // tClient
DEVICE_ID, // widget type
(DWORD) pParams->hPhoneApp, // client widget handle
NULL, // provider widget handle
&dwDeviceID, // privileges or device ID
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_PHONENEGOTIATEEXTVERSION,// provider func index
&pfnTSPI_phoneNegotiateExtVersion, // provider func pointer
NULL, // async request info
0, // client async request ID
"NegotiateExtVersion" // func name
)) == 0) { DWORD dwSPIVersion = (GetPhoneLookupEntry(dwDeviceID))->dwSPIVersion;
if (!IsAPIVersionInRange( pParams->dwAPIVersion, dwSPIVersion )) { pParams->lResult = PHONEERR_INCOMPATIBLEAPIVERSION; goto PNegotiateExtVersion_epilog; }
if ((pParams->lResult = CallSP5( pfnTSPI_phoneNegotiateExtVersion, "phoneNegotiateExtVersion", SP_FUNC_SYNC, (DWORD) dwDeviceID, (DWORD) dwSPIVersion, (DWORD) pParams->dwExtLowVersion, (DWORD) pParams->dwExtHighVersion, (ULONG_PTR) &pParams->dwExtVersion
)) == 0) { if (pParams->dwExtVersion == 0) { pParams->lResult = PHONEERR_INCOMPATIBLEEXTVERSION; } else { *pdwNumBytesReturned = sizeof(PHONENEGOTIATEEXTVERSION_PARAMS); } } }
PNegotiateExtVersion_epilog:
PHONEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "NegotiateExtVersion" ); }
void WINAPI POpen( PTCLIENT ptClient, PPHONEOPEN_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex, bOpenedtPhone = FALSE, bReleasetPhoneMutex = FALSE; LONG lResult; DWORD dwDeviceID = pParams->dwDeviceID, dwNumMonitors; HANDLE hMutex; PTPHONE ptPhone = NULL; PTPHONECLIENT ptPhoneClient = NULL; PTPHONELOOKUPENTRY pLookupEntry; HANDLE hLookupEntryMutex = NULL;
if ((lResult = PHONEPROLOG( ptClient, // tClient
DEVICE_ID, // widget type
(DWORD) pParams->hPhoneApp, // client widget handle
NULL, // provider widget handle
&dwDeviceID, // privileges or device ID
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
0, // provider func index
NULL, // provider func pointer
NULL, // async request info
0, // client async request ID
"Open" // func name
)) == 0) { DWORD dwPrivilege = pParams->dwPrivilege, dwExtVersion = pParams->dwExtVersion; PTPROVIDER ptProvider; BOOL bDuplicateOK = FALSE;
//
// Check if the global reinit flag is set
//
if (TapiGlobals.dwFlags & TAPIGLOBALS_REINIT) { lResult = PHONEERR_REINIT; goto POpen_cleanup; }
//
// Validate params
//
if ((dwPrivilege != PHONEPRIVILEGE_MONITOR) && (dwPrivilege != PHONEPRIVILEGE_OWNER)) { lResult = PHONEERR_INVALPRIVILEGE; goto POpen_cleanup; }
pLookupEntry = GetPhoneLookupEntry (dwDeviceID);
TapiEnterCriticalSection (&TapiGlobals.CritSec);
if ( pLookupEntry->hMutex ) { bDuplicateOK = DuplicateHandle( TapiGlobals.hProcess, pLookupEntry->hMutex, TapiGlobals.hProcess, &hLookupEntryMutex, 0, FALSE, DUPLICATE_SAME_ACCESS ); }
TapiLeaveCriticalSection(&TapiGlobals.CritSec);
if ( !bDuplicateOK ) { LOG((TL_ERROR, "DuplicateHandle failed!"));
lResult = PHONEERR_OPERATIONFAILED; goto POpen_cleanup; }
if (!IsAPIVersionInRange( pParams->dwAPIVersion, pLookupEntry->dwSPIVersion )) { lResult = PHONEERR_INCOMPATIBLEAPIVERSION; goto POpen_cleanup; }
ptProvider = pLookupEntry->ptProvider;
//
// Create & init a tPhoneClient & associated resources
//
if (!(ptPhoneClient = ServerAlloc (sizeof(TPHONECLIENT)))) { lResult = PHONEERR_NOMEM; goto POpen_cleanup; }
if (!(ptPhoneClient->hPhone = (HPHONE) NewObject( ghHandleTable, ptPhoneClient, 0 ))) { ptPhoneClient = NULL; ServerFree (ptPhoneClient); lResult = PHONEERR_NOMEM; goto POpen_cleanup; }
ptPhoneClient->ptClient = ptClient; ptPhoneClient->hRemotePhone = (pParams->hRemotePhone ? (DWORD) pParams->hRemotePhone : ptPhoneClient->hPhone); ptPhoneClient->dwAPIVersion = pParams->dwAPIVersion; ptPhoneClient->dwPrivilege = pParams->dwPrivilege; ptPhoneClient->OpenContext = pParams->OpenContext;
//
// Grab the tPhone's mutex, then start doing the open
//
POpen_waitForMutex:
if (WaitForSingleObject (hLookupEntryMutex, INFINITE) != WAIT_OBJECT_0) { LOG((TL_ERROR, "WaitForSingleObject failed!"));
lResult = PHONEERR_OPERATIONFAILED; goto POpen_cleanup; }
bReleasetPhoneMutex = TRUE;
//
// If the tPhone is in the process of being destroyed then spin
// until it's been completely destroyed (DestroytPhone() will
// NULLify pLookupEntry->ptPhone when it's finished). Make sure
// to release the mutex while sleeping so we don't block
// DestroytPhone.
//
try { while (pLookupEntry->ptPhone && pLookupEntry->ptPhone->dwKey != TPHONE_KEY) { ReleaseMutex (hLookupEntryMutex); Sleep (0); goto POpen_waitForMutex; } } myexcept { // If here pLookupEntry->ptPhone was NULLified, safe to continue
}
//
// Validate ext ver as appropriate
//
if (dwExtVersion != 0 && (!IsValidPhoneExtVersion (dwDeviceID, dwExtVersion) || ptProvider->apfn[SP_PHONESELECTEXTVERSION] == NULL)) { lResult = PHONEERR_INCOMPATIBLEEXTVERSION; goto POpen_cleanup; }
//
// Check for exclusive ownership as appropriate
//
ptPhone = pLookupEntry->ptPhone;
if (dwPrivilege == PHONEPRIVILEGE_OWNER && ptPhone && (ptPhone->dwNumOwners != 0) ) { lResult = PHONEERR_INUSE; goto POpen_cleanup; }
if (ptPhone == NULL) { if (!(ptPhone = ServerAlloc (sizeof(TPHONE)))) { lResult = PHONEERR_NOMEM; goto POpen_cleanup; }
if (!(ptPhone->hPhone = (HPHONE) NewObject( ghHandleTable, (LPVOID) ptPhone, NULL ))) { ServerFree (ptPhone); lResult = PHONEERR_NOMEM; goto POpen_cleanup; }
ptPhone->dwKey = TINCOMPLETEPHONE_KEY; ptPhone->hMutex = pLookupEntry->hMutex; ptPhone->ptProvider = ptProvider; ptPhone->dwDeviceID = dwDeviceID; ptPhone->dwSPIVersion = pLookupEntry->dwSPIVersion;
bOpenedtPhone = TRUE;
{ //
// Hack Alert!
//
// We need to pass the ext version through to
// remote sp, so we make this a special case
//
ULONG_PTR aParams[2]; ULONG_PTR param;
if (ptProvider == pRemoteSP) { aParams[0] = (ULONG_PTR) ptPhone; aParams[1] = dwExtVersion;
param = (ULONG_PTR) aParams; } else { param = (ULONG_PTR) ptPhone; }
if (ptProvider->apfn[SP_PHONEOPEN] == NULL) { lResult = PHONEERR_OPERATIONUNAVAIL; goto POpen_cleanup; }
if ((lResult = CallSP5( ptProvider->apfn[SP_PHONEOPEN], "phoneOpen", SP_FUNC_SYNC, (DWORD) dwDeviceID, (ULONG_PTR) param, (ULONG_PTR) &ptPhone->hdPhone, (DWORD) pLookupEntry->dwSPIVersion, (ULONG_PTR) PhoneEventProcSP
)) != 0) { goto POpen_cleanup; } } }
ptPhoneClient->ptPhone = ptPhone;
//
// If the client has specified a non-zero ext version then
// ask the driver to enable it and/or increment the ext
// version count.
//
if (dwExtVersion) { if (ptPhone->dwExtVersionCount == 0) { if (ptProvider != pRemoteSP && ((ptProvider->apfn[SP_PHONESELECTEXTVERSION] == NULL) || (lResult = CallSP2( ptProvider->apfn[SP_PHONESELECTEXTVERSION], "phoneSelectExtVersion", SP_FUNC_SYNC, (ULONG_PTR) ptPhone->hdPhone, (DWORD) dwExtVersion
)) != 0)) { if (bOpenedtPhone && ptProvider->apfn[SP_PHONECLOSE]) { CallSP1( ptProvider->apfn[SP_PHONECLOSE], "phoneClose", SP_FUNC_SYNC, (ULONG_PTR) ptPhone->hdPhone ); }
goto POpen_cleanup; }
ptPhone->dwExtVersion = dwExtVersion; }
ptPhoneClient->dwExtVersion = dwExtVersion; ptPhone->dwExtVersionCount++; }
//
//
//
if (dwPrivilege == PHONEPRIVILEGE_OWNER) { ptPhone->dwNumOwners++; } else { ptPhone->dwNumMonitors++; dwNumMonitors = ptPhone->dwNumMonitors; }
//
// Add the tPhoneClient to the tPhone's list
//
if ((ptPhoneClient->pNextSametPhone = ptPhone->ptPhoneClients)) { ptPhoneClient->pNextSametPhone->pPrevSametPhone = ptPhoneClient; }
ptPhone->ptPhoneClients = ptPhoneClient;
if (bOpenedtPhone) { pLookupEntry->ptPhone = ptPhone; ptPhone->dwKey = TPHONE_KEY; }
ReleaseMutex (hLookupEntryMutex);
bReleasetPhoneMutex = FALSE;
//
// Safely add the new tPhoneClient to the tPhoneApp's list
//
{ HANDLE hMutex; PTPHONEAPP ptPhoneApp;
if ((ptPhoneApp = WaitForExclusivePhoneAppAccess( pParams->hPhoneApp, ptClient ))) {
if (ptPhoneApp->dwAPIVersion <= TAPI_VERSION3_0) { FillMemory ( ptPhoneClient->adwEventSubMasks, sizeof(DWORD) * EM_NUM_MASKS, (BYTE) 0xff ); } else { CopyMemory ( ptPhoneClient->adwEventSubMasks, ptPhoneApp->adwEventSubMasks, sizeof(DWORD) * EM_NUM_MASKS ); }
if ((ptPhoneClient->pNextSametPhoneApp = ptPhoneApp->ptPhoneClients)) { ptPhoneClient->pNextSametPhoneApp->pPrevSametPhoneApp = ptPhoneClient; }
ptPhoneApp->ptPhoneClients = ptPhoneClient;
ptPhoneClient->ptPhoneApp = ptPhoneApp; ptPhoneClient->dwKey = TPHONECLIENT_KEY;
//
// Fill in the return values
//
pParams->hPhone = ptPhoneClient->hPhone;
UNLOCKTPHONEAPP(ptPhoneApp);
//
// Alert other clients that another open has occured
//
SendMsgToPhoneClients( ptPhone, ptPhoneClient, PHONE_STATE, (pParams->dwPrivilege == PHONEPRIVILEGE_OWNER ? PHONESTATE_OWNER : PHONESTATE_MONITORS), (pParams->dwPrivilege == PHONEPRIVILEGE_OWNER ? 1 : dwNumMonitors), 0 );
*pdwNumBytesReturned = sizeof (PHONEOPEN_PARAMS); } else { //
// If here the app handle is bad, & we've some special
// case cleanup to do. Since the tPhoneClient is not
// in the tPhoneApp's list, we can't simply call
// DestroytPhone(Client) to clean things up, since the
// pointer-resetting code will blow up. So we'll
// grab the tPhone's mutex and explicitly remove the
// new tPhoneClient from it's list, then do a conditional
// shutdown on the tPhone (in case any other clients
// have come along & opened it).
//
// Note: keep in mind that a PHONE_CLOSE might be being
// processed by another thread (if so, it will be
// spinning on trying to destroy the tPhoneClient
// which isn't valid at this point)
//
lResult = PHONEERR_INVALAPPHANDLE;
WaitForSingleObject (hLookupEntryMutex, INFINITE);
//
// Remove the tpHOneClient from the tLine's list & decrement
// the number of opens
//
if (ptPhoneClient->pNextSametPhone) { ptPhoneClient->pNextSametPhone->pPrevSametPhone = ptPhoneClient->pPrevSametPhone; }
if (ptPhoneClient->pPrevSametPhone) { ptPhoneClient->pPrevSametPhone->pNextSametPhone = ptPhoneClient->pNextSametPhone; } else { ptPhone->ptPhoneClients = ptPhoneClient->pNextSametPhone; }
if (dwPrivilege == PHONEPRIVILEGE_OWNER) { ptPhone->dwNumOwners--; } else { ptPhone->dwNumMonitors--; }
if (dwExtVersion != 0) { ptPhone->dwExtVersionCount--;
if (ptPhone->dwExtVersionCount == 0 && ptProvider->apfn[SP_PHONESELECTEXTVERSION]) { ptPhone->dwExtVersion = 0;
CallSP2( ptProvider->apfn[SP_PHONESELECTEXTVERSION], "phoneSelectExtVersion", SP_FUNC_SYNC, (ULONG_PTR) ptPhone->hdPhone, (DWORD) 0 ); } }
ReleaseMutex (hLookupEntryMutex);
DestroytPhone (ptPhone, FALSE); // conditional destroy
bOpenedtPhone = FALSE; // so we don't do err handling below
} }
CloseHandle (hLookupEntryMutex); }
POpen_cleanup:
if (bReleasetPhoneMutex) { ReleaseMutex (hLookupEntryMutex); CloseHandle (hLookupEntryMutex); }
if (lResult != 0) { if (ptPhoneClient) { DereferenceObject (ghHandleTable, ptPhoneClient->hPhone, 1); }
if (bOpenedtPhone) { DereferenceObject (ghHandleTable, ptPhone->hPhone, 1); } }
pParams->lResult = lResult;
PHONEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "Open" ); }
void WINAPI PSelectExtVersion( PTCLIENT ptClient, PPHONESELECTEXTVERSION_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex, bCloseMutex2; HANDLE hMutex, hMutex2; HDRVPHONE hdPhone; TSPIPROC pfnTSPI_phoneSelectExtVersion; DWORD dwPrivilege = 0; PTPHONECLIENT ptPhoneClient;
if ((pParams->lResult = PHONEPROLOG( ptClient, // tClient
ANY_RT_HPHONE, // widget type
(DWORD) pParams->hPhone, // client widget handle
(LPVOID) &hdPhone, // provider widget handle
&dwPrivilege, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_PHONESELECTEXTVERSION, // provider func index
&pfnTSPI_phoneSelectExtVersion, // provider func pointer
NULL, // async request info
0, // client async request ID
"SelectExtVersion" // func name
)) == 0) { if ((ptPhoneClient = ReferenceObject( ghHandleTable, pParams->hPhone, TPHONECLIENT_KEY ))) { if (WaitForExclusivetPhoneAccess( ptPhoneClient->ptPhone, &hMutex2, &bCloseMutex2, INFINITE )) { if (IsValidPhoneExtVersion( ptPhoneClient->ptPhone->dwDeviceID, pParams->dwExtVersion )) { if (pParams->dwExtVersion) { if (ptPhoneClient->ptPhone->dwExtVersionCount ||
(pParams->lResult = CallSP2( pfnTSPI_phoneSelectExtVersion, "phoneSelectExtVersion", SP_FUNC_SYNC, (ULONG_PTR) hdPhone, (DWORD) pParams->dwExtVersion
)) == 0) { ptPhoneClient->dwExtVersion = ptPhoneClient->ptPhone->dwExtVersion = pParams->dwExtVersion; ptPhoneClient->ptPhone->dwExtVersionCount++; } } else if (ptPhoneClient->ptPhone->dwExtVersionCount) { if (--ptPhoneClient->ptPhone->dwExtVersionCount == 0) { CallSP2( pfnTSPI_phoneSelectExtVersion, "phoneSelectExtVersion", SP_FUNC_SYNC, (ULONG_PTR) hdPhone, (DWORD) 0 );
ptPhoneClient->ptPhone->dwExtVersion = 0; }
ptPhoneClient->dwExtVersion = 0; } } else { pParams->lResult = PHONEERR_INCOMPATIBLEEXTVERSION; }
MyReleaseMutex (hMutex2, bCloseMutex2); } else { pParams->lResult = PHONEERR_INVALPHONEHANDLE; }
DereferenceObject (ghHandleTable, pParams->hPhone, 1); } else { pParams->lResult = PHONEERR_INVALPHONEHANDLE; } }
PHONEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "SelectExtVersion" );
}
void WINAPI PSetButtonInfo( PTCLIENT ptClient, PPHONESETBUTTONINFO_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVPHONE hdPhone; PASYNCREQUESTINFO pAsyncRequestInfo; TSPIPROC pfnTSPI_phoneSetButtonInfo; DWORD dwPrivilege = PHONEPRIVILEGE_OWNER;
if ((lRequestID = PHONEPROLOG( ptClient, // tClient
ANY_RT_HPHONE, // widget type
(DWORD) pParams->hPhone, // client widget handle
(LPVOID) &hdPhone, // provider widget handle
&dwPrivilege, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_PHONESETBUTTONINFO, // provider func index
&pfnTSPI_phoneSetButtonInfo,// provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
"SetButtonInfo" // func name
)) > 0) { LONG lResult; DWORD dwAPIVersion, dwSPIVersion; LPPHONEBUTTONINFO pButtonInfoApp = (LPPHONEBUTTONINFO) (pDataBuf + pParams->dwButtonInfoOffset), pButtonInfoSP;
//
// Verify size/offset/string params given our input buffer/size
//
if (IsBadStructParam( dwParamsBufferSize, pDataBuf, pParams->dwButtonInfoOffset )) { lRequestID = PHONEERR_STRUCTURETOOSMALL; goto PSetButtonInfo_epilog; }
//
// Safely get API & SPI version
//
if (GetPhoneVersions( pParams->hPhone, &dwAPIVersion, &dwSPIVersion
) != 0) { lRequestID = PHONEERR_INVALPHONEHANDLE; goto PSetButtonInfo_epilog; }
if ((lResult = ValidateButtonInfo( pButtonInfoApp, &pButtonInfoSP, dwAPIVersion, dwSPIVersion ))) { lRequestID = lResult; goto PSetButtonInfo_epilog; }
pParams->lResult = CallSP4( pfnTSPI_phoneSetButtonInfo, "phoneSetButtonInfo", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdPhone, (DWORD) pParams->dwButtonLampID, (ULONG_PTR) pButtonInfoSP );
if (pButtonInfoSP != pButtonInfoApp) { ServerFree (pButtonInfoSP); } }
PSetButtonInfo_epilog:
PHONEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, "SetButtonInfo" ); }
void WINAPI PSetData( PTCLIENT ptClient, PPHONESETDATA_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVPHONE hdPhone; PASYNCREQUESTINFO pAsyncRequestInfo; TSPIPROC pfnTSPI_phoneSetData; DWORD dwPrivilege = PHONEPRIVILEGE_OWNER;
//
// Verify size/offset/string params given our input buffer/size
//
if (ISBADSIZEOFFSET( dwParamsBufferSize, 0, pParams->dwSize, pParams->dwDataOffset, sizeof(DWORD), "PSetData", "pParams->Data" )) { pParams->lResult = PHONEERR_OPERATIONFAILED; return; }
if ((lRequestID = PHONEPROLOG( ptClient, // tClient
ANY_RT_HPHONE, // widget type
(DWORD) pParams->hPhone, // client widget handle
(LPVOID) &hdPhone, // provider widget handle
&dwPrivilege, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_PHONESETDATA, // provider func index
&pfnTSPI_phoneSetData, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
"SetData" // func name
)) > 0) { pParams->lResult = CallSP5( pfnTSPI_phoneSetData, "phoneSetData", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdPhone, (DWORD) pParams->dwDataID, (ULONG_PTR) (pParams->dwSize ? pDataBuf + pParams->dwDataOffset : NULL), (DWORD) pParams->dwSize ); }
PHONEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, "SetData" ); }
void WINAPI PSetDisplay( PTCLIENT ptClient, PPHONESETDISPLAY_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVPHONE hdPhone; PASYNCREQUESTINFO pAsyncRequestInfo; TSPIPROC pfnTSPI_phoneSetDisplay; DWORD dwPrivilege = PHONEPRIVILEGE_OWNER;
//
// Verify size/offset/string params given our input buffer/size
//
if (ISBADSIZEOFFSET( dwParamsBufferSize, 0, pParams->dwSize, pParams->dwDisplayOffset, sizeof(DWORD), "PSetDisplay", "pParams->Display" )) { pParams->lResult = PHONEERR_OPERATIONFAILED; return; }
if ((lRequestID = PHONEPROLOG( ptClient, // tClient
ANY_RT_HPHONE, // widget type
(DWORD) pParams->hPhone, // client widget handle
(LPVOID) &hdPhone, // provider widget handle
&dwPrivilege, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_PHONESETDISPLAY, // provider func index
&pfnTSPI_phoneSetDisplay, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
"SetDisplay" // func name
)) > 0) { pParams->lResult = CallSP6( pfnTSPI_phoneSetDisplay, "phoneSetDisplay", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdPhone, (DWORD) pParams->dwRow, (DWORD) pParams->dwColumn, (ULONG_PTR) (pParams->dwSize ? pDataBuf + pParams->dwDisplayOffset : NULL), (DWORD) pParams->dwSize ); }
PHONEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, "SetDisplay" ); }
void WINAPI PSetGain( PTCLIENT ptClient, PPHONESETGAIN_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVPHONE hdPhone; PASYNCREQUESTINFO pAsyncRequestInfo; TSPIPROC pfnTSPI_phoneSetGain; DWORD dwPrivilege = PHONEPRIVILEGE_OWNER;
if ((lRequestID = PHONEPROLOG( ptClient, // tClient
ANY_RT_HPHONE, // widget type
(DWORD) pParams->hPhone, // client widget handle
(LPVOID) &hdPhone, // provider widget handle
&dwPrivilege, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_PHONESETGAIN, // provider func index
&pfnTSPI_phoneSetGain, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
"SetGain" // func name
)) > 0) { if (!IsOnlyOneBitSetInDWORD (pParams->dwHookSwitchDev) || (pParams->dwHookSwitchDev & ~AllHookSwitchDevs)) { lRequestID = PHONEERR_INVALHOOKSWITCHDEV; } else { pParams->lResult = CallSP4( pfnTSPI_phoneSetGain, "phoneSetGain", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdPhone, (DWORD) pParams->dwHookSwitchDev, (DWORD) (pParams->dwGain > 0x0000ffff ? 0x0000ffff : pParams->dwGain) ); } }
PHONEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, "SetGain" ); }
void WINAPI PSetHookSwitch( PTCLIENT ptClient, PPHONESETHOOKSWITCH_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVPHONE hdPhone; PASYNCREQUESTINFO pAsyncRequestInfo; TSPIPROC pfnTSPI_phoneSetHookSwitch; DWORD dwPrivilege = PHONEPRIVILEGE_OWNER;
if ((lRequestID = PHONEPROLOG( ptClient, // tClient
ANY_RT_HPHONE, // widget type
(DWORD) pParams->hPhone, // client widget handle
(LPVOID) &hdPhone, // provider widget handle
&dwPrivilege, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_PHONESETHOOKSWITCH, // provider func index
&pfnTSPI_phoneSetHookSwitch,// provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
"SetHookSwitch" // func name
)) > 0) { if (!(pParams->dwHookSwitchDevs & AllHookSwitchDevs) || (pParams->dwHookSwitchDevs & (~AllHookSwitchDevs))) { lRequestID = PHONEERR_INVALHOOKSWITCHDEV; } else if (!IsOnlyOneBitSetInDWORD (pParams->dwHookSwitchMode) || (pParams->dwHookSwitchMode & ~AllHookSwitchModes)) { lRequestID = PHONEERR_INVALHOOKSWITCHMODE; } else { pParams->lResult = CallSP4( pfnTSPI_phoneSetHookSwitch, "phoneSetHookSwitch", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdPhone, (DWORD) pParams->dwHookSwitchDevs, (DWORD) pParams->dwHookSwitchMode ); } }
PHONEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, "SetHookSwitch" ); }
void WINAPI PSetLamp( PTCLIENT ptClient, PPHONESETLAMP_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVPHONE hdPhone; PASYNCREQUESTINFO pAsyncRequestInfo; TSPIPROC pfnTSPI_phoneSetLamp; DWORD dwPrivilege = PHONEPRIVILEGE_OWNER;
if ((lRequestID = PHONEPROLOG( ptClient, // tClient
ANY_RT_HPHONE, // widget type
(DWORD) pParams->hPhone, // client widget handle
(LPVOID) &hdPhone, // provider widget handle
&dwPrivilege, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_PHONESETLAMP, // provider func index
&pfnTSPI_phoneSetLamp, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
"SetLamp" // func name
)) > 0) { if (!IsOnlyOneBitSetInDWORD (pParams->dwLampMode) || (pParams->dwLampMode & ~AllLampModes)) { lRequestID = PHONEERR_INVALLAMPMODE; } else { pParams->lResult = CallSP4( pfnTSPI_phoneSetLamp, "phoneSetLamp", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdPhone, (DWORD) pParams->dwButtonLampID, (DWORD) pParams->dwLampMode ); } }
PHONEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, "SetLamp" ); }
void WINAPI PSetRing( PTCLIENT ptClient, PPHONESETRING_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVPHONE hdPhone; PASYNCREQUESTINFO pAsyncRequestInfo; TSPIPROC pfnTSPI_phoneSetRing; DWORD dwPrivilege = PHONEPRIVILEGE_OWNER;
if ((lRequestID = PHONEPROLOG( ptClient, // tClient
ANY_RT_HPHONE, // widget type
(DWORD) pParams->hPhone, // client widget handle
(LPVOID) &hdPhone, // provider widget handle
&dwPrivilege, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_PHONESETRING, // provider func index
&pfnTSPI_phoneSetRing, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
"SetRing" // func name
)) > 0) { pParams->lResult = CallSP4( pfnTSPI_phoneSetRing, "phoneSetRing", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdPhone, (DWORD) pParams->dwRingMode, (DWORD) (pParams->dwVolume > 0x0000ffff ? 0x0000ffff : pParams->dwVolume) ); }
PHONEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, "SetRing" ); }
void WINAPI PSetStatusMessages( PTCLIENT ptClient, PPHONESETSTATUSMESSAGES_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex, bCloseMutex2; HANDLE hMutex, hMutex2; HDRVPHONE hdPhone; TSPIPROC pfnTSPI_phoneSetStatusMessages; DWORD dwPrivilege = PHONEPRIVILEGE_MONITOR;
if ((pParams->lResult = PHONEPROLOG( ptClient, // tClient
ANY_RT_HPHONE, // widget type
pParams->hPhone, // client widget handle
(LPVOID) &hdPhone, // provider widget handle
&dwPrivilege, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_PHONESETSTATUSMESSAGES, // provider func index
&pfnTSPI_phoneSetStatusMessages, // provider func pointer
NULL, // async request info
0, // client async request ID
"SetStatusMessages" // func name
)) == 0) { DWORD dwAPIVersion, dwUnionPhoneStates, dwUnionButtonModes, dwUnionButtonStates; PTPHONECLIENT ptPhoneClient, ptPhoneClient2; PTPHONE ptPhone;
//
// Safely get the ptPhone & api version
//
if (!(ptPhoneClient = ReferenceObject( ghHandleTable, pParams->hPhone, 0 ))) { pParams->lResult = PHONEERR_INVALPHONEHANDLE; goto PSetStatusMessages_epilog; }
try { ptPhone = ptPhoneClient->ptPhone;
dwAPIVersion = ptPhoneClient->dwAPIVersion;
if (ptPhoneClient->dwKey != TPHONECLIENT_KEY) { pParams->lResult = PHONEERR_INVALPHONEHANDLE; goto PSetStatusMessages_Dereference; } } myexcept { pParams->lResult = PHONEERR_INVALPHONEHANDLE; goto PSetStatusMessages_Dereference; }
//
// Validate the params
//
{ DWORD dwValidPhoneStates, dwValidButtonStates;
switch (dwAPIVersion) { case TAPI_VERSION1_0:
dwValidPhoneStates = AllPhoneStates1_0; dwValidButtonStates = AllButtonStates1_0; break;
default: // case TAPI_VERSION1_4:
dwValidPhoneStates = AllPhoneStates1_4; dwValidButtonStates = AllButtonStates1_4; break;
}
if ((pParams->dwPhoneStates & ~dwValidPhoneStates)) { pParams->lResult = PHONEERR_INVALPHONESTATE; goto PSetStatusMessages_Dereference; }
if ((pParams->dwButtonStates & ~dwValidButtonStates)) { pParams->lResult = PHONEERR_INVALBUTTONSTATE; goto PSetStatusMessages_Dereference; }
if ((pParams->dwButtonModes & ~AllButtonModes)) { pParams->lResult = PHONEERR_INVALBUTTONMODE; goto PSetStatusMessages_Dereference; }
if (pParams->dwButtonModes && !pParams->dwButtonStates) { pParams->lResult = PHONEERR_INVALBUTTONSTATE; goto PSetStatusMessages_Dereference; } }
//
// Make sure the REINIT bit is always set
//
pParams->dwPhoneStates |= PHONESTATE_REINIT;
//
// Get exclusive access to the device, determine the
// new union of all the client's status message settings
// and call down to the SP as appropriate
//
dwUnionPhoneStates = pParams->dwPhoneStates; dwUnionButtonModes = pParams->dwButtonModes; dwUnionButtonStates = pParams->dwButtonStates;
waitForExclAccess:
if (WaitForExclusivetPhoneAccess( ptPhone, &hMutex2, &bCloseMutex2, INFINITE )) { if (ptPhone->dwBusy) { MyReleaseMutex (hMutex2, bCloseMutex2); Sleep (50); goto waitForExclAccess; }
for( ptPhoneClient2 = ptPhone->ptPhoneClients; ptPhoneClient2; ptPhoneClient2 = ptPhoneClient2->pNextSametPhone ) { if (ptPhoneClient2 != ptPhoneClient) { dwUnionPhoneStates |= ptPhoneClient2->dwPhoneStates; dwUnionButtonModes |= ptPhoneClient2->dwButtonModes; dwUnionButtonStates |= ptPhoneClient2->dwButtonStates; } }
if ((dwUnionPhoneStates != ptPhone->dwUnionPhoneStates) || (dwUnionButtonModes != ptPhone->dwUnionButtonModes) || (dwUnionButtonStates != ptPhone->dwUnionButtonStates)) { ptPhone->dwBusy = 1;
MyReleaseMutex (hMutex2, bCloseMutex2);
pParams->lResult = CallSP4( pfnTSPI_phoneSetStatusMessages, "phoneSetStatusMessages", SP_FUNC_SYNC, (ULONG_PTR) hdPhone, (DWORD) dwUnionPhoneStates, (DWORD) dwUnionButtonModes, (DWORD) dwUnionButtonStates );
if (WaitForExclusivetPhoneAccess( ptPhone, &hMutex2, &bCloseMutex2, INFINITE )) { ptPhone->dwBusy = 0;
if (pParams->lResult == 0) { ptPhone->dwUnionPhoneStates = dwUnionPhoneStates; ptPhone->dwUnionButtonModes = dwUnionButtonModes; ptPhone->dwUnionButtonStates = dwUnionButtonStates; }
MyReleaseMutex (hMutex2, bCloseMutex2); } else { pParams->lResult = PHONEERR_INVALPHONEHANDLE; } } else { MyReleaseMutex (hMutex2, bCloseMutex2); }
if (pParams->lResult == 0) { if (WaitForExclusivePhoneClientAccess (ptPhoneClient)) { ptPhoneClient->dwPhoneStates = pParams->dwPhoneStates; ptPhoneClient->dwButtonModes = pParams->dwButtonModes; ptPhoneClient->dwButtonStates = pParams->dwButtonStates;
UNLOCKTPHONECLIENT (ptPhoneClient); } else { //
// The client is invalid now, but don't bother
// restoring the status msg states (will eventually
// get reset correctly & worse case is that SP just
// sends some extra msgs that get discarded)
//
pParams->lResult = PHONEERR_INVALPHONEHANDLE; } } } else { pParams->lResult = PHONEERR_INVALPHONEHANDLE; }
PSetStatusMessages_Dereference:
DereferenceObject (ghHandleTable, pParams->hPhone, 1); }
PSetStatusMessages_epilog:
PHONEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "SetStatusMessages" ); }
void WINAPI PSetVolume( PTCLIENT ptClient, PPHONESETVOLUME_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVPHONE hdPhone; PASYNCREQUESTINFO pAsyncRequestInfo; TSPIPROC pfnTSPI_phoneSetVolume; DWORD dwPrivilege = PHONEPRIVILEGE_OWNER;
if ((lRequestID = PHONEPROLOG( ptClient, // tClient
ANY_RT_HPHONE, // widget type
(DWORD) pParams->hPhone, // client widget handle
(LPVOID) &hdPhone, // provider widget handle
&dwPrivilege, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_PHONESETVOLUME, // provider func index
&pfnTSPI_phoneSetVolume, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
"SetVolume" // func name
)) > 0) { if (!IsOnlyOneBitSetInDWORD (pParams->dwHookSwitchDev) || (pParams->dwHookSwitchDev & ~AllHookSwitchDevs)) { lRequestID = PHONEERR_INVALHOOKSWITCHDEV; } else { pParams->lResult = CallSP4( pfnTSPI_phoneSetVolume, "phoneSetVolume", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdPhone, (DWORD) pParams->dwHookSwitchDev, (DWORD) (pParams->dwVolume > 0x0000ffff ? 0x0000ffff : pParams->dwVolume) ); } }
PHONEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, "SetVolume" ); }
void WINAPI PShutdown( PTCLIENT ptClient, PPHONESHUTDOWN_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { pParams->lResult = DestroytPhoneApp (pParams->hPhoneApp);
#if DBG
{ char szResult[32];
LOG((TL_TRACE, "phoneShutdown: exit, result=%s", MapResultCodeToText (pParams->lResult, szResult) )); } #else
LOG((TL_TRACE, "phoneShutdown: exit, result=x%x", pParams->lResult )); #endif
}
|