Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

6541 lines
187 KiB

/*++ 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;
if (ptProvider->dwTSPIOptions & LINETSPIOPTION_NONREENTRANT)
{
WaitForSingleObject (ptProvider->hMutex, INFINITE);
}
if (ptProvider->apfn[SP_PHONECLOSE])
{
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
)
{
LOG((TL_TRACE, "PhoneEventProc: entered"));
switch (dwMsg)
{
case PHONE_CLOSE:
{
PTPHONE ptPhone;
ptPhone = ReferenceObject(ghHandleTable, (HPHONE)(ULONG_PTR)htPhone, 0);
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
}
DereferenceObject(ghHandleTable, (HPHONE)(ULONG_PTR)htPhone, 1);
break;
}
case PHONE_DEVSPECIFIC:
case PHONE_STATE:
case PHONE_BUTTON:
{
PTPHONE ptPhone;
if (ptPhone = ReferenceObject(ghHandleTable, (HPHONE)(ULONG_PTR)htPhone, TPHONE_KEY))
{
SendMsgToPhoneClients(
ptPhone,
NULL,
dwMsg,
DWORD_CAST(Param1,__FILE__,__LINE__),
DWORD_CAST(Param2,__FILE__,__LINE__),
DWORD_CAST(Param3,__FILE__,__LINE__)
);
DereferenceObject(ghHandleTable, (HPHONE)(ULONG_PTR)htPhone, 1);
}
else if (dwMsg == PHONE_STATE &&
htPhone == NULL &&
Param1 & PHONESTATE_REINIT)
{
SendReinitMsgToAllXxxApps();
}
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,
"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;
LOG((TL_TRACE, "PhoneEventProc: got a PHONE_REMOVE"));
TapiEnterCriticalSection (&TapiGlobals.CritSec);
if (!(pLookupEntry = GetPhoneLookupEntry ((DWORD) Param1)) ||
pLookupEntry->bRemoved)
{
TapiLeaveCriticalSection (&TapiGlobals.CritSec);
LOG((TL_TRACE, "PhoneEventProc: phone entry already removed"));
return;
}
if ( pLookupEntry->hMutex )
{
bOK = DuplicateHandle(
TapiGlobals.hProcess,
pLookupEntry->hMutex,
TapiGlobals.hProcess,
&hLookupEntryMutex,
0,
FALSE,
DUPLICATE_SAME_ACCESS
);
}
TapiLeaveCriticalSection(&TapiGlobals.CritSec);
if ( !bOK )
{
LOG((TL_ERROR, "PhoneEventProc: can't duplicate handle"));
return;
}
//
// Wait for the LookupEntry's mutex on the duplicate handle
//
if (WaitForSingleObject (hLookupEntryMutex, INFINITE)
!= WAIT_OBJECT_0)
{
LOG((TL_ERROR, "PhoneEventProc: error in WaitForSingleObject on the duplicate handle"));
return;
}
//
// Mark the lookup table entry as removed
//
LOG((TL_TRACE, "PhoneEventProc: marking the phone entry removed"));
pLookupEntry->bRemoved = 1;
//
// Release the mutex and close the duplicate handle
//
ReleaseMutex (hLookupEntryMutex);
CloseHandle (hLookupEntryMutex);
hLookupEntryMutex = NULL;
if (pLookupEntry->ptPhone)
{
LOG((TL_TRACE, "PhoneEventProc: calling DestroytPhone"));
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);
LOG((TL_TRACE, "PhoneEventProc: sending PHONE_REMOVE to all apps"));
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;
HPHONE hPhone;
//
// 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 (!(hPhone = (HPHONE) NewObject(
ghHandleTable,
(LPVOID) ptPhone,
NULL
)))
{
ServerFree (ptPhone);
lResult = PHONEERR_NOMEM;
goto POpen_cleanup;
}
ptPhone->hPhone = hPhone;
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) hPhone;
aParams[1] = dwExtVersion;
param = (ULONG_PTR) aParams;
}
else
{
param = (ULONG_PTR) hPhone;
}
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
}