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.
 
 
 
 
 
 

34479 lines
1.0 MiB

/*++ BUILD Version: 0000 // Increment this if a change has global effects
Copyright (c) 1995-1998 Microsoft Corporation
Module Name:
line.c
Abstract:
Src module for tapi server line funcs
Author:
Dan Knudson (DanKn) 01-Apr-1995
Revision History:
--*/
#include "windows.h"
#include "assert.h"
#include "prsht.h"
#include "stdlib.h"
#include "tapip.h" // private\inc\tapip.h
#include "tspi.h"
#include "utils.h"
#include "client.h"
#include "loc_comn.h"
#include "server.h"
#include "line.h"
#include "resource.h"
#include "tapihndl.h"
#include "tregupr2.h"
#include <tchar.h>
#include "private.h"
#include <MMSYSTEM.H>
#include <mmddk.h>
// PERF
#include "tapiperf.h"
#define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0]))
// PERF
extern PERFBLOCK PerfBlock;
LONG
RtlOpenCurrentUser(
IN ULONG DesiredAccess,
OUT PHANDLE CurrentUserKey
);
//NTSYSAPI
//NTSTATUS
//NTAPI
LONG
NtClose(
IN HANDLE Handle
);
LPLINECOUNTRYLIST gpCountryList = NULL;
LPDWORD gpCountryGroups = NULL;
extern TAPIGLOBALS TapiGlobals;
extern CRITICAL_SECTION gSafeMutexCritSec,
gPriorityListCritSec;
extern HANDLE ghHandleTable;
extern TCHAR gszProviderID[];
extern TCHAR gszNumProviders[];
extern TCHAR gszNextProviderID[];
extern TCHAR gszProviderFilename[];
extern TCHAR gszRegKeyTelephony[];
const TCHAR gszLocation[] = TEXT("Location");
const TCHAR gszLocations[] = TEXT("Locations");
const TCHAR gszAreaCodeRules[] = TEXT("AreaCodeRules");
extern TCHAR gszRegKeyProviders[];
extern PTPROVIDER pRemoteSP;
extern DWORD gdwNumSPEventHandlerThreads;
extern HINSTANCE ghInstance;
extern BOOL gbQueueSPEvents;
const TCHAR gszID[] = TEXT("ID");
const TCHAR gszCountry[] = TEXT("Country");
const TCHAR gszFlags[] = TEXT("Flags");
const TCHAR gszNoPrefixAreaCodes[] = TEXT("NoPrefAC");
const TCHAR gszNumEntries[] = TEXT("NumEntries");
const TCHAR gszCurrentID[] = TEXT("CurrentID");
const TCHAR gszNextID[] = TEXT("NextID");
const TCHAR gszLocationListVersion[]= TEXT("LocationListVersion");
const TCHAR gszCallingCard[] = TEXT("CallingCard");
const TCHAR gszSameAreaRuleW[] = TEXT("SameAreaRule");
const TCHAR gszLongDistanceRuleW[] = TEXT("LongDistanceRule");
const TCHAR gszInternationalRuleW[] = TEXT("InternationalRule");
const TCHAR gszCountryGroupW[] = TEXT("CountryGroup");
const TCHAR gszNameW[] = TEXT("Name");
const TCHAR gszNameResW[] = TEXT("NameResourceId");
const TCHAR gszAreaCodeW[] = TEXT("AreaCode");
const TCHAR gszLongDistanceCarrierCodeW[] = TEXT("LongDistanceCarrierCode");
const TCHAR gszInternationalCarrierCodeW[] = TEXT("InternationalCarrierCode");
const TCHAR gszOutsideAccessW[] = TEXT("OutsideAccess");
const TCHAR gszLongDistanceAccessW[] = TEXT("LongDistanceAccess");
const TCHAR gszDisableCallWaitingW[] = TEXT("DisableCallWaiting");
const TCHAR gszTollListW[] = TEXT("TollList");
const TCHAR gszCountryListVersionW[] = TEXT("CountryListVersion");
const TCHAR gszAreaCodeToCallW[] = TEXT("AreaCodeToCall");
const TCHAR gszNumberToDialW[] = TEXT("NumberToDial");
const TCHAR gszPrefixesW[] = TEXT("Prefixes");
//
// IMPORTANT NOTE: this value should be incremented any time there is a
// change to country.rc
//
#define TAPI_CURRENT_COUNTRY_LIST_VERSION 0x00000119
#define IS_LRESULT_NOTERROR( foo ) \
( ! ( 0x80000000 & foo ) && \
( (foo <= LINEERR_LASTERRORVALUE) || \
(foo > 0x90000000 && foo <= PHONEERR_LASTERRORVALUE) ) )
extern UINT guiAlignmentFaultEnabled;
extern BOOL gbWinNT;
extern BOOL gbNTServer;
extern BOOL gbServerInited;
extern HANDLE ghTapisrvHeap;
//
// The following are used for the call hub implementation.
//
// One call hub hash table is used for each service provider.
// When a outgoing call or is successfully made or an incoming
// call shows up, TAPI will retrieve the call ID for that
// call and stick it in the hash table using the algorithim :
//
// hashEntryIndex = callID % numHashTableEntries
//
// In the case of collision (hashEntry already in use by a
// different callID) then the DoCallHubHashing() function will
// try to create a dynamic entry to hang off the "static" entry.
//
// We will allow a total number (per table) of dynamic entries
// specified by the GetMaxDynamicHashTableEntries() macro below.
//
// We will allow a total number (per table entry) of dynamic
// entries specified by the symbolic MAX_DYNAMIC_HASH_ENTRIES_PER_SLOT
// constant below.
//
// TapiPrimes is an array of increasing prime numbers used
// for hash table sizes. We will not grow a hash table to more
// the 261983 (static) entries, this being a seemingly
// reasonable limitation at this point. If we try to hash
// a call and are unable to (out of memory, max table size, etc)
// then we will reset our internal copy of the call ID for
// the call to 0, meaning it's not hashed at all.
//
const DWORD TapiPrimes[] =
{
31, 61, 127, 257, 521, 1031, 2053, 4099, 8191,
16381, 32749, 65537, 131071, 261983, 0
};
#define GetMaxDynamicHashTableEntries(TotalNumEntries) \
(TotalNumEntries/10)
#define MAX_DYNAMIC_HASH_ENTRIES_PER_SLOT 3
#if DBG
extern DWORD gdwDebugLevel;
extern BOOL gfBreakOnSeriousProblems;
char *
PASCAL
MapResultCodeToText(
LONG lResult,
char *pszResult
);
#endif
void
PASCAL
DestroytCall(
PTCALL ptCall
);
void
PASCAL
DestroytCallClient(
PTCALLCLIENT ptCallClient
);
void
PASCAL
DestroytLineClient(
HLINE hLine
);
void
LDevSpecific_PostProcess(
PASYNCREQUESTINFO pAsyncRequestInfo,
PASYNCEVENTMSG pAsyncEventMsg,
LPVOID *ppBuf
);
void
LMakeCall_PostProcess(
PASYNCREQUESTINFO pAsyncRequestInfo,
PASYNCEVENTMSG pAsyncEventMsg,
LPVOID *ppBuf
);
void
CALLBACK
CompletionProcSP(
DWORD dwRequestID,
LONG lResult
);
LONG
PASCAL
GetPhoneAppListFromClient(
PTCLIENT ptClient,
PTPOINTERLIST *ppList
);
LONG
InitializeClient(
PTCLIENT ptClient
);
BOOL
GetLinePermanentIdFromDeviceID(
PTCLIENT ptClient,
DWORD dwDeviceID,
LPTAPIPERMANENTID pID
);
void
CALLBACK
LineEventProcSP(
HTAPILINE htLine,
HTAPICALL htCall,
DWORD dwMsg,
ULONG_PTR dwParam1,
ULONG_PTR dwParam2,
ULONG_PTR dwParam3
);
PTPHONELOOKUPENTRY
GetPhoneLookupEntry(
DWORD dwDeviceID
);
LONG
GetPermLineIDAndInsertInTable(
PTPROVIDER ptProvider,
DWORD dwDeviceID,
DWORD dwSPIVersion
);
LONG
AppendNewDeviceInfo (
BOOL bLine,
DWORD dwDeviceID
);
LONG
RemoveDeviceInfoEntry (
BOOL bLine,
DWORD dwDeviceID
);
BOOL
IsAPIVersionInRange(
DWORD dwAPIVersion,
DWORD dwSPIVersion
)
{
if (dwAPIVersion <= dwSPIVersion)
{
switch (dwAPIVersion)
{
case TAPI_VERSION_CURRENT:
case TAPI_VERSION3_0:
case TAPI_VERSION2_2:
case TAPI_VERSION2_1:
case TAPI_VERSION2_0:
case TAPI_VERSION1_4:
case TAPI_VERSION1_0:
return TRUE;
default:
break;
}
}
return FALSE;
}
LONG
GetLineVersions(
PTLINECLIENT ptLineClient,
LPDWORD lpdwAPIVersion,
LPDWORD lpdwSPIVersion
)
{
*lpdwAPIVersion = ptLineClient->dwAPIVersion;
*lpdwSPIVersion = ptLineClient->ptLine->dwSPIVersion;
if (ptLineClient->dwKey != TLINECLIENT_KEY)
{
return LINEERR_INVALLINEHANDLE;
}
return 0;
}
BOOL
InitTapiStruct(
LPVOID pTapiStruct,
DWORD dwTotalSize,
DWORD dwFixedSize,
BOOL bZeroInit
)
{
//
// Verify there's space enough for fixed data
//
if (dwTotalSize < dwFixedSize)
{
return FALSE;
}
//
// Init the dwTotalSize as specified, then init the dwUsedSize and
// dwNeededSize fields as the fixed size of the structure (saves the
// SP some work if it's not planning on adding any of it's own
// varible-length data to the structure)
//
*((LPDWORD) pTapiStruct) = dwTotalSize;
*(((LPDWORD) pTapiStruct) + 1) =
*(((LPDWORD) pTapiStruct) + 2) = dwFixedSize;
//
// Now zero out the rest of the buffer if the caller wants us to
//
if (bZeroInit)
{
ZeroMemory(
((LPDWORD) pTapiStruct) + 3,
dwTotalSize - 3 * sizeof (DWORD)
);
}
return TRUE;
}
#if DBG
BOOL
IsBadSizeOffset(
DWORD dwTotalSize,
DWORD dwFixedSize,
DWORD dwXxxSize,
DWORD dwXxxOffset,
DWORD dwAlignMask,
char *pszCallingFunc,
char *pszFieldName
)
#else
BOOL
IsBadSizeOffset(
DWORD dwTotalSize,
DWORD dwFixedSize,
DWORD dwXxxSize,
DWORD dwXxxOffset,
DWORD dwAlignMask
)
#endif
{
if (dwXxxSize != 0)
{
DWORD dwSum = dwXxxSize + dwXxxOffset;
if ((dwAlignMask == 2) || (dwAlignMask == 4) || (dwAlignMask == 8))
{
dwAlignMask--;
if (dwAlignMask & dwXxxOffset)
{
return TRUE;
}
}
if (dwXxxOffset < dwFixedSize)
{
#if DBG
LOG((TL_INFO,
"%s: dw%sOffset (=x%x) points at fixed portion (=x%x)" \
" of structure",
pszCallingFunc,
pszFieldName,
dwXxxSize,
dwFixedSize
));
#else
LOG((TL_INFO,
"Offset (=x%x) points at fixed portion (=x%x)" \
" of structure",
dwXxxSize,
dwFixedSize
));
#endif
return TRUE;
}
else if ((dwSum > dwTotalSize) || (dwSum < dwXxxSize))
{
#if DBG
LOG((TL_INFO,
"%s: sum of dw%sSize/Offset (=x%x/x%x) > dwTotalSize (=x%x)",
pszCallingFunc,
pszFieldName,
dwXxxSize,
dwXxxOffset,
dwFixedSize,
dwTotalSize
));
#endif
return TRUE;
}
}
return FALSE;
}
BOOL
IsBadStringParam(
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
DWORD dwStringOffset
)
{
WCHAR *p;
DWORD dwCharsLeft;
//
// Check if offset is not WCHAR-aligned or if offset lies outside buffer
//
if ((dwStringOffset & 1) || (dwStringOffset >= dwParamsBufferSize))
{
return TRUE;
}
//
// Ensure we have read access
//
if (IsBadReadPtr(pDataBuf + dwStringOffset, dwParamsBufferSize - dwStringOffset))
{
return TRUE;
}
//
// Walk the string & make sure it's NULL-terminated within the buffer
//
dwCharsLeft = (dwParamsBufferSize - dwStringOffset) / sizeof (WCHAR);
for(
p = (WCHAR *) (pDataBuf + dwStringOffset);
dwCharsLeft && *p;
dwCharsLeft--, p++
);
return (dwCharsLeft ? FALSE : TRUE);
}
BOOL
IsBadStructParam(
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
DWORD dwXxxOffset
)
{
DWORD dwTotalSize;
if ((dwXxxOffset & 0x3) ||
(dwParamsBufferSize < sizeof (DWORD)) ||
(dwXxxOffset >= (dwParamsBufferSize - sizeof (DWORD))))
{
return TRUE;
}
//
// Ensure we have read access
//
if (IsBadReadPtr(pDataBuf + dwXxxOffset, dwParamsBufferSize - dwXxxOffset))
{
return TRUE;
}
dwTotalSize = *((LPDWORD) (pDataBuf + dwXxxOffset));
if (dwTotalSize > (dwParamsBufferSize - dwXxxOffset))
{
return TRUE;
}
return FALSE;
}
LONG
PASCAL
ValidateCallParams(
LPLINECALLPARAMS pCallParamsApp,
LPLINECALLPARAMS *ppCallParamsSP,
DWORD dwAPIVersion,
DWORD dwSPIVersion,
DWORD dwAsciiCallParamsCodePage
)
{
//
// This routine checks the fields in a LINECALLPARAMS 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[] = "ValidateCallParams";
DWORD dwTotalSize = pCallParamsApp->dwTotalSize, dwFixedSizeApp,
dwFixedSizeSP, dwAllBearerModes, dwAllMediaModes,
dwAllCallParamFlags;
switch (dwAPIVersion)
{
case TAPI_VERSION1_0:
dwFixedSizeApp = 112; // 24 * sizeof (DWORD) + sizeof(LINEDIALPARAMS)
dwAllMediaModes = AllMediaModes1_0;
//
// HotFax v1.0 may be hot, but it's not real smart. It's
// negotating an API ver == 0x10003, and subsequently tries
// to sneak in a v1.4 bearer mode (PASSTHROUGH). We'll
// allow for it this time...
//
//dwAllBearerModes = AllBearerModes1_0;
dwAllBearerModes = AllBearerModes1_4; // HACK - see above
dwAllCallParamFlags = AllCallParamFlags1_0;
break;
case TAPI_VERSION1_4:
dwFixedSizeApp = 112; // 24 * sizeof (DWORD) + sizeof(LINEDIALPARAMS)
dwAllMediaModes = AllMediaModes1_4;
dwAllBearerModes = AllBearerModes1_4;
dwAllCallParamFlags = AllCallParamFlags1_0;
break;
case TAPI_VERSION2_0:
case TAPI_VERSION2_1:
case TAPI_VERSION2_2:
dwFixedSizeApp = 176; // 40 * sizeof (DWORD) + sizeof(LINEDIALPARAMS)
dwAllMediaModes = AllMediaModes2_1;
dwAllBearerModes = AllBearerModes2_0;
dwAllCallParamFlags = AllCallParamFlags2_0;
break;
case TAPI_VERSION3_0:
case TAPI_VERSION_CURRENT:
dwFixedSizeApp = sizeof (LINECALLPARAMS);
dwAllMediaModes = AllMediaModes2_1;
dwAllBearerModes = AllBearerModes2_0;
dwAllCallParamFlags = AllCallParamFlags2_0;
break;
default:
return LINEERR_OPERATIONFAILED;
}
switch (dwSPIVersion)
{
case TAPI_VERSION1_0:
case TAPI_VERSION1_4:
dwFixedSizeSP = 112; // 24 * sizeof (DWORD) + sizeof(LINEDIALPARAMS)
break;
case TAPI_VERSION2_0:
case TAPI_VERSION2_1:
case TAPI_VERSION2_2:
dwFixedSizeSP = 176; // 40 * sizeof (DWORD) + sizeof(LINEDIALPARAMS)
break;
case TAPI_VERSION3_0:
case TAPI_VERSION_CURRENT:
dwFixedSizeSP = sizeof (LINECALLPARAMS);
break;
default:
return LINEERR_OPERATIONFAILED;
}
if (dwTotalSize < dwFixedSizeApp)
{
LOG((TL_ERROR,
"%sbad dwTotalSize, x%x (minimum valid size=x%x)",
szFunc,
dwTotalSize,
dwFixedSizeApp
));
return LINEERR_STRUCTURETOOSMALL;
}
if (pCallParamsApp->dwBearerMode)
{
//
// Allow 1.x apps to pass >=1 valid bearer modes to 1.x service
// providers for backwards compatiblity, but enforce a single
// valid bearer mode for newer apps and/or service providers
//
if ((dwAPIVersion >= TAPI_VERSION2_0) ||
(dwSPIVersion >= TAPI_VERSION2_0))
{
if (!IsOnlyOneBitSetInDWORD (pCallParamsApp->dwBearerMode) ||
(pCallParamsApp->dwBearerMode & ~dwAllBearerModes))
{
bad_bearer_mode:
LOG((TL_ERROR,
"%sbad dwBearerMode, x%x",
szFunc,
pCallParamsApp->dwBearerMode
));
return LINEERR_INVALBEARERMODE;
}
}
else
{
if (pCallParamsApp->dwBearerMode & ~dwAllBearerModes)
{
goto bad_bearer_mode;
}
else if (!IsOnlyOneBitSetInDWORD (pCallParamsApp->dwBearerMode))
{
LOG((TL_ERROR,
"%sbad dwBearerMode, x%x, allowed for 1.x apps/SPs",
szFunc,
pCallParamsApp->dwBearerMode
));
}
}
}
else
{
//
// For clarity's sake reset 0 bearer mode to VOICE
//
pCallParamsApp->dwBearerMode = LINEBEARERMODE_VOICE;
}
{
DWORD dwMediaModeApp = pCallParamsApp->dwMediaMode;
if ((dwMediaModeApp & (0x00ffffff ^ dwAllMediaModes)) ||
// single media mode is version is less <= 2.1
( (dwAPIVersion <= TAPI_VERSION2_1) &&
!IsOnlyOneBitSetInDWORD (dwMediaModeApp) &&
!(dwMediaModeApp & LINEMEDIAMODE_UNKNOWN) ) )
{
//
// For clarity's sake reset 0 media mode to INTERACTIVEVOICE
//
if (dwMediaModeApp == 0)
{
pCallParamsApp->dwMediaMode = LINEMEDIAMODE_INTERACTIVEVOICE;
}
else
{
LOG((TL_ERROR, "%sbad dwMediaMode, x%x", szFunc, dwMediaModeApp));
return LINEERR_INVALMEDIAMODE;
}
}
}
if (pCallParamsApp->dwCallParamFlags & ~dwAllCallParamFlags)
{
LOG((TL_ERROR,
"%sbad dwCallParamFlags, x%x",
szFunc,
pCallParamsApp->dwCallParamFlags
));
return LINEERR_INVALCALLPARAMS;
}
//
// Note: an address mode of 0 means "default to any address,
// don't select a specific address" (says TNixon)
//
if (pCallParamsApp->dwAddressMode == LINEADDRESSMODE_ADDRESSID ||
pCallParamsApp->dwAddressMode == LINEADDRESSMODE_DIALABLEADDR)
{
// do nothing (it's a valid addr mode)
}
else if (pCallParamsApp->dwAddressMode == 0)
{
//
// For clarity's sake reset 0 addr mode to ADDRESSID
//
pCallParamsApp->dwAddressMode = LINEADDRESSMODE_ADDRESSID;
}
else
{
LOG((TL_ERROR,
"%sbad dwAddressMode, x%x",
szFunc,
pCallParamsApp->dwAddressMode
));
return LINEERR_INVALADDRESSMODE;
}
if (ISBADSIZEOFFSET(
dwTotalSize,
dwFixedSizeApp,
pCallParamsApp->dwOrigAddressSize,
pCallParamsApp->dwOrigAddressOffset,
(!guiAlignmentFaultEnabled) ? 0 :
((pCallParamsApp->dwAddressMode & LINEADDRESSMODE_DIALABLEADDR) ?
sizeof(TCHAR) : sizeof(DWORD)),
szFunc,
"OrigAddress"
) ||
ISBADSIZEOFFSET(
dwTotalSize,
dwFixedSizeApp,
pCallParamsApp->dwUserUserInfoSize,
pCallParamsApp->dwUserUserInfoOffset,
guiAlignmentFaultEnabled? sizeof(TCHAR) : 0,
szFunc,
"UserUserInfo"
) ||
ISBADSIZEOFFSET(
dwTotalSize,
dwFixedSizeApp,
pCallParamsApp->dwHighLevelCompSize,
pCallParamsApp->dwHighLevelCompOffset,
0,
szFunc,
"HighLevelComp"
) ||
ISBADSIZEOFFSET(
dwTotalSize,
dwFixedSizeApp,
pCallParamsApp->dwLowLevelCompSize,
pCallParamsApp->dwLowLevelCompOffset,
0,
szFunc,
"LowLevelComp"
) ||
ISBADSIZEOFFSET(
dwTotalSize,
dwFixedSizeApp,
pCallParamsApp->dwDevSpecificSize,
pCallParamsApp->dwDevSpecificOffset,
0,
szFunc,
"DevSpecificSize"
))
{
return LINEERR_INVALCALLPARAMS;
}
//
// The following is an attempt to compensate for 1.x tapi apps
// that borrowed dialer.exe's source code and package their
// call params incorrectly. The fix is to zero the offending
// dwXxxSize/Offset pair of the various information-only fields,
// so at worst some logging info will be lost, but the app will
// still be able to make calls. (Failure to correctly package
// any of the above var-length fields is considered "fatal" in
// any case.)
//
if (ISBADSIZEOFFSET(
dwTotalSize,
dwFixedSizeApp,
pCallParamsApp->dwDisplayableAddressSize,
pCallParamsApp->dwDisplayableAddressOffset,
guiAlignmentFaultEnabled? sizeof(TCHAR) : 0,
szFunc,
"DisplayableAddress"
))
{
if (dwAPIVersion < TAPI_VERSION2_0)
{
pCallParamsApp->dwDisplayableAddressSize =
pCallParamsApp->dwDisplayableAddressOffset = 0;
}
else
{
return LINEERR_INVALCALLPARAMS;
}
}
if (ISBADSIZEOFFSET(
dwTotalSize,
dwFixedSizeApp,
pCallParamsApp->dwCalledPartySize,
pCallParamsApp->dwCalledPartyOffset,
guiAlignmentFaultEnabled? sizeof(TCHAR) : 0,
szFunc,
"CalledParty"
))
{
if (dwAPIVersion < TAPI_VERSION2_0)
{
pCallParamsApp->dwCalledPartySize =
pCallParamsApp->dwCalledPartyOffset = 0;
}
else
{
return LINEERR_INVALCALLPARAMS;
}
}
if (ISBADSIZEOFFSET(
dwTotalSize,
dwFixedSizeApp,
pCallParamsApp->dwCommentSize,
pCallParamsApp->dwCommentOffset,
guiAlignmentFaultEnabled? sizeof(TCHAR) : 0,
szFunc,
"Comment"
))
{
if (dwAPIVersion < TAPI_VERSION2_0)
{
pCallParamsApp->dwCommentSize =
pCallParamsApp->dwCommentOffset = 0;
}
else
{
return LINEERR_INVALCALLPARAMS;
}
}
if (dwAPIVersion <= TAPI_VERSION1_4)
{
goto ValidateCallParams_checkFixedSizes;
}
#define AllCallStates \
(LINECALLSTATE_IDLE | \
LINECALLSTATE_OFFERING | \
LINECALLSTATE_ACCEPTED | \
LINECALLSTATE_DIALTONE | \
LINECALLSTATE_DIALING | \
LINECALLSTATE_RINGBACK | \
LINECALLSTATE_BUSY | \
LINECALLSTATE_SPECIALINFO | \
LINECALLSTATE_CONNECTED | \
LINECALLSTATE_PROCEEDING | \
LINECALLSTATE_ONHOLD | \
LINECALLSTATE_CONFERENCED | \
LINECALLSTATE_ONHOLDPENDCONF | \
LINECALLSTATE_ONHOLDPENDTRANSFER | \
LINECALLSTATE_DISCONNECTED | \
LINECALLSTATE_UNKNOWN)
if (pCallParamsApp->dwPredictiveAutoTransferStates & ~AllCallStates)
{
LOG((TL_ERROR,
"%sbad dwPredictiveAutoTransferStates, x%x",
szFunc,
pCallParamsApp->dwPredictiveAutoTransferStates
));
return LINEERR_INVALCALLPARAMS;
}
if (ISBADSIZEOFFSET(
dwTotalSize,
dwFixedSizeApp,
pCallParamsApp->dwTargetAddressSize,
pCallParamsApp->dwTargetAddressOffset,
guiAlignmentFaultEnabled? sizeof(TCHAR) : 0,
szFunc,
"TargetAddress"
) ||
ISBADSIZEOFFSET(
dwTotalSize,
dwFixedSizeApp,
pCallParamsApp->dwSendingFlowspecSize,
pCallParamsApp->dwSendingFlowspecOffset,
guiAlignmentFaultEnabled? sizeof(DWORD) : 0,
szFunc,
"SendingFlowspec"
) ||
ISBADSIZEOFFSET(
dwTotalSize,
dwFixedSizeApp,
pCallParamsApp->dwReceivingFlowspecSize,
pCallParamsApp->dwReceivingFlowspecOffset,
guiAlignmentFaultEnabled? sizeof(DWORD) : 0,
szFunc,
"ReceivingFlowspec"
) ||
ISBADSIZEOFFSET(
dwTotalSize,
dwFixedSizeApp,
pCallParamsApp->dwDeviceClassSize,
pCallParamsApp->dwDeviceClassOffset,
0,
szFunc,
"DeviceClass"
) ||
ISBADSIZEOFFSET(
dwTotalSize,
dwFixedSizeApp,
pCallParamsApp->dwDeviceConfigSize,
pCallParamsApp->dwDeviceConfigOffset,
0,
szFunc,
"DeviceConfig"
) ||
ISBADSIZEOFFSET(
dwTotalSize,
dwFixedSizeApp,
pCallParamsApp->dwCallDataSize,
pCallParamsApp->dwCallDataOffset,
0,
szFunc,
"CallData"
) ||
ISBADSIZEOFFSET(
dwTotalSize,
dwFixedSizeApp,
pCallParamsApp->dwCallingPartyIDSize,
pCallParamsApp->dwCallingPartyIDOffset,
0,
szFunc,
"CallingPartyID"
))
{
return LINEERR_INVALCALLPARAMS;
}
if (dwAPIVersion < TAPI_VERSION3_0)
{
goto ValidateCallParams_checkFixedSizes;
}
if (pCallParamsApp->dwAddressType == 0)
{
// pCallParamsApp->dwAddressType = LINEADDRESSTYPE_PHONENUMBER;
}
else if ((pCallParamsApp->dwAddressType & ~AllAddressTypes) ||
!IsOnlyOneBitSetInDWORD (pCallParamsApp->dwAddressType))
{
LOG((TL_ERROR,
"%sbad dwAddressType, x%x",
szFunc,
pCallParamsApp->dwAddressType
));
return LINEERR_INVALCALLPARAMS;
}
ValidateCallParams_checkFixedSizes:
if (dwAsciiCallParamsCodePage == TAPI_NO_DATA)
{
//
// If here we're getting unicode call params from the app
//
// Check to see if the fixed size of the app's call params
// are smaller than the fixed size of the call params
// required by the service provider (due to it's negotiated
// SPI version), and if so alloc a larger buffer to account
// for this different fixed size & set it up correctly
//
if (dwFixedSizeApp < dwFixedSizeSP)
{
DWORD dwFixedSizeDiff =
dwFixedSizeSP - dwFixedSizeApp;
LPLINECALLPARAMS pCallParamsSP;
if (!(pCallParamsSP = ServerAlloc (dwTotalSize + dwFixedSizeDiff)))
{
return LINEERR_NOMEM;
}
CopyMemory (pCallParamsSP, pCallParamsApp, dwFixedSizeApp);
pCallParamsSP->dwTotalSize = dwTotalSize + dwFixedSizeDiff;
CopyMemory(
((LPBYTE) pCallParamsSP) + dwFixedSizeSP,
((LPBYTE) pCallParamsApp) + dwFixedSizeApp,
dwTotalSize - dwFixedSizeApp
);
if (pCallParamsSP->dwOrigAddressOffset)
{
pCallParamsSP->dwOrigAddressOffset += dwFixedSizeDiff;
}
if (pCallParamsSP->dwDisplayableAddressOffset)
{
pCallParamsSP->dwDisplayableAddressOffset += dwFixedSizeDiff;
}
if (pCallParamsSP->dwCalledPartyOffset)
{
pCallParamsSP->dwCalledPartyOffset += dwFixedSizeDiff;
}
if (pCallParamsSP->dwCommentOffset)
{
pCallParamsSP->dwCommentOffset += dwFixedSizeDiff;
}
if (pCallParamsSP->dwUserUserInfoOffset)
{
pCallParamsSP->dwUserUserInfoOffset += dwFixedSizeDiff;
}
if (pCallParamsSP->dwHighLevelCompOffset)
{
pCallParamsSP->dwHighLevelCompOffset += dwFixedSizeDiff;
}
if (pCallParamsSP->dwLowLevelCompOffset)
{
pCallParamsSP->dwLowLevelCompOffset += dwFixedSizeDiff;
}
if (pCallParamsSP->dwDevSpecificOffset)
{
pCallParamsSP->dwDevSpecificOffset += dwFixedSizeDiff;
}
if (dwAPIVersion >= TAPI_VERSION2_0)
{
if (pCallParamsSP->dwTargetAddressOffset)
{
pCallParamsSP->dwTargetAddressOffset += dwFixedSizeDiff;
}
if (pCallParamsSP->dwSendingFlowspecOffset)
{
pCallParamsSP->dwSendingFlowspecOffset += dwFixedSizeDiff;
}
if (pCallParamsSP->dwReceivingFlowspecOffset)
{
pCallParamsSP->dwReceivingFlowspecOffset +=dwFixedSizeDiff;
}
if (pCallParamsSP->dwDeviceClassOffset)
{
pCallParamsSP->dwDeviceClassOffset += dwFixedSizeDiff;
}
if (pCallParamsSP->dwDeviceConfigOffset)
{
pCallParamsSP->dwDeviceConfigOffset += dwFixedSizeDiff;
}
if (pCallParamsSP->dwCallDataOffset)
{
pCallParamsSP->dwCallDataOffset += dwFixedSizeDiff;
}
if (pCallParamsSP->dwCallingPartyIDOffset)
{
pCallParamsSP->dwCallingPartyIDOffset += dwFixedSizeDiff;
}
}
*ppCallParamsSP = pCallParamsSP;
}
else
{
*ppCallParamsSP = pCallParamsApp;
}
}
else // see if there's ascii var data fields to translate
{
//
// If here we're getting ascii call params form the app
//
// We may need to due ascii -> unicode conversions on some
// of the var fields, as well as account for differences
// in the fixed sizes of the call params structs as described
// above
//
DWORD dwAsciiVarDataSize,
dwFixedSizeDiff = dwFixedSizeSP - dwFixedSizeApp;
dwAsciiVarDataSize =
pCallParamsApp->dwOrigAddressSize +
pCallParamsApp->dwDisplayableAddressSize +
pCallParamsApp->dwCalledPartySize +
pCallParamsApp->dwCommentSize;
if (dwAPIVersion > TAPI_VERSION1_4)
{
dwAsciiVarDataSize +=
pCallParamsApp->dwTargetAddressSize +
pCallParamsApp->dwDeviceClassSize +
pCallParamsApp->dwCallingPartyIDSize;
}
if (dwFixedSizeDiff != 0 || dwAsciiVarDataSize != 0)
{
LPLINECALLPARAMS pCallParamsSP;
// alloc 3 extra for alignment
if (!(pCallParamsSP = ServerAlloc(
dwTotalSize + dwFixedSizeDiff + 2 * dwAsciiVarDataSize + 3
)))
{
return LINEERR_NOMEM;
}
if (dwFixedSizeDiff)
{
CopyMemory (pCallParamsSP, pCallParamsApp, dwFixedSizeApp);
CopyMemory(
((LPBYTE) pCallParamsSP) + dwFixedSizeSP,
((LPBYTE) pCallParamsApp) + dwFixedSizeApp,
dwTotalSize - dwFixedSizeApp
);
if (pCallParamsSP->dwUserUserInfoOffset)
{
pCallParamsSP->dwUserUserInfoOffset += dwFixedSizeDiff;
}
if (pCallParamsSP->dwHighLevelCompOffset)
{
pCallParamsSP->dwHighLevelCompOffset += dwFixedSizeDiff;
}
if (pCallParamsSP->dwLowLevelCompOffset)
{
pCallParamsSP->dwLowLevelCompOffset += dwFixedSizeDiff;
}
if (pCallParamsSP->dwDevSpecificOffset)
{
pCallParamsSP->dwDevSpecificOffset += dwFixedSizeDiff;
}
if (dwAPIVersion >= TAPI_VERSION2_0)
{
if (pCallParamsSP->dwSendingFlowspecOffset)
{
pCallParamsSP->dwSendingFlowspecOffset +=
dwFixedSizeDiff;
}
if (pCallParamsSP->dwReceivingFlowspecOffset)
{
pCallParamsSP->dwReceivingFlowspecOffset +=
dwFixedSizeDiff;
}
if (pCallParamsSP->dwDeviceConfigOffset)
{
pCallParamsSP->dwDeviceConfigOffset +=
dwFixedSizeDiff;
}
if (pCallParamsSP->dwCallDataOffset)
{
pCallParamsSP->dwCallDataOffset +=
dwFixedSizeDiff;
}
}
}
else
{
CopyMemory (pCallParamsSP, pCallParamsApp, dwTotalSize);
}
pCallParamsSP->dwTotalSize = dwTotalSize + dwFixedSizeDiff +
2*dwAsciiVarDataSize + 3;
if (dwAsciiVarDataSize)
{
LPDWORD alpdwXxxSize[] =
{
&pCallParamsSP->dwOrigAddressSize,
&pCallParamsSP->dwDisplayableAddressSize,
&pCallParamsSP->dwCalledPartySize,
&pCallParamsSP->dwCommentSize,
(dwAPIVersion > TAPI_VERSION1_4 ?
&pCallParamsSP->dwTargetAddressSize : NULL),
(dwAPIVersion > TAPI_VERSION1_4 ?
&pCallParamsSP->dwDeviceClassSize : NULL),
(dwAPIVersion > TAPI_VERSION1_4 ?
&pCallParamsSP->dwCallingPartyIDSize : NULL),
NULL
};
// align dwXxxOffset
DWORD i, dwXxxOffset = (dwTotalSize + dwFixedSizeDiff + 3) &
0xFFFFFFFC;
for (i = 0; alpdwXxxSize[i]; i++)
{
if (*alpdwXxxSize[i] != 0)
{
MultiByteToWideChar(
(UINT) dwAsciiCallParamsCodePage,
MB_PRECOMPOSED,
(LPCSTR) (((LPBYTE) pCallParamsApp) +
*(alpdwXxxSize[i] + 1)), // dwXxxOffset
*alpdwXxxSize[i],
(LPWSTR) (((LPBYTE) pCallParamsSP) + dwXxxOffset),
*alpdwXxxSize[i]
);
*(alpdwXxxSize[i] + 1) = dwXxxOffset;
*alpdwXxxSize[i] *= 2;
dwXxxOffset += *alpdwXxxSize[i];
}
}
}
*ppCallParamsSP = pCallParamsSP;
}
else
{
*ppCallParamsSP = pCallParamsApp;
}
}
return 0; // success
}
void
PASCAL
InsertVarData(
LPVOID lpXxx,
LPDWORD pdwXxxSize,
LPVOID *pData,
DWORD dwDataSize
)
{
DWORD dwAlignedSize, dwUsedSize;
LPVARSTRING lpVarString = (LPVARSTRING) lpXxx;
if (dwDataSize != 0)
{
//
// Align var data on 64-bit boundaries
//
if ((dwAlignedSize = dwDataSize) & 7)
{
dwAlignedSize += 8;
dwAlignedSize &= 0xfffffff8;
}
//
// The following if statement should only be TRUE the first time
// we're inserting data into a given structure that does not have
// an even number of DWORD fields
//
if ((dwUsedSize = lpVarString->dwUsedSize) & 7)
{
dwUsedSize += 8;
dwUsedSize &= 0xfffffff8;
lpVarString->dwNeededSize += dwUsedSize - lpVarString->dwUsedSize;
}
lpVarString->dwNeededSize += dwAlignedSize;
if ((dwUsedSize + dwAlignedSize) <= lpVarString->dwTotalSize)
{
CopyMemory(
((LPBYTE) lpVarString) + dwUsedSize,
pData,
dwDataSize
);
*pdwXxxSize = dwDataSize;
pdwXxxSize++; // pdwXxxSize = pdwXxxOffset
*pdwXxxSize = dwUsedSize;
lpVarString->dwUsedSize = dwUsedSize + dwAlignedSize;
}
}
}
PTLINELOOKUPENTRY
GetLineLookupEntry(
DWORD dwDeviceID
)
{
DWORD dwDeviceIDBase = 0;
PTLINELOOKUPTABLE pLookupTable = TapiGlobals.pLineLookup;
if (dwDeviceID >= TapiGlobals.dwNumLines)
{
return ((PTLINELOOKUPENTRY) NULL);
}
while (pLookupTable)
{
if (dwDeviceID < pLookupTable->dwNumTotalEntries)
{
return (pLookupTable->aEntries + dwDeviceID);
}
dwDeviceID -= pLookupTable->dwNumTotalEntries;
pLookupTable = pLookupTable->pNext;
}
return ((PTLINELOOKUPENTRY) NULL);
}
BOOL
PASCAL
IsValidLineExtVersion(
DWORD dwDeviceID,
DWORD dwExtVersion
)
{
BOOL bResult;
PTLINE ptLine;
PTPROVIDER ptProvider;
PTLINELOOKUPENTRY pLookupEntry;
if (dwExtVersion == 0)
{
return TRUE;
}
if (!(pLookupEntry = GetLineLookupEntry (dwDeviceID)))
{
return FALSE;
}
ptLine = pLookupEntry->ptLine;
if (ptLine)
{
try
{
if (ptLine->dwExtVersionCount)
{
bResult = (dwExtVersion == ptLine->dwExtVersion ?
TRUE : FALSE);
if (ptLine->dwKey == TLINE_KEY)
{
goto IsValidLineExtVersion_return;
}
}
}
myexcept
{
//
// if here the line was closed, just drop thru to the code below
//
}
}
ptProvider = pLookupEntry->ptProvider;
if (ptProvider->apfn[SP_LINENEGOTIATEEXTVERSION])
{
LONG lResult;
DWORD dwNegotiatedExtVersion;
lResult = CallSP5(
ptProvider->apfn[SP_LINENEGOTIATEEXTVERSION],
"lineNegotiateExtVersion",
SP_FUNC_SYNC,
(DWORD) dwDeviceID,
(DWORD) pLookupEntry->dwSPIVersion,
(DWORD) dwExtVersion,
(DWORD) dwExtVersion,
(ULONG_PTR) &dwNegotiatedExtVersion
);
bResult = ((lResult || !dwNegotiatedExtVersion) ? FALSE : TRUE);
}
else
{
bResult = FALSE;
}
IsValidLineExtVersion_return:
return bResult;
}
PTCALLCLIENT
PASCAL
ReferenceCall(
HCALL hCall,
PTCLIENT ptClient
)
{
PTCALLCLIENT ptCallClient;
if ((ptCallClient = ReferenceObject(
ghHandleTable,
hCall,
TCALLCLIENT_KEY
)))
{
if (ptCallClient->ptClient != ptClient)
{
DereferenceObject (ghHandleTable, hCall, 1);
ptCallClient = NULL;
}
}
return ptCallClient;
}
PTCALLHUBCLIENT
PASCAL
IsValidCallHub(
HCALLHUB hCallHub,
PTCLIENT ptClient
)
{
PTCALLHUBCLIENT ptCallHubClient = NULL;
if (hCallHub == 0)
{
goto ExitHere;
}
try
{
ptCallHubClient = ReferenceObject (
ghHandleTable,
hCallHub,
TCALLHUBCLIENT_KEY);
if (ptCallHubClient)
{
if ((ptCallHubClient->ptClient != ptClient) ||
(ptCallHubClient->hCallHub != hCallHub))
{
ptCallHubClient = NULL;
}
DereferenceObject(ghHandleTable, hCallHub, 1);
}
}
myexcept
{
}
ExitHere:
return ptCallHubClient;
}
PTLINEAPP
PASCAL
IsValidLineApp(
HLINEAPP hLineApp,
PTCLIENT ptClient
)
{
PTLINEAPP ptLineApp;
if ((ptLineApp = ReferenceObject (ghHandleTable, hLineApp, TLINEAPP_KEY)))
{
if (ptLineApp->ptClient != ptClient)
{
ptLineApp = NULL;
}
DereferenceObject (ghHandleTable, hLineApp, 1);
}
return ptLineApp;
}
BOOL
PASCAL
WaitForExclusivetCallAccess(
PTCALL ptCall,
DWORD dwKey
)
{
//
// Retrieve the call instance & check the key to make sure it's
// really a tCall object, then wait for exclusive access, then
// reverify the key and the call instance (it's possible the tCall
// object might have been freed & reallocated while we were waiting,
// in which case it will have come back to life with a different
// dwCallInstance value)
//
BOOL bUnlock = FALSE;
try
{
HCALL hCall = ptCall->hCall;
if (ptCall->dwKey == dwKey)
{
LOCKTCALL (ptCall);
bUnlock = TRUE;
if (ptCall->dwKey == dwKey &&
ptCall->hCall == hCall)
{
return TRUE;
}
}
}
myexcept
{
// just fall thru
}
if (bUnlock)
{
UNLOCKTCALL (ptCall);
}
return FALSE;
}
BOOL
PASCAL
WaitForExclusivetLineAccess(
PTLINE ptLine,
HANDLE *phMutex,
BOOL *pbDupedMutex,
DWORD dwTimeout
)
{
BOOL bResult = FALSE;
try
{
if (ptLine->dwKey == TLINE_KEY &&
WaitForMutex(
ptLine->hMutex,
phMutex,
pbDupedMutex,
(LPVOID) ptLine,
TLINE_KEY,
dwTimeout
))
{
if (ptLine->dwKey == TLINE_KEY)
{
bResult = TRUE;
}
else
{
MyReleaseMutex (*phMutex, *pbDupedMutex);
}
}
}
myexcept
{
// do nothing
}
return bResult;
}
BOOL
PASCAL
WaitForExclusiveLineClientAccess(
PTLINECLIENT ptLineClient
)
{
//
// Assumes ptXxxClient->hXxx has already been referenced,
// so we can safely access ptXxxClient
//
LOCKTLINECLIENT (ptLineClient);
if (ptLineClient->dwKey == TLINECLIENT_KEY)
{
return TRUE;
}
UNLOCKTLINECLIENT (ptLineClient);
return FALSE;
}
PTLINEAPP
PASCAL
WaitForExclusiveLineAppAccess(
HLINEAPP hLineApp,
PTCLIENT ptClient
)
{
PTLINEAPP ptLineApp;
if (!(ptLineApp = ReferenceObject(
ghHandleTable,
hLineApp,
TLINEAPP_KEY
)))
{
return NULL;
}
LOCKTLINEAPP (ptLineApp);
if ((ptLineApp->dwKey != TLINEAPP_KEY) ||
(ptLineApp->ptClient != ptClient))
{
UNLOCKTLINEAPP (ptLineApp);
ptLineApp = NULL;
}
DereferenceObject (ghHandleTable, hLineApp, 1);
return ptLineApp;
}
PTCLIENT
PASCAL
WaitForExclusiveClientAccess(
PTCLIENT ptClient
)
{
LOCKTCLIENT (ptClient);
try
{
if (ptClient->dwKey == TCLIENT_KEY)
{
return (ptClient);
}
}
myexcept
{
}
UNLOCKTCLIENT (ptClient);
return NULL;
}
LONG
PASCAL
FindProxy(
PTLINECLIENT ptLineClient,
DWORD dwAddressID,
DWORD dwRequestType,
PTLINECLIENT *ppProxy,
LPDWORD lpdwDeviceID,
DWORD dwMinAPIVersion
)
{
LONG lResult;
PTLINE ptLine;
try
{
if (ptLineClient->ptLineApp->dwAPIVersion >= dwMinAPIVersion)
{
ptLine = ptLineClient->ptLine;
*ppProxy = ptLine->apProxys[dwRequestType];
*lpdwDeviceID = ptLine->dwDeviceID;
if (dwAddressID >= ptLine->dwNumAddresses)
{
lResult = LINEERR_INVALADDRESSID;
}
else if (ptLine->dwKey != TLINE_KEY)
{
lResult = LINEERR_INVALLINEHANDLE;
}
else
{
lResult = 0;
}
}
else
{
lResult = LINEERR_INCOMPATIBLEAPIVERSION;
}
}
myexcept
{
lResult = LINEERR_OPERATIONUNAVAIL;
}
return lResult;
}
LONG
PASCAL
CreateProxyRequest(
PTLINECLIENT pProxy,
DWORD dwRequestType,
DWORD dwExtraBytes,
PASYNCREQUESTINFO pAsyncReqInfo,
PPROXYREQUESTWRAPPER *ppWrapper
)
{
HLINE hLine;
DWORD dwSize, dwComputerNameSize, dwUserNameSize;
PTCLIENT ptClient = pAsyncReqInfo->ptClient;
DWORD initContext, openContext;
PPROXYREQUESTWRAPPER pWrapper;
LOG((TL_TRACE, "CreateProxyRequest: enter..."));
//
// Safely get info from the proxy, then make sure it's still valid
// if the proxy is refusing LINE_PROXYREQUEST msg, return failure
//
try
{
hLine = pProxy->hLine;
initContext = pProxy->ptLineApp->InitContext;
openContext = pProxy->OpenContext;
if (pProxy->dwKey != TLINECLIENT_KEY ||
(FMsgDisabled(
pProxy->ptLineApp->dwAPIVersion,
pProxy->adwEventSubMasks,
LINE_PROXYREQUEST,
0)))
{
return LINEERR_OPERATIONUNAVAIL;
}
}
myexcept
{
return LINEERR_OPERATIONUNAVAIL;
}
dwComputerNameSize = (ptClient->dwComputerNameSize + TALIGN_COUNT) & TALIGN_MASK;
dwUserNameSize = (ptClient->dwUserNameSize + TALIGN_COUNT) & TALIGN_MASK;
//
// Calculate, alloc, & initalize a PROXYREQUESTWRAPPER struct. At the
// head of this struct is the msg info for the LINE_PROXYREQUEST,
// followed by the actual request data.
//
dwSize =
(sizeof (ASYNCEVENTMSG) + // LINE_PROXYREQUEST msg info
7 * sizeof (DWORD) + // Non-union fields in LINEPROXYREQUEST
dwExtraBytes + // Request-specific size
dwUserNameSize + // User name size
dwComputerNameSize + // Computer name size
TALIGN_COUNT) & TALIGN_MASK;// make sure size is a ULONG_PTR multiple
// so our lstrcpyW's below don't fault
// and so that when this msg eventually
// gets copied to some client's async
// event buf we don't start running into
// alignment problems (the msgs's
// TotalSize field must be ULONG_PTR-
// aligned)
if (!(pWrapper = ServerAlloc (dwSize)))
{
return LINEERR_NOMEM;
}
pWrapper->AsyncEventMsg.TotalSize = dwSize;
pWrapper->AsyncEventMsg.InitContext = initContext;
//pWrapper->AsyncEventMsg.hfnPostProcessProc =
pWrapper->AsyncEventMsg.hDevice = pProxy->hLine;
pWrapper->AsyncEventMsg.Msg = LINE_PROXYREQUEST;
pWrapper->AsyncEventMsg.OpenContext = openContext;
pWrapper->AsyncEventMsg.Param1 =
pAsyncReqInfo->dwLocalRequestID;
//pWrapper->AsyncEventMsg.Param2 =
//pWrapper->AsyncEventMsg.Param3 =
//pWrapper->AsyncEventMsg.Param4 =
dwSize -= sizeof (ASYNCEVENTMSG);
pWrapper->ProxyRequest.dwSize = dwSize;
pWrapper->ProxyRequest.dwClientMachineNameSize = ptClient->dwComputerNameSize;
pWrapper->ProxyRequest.dwClientMachineNameOffset =
dwSize - dwComputerNameSize;
if (NULL != ptClient->pszComputerName)
{
wcscpy(
(PWSTR)((LPBYTE) &pWrapper->ProxyRequest +
pWrapper->ProxyRequest.dwClientMachineNameOffset),
ptClient->pszComputerName
);
}
pWrapper->ProxyRequest.dwClientUserNameSize = ptClient->dwUserNameSize;
pWrapper->ProxyRequest.dwClientUserNameOffset =
(dwSize - dwComputerNameSize) - dwUserNameSize;
if (NULL != ptClient->pszUserName)
{
wcscpy(
(PWSTR)((LPBYTE) &pWrapper->ProxyRequest +
pWrapper->ProxyRequest.dwClientUserNameOffset),
ptClient->pszUserName
);
}
pWrapper->ProxyRequest.dwClientAppAPIVersion = 0;
pWrapper->ProxyRequest.dwRequestType = dwRequestType;
*ppWrapper = pWrapper;
//
// Change the AsyncRequestInfo struct's key value to be ==
// the proxy's hLine, so we can verify when app calls
// lineProxyResponse
//
pAsyncReqInfo->dwKey = hLine;
return 0;
}
LONG
PASCAL
SendProxyRequest(
PTLINECLIENT pProxy,
PPROXYREQUESTWRAPPER pWrapper,
PASYNCREQUESTINFO pAsyncRequestInfo
)
{
LONG lResult;
BOOL bUnlock = FALSE;
//
// Add the request to the proxy's list, then send it the request.
// Since the proxy (tLineClient) could get closed at any time we
// wrap the following in a try/except.
//
// Note: the AsyncReqInfo.dwParam4 & dwParam5 fields are used as
// the prev & next pointers for maintaining the list of proxy
// requests pending on tLineClient.
//
try
{
if (WaitForExclusiveLineClientAccess (pProxy))
{
bUnlock = TRUE;
if ((pAsyncRequestInfo->dwParam5 = (ULONG_PTR)
pProxy->pPendingProxyRequests))
{
((PASYNCREQUESTINFO) pAsyncRequestInfo->dwParam5)->dwParam4 =
(ULONG_PTR) pAsyncRequestInfo;
}
pProxy->pPendingProxyRequests = pAsyncRequestInfo;
UNLOCKTLINECLIENT (pProxy);
bUnlock = FALSE;
WriteEventBuffer (pProxy->ptClient, (PASYNCEVENTMSG) pWrapper);
lResult = 0;
}
else
{
lResult = LINEERR_OPERATIONUNAVAIL;
}
}
myexcept
{
lResult = LINEERR_OPERATIONUNAVAIL;
}
if (bUnlock)
{
UNLOCKTLINECLIENT (pProxy);
}
ServerFree (pWrapper);
return lResult;
}
BOOL
PASCAL
NotifyHighestPriorityRequestRecipient(
void
)
{
//
// Send a LINE_REQUEST msg to the highest priority request recipient
// to inform it that there are requests available for processing
//
PTLINEAPP ptLineApp;
ASYNCEVENTMSG msg;
LOG((TL_TRACE, "NotifyHighestPriorityRequestRecipient: enter..."));
EnterCriticalSection (&gPriorityListCritSec);
ptLineApp = TapiGlobals.pHighestPriorityRequestRecipient->ptLineApp;
msg.TotalSize = sizeof (ASYNCEVENTMSG);
msg.InitContext = ptLineApp->InitContext;
msg.fnPostProcessProcHandle = 0;
msg.hDevice = 0;
msg.Msg = LINE_REQUEST;
msg.OpenContext =
(TapiGlobals.pHighestPriorityRequestRecipient->dwRegistrationInstance);
msg.Param1 = LINEREQUESTMODE_MAKECALL;
msg.Param2 =
msg.Param3 = 0;
WriteEventBuffer (ptLineApp->ptClient, &msg);
LeaveCriticalSection (&gPriorityListCritSec);
LOG((TL_TRACE, "NotifyHighestPriorityRequestRecipient: finished."));
return TRUE;
}
void
SetDrvCallFlags(
HCALL hCall,
DWORD dwDrvCallFlags
)
{
//
// This func is called on return from TSPI_lineMakeCall (and other
// TSPI_lineXxx funcs where calls are created) and sets the
// dwDrvCallFlags field in the tCall as specified. This keeps
// another thread which is currently doing a DestroytCall on this
// call from passing an invalid hdCall to the provider when
// doing a TSPI_lineCloseCall.
//
//
PTCALL ptCall;
if (ptCall = ReferenceObject(ghHandleTable, hCall, 0))
{
LOCKTCALL (ptCall);
if ((ptCall->dwKey == TINCOMPLETECALL_KEY) ||
(ptCall->dwKey == TCALL_KEY) ||
(ptCall->dwKey == TZOMBIECALL_KEY))
{
// only set the loword
ptCall->dwDrvCallFlags = MAKELONG(LOWORD(dwDrvCallFlags),
HIWORD(ptCall->dwDrvCallFlags));
}
UNLOCKTCALL (ptCall);
DereferenceObject(ghHandleTable, hCall, 1);
}
}
LONG
PASCAL
SetCallConfList(
PTCALL ptCall,
PTCONFERENCELIST pConfList,
BOOL bAddToConfPostProcess
)
{
LONG lResult;
BOOL bAddToConfList = FALSE;
if (WaitForExclusivetCallAccess (ptCall, TCALL_KEY))
{
if (pConfList)
{
if (ptCall->pConfList && !bAddToConfPostProcess)
{
lResult = LINEERR_INVALCALLHANDLE;
}
else
{
ptCall->pConfList = pConfList;
lResult = 0;
bAddToConfList = TRUE;
}
}
else
{
if (ptCall->pConfList)
{
pConfList = ptCall->pConfList;
ptCall->pConfList = NULL;
lResult = 0;
}
else
{
lResult = LINEERR_INVALCALLHANDLE;
}
}
UNLOCKTCALL (ptCall);
}
else
{
lResult = LINEERR_INVALCALLHANDLE;
}
if (pConfList &&
(pConfList != (PTCONFERENCELIST) LongToPtr(0xffffffff) ) &&
(lResult == 0))
{
if (bAddToConfList)
{
while (pConfList->dwNumUsedEntries >=
pConfList->dwNumTotalEntries)
{
if (pConfList->pNext)
{
pConfList = pConfList->pNext;
}
else
{
DWORD dwSize;
PTCONFERENCELIST pNewConfList;
dwSize = sizeof (TCONFERENCELIST) + sizeof (PTCALL) *
(2 * pConfList->dwNumTotalEntries - 1);
if (!(pNewConfList = ServerAlloc (dwSize)))
{
ptCall->pConfList = NULL;
return LINEERR_NOMEM;
}
pNewConfList->dwNumTotalEntries =
2 * pConfList->dwNumTotalEntries;
pConfList->pNext = pNewConfList;
pConfList = pNewConfList;
}
}
pConfList->aptCalls[pConfList->dwNumUsedEntries++] = ptCall;
}
else
{
while (pConfList)
{
DWORD i, dwNumUsedEntries = pConfList->dwNumUsedEntries;
PTCALL *pptCall = pConfList->aptCalls;
for (i = 0; i < dwNumUsedEntries; i++)
{
if (pConfList->aptCalls[i] == ptCall)
{
//
// Found the call in the list, shuffle all the
// following calls in list down by 1 to maintain
// continuity
//
for (; i < (dwNumUsedEntries - 1); i++)
{
pConfList->aptCalls[i] = pConfList->aptCalls[i+1];
}
pConfList->dwNumUsedEntries--;
pConfList = NULL;
break;
}
pptCall++;
}
if (pConfList)
{
pConfList = pConfList->pNext;
}
}
}
}
return lResult;
}
LONG
PASCAL
RemoveCallFromLineList(
PTCALL ptCall
)
{
PTLINE ptLine = (PTLINE) ptCall->ptLine;
WaitForSingleObject (ptLine->hMutex, INFINITE);
if (ptCall->pNext)
{
ptCall->pNext->pPrev = ptCall->pPrev;
}
if (ptCall->pPrev)
{
ptCall->pPrev->pNext = ptCall->pNext;
}
else
{
ptLine->ptCalls = ptCall->pNext;
}
ReleaseMutex (ptLine->hMutex);
return 0;
}
LONG
PASCAL
RemoveCallClientFromLineClientList(
PTCALLCLIENT ptCallClient
)
{
PTLINECLIENT ptLineClient = ptCallClient->ptLineClient;
LOCKTLINECLIENT (ptLineClient);
if (ptCallClient->pNextSametLineClient)
{
ptCallClient->pNextSametLineClient->pPrevSametLineClient =
ptCallClient->pPrevSametLineClient;
}
if (ptCallClient->pPrevSametLineClient)
{
ptCallClient->pPrevSametLineClient->pNextSametLineClient =
ptCallClient->pNextSametLineClient;
}
else
{
ptLineClient->ptCallClients = ptCallClient->pNextSametLineClient;
}
UNLOCKTLINECLIENT (ptLineClient);
return 0;
}
LONG
PASCAL
GetConfCallListFromConf(
PTCONFERENCELIST pConfList,
PTPOINTERLIST *ppList
)
{
DWORD dwNumTotalEntries = DEF_NUM_PTR_LIST_ENTRIES,
dwNumUsedEntries = 0, i;
PTPOINTERLIST pList = *ppList;
while (pConfList)
{
if ((dwNumUsedEntries + pConfList->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;
do
{
dwNumTotalEntries <<= 1;
} while ((dwNumUsedEntries + pConfList->dwNumUsedEntries) >
dwNumTotalEntries);
if (!(pNewList = ServerAlloc(
sizeof (TPOINTERLIST) + sizeof (LPVOID) *
(dwNumTotalEntries - DEF_NUM_PTR_LIST_ENTRIES)
)))
{
return LINEERR_NOMEM;
}
CopyMemory(
pNewList->aEntries,
pList->aEntries,
dwNumUsedEntries * sizeof (LPVOID)
);
if (pList != *ppList)
{
ServerFree (pList);
}
pList = pNewList;
}
for (i = 0; i < pConfList->dwNumUsedEntries; i++)
{
pList->aEntries[dwNumUsedEntries++] = pConfList->aptCalls[i];
}
pConfList = pConfList->pNext;
}
pList->dwNumUsedEntries = dwNumUsedEntries;
*ppList = pList;
return 0;
}
LONG
PASCAL
GetList(
LIST_ENTRY *pListHead,
PTPOINTERLIST *ppList
)
{
DWORD dwNumTotalEntries = DEF_NUM_PTR_LIST_ENTRIES,
dwNumUsedEntries = 0;
PTPOINTERLIST pList = *ppList;
LIST_ENTRY *pEntry;
pEntry = pListHead->Flink;
while (pEntry != pListHead)
{
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)
)))
{
return LINEERR_NOMEM;
}
CopyMemory(
pNewList->aEntries,
pList->aEntries,
dwNumUsedEntries * sizeof (LPVOID)
);
if (pList != *ppList)
{
ServerFree (pList);
}
pList = pNewList;
}
pList->aEntries[dwNumUsedEntries++] = pEntry;
pEntry = pEntry->Flink;
}
pList->dwNumUsedEntries = dwNumUsedEntries;
*ppList = pList;
return 0;
}
LONG
PASCAL
GetCallClientListFromCall(
PTCALL ptCall,
PTPOINTERLIST *ppList
)
{
if (WaitForExclusivetCallAccess (ptCall, TCALL_KEY))
{
DWORD dwNumTotalEntries = DEF_NUM_PTR_LIST_ENTRIES,
dwNumUsedEntries = 0;
PTPOINTERLIST pList = *ppList;
PTCALLCLIENT ptCallClient = ptCall->ptCallClients;
while (ptCallClient)
{
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)
)))
{
UNLOCKTCALL (ptCall);
return LINEERR_NOMEM;
}
CopyMemory(
pNewList->aEntries,
pList->aEntries,
dwNumUsedEntries * sizeof (LPVOID)
);
if (pList != *ppList)
{
ServerFree (pList);
}
pList = pNewList;
}
pList->aEntries[dwNumUsedEntries++] = ptCallClient;
ptCallClient = ptCallClient->pNextSametCall;
}
UNLOCKTCALL (ptCall);
pList->dwNumUsedEntries = dwNumUsedEntries;
*ppList = pList;
}
else
{
return LINEERR_INVALCALLHANDLE;
}
return 0;
}
LONG
PASCAL
GetCallListFromLine(
PTLINE ptLine,
PTPOINTERLIST *ppList
)
{
BOOL bDupedMutex;
HANDLE hMutex;
if (WaitForExclusivetLineAccess(
ptLine,
&hMutex,
&bDupedMutex,
INFINITE
))
{
DWORD dwNumTotalEntries = DEF_NUM_PTR_LIST_ENTRIES,
dwNumUsedEntries = 0;
PTCALL ptCall = ptLine->ptCalls;
PTPOINTERLIST pList = *ppList;
while (ptCall)
{
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 LINEERR_NOMEM;
}
CopyMemory(
pNewList->aEntries,
pList->aEntries,
dwNumUsedEntries * sizeof (LPVOID)
);
if (pList != *ppList)
{
ServerFree (pList);
}
pList = pNewList;
}
pList->aEntries[dwNumUsedEntries++] = ptCall;
ptCall = ptCall->pNext;
}
MyReleaseMutex (hMutex, bDupedMutex);
pList->dwNumUsedEntries = dwNumUsedEntries;
*ppList = pList;
}
else
{
LOG((TL_TRACE, "GetCallListFromLine: inval ptLine=x%p", ptLine));
return LINEERR_INVALLINEHANDLE;
}
return 0;
}
LONG
PASCAL
GetLineClientListFromLine(
PTLINE ptLine,
PTPOINTERLIST *ppList
)
{
BOOL bDupedMutex;
HANDLE hMutex;
if (WaitForExclusivetLineAccess(
ptLine,
&hMutex,
&bDupedMutex,
INFINITE
))
{
DWORD dwNumTotalEntries = DEF_NUM_PTR_LIST_ENTRIES,
dwNumUsedEntries = 0;
PTPOINTERLIST pList = *ppList;
PTLINECLIENT ptLineClient = ptLine->ptLineClients;
while (ptLineClient)
{
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 LINEERR_NOMEM;
}
CopyMemory(
pNewList->aEntries,
pList->aEntries,
dwNumUsedEntries * sizeof (LPVOID)
);
if (pList != *ppList)
{
ServerFree (pList);
}
pList = pNewList;
}
pList->aEntries[dwNumUsedEntries++] = ptLineClient;
ptLineClient = ptLineClient->pNextSametLine;
}
MyReleaseMutex (hMutex, bDupedMutex);
pList->dwNumUsedEntries = dwNumUsedEntries;
*ppList = pList;
}
else
{
LOG((TL_ERROR, "GetLineClientListFromLine: inval ptLine=x%p", ptLine));
return LINEERR_INVALLINEHANDLE;
}
return 0;
}
LONG
PASCAL
GetLineAppListFromClient(
PTCLIENT ptClient,
PTPOINTERLIST *ppList
)
{
if (WaitForExclusiveClientAccess (ptClient))
{
DWORD dwNumTotalEntries = DEF_NUM_PTR_LIST_ENTRIES,
dwNumUsedEntries = 0;
PTLINEAPP ptLineApp = ptClient->ptLineApps;
PTPOINTERLIST pList = *ppList;
while (ptLineApp)
{
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 LINEERR_NOMEM;
}
CopyMemory(
pNewList->aEntries,
pList->aEntries,
dwNumUsedEntries * sizeof (LPVOID)
);
if (pList != *ppList)
{
ServerFree (pList);
}
pList = pNewList;
}
pList->aEntries[dwNumUsedEntries++] = ptLineApp;
ptLineApp = ptLineApp->pNext;
}
UNLOCKTCLIENT (ptClient);
pList->dwNumUsedEntries = dwNumUsedEntries;
*ppList = pList;
}
else
{
return LINEERR_OPERATIONFAILED;
}
return 0;
}
LONG
PASCAL
GetClientList(
BOOL bAdminOnly,
PTPOINTERLIST *ppList
)
{
DWORD dwNumTotalEntries = DEF_NUM_PTR_LIST_ENTRIES,
dwNumUsedEntries = 0;
PTPOINTERLIST pList = *ppList;
PTCLIENT ptClient;
TapiEnterCriticalSection (&TapiGlobals.CritSec);
ptClient = TapiGlobals.ptClients;
while (ptClient)
{
if (!bAdminOnly || IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR))
{
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)
)))
{
TapiLeaveCriticalSection (&TapiGlobals.CritSec);
return LINEERR_NOMEM;
}
CopyMemory(
pNewList->aEntries,
pList->aEntries,
dwNumUsedEntries * sizeof (LPVOID)
);
if (pList != *ppList)
{
ServerFree (pList);
}
pList = pNewList;
}
pList->aEntries[dwNumUsedEntries++] = ptClient;
}
ptClient = ptClient->pNext;
}
TapiLeaveCriticalSection (&TapiGlobals.CritSec);
pList->dwNumUsedEntries = dwNumUsedEntries;
*ppList = pList;
return 0;
}
void
PASCAL
SendMsgToCallClients(
PTCALL ptCall,
PTCALLCLIENT ptCallClientToExclude,
DWORD Msg,
/*
ULONG_PTR Param1,
ULONG_PTR Param2,
ULONG_PTR Param3 */
DWORD Param1,
DWORD Param2,
DWORD Param3
)
{
DWORD i;
TPOINTERLIST clientList, *pClientList = &clientList;
ASYNCEVENTMSG msg[2];
if (GetCallClientListFromCall (ptCall, &pClientList) != 0)
{
return;
}
msg->TotalSize = sizeof (ASYNCEVENTMSG) + sizeof (HCALLHUB);
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;
PTCALLCLIENT ptCallClient = pClientList->aEntries[i];
PTLINECLIENT ptLineClient = ptCallClient->ptLineClient;
if (ptCallClient == ptCallClientToExclude)
{
continue;
}
if (Msg == LINE_MONITORDIGITS)
{
if ((ptCallClient->dwMonitorDigitModes & Param2) == 0)
{
continue;
}
}
else if (Msg == LINE_MONITORMEDIA)
{
// ULONG_PTR mediaModes = Param1;
DWORD mediaModes = Param1;
//
// Munge the media modes so we don't pass unexpected flags
// to old apps
//
if (ptLineClient->dwAPIVersion == TAPI_VERSION1_0)
{
if ((mediaModes & ~AllMediaModes1_0))
{
mediaModes = (mediaModes & AllMediaModes1_0) |
LINEMEDIAMODE_UNKNOWN;
}
}
if (ptCallClient->dwMonitorMediaModes & mediaModes)
{
msg->Param1 = mediaModes;
}
else
{
continue;
}
}
else if (Msg == LINE_MONITORTONE)
{
if (!ptCallClient->bMonitoringTones)
{
continue;
}
}
else if (FMsgDisabled(
ptCallClient->ptLineClient->ptLineApp->dwAPIVersion,
ptCallClient->adwEventSubMasks,
(DWORD) Msg,
(DWORD) Param1
))
{
continue;
}
msg->InitContext = ptLineClient->ptLineApp->InitContext;
msg->hDevice = ptCallClient->hCall;
msg->OpenContext = ptLineClient->OpenContext;
//
// Indicate the hRemoteLine in p4 to make life easier for remotesp
//
msg->Param4 = ptLineClient->hRemoteLine;
*((LPHCALLHUB)(&msg->Param4 + 1)) =
(ptCallClient->ptCallHubClient)?
ptCallClient->ptCallHubClient->hCallHub :
(HCALLHUB)0;
ptClient = ptLineClient->ptClient;
if (ptCallClient->dwKey == TCALLCLIENT_KEY)
{
WriteEventBuffer (ptClient, msg);
}
}
myexcept
{
// just continue
}
}
if (pClientList != &clientList)
{
ServerFree (pClientList);
}
}
void
PASCAL
SendBufferMsgToCallClients(
PTCALL ptCall,
PTCALLCLIENT ptCallClientToExclude,
DWORD Msg,
DWORD Param1,
DWORD Size,
LPBYTE pBuffer
)
{
DWORD i;
TPOINTERLIST clientList, *pClientList = &clientList;
PASYNCEVENTMSG pmsg;
DWORD dwTotalSize =
(sizeof (ASYNCEVENTMSG) + (DWORD) Size +
TALIGN_COUNT) & TALIGN_MASK;
if (!(pmsg = (ASYNCEVENTMSG *) ServerAlloc (dwTotalSize)))
{
return;
}
if (GetCallClientListFromCall (ptCall, &pClientList) != 0)
{
ServerFree( pmsg );
return;
}
pmsg->TotalSize = dwTotalSize;
pmsg->fnPostProcessProcHandle = 0;
pmsg->Msg = Msg;
pmsg->Param2 = Size;
pmsg->Param3 = 0;
CopyMemory ((PBYTE)(pmsg+1), pBuffer, Size);
for (i = 0; i < pClientList->dwNumUsedEntries; i++)
{
try
{
PTCLIENT ptClient;
PTCALLCLIENT ptCallClient = pClientList->aEntries[i];
PTLINECLIENT ptLineClient = ptCallClient->ptLineClient;
if (ptCallClient == ptCallClientToExclude)
{
continue;
}
if (FMsgDisabled (
ptCallClient->ptLineClient->ptLineApp->dwAPIVersion,
ptCallClient->adwEventSubMasks,
(DWORD) Msg,
(DWORD) Param1
))
{
continue;
}
pmsg->Param1 = (DWORD) ptCallClient->hCall;
pmsg->InitContext = ptLineClient->ptLineApp->InitContext;
pmsg->hDevice = (DWORD) ptLineClient->hLine;
pmsg->OpenContext = ptLineClient->OpenContext;
//
// Indicate the hRemoteLine in p4 to make life easier for remotesp
//
pmsg->Param4 = ptLineClient->hRemoteLine;
ptClient = ptCallClient->ptClient;
if (ptCallClient->dwKey == TCALLCLIENT_KEY)
{
WriteEventBuffer (ptClient, pmsg);
}
}
myexcept
{
// just continue
}
}
if (pClientList != &clientList)
{
ServerFree (pClientList);
}
ServerFree( pmsg );
}
void
PASCAL
SendAMsgToAllLineApps(
DWORD dwWantVersion,
DWORD Msg,
DWORD Param1, // ULONG_PTR Param1,
DWORD Param2, // ULONG_PTR Param2
DWORD Param3 // ULONG_PTR Param3
)
{
DWORD i, j;
TPOINTERLIST clientList, *pClientList = &clientList;
ASYNCEVENTMSG lineMsg;
if (GetClientList (FALSE, &pClientList) != 0)
{
return;
}
ZeroMemory (&lineMsg, sizeof (ASYNCEVENTMSG));
lineMsg.TotalSize = sizeof (ASYNCEVENTMSG);
lineMsg.Msg = Msg;
lineMsg.Param2 = Param2;
lineMsg.Param3 = Param3;
for (i = 0; i < pClientList->dwNumUsedEntries; i++)
{
PTCLIENT ptClient = (PTCLIENT) pClientList->aEntries[i];
TPOINTERLIST xxxAppList, *pXxxAppList = &xxxAppList;
if (NULL == ptClient)
{
break;
}
lineMsg.Param1 = Param1;
//
// For LINE_REMOVE, need to remap the dwDeviceID(Param1)
//
if (Msg == LINE_REMOVE)
{
DWORD dwNumDevices;
LPDWORD lpdwDevices;
if ((TapiGlobals.dwFlags & TAPIGLOBALS_SERVER) &&
WaitForExclusiveClientAccess (ptClient))
{
if (!IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR))
{
dwNumDevices = ptClient->dwLineDevices;
lpdwDevices = ptClient->pLineDevices;
for (j = 0; j < dwNumDevices; ++j, ++lpdwDevices)
{
if (*lpdwDevices == Param1)
{
break;
}
}
if (j >= dwNumDevices)
{
// Not found in the device map, ignore
UNLOCKTCLIENT (ptClient);
continue;
}
else
{
lineMsg.Param1 = j;
}
}
UNLOCKTCLIENT (ptClient);
}
}
else if (Msg == LINE_CREATE)
{
if ((TapiGlobals.dwFlags & TAPIGLOBALS_SERVER) &&
WaitForExclusiveClientAccess (ptClient))
{
BOOL bAdmin = IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR);
UNLOCKTCLIENT (ptClient);
if (!bAdmin)
{
continue;
}
}
}
if (GetLineAppListFromClient (ptClient, &pXxxAppList) == 0)
{
for (j = 0; j < pXxxAppList->dwNumUsedEntries; j++)
{
PTLINEAPP ptLineApp = (PTLINEAPP) pXxxAppList->aEntries[j];
try
{
lineMsg.InitContext = ptLineApp->InitContext;
if ((ptLineApp->dwKey == TLINEAPP_KEY) &&
((dwWantVersion == 0) ||
(ptLineApp->dwAPIVersion == dwWantVersion) ||
((dwWantVersion & 0x80000000) &&
(ptLineApp->dwAPIVersion >=
(dwWantVersion & 0x7fffffff)))))
{
if (!FMsgDisabled (
ptLineApp->dwAPIVersion,
ptLineApp->adwEventSubMasks,
(DWORD) Msg,
(DWORD) Param1
))
{
WriteEventBuffer (ptClient, &lineMsg);
}
}
}
myexcept
{
// just continue
}
}
if (pXxxAppList != &xxxAppList)
{
ServerFree (pXxxAppList);
}
}
}
if (pClientList != &clientList)
{
ServerFree (pClientList);
}
}
void
PASCAL
SendAMsgToAllPhoneApps(
DWORD dwWantVersion,
DWORD Msg,
DWORD Param1, // ULONG_PTR Param1,
DWORD Param2, // ULONG_PTR Param2,
DWORD Param3 // ULONG_PTR Param3
)
{
DWORD i, j;
TPOINTERLIST clientList, *pClientList = &clientList;
ASYNCEVENTMSG phoneMsg;
if (GetClientList (FALSE, &pClientList) != 0)
{
return;
}
ZeroMemory (&phoneMsg, sizeof (ASYNCEVENTMSG));
phoneMsg.TotalSize = sizeof (ASYNCEVENTMSG);
phoneMsg.Msg = Msg;
phoneMsg.Param2 = Param2;
phoneMsg.Param3 = Param3;
for (i = 0; i < pClientList->dwNumUsedEntries; i++)
{
PTCLIENT ptClient = (PTCLIENT) pClientList->aEntries[i];
TPOINTERLIST xxxAppList, *pXxxAppList = &xxxAppList;
if (NULL == ptClient)
{
break;
}
phoneMsg.Param1 = Param1;
//
// For PHONE_REMOVE, need to remap the dwDeviceID(Param1)
//
if (Msg == PHONE_REMOVE)
{
DWORD dwNumDevices;
LPDWORD lpdwDevices;
if ((TapiGlobals.dwFlags & TAPIGLOBALS_SERVER) &&
WaitForExclusiveClientAccess (ptClient))
{
if (!IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR))
{
dwNumDevices = ptClient->dwPhoneDevices;
lpdwDevices = ptClient->pPhoneDevices;
for (j = 0; j < dwNumDevices; ++j, ++lpdwDevices)
{
if (*lpdwDevices == Param1)
{
break;
}
}
if (j >= dwNumDevices)
{
// Not found in the device map, ignore
UNLOCKTCLIENT (ptClient);
continue;
}
else
{
phoneMsg.Param1 = j;
}
}
UNLOCKTCLIENT (ptClient);
}
}
else if (Msg == PHONE_CREATE)
{
if ((TapiGlobals.dwFlags & TAPIGLOBALS_SERVER) &&
WaitForExclusiveClientAccess (ptClient))
{
BOOL bAdmin = IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR);
UNLOCKTCLIENT (ptClient);
if (!bAdmin)
{
continue;
}
}
}
if (GetPhoneAppListFromClient (ptClient, &pXxxAppList) == 0)
{
for (j = 0; j < pXxxAppList->dwNumUsedEntries; j++)
{
PTPHONEAPP ptPhoneApp = (PTPHONEAPP) pXxxAppList->aEntries[j];
try
{
phoneMsg.InitContext = ptPhoneApp->InitContext;
if ((ptPhoneApp->dwKey == TPHONEAPP_KEY) &&
((dwWantVersion == 0) ||
(ptPhoneApp->dwAPIVersion == dwWantVersion) ||
((dwWantVersion & 0x80000000) &&
(ptPhoneApp->dwAPIVersion >=
(dwWantVersion & 0x7fffffff)))))
{
if (!FMsgDisabled (
ptPhoneApp->dwAPIVersion,
ptPhoneApp->adwEventSubMasks,
(DWORD) Msg,
(DWORD) Param1
))
{
WriteEventBuffer (ptClient, &phoneMsg);
}
}
}
myexcept
{
LOG((TL_TRACE, "SendAMsgToAllPhoneApps - exception"));
// just continue
}
}
if (pXxxAppList != &xxxAppList)
{
ServerFree (pXxxAppList);
}
}
}
if (pClientList != &clientList)
{
ServerFree (pClientList);
}
}
void
PASCAL
SendReinitMsgToAllXxxApps(
void
)
{
TapiGlobals.dwFlags |= TAPIGLOBALS_REINIT;
SendAMsgToAllLineApps (0, LINE_LINEDEVSTATE, LINEDEVSTATE_REINIT, 0, 0);
SendAMsgToAllPhoneApps (0, PHONE_STATE, PHONESTATE_REINIT, 0, 0);
}
void
PASCAL
SendBufferMsgToLineClients(
PTLINE ptLine,
PTLINECLIENT ptLineClientToExclude,
DWORD dwMsg,
DWORD dwParam1, // ULONG_PTR dwParam1,
DWORD dwSize, // ULONG_PTR dwSize,
LPBYTE pBuffer
)
{
DWORD i;
TPOINTERLIST clientList, *pClientList = &clientList;
ASYNCEVENTMSG * pmsg;
DWORD dwTotalSize = (sizeof (ASYNCEVENTMSG) +
(DWORD) dwSize + TALIGN_COUNT) & TALIGN_MASK;
if (!(pmsg = (ASYNCEVENTMSG *) ServerAlloc (dwTotalSize)))
{
LOG((TL_ERROR, "SendBufferMsgToLineClients - Cannot allocate memory for message"));
return;
}
if (GetLineClientListFromLine (ptLine, &pClientList) != 0)
{
ServerFree (pmsg);
return;
}
pmsg->TotalSize = dwTotalSize;
pmsg->fnPostProcessProcHandle = 0;
pmsg->Msg = dwMsg;
pmsg->Param1 = dwParam1;
pmsg->Param2 = dwSize;
pmsg->Param3 = 0;
pmsg->Param4 = 0; // remotesp chks this on LINE_DEVSPEC(FEATURE)
CopyMemory ((PBYTE)(pmsg+1), pBuffer, dwSize);
for (i = 0; i < pClientList->dwNumUsedEntries; i++)
{
try
{
PTCLIENT ptClient;
PTLINECLIENT ptLineClient = pClientList->aEntries[i];
if (ptLineClient == ptLineClientToExclude)
{
continue;
}
if (FMsgDisabled (
ptLineClient->ptLineApp->dwAPIVersion,
ptLineClient->adwEventSubMasks,
dwMsg,
(DWORD) dwParam1
))
{
continue;
}
pmsg->InitContext = ptLineClient->ptLineApp->InitContext;
pmsg->hDevice = ptLineClient->hRemoteLine;
pmsg->OpenContext = ptLineClient->OpenContext;
ptClient = ptLineClient->ptClient;
if (ptLineClient->dwKey == TLINECLIENT_KEY)
{
WriteEventBuffer (ptClient, pmsg);
}
}
myexcept
{
// just continue
}
}
if (pClientList != &clientList)
{
ServerFree (pClientList);
}
ServerFree (pmsg);
}
void
PASCAL
SendMsgToLineClients(
PTLINE ptLine,
PTLINECLIENT ptLineClientToExclude,
DWORD Msg,
DWORD Param1, // ULONG_PTR Param1,
DWORD Param2, // ULONG_PTR Param2,
DWORD Param3 // ULONG_PTR Param3
)
{
DWORD i;
TPOINTERLIST clientList, *pClientList = &clientList;
ASYNCEVENTMSG msg;
LOG((TL_TRACE, "SendMsgToLineClients - enter"));
if (Msg == LINE_LINEDEVSTATE && Param1 & LINEDEVSTATE_REINIT)
{
SendReinitMsgToAllXxxApps();
if (Param1 == LINEDEVSTATE_REINIT)
{
return;
}
else
{
Param1 &= ~LINEDEVSTATE_REINIT;
}
}
if (GetLineClientListFromLine (ptLine, &pClientList) != 0)
{
return;
}
msg.TotalSize = sizeof (ASYNCEVENTMSG);
msg.fnPostProcessProcHandle = 0;
msg.Msg = Msg;
msg.Param1 = Param1;
msg.Param2 = Param2;
msg.Param3 = Param3;
msg.Param4 = 0; // remotesp chks this on LINE_DEVSPEC(FEATURE)
LOG((TL_INFO, "SendMsgToLineClients - number of Clients:%u", pClientList->dwNumUsedEntries));
for (i = 0; i < pClientList->dwNumUsedEntries; i++)
{
try
{
PTCLIENT ptClient;
PTLINECLIENT ptLineClient = pClientList->aEntries[i];
if (ptLineClient == ptLineClientToExclude)
{
continue;
}
LOG((TL_INFO, "SendMsgToLineClients: Msg:%x -- Param1:%x", Msg, Param1));
if (FMsgDisabled (
ptLineClient->ptLineApp->dwAPIVersion,
ptLineClient->adwEventSubMasks,
(DWORD) Msg,
(DWORD) Param1
))
{
continue;
}
if (Msg == LINE_ADDRESSSTATE)
{
DWORD addressStates = Param2; // ULONG_PTR addressStates = Param2;
//
// Munge the state flags so we don't pass
// unexpected flags to old apps
//
switch (ptLineClient->dwAPIVersion)
{
case TAPI_VERSION1_0:
addressStates &= AllAddressStates1_0;
break;
//case TAPI_VERSION1_4:
//case TAPI_VERSION2_0:
//case TAPI_VERSION2_1:
//case TAPI_VERSION2_2:
//case TAPI_VERSION_CURRENT:
default:
addressStates &= AllAddressStates1_4;
break;
}
if ((addressStates &= ptLineClient->dwAddressStates))
{
msg.Param2 = addressStates;
}
else
{
continue;
}
if ((Param2 & LINEADDRESSSTATE_CAPSCHANGE))
{
}
}
else if (Msg == LINE_LINEDEVSTATE)
{
DWORD lineStates = Param1; // ULONG_PTR lineStates = Param1;
//
// Munge the state flags so we don't pass unexpected flags
// to old apps
//
switch (ptLineClient->dwAPIVersion)
{
case TAPI_VERSION1_0:
lineStates &= AllLineStates1_0;
break;
default: // case TAPI_VERSION1_4:
// case TAPI_VERSION_CURRENT:
lineStates &= AllLineStates1_4;
break;
}
if ((lineStates &= ptLineClient->dwLineStates))
{
msg.Param1 = lineStates;
}
else
{
continue;
}
if ((Param1 & (LINEDEVSTATE_CAPSCHANGE |
LINEDEVSTATE_TRANSLATECHANGE)))
{
}
}
else if (Msg == LINE_PROXYSTATUS)
{
//
// Don't pass this message to older apps
//
if (ptLineClient->dwAPIVersion < TAPI_VERSION2_2)
{
continue;
}
}
msg.InitContext = ptLineClient->ptLineApp->InitContext;
msg.hDevice = ptLineClient->hRemoteLine;
msg.OpenContext = ptLineClient->OpenContext;
ptClient = ptLineClient->ptClient;
if (ptLineClient->dwKey == TLINECLIENT_KEY)
{
WriteEventBuffer (ptClient, &msg);
}
}
myexcept
{
// just continue
}
}
if (pClientList != &clientList)
{
ServerFree (pClientList);
}
}
LONG
PASCAL
GetCallIDs(
PTCALL ptCall
)
{
//
// NOTE: Caller must already have exclusive access to the
// tCall when invoking this function. On return they
// will still have exclusive access to the tCall.
//
// Also, it is assumed that only the LINE_CALLSTATE
// msg handler & MakeCallPostProcess-style functions
// will call this function. Otherwise, the code that
// resets the tCall's dwKey down below will need to
// be changed.
//
//
// We don't want to hold the lock while we call the provider,
// since this request might take a while (possible ring
// transitions, etc). But we also don't want another thread
// to destroy this tCall in the meantime (because we didn't
// allow for that in NT 4.0, and because it makes life more
// difficult for the calling function). So, we'll reset the
// tCall's dwKey value to ZOMBIE, thereby causing any other
// thread(s) that is waiting to destroy this call to effectively
// wait/spin, and we'll then restore the dwKey value down below
// after we reacquire the lock. (Since this func is only called
// by MakeCallPostProcess-style functions & the LINE_CALLSTATE
// handler [on the first callstate msg received on an incoming
// call], the only way another thread would be destroying this
// call is if the line is being closed, either by an app or as
// the result of a LINE_CLOSE, and DestroytLine spins until
// it has destroyed all tCall's in the tLine's list.)
DWORD dwNumAddresses = ptCall->ptLine->dwNumAddresses, dwSavedKey;
PTPROVIDER ptProvider = ptCall->ptProvider;
if (ptProvider->apfn[SP_LINEGETCALLINFO] == NULL)
{
return LINEERR_OPERATIONUNAVAIL;
}
dwSavedKey = ptCall->dwKey;
ptCall->dwKey = TZOMBIECALL_KEY;
UNLOCKTCALL (ptCall);
if (ptProvider->apfn[SP_LINEGETCALLIDS])
{
CallSP4(
ptProvider->apfn[SP_LINEGETCALLIDS],
"lineGetCalIDs",
SP_FUNC_SYNC,
(ULONG_PTR) ptCall->hdCall,
(ULONG_PTR) &ptCall->dwAddressID,
(ULONG_PTR) &ptCall->dwCallID,
(ULONG_PTR) &ptCall->dwRelatedCallID
);
}
else
{
DWORD dwSPIVersion, dwFixedSizeSP;
LINECALLINFO callInfo;
//
// Determine the fixed size of the structure expected by the SP
//
dwSPIVersion = ((PTLINE) ptCall->ptLine)->dwSPIVersion;
switch (dwSPIVersion)
{
case TAPI_VERSION1_0:
case TAPI_VERSION1_4:
dwFixedSizeSP = 296; // 69 * sizeof(DWORD) + sizeof (HLINE)
// + sizeof (LINEDIALPARAMS)
break;
case TAPI_VERSION2_0:
case TAPI_VERSION2_1:
case TAPI_VERSION2_2:
dwFixedSizeSP = 324; // 76 * sizeof(DWORD) + sizeof (HLINE)
// + sizeof (LINEDIALPARAMS)
break;
default: // (fix ppc build wrn) case TAPI_VERSION_CURRENT:
dwFixedSizeSP = sizeof (LINECALLINFO);
break;
}
InitTapiStruct (&callInfo, dwFixedSizeSP, dwFixedSizeSP, TRUE);
CallSP2(
ptProvider->apfn[SP_LINEGETCALLINFO],
"lineGetCallInfo",
SP_FUNC_SYNC,
(ULONG_PTR) ptCall->hdCall,
(ULONG_PTR) &callInfo
);
ptCall->dwAddressID = callInfo.dwAddressID;
ptCall->dwCallID = callInfo.dwCallID;
ptCall->dwRelatedCallID = callInfo.dwRelatedCallID;
}
//
// Reacquire the call lock, restore the dwKey value, & fill
// in the address id
//
LOCKTCALL (ptCall);
ptCall->dwKey = dwSavedKey;
return 0;
}
VOID
PASCAL
AcquireHashTableReaderLock(
PTPROVIDER ptProvider
)
{
EnterCriticalSection (&ptProvider->HashTableCritSec);
InterlockedIncrement (&ptProvider->lHashTableReaderCount);
LeaveCriticalSection (&ptProvider->HashTableCritSec);
}
VOID
PASCAL
AcquireHashTableWriterLock(
PTPROVIDER ptProvider
)
{
EnterCriticalSection (&ptProvider->HashTableCritSec);
if (InterlockedDecrement (&ptProvider->lHashTableReaderCount) >= 0)
{
WaitForSingleObject (ptProvider->hHashTableReaderEvent, INFINITE);
}
}
VOID
PASCAL
ReleaseHashTableReaderLock(
PTPROVIDER ptProvider
)
{
if (InterlockedDecrement (&ptProvider->lHashTableReaderCount) < 0)
{
SetEvent (ptProvider->hHashTableReaderEvent);
}
}
VOID
PASCAL
ReleaseHashTableWriterLock(
PTPROVIDER ptProvider
)
{
InterlockedIncrement (&ptProvider->lHashTableReaderCount);
LeaveCriticalSection (&ptProvider->HashTableCritSec);
}
PTHASHTABLEENTRY
PASCAL
AcquireHashTableEntryLock(
PTPROVIDER ptProvider,
DWORD dwCallHubID
)
{
LONG lPreviousCookie;
PTHASHTABLEENTRY pEntry;
AcquireHashTableReaderLock (ptProvider);
pEntry = ptProvider->pHashTable +
(dwCallHubID % ptProvider->dwNumHashTableEntries);
do
{
lPreviousCookie = InterlockedExchange (&pEntry->lCookie, 1);
} while (lPreviousCookie != 0);
return pEntry;
}
VOID
PASCAL
ReleaseHashTableEntryLock(
PTPROVIDER ptProvider,
PTHASHTABLEENTRY pEntry
)
{
InterlockedExchange (&pEntry->lCookie, 0);
ReleaseHashTableReaderLock (ptProvider);
}
VOID
PASCAL
FreeHashTable(
PTHASHTABLEENTRY pHashTable,
DWORD dwNumHashTableEntries,
DWORD dwNumDynamicHashTableEntries
)
{
//
// Walk thru hash table to find any dynamic entries that need to
// be freed. We compare against both dwNumDynamicHashTableEntries
// and dwNumHashTableEntries in case something went wrong somewhere.
//
// Then free the table itself & return
//
DWORD i;
PTHASHTABLEENTRY pEntry, pEntry2;
for(
i = 0, pEntry = pHashTable;
dwNumDynamicHashTableEntries && i < dwNumHashTableEntries;
i++, pEntry++
)
{
while (pEntry->pNext)
{
dwNumDynamicHashTableEntries--;
pEntry2 = pEntry->pNext->pNext;
ServerFree (pEntry->pNext);
pEntry->pNext = pEntry2;
}
}
ServerFree (pHashTable);
}
PTHASHTABLEENTRY
PASCAL
FindDynamicHashTableEntry(
PTHASHTABLEENTRY pEntry,
DWORD dwCallHubID
)
{
//
// Note that the pEntry passed to us is static, so no need to check that
//
while (pEntry->pNext)
{
if (pEntry->pNext->dwCallHubID == dwCallHubID)
{
break;
}
pEntry = pEntry->pNext;
}
return pEntry->pNext;
}
VOID
PASCAL
RemoveDynamicHashTableEntry(
PTPROVIDER ptProvider,
PTHASHTABLEENTRY pStaticEntry,
PTHASHTABLEENTRY pDynamicEntry
)
{
while (pStaticEntry->pNext != pDynamicEntry)
{
pStaticEntry = pStaticEntry->pNext;
}
pStaticEntry->pNext = pDynamicEntry->pNext;
ServerFree (pDynamicEntry);
InterlockedDecrement ((LPLONG) &ptProvider->dwNumDynamicHashTableEntries);
}
DWORD
PASCAL
GetNumDynamicHashTableEntries(
PTHASHTABLEENTRY pEntry
)
{
//
// Note that the pEntry passed to us is static, so no need to count that
//
DWORD i;
for (i = 0; (pEntry = pEntry->pNext); i++);
return i;
}
//
// SendNewCallHubEvent
//
// Utility function used by DoCallHubHashing & UpdateCallHubHashing
// to send LINE_NEWCALLHUB event if not sent yet
//
LONG
PASCAL
SendNewCallHubEvent (
PTCALL ptCall,
PTHASHTABLEENTRY pTargetEntry
)
{
//
// For each tCallClient see if tLineClient has tracking
// enabled, and if so then see if there is already an
// associated (via common tLineApp) tCallHubClient - if
// not then create one & notify the app
//
DWORD i;
BOOL bExistingCallHubClients =
(pTargetEntry->ptCallHubClients != NULL);
TPOINTERLIST fastCallClientList, *ptCallClientList;
if (ptCall->ptLine->dwNumCallHubTrackers != 0)
{
ptCallClientList = &fastCallClientList;
if (GetCallClientListFromCall (ptCall, &ptCallClientList) != 0)
{
ptCallClientList = NULL;
}
}
else
{
ptCallClientList = NULL;
}
if (ptCallClientList == NULL || pTargetEntry == NULL)
{
return 0;
}
for (i = 0; i < ptCallClientList->dwNumUsedEntries; i++)
{
PTLINEAPP ptLineApp;
PTCALLCLIENT ptCallClient = ptCallClientList->aEntries[i];
ASYNCEVENTMSG msg;
PTCALLHUBCLIENT ptCallHubClient;
if (ptCallClient->ptLineClient->dwCurrentTracking ||
bExistingCallHubClients)
{
ptLineApp = ptCallClient->ptLineClient->ptLineApp;
ptCallHubClient = pTargetEntry->ptCallHubClients;
while (ptCallHubClient)
{
if (ptCallHubClient->ptLineApp == ptLineApp)
{
break;
}
ptCallHubClient = ptCallHubClient->pNext;
}
if (ptCallClient->ptLineClient->dwCurrentTracking &&
!ptCallHubClient &&
(!FMsgDisabled (
ptCallClient->ptLineClient->ptLineApp->dwAPIVersion,
ptCallClient->adwEventSubMasks,
LINE_APPNEWCALLHUB,
0)))
{
DWORD hptClientHandle = 0;
ptCallHubClient = ServerAlloc (sizeof(TCALLHUBCLIENT));
if (!ptCallHubClient)
{
i = ptCallClientList->dwNumUsedEntries;
continue;
}
ptCallHubClient->hCallHub = (DWORD) NewObject(
ghHandleTable,
ptCallHubClient,
NULL
);
if (!ptCallHubClient->hCallHub)
{
ServerFree(ptCallHubClient);
i = ptCallClientList->dwNumUsedEntries;
continue;
}
ptCallHubClient->dwKey = TCALLHUBCLIENT_KEY;
ptCallHubClient->ptClient = ptCallClient->ptClient;
ptCallHubClient->ptProvider = ptCall->ptProvider;
ptCallHubClient->dwCallHubID = ptCall->dwCallID;
ptCallHubClient->ptLineApp = ptLineApp;
ptCallHubClient->pNext = pTargetEntry->ptCallHubClients;
pTargetEntry->ptCallHubClients = ptCallHubClient;
//
// Queue a msg to alert the app of the new call
// hub. We do this rather than sending a msg
// directly from here to make sure the app gets
// the LINE_REPLY and/or APPNEWCALL msgs first
// (i.e. before calling lineGetHubRelatedCalls
// in response to LINE_APPNEWCALLHUB)
//
LineEventProcSP(
(HTAPILINE) 0,
(HTAPICALL) 0,
LINE_APPNEWCALLHUB,
ptCallHubClient->hCallHub,
ptLineApp->InitContext,
(ULONG_PTR)ptLineApp->ptClient
);
}
ptCallClient->ptCallHubClient = ptCallHubClient;
}
}
return 0;
}
//
// Per Bug 7591
// There might be a owner ship transferring of a call after
// it has been created. The new owner will not get the new call
// hub event since such event is only generated while the call
// is created. UpdateCallHubHashing goes through the call client
// if any of the client did not receive the LINE_NEWCALLHUB event
// it will send it one.
//
LONG
PASCAL
UpdateCallHubHashing (
PTCALL ptCall
)
{
if (WaitForExclusivetCallAccess (ptCall, TCALL_KEY))
{
PTHASHTABLEENTRY pStaticEntry, pTargetEntry;
pStaticEntry = AcquireHashTableEntryLock(
ptCall->ptProvider,
ptCall->dwCallID
);
if (pStaticEntry->dwCallHubID == ptCall->dwCallID)
{
pTargetEntry = pStaticEntry;
}
else
{
pTargetEntry = FindDynamicHashTableEntry(
pStaticEntry,
ptCall->dwCallID
);
}
if (pTargetEntry)
{
SendNewCallHubEvent (ptCall, pTargetEntry);
}
ReleaseHashTableEntryLock (ptCall->ptProvider, pStaticEntry);
UNLOCKTCALL (ptCall);
}
return 0;
}
LONG
PASCAL
DoCallHubHashing(
PTCALL ptCall,
DWORD dwPreviousCallID
)
{
//
// Assumes caller has exclusive access to the tCall
//
DWORD i;
PTPROVIDER ptProvider = ptCall->ptProvider;
PTHASHTABLEENTRY pStaticEntry, pDynamicEntry;
if (ptCall->dwCallID == dwPreviousCallID)
{
return 0;
}
if (dwPreviousCallID != 0)
{
//
// Remove tCall from call hub hash table (based on
// previous call id). If this is the last tCall in
// that hash table entry then destroy any associated
// tCallHubClients and alert apps.
//
// Note that (when freeing tCallHubClients) we call
// LineEventProcSP() to queue the CALLHUBCLOSE msgs
// rather than sending them directly via
// WriteEventBuffer() because we already own the
// tCall lock and we don't want to entertain the
// possibility of deadlock by grabbing other locks.
//
PTCALLHUBCLIENT ptCallHubClient = NULL, pNext;
pStaticEntry = AcquireHashTableEntryLock(
ptProvider,
dwPreviousCallID
);
if (pStaticEntry->dwCallHubID == dwPreviousCallID)
{
RemoveEntryList (&ptCall->CallHubList);
ptCall->CallHubList.Flink = NULL;
ptCall->CallHubList.Blink = NULL;
if (IsListEmpty (&pStaticEntry->CallHubList))
{
ptCallHubClient = pStaticEntry->ptCallHubClients;
pStaticEntry->ptCallHubClients = NULL;
pStaticEntry->dwCallHubID = 0;
}
}
else if ((pDynamicEntry = FindDynamicHashTableEntry(
pStaticEntry,
dwPreviousCallID
)))
{
RemoveEntryList (&ptCall->CallHubList);
ptCall->CallHubList.Flink = NULL;
ptCall->CallHubList.Blink = NULL;
if (IsListEmpty (&pDynamicEntry->CallHubList))
{
ptCallHubClient = pDynamicEntry->ptCallHubClients;
RemoveDynamicHashTableEntry(
ptProvider,
pStaticEntry,
pDynamicEntry
);
}
}
else
{
// TODO assert
}
ReleaseHashTableEntryLock (ptProvider, pStaticEntry);
if (ptCallHubClient)
{
while (ptCallHubClient)
{
BOOL bSendMsg = FALSE;
DWORD param2 = 0;
DWORD param3 = 0; // ULONG_PTR param2, param3;
PTLINEAPP ptLineApp;
try
{
ptLineApp = ptCallHubClient->ptLineApp;
param2 = ptLineApp->InitContext;
if (ptLineApp->dwKey == TLINEAPP_KEY &&
(!FMsgDisabled(
ptLineApp->dwAPIVersion,
ptLineApp->adwEventSubMasks,
LINE_CALLHUBCLOSE,
0
)))
{
bSendMsg = TRUE;
}
}
except (EXCEPTION_EXECUTE_HANDLER)
{
// tLineApp is gone, just fall through
}
if (bSendMsg)
{
LineEventProcSP(
(HTAPILINE) UIntToPtr(ptCallHubClient->hCallHub), // "random" seed for MP
(HTAPICALL) 0,
LINE_CALLHUBCLOSE,
ptCallHubClient->hCallHub,
param2,
(ULONG_PTR)ptLineApp->ptClient
);
}
pNext = ptCallHubClient->pNext;
ptCallHubClient->dwKey = INVAL_KEY;
DereferenceObject(
ghHandleTable,
ptCallHubClient->hCallHub,
1
);
ptCallHubClient = pNext;
}
}
}
if (ptCall->dwCallID != 0 &&
ptCall->CallHubList.Flink == NULL &&
ptCall->CallHubList.Blink == NULL)
{
//
// If at least one tLineClient has call hub tracking enabled
// then retrieve the list of tCallClients before we acquire
// exclusive access to the hash table
//
DWORD dwOldNumHashTableEntries,
dwOldNumDynamicHashTableEntries;
PTHASHTABLEENTRY pOldHashTable = NULL, pTargetEntry;
//
// Insert tCall in call hub hash table (based on current call ID).
//
// In the event of collision, first check to see if there's an
// existing dynamic entry with corresponding to the call ID.
// If so, party on the dynamic entry. Otherwise, try to create
// a dynamic entry if we're still within the dynamic entry
// threshholds.
//
// Finally, failing all the above, attempt to grow the hash table.
//
acquireTableEntryLock:
pStaticEntry = AcquireHashTableEntryLock(
ptProvider,
ptCall->dwCallID
);
if (pStaticEntry->dwCallHubID == ptCall->dwCallID)
{
//
// Add tCall to list (static entry)
//
InsertTailList (&pStaticEntry->CallHubList, &ptCall->CallHubList);
pTargetEntry = pStaticEntry;
}
else if(pStaticEntry->dwCallHubID == 0)
{
//
// Check to see if there is already a dynamic entry for this dwCallID,
// if so, use it
//
pTargetEntry = pStaticEntry->pNext;
while (pTargetEntry && pTargetEntry->dwCallHubID != ptCall->dwCallID)
{
pTargetEntry = pTargetEntry->pNext;
}
if (pTargetEntry == NULL)
{
pTargetEntry = pStaticEntry;
pTargetEntry->dwCallHubID = ptCall->dwCallID;
}
InsertTailList (&pTargetEntry->CallHubList, &ptCall->CallHubList);
}
else if ((pTargetEntry = FindDynamicHashTableEntry(
pStaticEntry,
ptCall->dwCallID
)))
{
//
// Add tCall to list (existing dynamic entry)
//
InsertTailList (&pTargetEntry->CallHubList, &ptCall->CallHubList);
}
else if (InterlockedIncrement(
(LPLONG) &ptProvider->dwNumDynamicHashTableEntries
)
< (LONG) GetMaxDynamicHashTableEntries(
ptProvider->dwNumHashTableEntries
) &&
GetNumDynamicHashTableEntries (pStaticEntry)
< MAX_DYNAMIC_HASH_ENTRIES_PER_SLOT)
{
//
// Add tCall to list (new dynamic entry)
//
if (!(pTargetEntry = ServerAlloc (sizeof (*pTargetEntry))))
{
//
// Failed to allocate memory, so we'll reset the call
// hub id for this call to zero so as not to confuse
// things later
//
InterlockedDecrement(
(LPLONG) &ptProvider->dwNumDynamicHashTableEntries
);
ReleaseHashTableEntryLock (ptProvider, pStaticEntry);
ptCall->dwCallID = 0;
return 0;
}
pTargetEntry->dwCallHubID = ptCall->dwCallID;
InitializeListHead (&pTargetEntry->CallHubList);
InsertTailList (&pTargetEntry->CallHubList, &ptCall->CallHubList);
pTargetEntry->pNext = pStaticEntry->pNext;
pStaticEntry->pNext = pTargetEntry;
}
else
{
//
// Grow table
//
DWORD dwNewNumHashTableEntries, dwMaxDynamicEntries,
dwNewNumDynamicHashTableEntries;
PTHASHTABLEENTRY pNewHashTable, pNewEntry, pEntry2, pEndOfTable;
//
// Decrement to compensate for the failed check above
//
InterlockedDecrement(
&ptProvider->dwNumDynamicHashTableEntries
);
//
// Grab the current number of hash table entries before
// we release the entry lock, so we can compare with
// that after the table writer lock is acquired. (Another
// thread might have grown table in time it took to acquire
// table writer lock, in which case we want to jump up
// top again.)
//
// The chances of another thread having released the
// entry we collided with (or freed up a related dynamic
// entry, etc) are fairly slim, so we won't bother checking
// for that
//
{
DWORD dwNumHashTableEntries =
ptProvider->dwNumHashTableEntries;
ReleaseHashTableEntryLock (ptProvider, pStaticEntry);
AcquireHashTableWriterLock (ptProvider);
if (dwNumHashTableEntries < ptProvider->dwNumHashTableEntries)
{
ReleaseHashTableWriterLock (ptProvider);
goto acquireTableEntryLock;
}
//
// Because we released the lock & reaquired a lock, if
// another call with the same dwCallID got hashed in, we
// would got two hash table entries with the same dwCallHubID
// that eventually leads to memory corruption when grow
// the table again. So check for it
//
pTargetEntry = ptProvider->pHashTable +
(ptCall->dwCallID % ptProvider->dwNumHashTableEntries);
while (pTargetEntry && pTargetEntry->dwCallHubID != ptCall->dwCallID)
{
pTargetEntry = pTargetEntry->pNext;
}
if (pTargetEntry)
{
//
// Found such entry, go back & retry
//
ReleaseHashTableWriterLock (ptProvider);
goto acquireTableEntryLock;
}
}
//
// Ok, we really do need to grow the table. Find the next
// larger number of entries.
//
for(
i = 0;
ptProvider->dwNumHashTableEntries >= TapiPrimes[i] &&
TapiPrimes[i];
i++
);
alloc_new_hash_table:
if (!(dwNewNumHashTableEntries = TapiPrimes[i]))
{
//
// We won't attempt to grow the hash table any further,
// so we'll reset the call hub id for this call to zero
// so as not to confuse things later
//
ptCall->dwCallID = 0;
ReleaseHashTableWriterLock (ptProvider);
return 0;
}
pNewHashTable = ServerAlloc(
dwNewNumHashTableEntries * sizeof (THASHTABLEENTRY)
);
if (!pNewHashTable)
{
//
// Failed to allocate a new hash table, so we'll reset the
// call hub id for this call to zero so as not to confuse
// things later
//
ptCall->dwCallID = 0;
ReleaseHashTableWriterLock (ptProvider);
return 0;
}
//
// Move all existing hash table entries to new table
//
pEndOfTable = ptProvider->pHashTable +
ptProvider->dwNumHashTableEntries;
dwNewNumDynamicHashTableEntries = 0;
dwMaxDynamicEntries = GetMaxDynamicHashTableEntries(
dwNewNumHashTableEntries
);
for(
pStaticEntry = ptProvider->pHashTable;
pStaticEntry != pEndOfTable;
pStaticEntry++
)
{
//
// If this entry is in use somehow, check to see
// if we need to start walking at the static entry
// or the dynamic entry. Else, simply continue.
//
if (pStaticEntry->dwCallHubID == 0)
{
if (!pStaticEntry->pNext)
{
continue;
}
pEntry2 = pStaticEntry->pNext;
}
else
{
pEntry2 = pStaticEntry;
}
while (pEntry2)
{
pNewEntry = pNewHashTable +
(pEntry2->dwCallHubID % dwNewNumHashTableEntries);
if (pNewEntry->dwCallHubID != 0)
{
//
// Collision, try to add a dynamic entry
//
if (dwNewNumDynamicHashTableEntries <
dwMaxDynamicEntries &&
GetNumDynamicHashTableEntries (pNewEntry)
< MAX_DYNAMIC_HASH_ENTRIES_PER_SLOT)
{
if (!(pDynamicEntry = ServerAlloc(
sizeof (*pDynamicEntry)
)))
{
//
// Failed to allocate a new dynamic entry,
// so we'll reset the call hub id for this
// call to zero so as not to confuse things
// later
//
ptCall->dwCallID = 0;
ReleaseHashTableWriterLock (ptProvider);
FreeHashTable(
pNewHashTable,
dwNewNumHashTableEntries,
dwNewNumDynamicHashTableEntries
);
return 0;
}
pDynamicEntry->pNext = pNewEntry->pNext;
pNewEntry->pNext = pDynamicEntry;
pNewEntry = pDynamicEntry;
dwNewNumDynamicHashTableEntries++;
}
else
{
//
// Free new table and try for a larger one
//
FreeHashTable(
pNewHashTable,
dwNewNumHashTableEntries,
dwNewNumDynamicHashTableEntries
);
i++;
goto alloc_new_hash_table;
}
}
pNewEntry->dwCallHubID = pEntry2->dwCallHubID;
pNewEntry->CallHubList.Flink = pEntry2->CallHubList.Flink;
pNewEntry->CallHubList.Blink = pEntry2->CallHubList.Blink;
pNewEntry->ptCallHubClients = pEntry2->ptCallHubClients;
pEntry2 = pEntry2->pNext;
}
}
//
// Now init the new entry
//
pNewEntry = pNewHashTable +
(ptCall->dwCallID % dwNewNumHashTableEntries);
if (pNewEntry->dwCallHubID != 0)
{
//
// Collision, try to add a dynamic entry.
//
// We intentionally ignore the dyna entry threshhold
// checks, as they'd be overkill here.
//
if ((pDynamicEntry = ServerAlloc (sizeof(*pDynamicEntry))))
{
pDynamicEntry->pNext = pNewEntry->pNext;
pNewEntry->pNext = pDynamicEntry;
pNewEntry = pDynamicEntry;
dwNewNumDynamicHashTableEntries++;
}
else
{
FreeHashTable(
pNewHashTable,
dwNewNumHashTableEntries,
dwNewNumDynamicHashTableEntries
);
i++;
goto alloc_new_hash_table;
}
}
pNewEntry->dwCallHubID = ptCall->dwCallID;
pNewEntry->CallHubList.Flink =
pNewEntry->CallHubList.Blink = &ptCall->CallHubList;
//
// Save the old table info (so we can free it & dyna
// entries later when the lock is released), then save
// the new table info
//
pOldHashTable = ptProvider->pHashTable;
dwOldNumHashTableEntries = ptProvider->dwNumHashTableEntries;
dwOldNumDynamicHashTableEntries =
ptProvider->dwNumDynamicHashTableEntries;
ptProvider->pHashTable = pNewHashTable;
ptProvider->dwNumHashTableEntries = dwNewNumHashTableEntries;
ptProvider->dwNumDynamicHashTableEntries =
dwNewNumDynamicHashTableEntries;
//
// Init the unused table entries and the head & tail
// list items in the used entries
//
pEndOfTable = ptProvider->pHashTable +
ptProvider->dwNumHashTableEntries;
for(
pStaticEntry = ptProvider->pHashTable;
pStaticEntry != pEndOfTable;
pStaticEntry++
)
{
if (pStaticEntry->dwCallHubID == 0)
{
InitializeListHead (&pStaticEntry->CallHubList);
}
else
{
pEntry2 = pStaticEntry;
while (pEntry2)
{
pEntry2->CallHubList.Flink->Blink =
pEntry2->CallHubList.Blink->Flink =
&pEntry2->CallHubList;
pEntry2 = pEntry2->pNext;
}
}
}
//
// Set pTargetEntry to point to the "new" entry (as expected below)
//
pTargetEntry = pNewEntry;
}
//
// Check to see if we need to create any tCallHubClient objects
//
SendNewCallHubEvent (ptCall, pTargetEntry);
//
// Release the appropriate hash table lock, then if we grew
// the table free the old table & dynamic table entries
//
if (!pOldHashTable)
{
ReleaseHashTableEntryLock (ptProvider, pStaticEntry);
}
else
{
ReleaseHashTableWriterLock (ptProvider);
FreeHashTable(
pOldHashTable,
dwOldNumHashTableEntries,
dwOldNumDynamicHashTableEntries
);
}
}
return 0;
}
LONG
PASCAL
CreatetCall(
PTLINE ptLine,
BOOL bIncoming,
HDRVCALL hdCall,
PTCALL *pptCall,
LPLINECALLPARAMS pCallParams,
HCALL *phCall,
PTCALL ptCallAssociate
)
{
BOOL bDupedMutex;
DWORD dwExtraBytes;
HANDLE hMutex;
PTCALL ptCall;
LOG((TL_TRACE, "CreatetCall: enter, ptLine=%p", ptLine));
//
// If there's call params specified check to see if we need to alloc
// any extra space for the CalledParty, DisplayableAddr, or Comment
// fields. Also, if any of these fields are non-NULL make sure to
// get extra space to keep these fields 64-bit aligned.
//
dwExtraBytes = (pCallParams == NULL ? 0 : pCallParams->dwCalledPartySize +
pCallParams->dwDisplayableAddressSize + pCallParams->dwCommentSize);
if (dwExtraBytes != 0)
{
dwExtraBytes += (sizeof (TCALL) & 4) + 16;
}
//
// Alloc necessary resources
//
if (!(ptCall = ServerAlloc (sizeof (TCALL) + dwExtraBytes)))
{
return LINEERR_NOMEM;
}
//
// Init tCall & add to tLine's tCall list
//
if (bIncoming)
{
//
// This is an incoming call (we're being called by the
// LINE_NEWCALL handler)
//
ptCall->dwKey = INVAL_KEY;
ptCall->dwDrvCallFlags = DCF_SPIRETURNED | DCF_DRVCALLVALID;
ptCall->bAlertApps = TRUE;
ptCall->dwCallState = LINECALLSTATE_UNKNOWN;
ptCall->hdCall = hdCall;
}
else
{
//
// This is an outgoing call (we're not being called by
// the LINE_NEWCALL handler)
//
ptCall->dwKey = TINCOMPLETECALL_KEY;
}
if (pCallParams)
{
DWORD dwOffset = sizeof (TCALL) + (sizeof (TCALL) & 4);
if (pCallParams->dwDisplayableAddressSize != 0)
{
CopyMemory(
(ptCall->pszDisplayableAddress = (WCHAR *)
(((LPBYTE) ptCall) + dwOffset)),
((LPBYTE) pCallParams) +
pCallParams->dwDisplayableAddressOffset,
(ptCall->dwDisplayableAddressSize =
pCallParams->dwDisplayableAddressSize)
);
dwOffset += ((ptCall->dwDisplayableAddressSize + 8) & 0xfffffff8);
}
if (pCallParams->dwCalledPartySize)
{
CopyMemory(
(ptCall->pszCalledParty = (WCHAR *)
(((LPBYTE)ptCall) + dwOffset)),
((LPBYTE) pCallParams) + pCallParams->dwCalledPartyOffset,
(ptCall->dwCalledPartySize = pCallParams->dwCalledPartySize)
);
dwOffset += ((ptCall->dwCalledPartySize + 8) & 0xfffffff8);
}
if (pCallParams->dwCommentSize)
{
CopyMemory(
(ptCall->pszComment = (WCHAR *)
(((LPBYTE) ptCall) + dwOffset)),
((LPBYTE) pCallParams) + pCallParams->dwCommentOffset,
(ptCall->dwCommentSize = pCallParams->dwCommentSize)
);
}
}
LOG((TL_INFO, "CreatetCall: calling NewObject ptCall %p", ptCall));
ptCall->hCall = (HCALL) NewObject(
ghHandleTable,
ptCall,
NULL
);
LOG((TL_TRACE, "CreatetCall: NewObject returned 0x%lx", ptCall->hCall));
*phCall = ptCall->hCall;
if (!ptCall->hCall)
{
ServerFree (ptCall);
return LINEERR_NOMEM;
}
//
// Add the new tCall to the tLine's list
//
if (WaitForExclusivetLineAccess(
ptLine,
&hMutex,
&bDupedMutex,
INFINITE
))
{
ptCall->ptLine = ptLine;
ptCall->ptProvider = ptLine->ptProvider;
if ((ptCall->pNext = ptLine->ptCalls))
{
ptCall->pNext->pPrev = ptCall;
}
ptLine->ptCalls = ptCall;
MyReleaseMutex (hMutex, bDupedMutex);
}
else
{
//
// tLine was destroyed, so clean up. Note that we return
// a generic OPFAILED error, since some calling routines
// might no be spec'd to return INVALLINEHANDLE, etc.
//
DereferenceObject (ghHandleTable, ptCall->hCall, 1);
return LINEERR_OPERATIONFAILED;
}
//
// Fill in caller's pointer & return success
//
*pptCall = ptCall;
PerfBlock.dwTotalOutgoingCalls++;
PerfBlock.dwCurrentOutgoingCalls++;
//
// For incoming call, the call is ready to be used
//
if (bIncoming)
{
ptCall->dwKey = TCALL_KEY;
}
LOG((TL_TRACE, "CreatetCall: exit, new ptCall=%p", *pptCall));
return 0;
}
LONG
PASCAL
CreatetCallClient(
PTCALL ptCall,
PTLINECLIENT ptLineClient,
DWORD dwPrivilege,
BOOL bValidate,
BOOL bSendCallInfoMsg,
PTCALLCLIENT *pptCallClient,
BOOL bIndicatePrivilege
)
{
BOOL bFastCallClient, bValidLineClient;
PTCALLCLIENT ptCallClient;
PTLINECLIENT ptLineClient2 = NULL;
LOG((TL_TRACE, "CreatetCallClient: enter, ptCall=%p,", ptCall));
if (WaitForExclusivetCallAccess(
ptCall,
(bValidate ? TCALL_KEY : TINCOMPLETECALL_KEY)
))
{
if (ptCall->lUsedFastCallClients < DEF_NUM_FAST_CALLCLIENTS)
{
ptCallClient = ptCall->aFastCallClients +
ptCall->lUsedFastCallClients++;
ptCall->lActiveFastCallClients++;
bFastCallClient = TRUE;
}
else if ((ptCallClient = ServerAlloc (sizeof(TCALLCLIENT))))
{
bFastCallClient = FALSE;
}
else
{
UNLOCKTCALL(ptCall);
return LINEERR_NOMEM;
}
LOG((TL_INFO, "CreatetCallClient: calling NewObject, ptCallClient = [%p]", ptCallClient));
if (!(ptCallClient->hCall = (HCALL) NewObject(
ghHandleTable,
ptCallClient,
(LPVOID) UIntToPtr(bFastCallClient)
)))
{
if (bFastCallClient)
{
ptCall->lActiveFastCallClients--;
ptCall->lUsedFastCallClients--;
}
else
{
ServerFree (ptCallClient);
}
UNLOCKTCALL(ptCall);
return LINEERR_NOMEM;
}
if (dwPrivilege == LINECALLPRIVILEGE_OWNER)
{
ptCall->dwNumOwners++;
}
else
{
ptCall->dwNumMonitors++;
}
if ((ptCallClient->pNextSametCall = ptCall->ptCallClients))
{
ptCallClient->pNextSametCall->pPrevSametCall =
ptCallClient;
}
ptCall->ptCallClients = ptCallClient;
UNLOCKTCALL (ptCall);
ptCallClient->ptLineClient = ptLineClient;
ptCallClient->ptCall = ptCall;
ptCallClient->dwPrivilege = dwPrivilege;
ptCallClient->bIndicatePrivilege = (bIndicatePrivilege ? 1 : 0);
}
else
{
//
// tCall was destroyed, so return error. Note that we return
// a generic OPFAILED error, since some calling routines
// might not be spec'd to return INVALCALLHANDLE, etc.
//
return LINEERR_OPERATIONFAILED;
}
//
// Add to tLineClient's tCallClient list
//
LOCKTLINECLIENT (ptLineClient);
try
{
bValidLineClient =
(ptLineClient->dwKey == TLINECLIENT_KEY ? TRUE : FALSE);
if (bValidLineClient)
{
ptLineClient2 = (PTLINECLIENT) ReferenceObject (
ghHandleTable,
ptLineClient->hLine,
TLINECLIENT_KEY
);
if (ptLineClient2 == NULL || ptLineClient != ptLineClient2)
{
bValidLineClient = FALSE;
}
}
}
myexcept
{
bValidLineClient = FALSE;
}
if (bValidLineClient)
{
ptCallClient->ptClient = ptLineClient->ptClient;
if ((ptCallClient->pNextSametLineClient = ptLineClient->ptCallClients))
{
ptCallClient->pNextSametLineClient->pPrevSametLineClient =
ptCallClient;
}
ptLineClient->ptCallClients = ptCallClient;
if (ptLineClient2)
{
DereferenceObject (
ghHandleTable,
ptLineClient2->hLine,
1
);
}
if (ptLineClient->ptLineApp->dwAPIVersion <= TAPI_VERSION3_0)
{
FillMemory (
ptCallClient->adwEventSubMasks,
sizeof(DWORD) * EM_NUM_MASKS,
(BYTE) 0xff
);
}
else
{
CopyMemory (
ptCallClient->adwEventSubMasks,
ptLineClient->adwEventSubMasks,
sizeof(DWORD) * EM_NUM_MASKS
);
}
UNLOCKTLINECLIENT (ptLineClient);
}
else
{
if (ptLineClient2)
{
DereferenceObject (
ghHandleTable,
ptLineClient2->hLine,
1
);
}
UNLOCKTLINECLIENT (ptLineClient);
//
// Couldn't add tCallClient to tLineClient's list, so safely
// remove it from tCall's list, dec the owner or monitor count,
// free the tCallClient, and return an appropriate error
//
// Note that no validation of tCall is necessary - it has to be
// valid since we previously added a tCallClient to it's list,
// and that tCallClient's key was not yet validated (so any
// threads attempting to destroy the tCall would be spinning)
//
LOCKTCALL (ptCall);
if (dwPrivilege == LINECALLPRIVILEGE_OWNER)
{
ptCall->dwNumOwners--;
}
else
{
ptCall->dwNumMonitors--;
}
if (ptCallClient->pNextSametCall)
{
ptCallClient->pNextSametCall->pPrevSametCall =
ptCallClient->pPrevSametCall;
}
if (ptCallClient->pPrevSametCall)
{
ptCallClient->pPrevSametCall->pNextSametCall =
ptCallClient->pNextSametCall;
}
else
{
ptCall->ptCallClients = ptCallClient->pNextSametCall;
}
if (bFastCallClient)
{
ptCall->lActiveFastCallClients--;
}
UNLOCKTCALL (ptCall);
DereferenceObject (ghHandleTable, ptCallClient->hCall, 1);
return LINEERR_INVALLINEHANDLE;
}
//
// If here success, so mark tCallClient as valid (if another thread
// was tearing down the corresponding tCall or tLineClient it will
// have been spinning waiting for us to validate this tCallClient)
//
ptCallClient->dwKey = (bValidate ? TCALLCLIENT_KEY :
TINCOMPLETECALLCLIENT_KEY);
//
// Send a call info msg other call clients if appropriate
//
if (bSendCallInfoMsg)
{
SendMsgToCallClients(
ptCall,
ptCallClient,
LINE_CALLINFO,
(dwPrivilege == LINECALLPRIVILEGE_OWNER ?
LINECALLINFOSTATE_NUMOWNERINCR :
LINECALLINFOSTATE_NUMMONITORS),
0,
0
);
}
//
// Fill in caller's pointer & return success
//
*pptCallClient = ptCallClient;
LOG((TL_TRACE,
"CreatetCallClient: exit, new ptCallClient=%p",
*pptCallClient
));
return 0;
}
LONG
PASCAL
CreatetCallAndClient(
PTLINECLIENT ptLineClient,
PTCALL *pptCall,
PTCALLCLIENT *pptCallClient,
LPLINECALLPARAMS pCallParams,
HCALL *phCall,
PTCALL ptCallAssociate
)
{
LONG lResult = 0;
DWORD dwAppNameSize;
WCHAR *pszAppName = NULL;
PTCALL ptCall = NULL;
PTLINE ptLine;
LOG((TL_TRACE, "CreatetCallAndClient: enter, ptLineClient=%p", ptLineClient));
try
{
ptLine = ptLineClient->ptLine;
dwAppNameSize = ptLineClient->ptLineApp->dwFriendlyNameSize;
if (ptLineClient->dwKey != TLINECLIENT_KEY)
{
lResult = LINEERR_INVALLINEHANDLE;
}
else if ((pszAppName = ServerAlloc (dwAppNameSize)))
{
CopyMemory(
pszAppName,
ptLineClient->ptLineApp->pszFriendlyName,
dwAppNameSize
);
}
else
{
lResult = LINEERR_NOMEM;
}
}
myexcept
{
ServerFree (pszAppName);
lResult = LINEERR_INVALLINEHANDLE;
}
if (lResult != 0)
{
return lResult;
}
if ((lResult = CreatetCall(
ptLine,
FALSE,
(HDRVCALL) 0,
&ptCall,
pCallParams,
phCall,
ptCallAssociate
)) != 0)
{
ServerFree (pszAppName);
return lResult;
}
if ((lResult = CreatetCallClient(
ptCall,
ptLineClient,
LINECALLPRIVILEGE_OWNER,
FALSE,
FALSE,
pptCallClient,
FALSE
)) != 0)
{
ServerFree (pszAppName);
ptCall->dwDrvCallFlags = DCF_SPIRETURNED;
DestroytCall (ptCall);
*pptCall = (PTCALL) NULL;
*phCall = 0;
return lResult;
}
ptCall->dwAppNameSize = dwAppNameSize;
ptCall->pszAppName = pszAppName;
*pptCall = ptCall;
return lResult;
}
LONG
PASCAL
CreateCallMonitors(
PTCALL ptCall,
BOOL bIncoming
)
{
//
// This func is called by post processing routines when
// a call was successfully created, or on receiving the
// first call state message for an incoming call, at
// which times we want to create call handles for any
// monitoring apps.
//
// Assumes tCall only has has either no clients at all
// or a single (owner) client
//
// Returns the # of monitor call clients created (>=0) or
// an error value (<0)
//
LONG lResult;
BOOL bInitializedMsgs, bRemote, bConfParent = FALSE;
DWORD i, dwAddressID, dwCallID, dwRelatedCallID;
TPOINTERLIST lineClients, *pLineClients = &lineClients;
PTLINE ptLine;
PTLINECLIENT ptLineClientOwner;
ASYNCEVENTMSG newCallMsg[2], callStateUnkMsg[2];
//
// Determine if this call is conf parent and get a list of line clients
//
try
{
PTCONFERENCELIST pConfList;
if ((pConfList = ptCall->pConfList) &&
(pConfList != (PTCONFERENCELIST) LongToPtr(0xffffffff)) &&
(pConfList->aptCalls[0] == ptCall))
{
bConfParent = TRUE;
}
dwAddressID = ptCall->dwAddressID;
dwCallID = ptCall->dwCallID;
dwRelatedCallID = ptCall->dwRelatedCallID;
ptLine = (PTLINE) ptCall->ptLine;
ptLineClientOwner = (ptCall->ptCallClients ?
ptCall->ptCallClients->ptLineClient : NULL);
}
myexcept
{
return LINEERR_OPERATIONFAILED;
}
if ((lResult = GetLineClientListFromLine (ptLine, &pLineClients)))
{
return lResult;
}
//
// Look at each line client in the list, and if it has
// monitor privileges and is not the one associated with
// the existing owner call client then create a monitor
// call client
//
//
bInitializedMsgs = FALSE;
for (i = 0; i < pLineClients->dwNumUsedEntries; i++)
{
PTCALLCLIENT ptCallClientMonitor;
PTLINECLIENT ptLineClient = pLineClients->aEntries[i];
BOOL fContinue;
try
{
if (!(ptLineClient->dwPrivileges & LINECALLPRIVILEGE_MONITOR) ||
(ptLineClient == ptLineClientOwner))
{
fContinue = TRUE;
}
else
{
fContinue = FALSE;
bRemote = IS_REMOTE_CLIENT (ptLineClient->ptClient);
}
}
myexcept
{
//
// If here the tLineClient or tCallClient was destroyed,
// just continue
//
fContinue = TRUE;
}
if (fContinue)
{
continue;
}
//
// NOTE: If client is remote(sp) then create the call client
// with OWNER privileges so client can still do everything.
// The remote tapisrv will deal with all the remote
// privilege issues. We'll still send the appropriate
// MONITOR privilege flag so the remote tapisrv will know
// not to look for an owner app.
//
// This scheme might end up confusing other apps since
// a LINE_CALLINFO\NUMOWNERINCR (not NUMMONITORS) msgs
// get sent, but it certainly beats what we had in tapi 2.1 -
// that is, if a remote client did not initially have owner
// privilege then it could *never* get owner privilege.
//
if (CreatetCallClient(
ptCall,
ptLineClient,
(bRemote ? LINECALLPRIVILEGE_OWNER :LINECALLPRIVILEGE_MONITOR),
TRUE,
FALSE,
&ptCallClientMonitor,
bIncoming
) == 0)
{
//
// If this is an incoming call simply increment the number of
// monitor call clients created and continue.
//
// Else this is an outgoing call, so send the monitor app
// LINE_APPNEWCALL & LINE_CALLSTATE\UNKNOWN messages to alert
// it of new outgoing call
//
if (bIncoming)
{
lResult++;
continue;
}
if (!bInitializedMsgs)
{
newCallMsg->TotalSize = sizeof (ASYNCEVENTMSG) +
3 * sizeof (DWORD);
newCallMsg->fnPostProcessProcHandle = 0;
newCallMsg->Msg = LINE_APPNEWCALL;
newCallMsg->Param1 = dwAddressID;
newCallMsg->Param3 = LINECALLPRIVILEGE_MONITOR;
*(&newCallMsg->Param4 + 1) = dwCallID;
*(&newCallMsg->Param4 + 2) = dwRelatedCallID;
*(&newCallMsg->Param4 + 3) = (DWORD)bConfParent;
callStateUnkMsg->TotalSize = sizeof(ASYNCEVENTMSG)
+ sizeof (HCALLHUB);
callStateUnkMsg->fnPostProcessProcHandle = 0;
callStateUnkMsg->Msg = LINE_CALLSTATE;
callStateUnkMsg->Param1 = LINECALLSTATE_UNKNOWN;
*((LPHCALLHUB)(callStateUnkMsg + 1)) = (HCALLHUB)0;
bInitializedMsgs = TRUE;
}
try
{
//
// We're presenting the app with a new call handle; for
// 2.0 & newer apps we indicate this with an APPNEWCALL
// msg, while older apps just get the privilege field
// set in the call state msg.
//
if (ptLineClient->ptLineApp->dwAPIVersion >= TAPI_VERSION2_0)
{
if (!FMsgDisabled(
ptLineClient->ptLineApp->dwAPIVersion,
ptLineClient->adwEventSubMasks,
LINE_APPNEWCALL,
0
))
{
newCallMsg->InitContext =
ptLineClient->ptLineApp->InitContext;
newCallMsg->hDevice = ptLineClient->hRemoteLine;
newCallMsg->OpenContext = ptLineClient->OpenContext;
newCallMsg->Param2 = ptCallClientMonitor->hCall;
WriteEventBuffer (ptLineClient->ptClient, newCallMsg);
}
callStateUnkMsg->Param3 = 0;
}
else
{
callStateUnkMsg->Param3 = LINECALLPRIVILEGE_MONITOR;
}
if (FMsgDisabled (
ptLineClient->ptLineApp->dwAPIVersion,
ptLineClient->adwEventSubMasks,
LINE_CALLSTATE,
LINECALLSTATE_UNKNOWN
))
{
continue;
}
callStateUnkMsg->InitContext =
ptLineClient->ptLineApp->InitContext;
callStateUnkMsg->hDevice = ptCallClientMonitor->hCall;
callStateUnkMsg->OpenContext = ptLineClient->OpenContext;
//
// Indicate hRemoteLine in p4 to make life easier for remotesp
//
callStateUnkMsg->Param4 = ptLineClient->hRemoteLine;
//
// REMOTESP HACK: See note in LINE_CALLSTATE msg handler
//
if (IS_REMOTE_CLIENT (ptLineClient->ptClient))
{
callStateUnkMsg->Param2 = LINECALLPRIVILEGE_MONITOR;
callStateUnkMsg->Param3 = LINEMEDIAMODE_UNKNOWN;
}
else
{
callStateUnkMsg->Param2 = 0;
}
WriteEventBuffer (ptLineClient->ptClient, callStateUnkMsg);
lResult++;
}
myexcept
{
// just continue
}
}
}
if (pLineClients != &lineClients)
{
ServerFree (pLineClients);
}
//
// Now safely set the flag that says it's ok for other routines like
// lineGetNewCalls to create new call handles for apps for this call
//
{
if (WaitForExclusivetCallAccess (ptCall, TCALL_KEY))
{
//
// Only do call hub hashing if there's >0 call clients,
// since the (incoming) call will get destroyed otherwise
//
// $$ Per bug 87355
// It is necessary to do DoCallHubHashing even if we do
// not have a client now. So we removed the check for
// ptCall->ptCallClients. For incoming call who has got
// an owner, we behave the same; for incoming call without
// an owner, we would hash the call for now and remove the
// call from hash table when destroying the call, so we
// are safe either way.
//
DoCallHubHashing (ptCall, 0);
ptCall->bCreatedInitialMonitors = TRUE;
UNLOCKTCALL (ptCall);
}
else
{
lResult = LINEERR_OPERATIONFAILED;
}
}
return lResult;
}
PTREQUESTRECIPIENT
PASCAL
GetHighestPriorityRequestRecipient(
void
)
{
BOOL bFoundRecipientInPriorityList = FALSE;
WCHAR *pszAppInPriorityList,
*pszAppInPriorityListPrev = (WCHAR *) LongToPtr(0xffffffff);
PTREQUESTRECIPIENT pRequestRecipient,
pHighestPriorityRequestRecipient = NULL;
EnterCriticalSection (&gPriorityListCritSec);
pRequestRecipient = TapiGlobals.pRequestRecipients;
while (pRequestRecipient)
{
if (TapiGlobals.pszReqMakeCallPriList &&
(pszAppInPriorityList = wcsstr(
TapiGlobals.pszReqMakeCallPriList,
pRequestRecipient->ptLineApp->pszModuleName
)))
{
if (pszAppInPriorityList <= pszAppInPriorityListPrev)
{
pHighestPriorityRequestRecipient = pRequestRecipient;
pszAppInPriorityListPrev = pszAppInPriorityList;
bFoundRecipientInPriorityList = TRUE;
}
}
else if (!bFoundRecipientInPriorityList)
{
pHighestPriorityRequestRecipient = pRequestRecipient;
}
pRequestRecipient = pRequestRecipient->pNext;
}
LeaveCriticalSection (&gPriorityListCritSec);
return pHighestPriorityRequestRecipient;
}
void
PASCAL
FreetCall(
PTCALL ptCall
)
{
if (ptCall->pszAppName)
{
ServerFree (ptCall->pszAppName);
}
if (ptCall->dwDrvCallFlags & DCF_INCOMINGCALL)
{
PerfBlock.dwCurrentIncomingCalls--;
}
else
{
PerfBlock.dwCurrentOutgoingCalls--;
}
DereferenceObject (ghHandleTable, ptCall->hCall, 1);
}
void
PASCAL
DestroytCall(
PTCALL ptCall
)
{
DWORD dwKey;
LOG((TL_TRACE, "DestroytCall: enter, ptCall=x%p", ptCall));
//
// Safely get the call's current key, then grab the call's lock.
// The two waits allow us to deal with the case where the tCall's
// key is either TINCOMPLETECALL_KEY or TCALL_KEY, or changing
// from the former to the latter (the completion proc was called)
//
try
{
dwKey = (ptCall->dwKey == TCALL_KEY ? TCALL_KEY : TINCOMPLETECALL_KEY);
}
myexcept
{
LOG((TL_ERROR, "DestroytCall: excepted looking at key"));
return;
}
if (WaitForExclusivetCallAccess (ptCall, dwKey) ||
WaitForExclusivetCallAccess (ptCall, TCALL_KEY))
{
PTPROVIDER ptProvider;
PTCALL ptCall2;
ptCall2 = ReferenceObject (
ghHandleTable,
ptCall->hCall,
dwKey
);
if (ptCall2)
{
DereferenceObject (
ghHandleTable,
ptCall2->hCall,
1
);
}
if (ptCall2 == NULL || ptCall != ptCall2)
{
UNLOCKTCALL (ptCall);
return;
}
//
// Invalidate the tCall
//
ptCall->dwKey = TZOMBIECALL_KEY;
UNLOCKTCALL (ptCall);
//
// If the provider has not returned from it's call-creation
// routine yet (i.e. TSPI_lineMakeCall) wait for it to do so
//
while (!(ptCall->dwDrvCallFlags & DCF_SPIRETURNED))
{
Sleep (0);
}
ptProvider = ptCall->ptProvider;
//
// Remove tCall from call hub list if appropriate
//
// Note that there's a window of time between which the call IDs
// are retrieved and the call is inserted in a hash time, and so
// we need to check for that case as well (CallHubList.Flink == 0)
//
if (ptCall->dwCallID != 0)
{
PTHASHTABLEENTRY pStaticEntry, pEntry;
pStaticEntry = AcquireHashTableEntryLock(
ptCall->ptProvider,
ptCall->dwCallID
);
if (ptCall->CallHubList.Flink == 0 ||
ptCall->CallHubList.Blink == 0)
{
ReleaseHashTableEntryLock (ptCall->ptProvider, pStaticEntry);
goto finished_callhubID;
}
RemoveEntryList (&ptCall->CallHubList);
ptCall->CallHubList.Flink = NULL;
ptCall->CallHubList.Blink = NULL;
pEntry = (pStaticEntry->dwCallHubID == ptCall->dwCallID ?
pStaticEntry :
FindDynamicHashTableEntry (pStaticEntry, ptCall->dwCallID)
);
if (IsListEmpty (&pEntry->CallHubList))
{
PTCALLHUBCLIENT ptCallHubClient, pNext;
ptCallHubClient = pEntry->ptCallHubClients;
if (pEntry == pStaticEntry)
{
pStaticEntry->dwCallHubID = 0;
pStaticEntry->ptCallHubClients = NULL;
}
else
{
RemoveDynamicHashTableEntry(
ptProvider,
pStaticEntry,
pEntry
);
}
ReleaseHashTableEntryLock (ptCall->ptProvider, pStaticEntry);
if (ptCallHubClient)
{
ASYNCEVENTMSG msg;
msg.TotalSize = sizeof (ASYNCEVENTMSG);
msg.Msg = LINE_CALLHUBCLOSE;
msg.fnPostProcessProcHandle = 0;
msg.hDevice = 0;
msg.OpenContext = 0;
msg.Param2 = 0;
msg.Param3 = 0;
while (ptCallHubClient)
{
msg.Param1 = ptCallHubClient->hCallHub;
try
{
msg.InitContext =
ptCallHubClient->ptLineApp->InitContext;
if (ptCallHubClient->ptLineApp->dwKey ==
TLINEAPP_KEY &&
(!FMsgDisabled(
ptCallHubClient->ptLineApp->dwAPIVersion,
ptCallHubClient->ptLineApp->adwEventSubMasks,
LINE_CALLHUBCLOSE,
0
)))
{
WriteEventBuffer(
ptCallHubClient->ptClient,
&msg
);
}
}
except (EXCEPTION_EXECUTE_HANDLER)
{
// tLineApp is gone, just fall through
}
pNext = ptCallHubClient->pNext;
ptCallHubClient->dwKey = INVAL_KEY;
DereferenceObject(
ghHandleTable,
ptCallHubClient->hCallHub,
1
);
ptCallHubClient = pNext;
}
}
}
else
{
ReleaseHashTableEntryLock (ptCall->ptProvider, pStaticEntry);
}
}
finished_callhubID:
//
// Destroy all the tCallClient's
//
if (ptCall->ptCallClients)
{
while (ptCall->ptCallClients)
{
DestroytCallClient (ptCall->ptCallClients);
}
}
//
// Tell the provider to close the call, but only if the hdCall
// is valid (we might be destroying a call that
// LMakeCall_PostProcess would normally destroy in the event
// of a failed make-call request, and we wouldn't want to pass
// an invalid hdCall to the driver)
//
if (ptCall->dwDrvCallFlags & DCF_DRVCALLVALID)
{
if (ptProvider->dwTSPIOptions & LINETSPIOPTION_NONREENTRANT)
{
WaitForSingleObject (ptProvider->hMutex, INFINITE);
}
if (ptProvider->apfn[SP_LINECLOSECALL])
{
CallSP1(
ptProvider->apfn[SP_LINECLOSECALL],
"lineCloseCall",
SP_FUNC_SYNC,
(ULONG_PTR) ptCall->hdCall
);
}
if (ptProvider->dwTSPIOptions & LINETSPIOPTION_NONREENTRANT)
{
ReleaseMutex (ptProvider->hMutex);
}
}
//
// Remove tCall from the tLine's tCall list
//
RemoveCallFromLineList (ptCall);
//
// Free the resources
//
{
PTCONFERENCELIST pConfList;
if ((pConfList = ptCall->pConfList) &&
(pConfList != (PTCONFERENCELIST) LongToPtr(0xffffffff)))
{
DWORD i;
if (pConfList->aptCalls[0] == ptCall)
{
//
// We're destroying a conf parent so we want to zero
// out the pConfList field of all the conf children,
// essentially removing them from the conference.
//
TPOINTERLIST confCallList,
*pConfCallList = &confCallList;
if (GetConfCallListFromConf(
pConfList,
&pConfCallList
) == 0)
{
for(
i = 1;
i < pConfCallList->dwNumUsedEntries;
i++
)
{
SetCallConfList(
pConfCallList->aEntries[i],
NULL,
FALSE
);
}
if (pConfCallList != &confCallList)
{
ServerFree (pConfCallList);
}
}
while (pConfList)
{
PTCONFERENCELIST pNextConfList =
pConfList->pNext;
ServerFree (pConfList);
pConfList = pNextConfList;
}
}
else
{
}
}
}
while (ptCall->lActiveFastCallClients != 0)
{
Sleep (5);
}
FreetCall (ptCall);
}
else
{
LOG((TL_ERROR, "DestroytCall: two waits failed!"));
}
}
void
PASCAL
DestroytCallClient(
PTCALLCLIENT ptCallClient
)
{
BOOL bUnlock = FALSE,
bExit = TRUE,
bDestroytCall,
bSendCallInfoMsgs,
bFastCallClient;
HCALL hCall;
PTCALL ptCall;
PTCALLCLIENT ptCallClient2;
LOG((TL_TRACE, "DestroytCallClient: enter, ptCallCli=x%p", ptCallClient));
//
// Check that this is a valid tCallClient, & if so lock the
// corresponding tCall (and recheck)
//
try
{
if (ptCallClient->dwKey == TINCOMPLETECALLCLIENT_KEY ||
ptCallClient->dwKey == TCALLCLIENT_KEY)
{
ptCall = ptCallClient->ptCall;
LOCKTCALL (ptCall);
bUnlock = TRUE;
//
// Check to be sure we are working on a valid memory
//
ptCallClient2 = ReferenceObject (
ghHandleTable,
ptCallClient->hCall,
ptCallClient->dwKey
);
if (ptCallClient2 != NULL)
{
DereferenceObject (
ghHandleTable,
ptCallClient2->hCall,
1
);
}
if ((ptCallClient->dwKey == TINCOMPLETECALLCLIENT_KEY ||
ptCallClient->dwKey == TCALLCLIENT_KEY) &&
ptCall == ptCallClient->ptCall &&
ptCallClient2 == ptCallClient)
{
//
// We can continue detroying this tCallClient
//
bExit = FALSE;
}
}
}
myexcept
{
LOG((TL_ERROR, "DestroytCallClient: %lx faulted looking at key",
ptCallClient ));
}
if (bExit)
{
if (bUnlock)
{
UNLOCKTCALL (ptCall);
}
return;
}
//
// Mark tCallClient as bad
//
ptCallClient->dwKey = INVAL_KEY;
//
// Munge tCall's num owners/monitors fields
//
if (ptCallClient->dwPrivilege == LINECALLPRIVILEGE_OWNER)
{
ptCall->dwNumOwners--;
//
// NOTE: per bug #20545 we're no longer auto-dropping
// non-IDLE calls; figured this would be the
// wrong thing to do in a distributed system
//
// dankn 02/15/96
//
}
else
{
ptCall->dwNumMonitors--;
//
// NOTE: per bug #20545 we're no longer auto-dropping
// non-IDLE calls; figured this would be the
// wrong thing to do in a distributed system
//
// dankn 02/15/96
//
}
//
// Remove it from the tCall's tCallClient list
//
bDestroytCall = FALSE;
bSendCallInfoMsgs = (ptCall->dwKey == TCALL_KEY ? TRUE : FALSE);
if (ptCallClient->pNextSametCall)
{
ptCallClient->pNextSametCall->pPrevSametCall =
ptCallClient->pPrevSametCall;
}
if (ptCallClient->pPrevSametCall)
{
ptCallClient->pPrevSametCall->pNextSametCall =
ptCallClient->pNextSametCall;
}
else if (ptCallClient->pNextSametCall)
{
ptCall->ptCallClients = ptCallClient->pNextSametCall;
}
else // last call client so destroy the tCall too
{
ptCall->ptCallClients = NULL;
bDestroytCall = TRUE;
}
UNLOCKTCALL (ptCall);
//
// Remove tCallClient from the tLineClient's tCallClient list
//
RemoveCallClientFromLineClientList (ptCallClient);
//
// Save the hCall in a local because it won't be safe to access
// ptCallClient->hCall once we've decremented
// ptCall->lActiveFastCallClients below
//
hCall = ptCallClient->hCall;
//
// If this is a fast call client decrement the number of active
// fast call clients prior to calling DestroytCall
//
bFastCallClient = (ptCallClient >= ptCall->aFastCallClients &&
ptCallClient < (ptCall->aFastCallClients + DEF_NUM_FAST_CALLCLIENTS));
if (bFastCallClient)
{
InterlockedDecrement (&ptCall->lActiveFastCallClients);
}
if (bDestroytCall)
{
DestroytCall (ptCall);
bSendCallInfoMsgs = FALSE;
}
//
// Send call info msgs as appropriate
//
if (bSendCallInfoMsgs)
{
SendMsgToCallClients(
ptCall,
NULL,
LINE_CALLINFO,
(ptCallClient->dwPrivilege ==
LINECALLPRIVILEGE_OWNER ?
LINECALLINFOSTATE_NUMOWNERDECR :
LINECALLINFOSTATE_NUMMONITORS),
0,
0
);
}
//
// Decrement reference count remove the initial (creation) reference
//
DereferenceObject (ghHandleTable, hCall, 1);
}
void
PASCAL
DestroytLine(
PTLINE ptLine,
BOOL bUnconditional
)
{
BOOL bCloseMutex;
HANDLE hMutex;
LOG((TL_TRACE,
"DestroytLine: enter, ptLine=x%p, bUnconditional=%d",
ptLine,
bUnconditional
));
if (WaitForExclusivetLineAccess(
ptLine,
&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
// SendMsgToLineClients 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 (ptLine->dwKey == TLINE_KEY &&
(bUnconditional == TRUE || ptLine->ptLineClients == NULL))
{
if (GetLineClientListFromLine (ptLine, &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;
}
ptLine->dwKey = INVAL_KEY;
bExit = FALSE;
}
else
{
bExit = TRUE;
}
MyReleaseMutex (hMutex, bCloseMutex);
if (bExit)
{
LOG((TL_TRACE,
"DestroytLine: exit, didn't destroy tLine=x%p",
ptLine
));
return;
}
if (pClientList->dwNumUsedEntries)
{
DWORD i;
PTCLIENT ptClient;
PTLINECLIENT ptLineClient;
ASYNCEVENTMSG msg;
ZeroMemory (&msg, sizeof (msg));
msg.TotalSize = sizeof (ASYNCEVENTMSG);
msg.Msg = LINE_CLOSE;
for (i = 0; i < pClientList->dwNumUsedEntries; i++)
{
ptLineClient = (PTLINECLIENT) pClientList->aEntries[i];
try
{
msg.InitContext = ptLineClient->ptLineApp->InitContext;
msg.hDevice = ptLineClient->hRemoteLine;
msg.OpenContext = ptLineClient->OpenContext;
ptClient = ptLineClient->ptClient;
if (ptLineClient->dwKey == TLINECLIENT_KEY &&
(!FMsgDisabled(
ptLineClient->ptLineApp->dwAPIVersion,
ptLineClient->adwEventSubMasks,
LINE_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.
//
{
HLINE hLine;
hMutex = ptLine->hMutex;
destroy_tLineClients:
WaitForSingleObject (hMutex, INFINITE);
hLine = (ptLine->ptLineClients ?
ptLine->ptLineClients->hLine : (HLINE) 0);
ReleaseMutex (hMutex);
if (hLine)
{
DestroytLineClient (hLine);
goto destroy_tLineClients;
}
}
//
// There may yet be some tCall's hanging around, i.e. incoming
// calls that we have not processed the 1st call state msg for
// and hence have no associated owner/monitor that would have
// been destroyed in the loop above, so destroy any of these
// before proceeding
//
//
{
PTCALL ptCall;
destroy_UnownedtCalls:
WaitForSingleObject (hMutex, INFINITE);
ptCall = ptLine->ptCalls;
ReleaseMutex (hMutex);
if (ptCall)
{
DestroytCall (ptCall);
goto destroy_UnownedtCalls;
}
}
//
// Tell the provider to close the widget
//
{
PTPROVIDER ptProvider = ptLine->ptProvider;
if (ptProvider->dwTSPIOptions & LINETSPIOPTION_NONREENTRANT)
{
WaitForSingleObject (ptProvider->hMutex, INFINITE);
}
if ( ptProvider->apfn[SP_LINECLOSE] )
{
CallSP1(
ptProvider->apfn[SP_LINECLOSE],
"lineClose",
SP_FUNC_SYNC,
(ULONG_PTR) ptLine->hdLine
);
}
if (ptProvider->dwTSPIOptions & LINETSPIOPTION_NONREENTRANT)
{
ReleaseMutex (ptProvider->hMutex);
}
}
//
// NULLify the ptLine field in the lookup entry, so LOpen will
// know it has to open the SP's line on the next open request
//
{
PTLINELOOKUPENTRY pEntry;
pEntry = GetLineLookupEntry (ptLine->dwDeviceID);
if (NULL != pEntry)
{
pEntry->ptLine = NULL;
}
}
DereferenceObject (ghHandleTable, ptLine->hLine, 1);
}
else
{
LOG((TL_ERROR,
"DestroytLine: WaitForExclusivetLineAccess failed"
));
}
// PERF
if (PerfBlock.dwLinesInUse)
{
PerfBlock.dwLinesInUse--;
}
else
{
LOG((TL_INFO, "PERF: dwNumLinesInUse below 0"));
}
LOG((TL_TRACE, "DestroytLine: exit, destroyed line=x%p", ptLine));
}
void
PASCAL
DestroytLineClient(
HLINE hLine
)
{
BOOL bDupedMutex;
HANDLE hMutex;
PTLINECLIENT ptLineClient;
LOG((TL_TRACE, "DestroytLineClient: enter, hLine=x%x", hLine));
if (!(ptLineClient = ReferenceObject (ghHandleTable, hLine, 0)))
{
return;
}
//
// If we can get exclusive access to this tLineClient then mark
// it (the dwKey) as bad & continue with teardown. Else, another
// thread is already in the process of destrying this tLineClient
//
//
if (WaitForExclusiveLineClientAccess (ptLineClient))
{
BOOL bSendDevStateCloseMsg = FALSE;
DWORD dwProxyCloseMsgs = 0;
PTLINE ptLine;
PTPROVIDER ptProvider = ptLineClient->ptLine->ptProvider;
HANDLE hProviderMutex = NULL;
if (ptProvider->dwTSPIOptions & LINETSPIOPTION_NONREENTRANT)
{
hProviderMutex = ptProvider->hMutex;
}
ptLineClient->dwKey = INVAL_KEY;
//
// Remove the proxy server publishing if any
//
if (ptLineClient->szProxyClsid)
{
OnProxyLineClose (ptLineClient->szProxyClsid);
ServerFree (ptLineClient->szProxyClsid);
}
//
// Destroy all the tCallClients. Note that we want to grab the
// lock each time we reference the list of tCallClient's, since
// another thread might be destroying a tCallClient too.
//
{
PTCALLCLIENT ptCallClient;
destroy_tCallClients:
ptCallClient = ptLineClient->ptCallClients;
UNLOCKTLINECLIENT (ptLineClient);
if (ptCallClient)
{
DestroytCallClient (ptCallClient);
LOCKTLINECLIENT (ptLineClient);
goto destroy_tCallClients;
}
}
//
// Remove tLineClient from tLineApp's list. Note that we don't
// have to worry validating the tLineApp here, since we know
// it's valid (another thread trying to destroy the tLineApp
// will be spinning until the tLineClient we're destroying here
// is removed from the tLineApp's list)
//
{
PTLINEAPP ptLineApp = (PTLINEAPP) ptLineClient->ptLineApp;
LOCKTLINEAPP (ptLineApp);
if (ptLineClient->pNextSametLineApp)
{
ptLineClient->pNextSametLineApp->pPrevSametLineApp =
ptLineClient->pPrevSametLineApp;
}
if (ptLineClient->pPrevSametLineApp)
{
ptLineClient->pPrevSametLineApp->pNextSametLineApp =
ptLineClient->pNextSametLineApp;
}
else
{
ptLineApp->ptLineClients = ptLineClient->pNextSametLineApp;
}
UNLOCKTLINEAPP (ptLineApp);
}
//
// Grab the tLine's mutex & start munging. 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.
//
ptLine = ptLineClient->ptLine;
hMutex = ptLine->hMutex;
WaitForSingleObject (hMutex, INFINITE);
//
// If client had call hub tracking enabled then adjust tLine
//
if (ptLineClient->dwCurrentTracking)
{
--ptLine->dwNumCallHubTrackers;
if ((ptLineClient->dwCurrentTracking &
LINECALLHUBTRACKING_PROVIDERLEVEL) &&
(--ptLine->dwNumCallHubTrackersSPLevel == 0))
{
const LINECALLHUBTRACKINGINFO trackingInfo =
{
sizeof (LINECALLHUBTRACKINGINFO),
sizeof (LINECALLHUBTRACKINGINFO),
sizeof (LINECALLHUBTRACKINGINFO),
0,
LINECALLHUBTRACKING_NONE
};
if (hProviderMutex)
{
WaitForSingleObject (hProviderMutex, INFINITE);
}
if (ptLine->ptProvider->apfn[SP_LINESETCALLHUBTRACKING])
{
CallSP2(
ptLine->ptProvider->apfn[SP_LINESETCALLHUBTRACKING],
"lineSetCallHubTracking",
SP_FUNC_SYNC,
(ULONG_PTR) ptLine->hdLine,
(ULONG_PTR) &trackingInfo
);
}
if (hProviderMutex)
{
ReleaseMutex (hProviderMutex);
}
}
}
//
// If client registered as a proxy then unregister it
//
if (ptLineClient->dwPrivileges & LINEOPENOPTION_PROXY)
{
DWORD i;
for(
i = LINEPROXYREQUEST_SETAGENTGROUP;
i <= LINEPROXYREQUEST_LASTVALUE;
i++
)
{
if (ptLine->apProxys[i] == ptLineClient)
{
//
// Alert other clients that a proxy close has occured
//
LOG((TL_INFO, "tell clients proxy %02X closed", i));
dwProxyCloseMsgs |= (1 << (i - 1));
ptLine->apProxys[i] = NULL;
}
}
}
//
//
//
if (ptLineClient->dwExtVersion)
{
if ((--ptLine->dwExtVersionCount) == 0)
{
if (hProviderMutex)
{
WaitForSingleObject (hProviderMutex, INFINITE);
}
if (ptLine->ptProvider->apfn[SP_LINESELECTEXTVERSION])
{
CallSP2(
ptLine->ptProvider->apfn[SP_LINESELECTEXTVERSION],
"lineSelectExtVersion",
SP_FUNC_SYNC,
(ULONG_PTR) ptLine->hdLine,
(DWORD) 0
);
}
if (hProviderMutex)
{
ReleaseMutex (hProviderMutex);
}
ptLine->dwExtVersion = 0;
}
}
//
// Remove the tLineClient from the tLine's list & decrement
// the number of opens
//
if (ptLineClient->pNextSametLine)
{
ptLineClient->pNextSametLine->pPrevSametLine =
ptLineClient->pPrevSametLine;
}
if (ptLineClient->pPrevSametLine)
{
ptLineClient->pPrevSametLine->pNextSametLine =
ptLineClient->pNextSametLine;
}
else
{
ptLine->ptLineClients = ptLineClient->pNextSametLine;
}
ptLine->dwNumOpens--;
//
// See if we need to reset the monitored media modes or close
// the tLine (still hanging on the the mutex)
//
if (ptLine->dwKey == TLINE_KEY)
{
LOG((TL_INFO, "It's a line_key"));
if (ptLine->ptLineClients)
{
LOG((TL_INFO, "...and there are still clients"));
if (ptLine->dwOpenMediaModes && ptLineClient->dwMediaModes)
{
DWORD dwUnionMediaModes = 0;
PTLINECLIENT ptLineClientTmp =
ptLine->ptLineClients;
while (ptLineClientTmp)
{
if (ptLineClientTmp->dwPrivileges &
LINECALLPRIVILEGE_OWNER)
{
dwUnionMediaModes |=
ptLineClientTmp->dwMediaModes;
}
ptLineClientTmp = ptLineClientTmp->pNextSametLine;
}
if (dwUnionMediaModes != ptLine->dwOpenMediaModes)
{
LONG lResult;
if (hProviderMutex)
{
WaitForSingleObject (hProviderMutex, INFINITE);
}
if (ptLine->ptProvider->apfn
[SP_LINESETDEFAULTMEDIADETECTION])
{
lResult = CallSP2(
ptLine->ptProvider->apfn
[SP_LINESETDEFAULTMEDIADETECTION],
"lineSetDefaultMediaDetection",
SP_FUNC_SYNC,
(ULONG_PTR) ptLine->hdLine,
(DWORD) dwUnionMediaModes
);
}
else
{
lResult = LINEERR_OPERATIONUNAVAIL;
}
if (hProviderMutex)
{
ReleaseMutex (hProviderMutex);
}
ptLine->dwOpenMediaModes = dwUnionMediaModes;
}
}
bSendDevStateCloseMsg = TRUE;
//
// 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 ((ptLineClient->dwLineStates & ~LINEDEVSTATE_REINIT) ||
ptLineClient->dwAddressStates)
{
DWORD dwUnionLineStates = 0,
dwUnionAddressStates = 0;
PTLINECLIENT ptLC;
while (ptLine->dwBusy)
{
BOOL bClosed = TRUE;
ReleaseMutex (hMutex);
Sleep (50);
WaitForSingleObject (hMutex, INFINITE);
try
{
if (ptLine->dwKey == TLINE_KEY)
{
bClosed = FALSE;
}
}
myexcept
{
// do nothing
}
if (bClosed)
{
goto releasMutex;
}
}
for(
ptLC = ptLine->ptLineClients;
ptLC;
ptLC = ptLC->pNextSametLine
)
{
dwUnionLineStates |= ptLC->dwLineStates;
dwUnionAddressStates |= ptLC->dwAddressStates;
}
if ((dwUnionLineStates != ptLine->dwUnionLineStates) ||
(dwUnionAddressStates != ptLine->dwUnionAddressStates))
{
if (ptLine->ptProvider->apfn[SP_LINESETSTATUSMESSAGES])
{
LONG lResult;
TSPIPROC pfn;
HDRVLINE hdLine = ptLine->hdLine;
pfn = ptLine->ptProvider->
apfn[SP_LINESETSTATUSMESSAGES];
ptLine->dwBusy = 1;
ReleaseMutex (hMutex);
if (hProviderMutex)
{
WaitForSingleObject (hProviderMutex, INFINITE);
}
lResult = CallSP3(
pfn,
"lineSetStatusMessages",
SP_FUNC_SYNC,
(ULONG_PTR) hdLine,
(DWORD) dwUnionLineStates,
(DWORD) dwUnionAddressStates
);
if (hProviderMutex)
{
ReleaseMutex (hProviderMutex);
}
WaitForSingleObject (hMutex, INFINITE);
try
{
if (ptLine->dwKey == TLINE_KEY)
{
ptLine->dwBusy = 0;
if (lResult == 0)
{
ptLine->dwUnionLineStates =
dwUnionLineStates;
ptLine->dwUnionAddressStates =
dwUnionAddressStates;
}
}
}
myexcept
{
// do nothing
}
}
}
}
}
else
{
//
// This was the last client so destroy the tLine too
//
LOG((TL_INFO, "...and it's the last one out"));
ReleaseMutex (hMutex);
hMutex = NULL;
DestroytLine (ptLine, FALSE); // conditional destroy
}
}
releasMutex:
if (hMutex)
{
ReleaseMutex (hMutex);
}
//
// Now that the mutex is released send any necessary msgs
//
if (bSendDevStateCloseMsg)
{
DWORD dwOrdinal, dwBitFlag;
SendMsgToLineClients(
ptLine,
NULL,
LINE_LINEDEVSTATE,
LINEDEVSTATE_CLOSE,
0,
0
);
for(
dwOrdinal = LINEPROXYREQUEST_SETAGENTGROUP, dwBitFlag = 1;
dwProxyCloseMsgs != 0;
dwOrdinal++, dwBitFlag <<= 1)
{
if (dwProxyCloseMsgs & dwBitFlag)
{
SendMsgToLineClients(
ptLine,
NULL,
LINE_PROXYSTATUS,
LINEPROXYSTATUS_CLOSE,
dwOrdinal, // LINEPROXYREQUEST_xx
0
);
dwProxyCloseMsgs ^= dwBitFlag;
}
}
}
//
// Complete any remaining
// proxy requests
//
if (ptLineClient->dwPrivileges & LINEOPENOPTION_PROXY)
{
PASYNCREQUESTINFO pAsyncRequestInfo =
ptLineClient->pPendingProxyRequests,
pNextAsyncRequestInfo;
while (pAsyncRequestInfo)
{
pNextAsyncRequestInfo = (PASYNCREQUESTINFO)
pAsyncRequestInfo->dwParam5;
pAsyncRequestInfo->dwKey = TASYNC_KEY;
CompletionProc (pAsyncRequestInfo, LINEERR_OPERATIONUNAVAIL);
DereferenceObject(
ghHandleTable,
pAsyncRequestInfo->dwLocalRequestID,
1
);
pAsyncRequestInfo = pNextAsyncRequestInfo;
}
}
//
// Free resources
//
if (ptLineClient->aNumRings)
{
ServerFree (ptLineClient->aNumRings);
}
//
// Decrement reference count by two to remove the initial
// reference & the reference above
//
DereferenceObject (ghHandleTable, hLine, 2);
}
else
{
DereferenceObject (ghHandleTable, hLine, 1);
LOG((TL_ERROR, "DestroytLineClient: WaitForExclLineClientAccess failed!"));
}
}
LONG
PASCAL
DestroytLineApp(
HLINEAPP hLineApp
)
{
PTCLIENT ptClient;
PTLINEAPP ptLineApp;
LOG((TL_TRACE, "DestroytLineApp: enter, hLineApp=x%x", hLineApp));
if (!(ptLineApp = ReferenceObject (ghHandleTable, hLineApp, TLINEAPP_KEY)))
{
return (TapiGlobals.dwNumLineInits ?
LINEERR_INVALAPPHANDLE : LINEERR_UNINITIALIZED);
}
//
// See if this this is a valid tLineApp, & if so grab the lock
// and mark it as bad, then continue teardown. Else, another
// thread is in the processing of tearing down this tLineApp,
// so return.
//
LOCKTLINEAPP (ptLineApp);
if (ptLineApp->dwKey != TLINEAPP_KEY)
{
UNLOCKTLINEAPP (ptLineApp);
DereferenceObject (ghHandleTable, hLineApp, 1);
return (TapiGlobals.dwNumPhoneInits ?
LINEERR_INVALAPPHANDLE : LINEERR_UNINITIALIZED);
}
ptLineApp->dwKey = INVAL_KEY;
ptClient = (PTCLIENT) ptLineApp->ptClient;
//
// Destroy all the tLineClients. Note that we want to grab the
// lock each time we reference the list of tLineClient's, since
// another thread might be destroying a tLineClient too.
//
{
HLINE hLine;
destroy_tLineClients:
hLine = (ptLineApp->ptLineClients ?
ptLineApp->ptLineClients->hLine : (HLINE) 0);
UNLOCKTLINEAPP (ptLineApp);
if (hLine)
{
DestroytLineClient (hLine);
LOCKTLINEAPP (ptLineApp);
goto destroy_tLineClients;
}
}
//
// Remove tLineApp 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.
//
LOCKTCLIENT (ptClient);
if (ptLineApp->pNext)
{
ptLineApp->pNext->pPrev = ptLineApp->pPrev;
}
if (ptLineApp->pPrev)
{
ptLineApp->pPrev->pNext = ptLineApp->pNext;
}
else
{
ptClient->ptLineApps = ptLineApp->pNext;
}
//
// Clean up any existing generic dialog instances if this is the
// last tLineApp on this tClient
//
if (ptClient->pGenericDlgInsts && ptClient->ptLineApps == NULL)
{
PTAPIDIALOGINSTANCE pGenericDlgInst =
ptClient->pGenericDlgInsts,
pNextGenericDlgInst;
TAPI32_MSG params;
while (pGenericDlgInst)
{
pNextGenericDlgInst = pGenericDlgInst->pNext;
params.u.Req_Func = 0;
params.Params[0] = pGenericDlgInst->htDlgInst;
params.Params[1] = LINEERR_OPERATIONFAILED;
FreeDialogInstance(
ptClient,
(PFREEDIALOGINSTANCE_PARAMS) &params,
sizeof (params),
NULL,
NULL
);
pGenericDlgInst = pNextGenericDlgInst;
}
}
UNLOCKTCLIENT (ptClient);
//
// Decrement total num inits & see if we need to go thru shutdown
//
TapiEnterCriticalSection (&TapiGlobals.CritSec);
//assert(TapiGlobals.dwNumLineInits != 0);
TapiGlobals.dwNumLineInits--;
if ((TapiGlobals.dwNumLineInits == 0) &&
(TapiGlobals.dwNumPhoneInits == 0) &&
!(TapiGlobals.dwFlags & TAPIGLOBALS_SERVER))
{
ServerShutdown();
gbServerInited = FALSE;
}
TapiLeaveCriticalSection (&TapiGlobals.CritSec);
//
// Check to see if this tLineApp is a registered request
// recipient, and if so do the appropriate munging
//
{
BOOL bResetHighestPriorityRequestRecipient;
PTREQUESTRECIPIENT pRequestRecipient;
if ((pRequestRecipient = ptLineApp->pRequestRecipient))
{
EnterCriticalSection (&gPriorityListCritSec);
bResetHighestPriorityRequestRecipient =
(TapiGlobals.pHighestPriorityRequestRecipient ==
pRequestRecipient ? TRUE : FALSE);
if (pRequestRecipient->pNext)
{
pRequestRecipient->pNext->pPrev = pRequestRecipient->pPrev;
}
if (pRequestRecipient->pPrev)
{
pRequestRecipient->pPrev->pNext = pRequestRecipient->pNext;
}
else
{
TapiGlobals.pRequestRecipients = pRequestRecipient->pNext;
}
if (bResetHighestPriorityRequestRecipient)
{
TapiGlobals.pHighestPriorityRequestRecipient =
GetHighestPriorityRequestRecipient();
if (TapiGlobals.pRequestMakeCallList)
{
if (TapiGlobals.pHighestPriorityRequestRecipient)
{
NotifyHighestPriorityRequestRecipient();
}
else
{
//
// We couldn't start a request recipient so
// nuke all pending request make calls
//
PTREQUESTMAKECALL pRequestMakeCall,
pNextRequestMakeCall;
pRequestMakeCall =
TapiGlobals.pRequestMakeCallList;
TapiGlobals.pRequestMakeCallList =
TapiGlobals.pRequestMakeCallListEnd = NULL;
while (pRequestMakeCall)
{
pNextRequestMakeCall =
pRequestMakeCall->pNext;
ServerFree (pRequestMakeCall);
pRequestMakeCall = pNextRequestMakeCall;
}
LOG((TL_INFO,
"DestroytLineApp: deleting pending " \
"MakeCall requests"
));
}
}
}
LeaveCriticalSection (&gPriorityListCritSec);
ServerFree (pRequestRecipient);
}
}
//
// Decrement reference count by two to remove the initial
// reference & the reference above
//
DereferenceObject (ghHandleTable, hLineApp, 2);
return 0;
}
BOOL
FillupACountryEntry(
HKEY hKey,
PBYTE pcl,
LPLINECOUNTRYENTRY pce,
PBYTE *ppVarOffset
)
{
PBYTE pVarOffset = *ppVarOffset;
DWORD dwSize;
DWORD dwType;
LONG lTemp;
dwSize = sizeof(pce->dwCountryCode);
lTemp = RegQueryValueEx(
hKey,
TEXT("CountryCode"),
NULL,
&dwType,
(LPBYTE)&(pce->dwCountryCode),
&dwSize
);
//
// If we failed to get the country code, the rest of this work
// is meaningless...
//
if ( ERROR_SUCCESS == lTemp )
{
//
// Read the country name string resource ID
//
dwSize = sizeof(DWORD);
lTemp = RegQueryValueEx(
hKey,
gszNameResW,
NULL,
&dwType,
pVarOffset,
&dwSize
);
if ( ERROR_SUCCESS == lTemp )
{
pce->dwCountryNameOffset = (DWORD) (pVarOffset - pcl);
pce->dwCountryNameSize = dwSize;
pVarOffset += dwSize;
}
dwSize = MAXLEN_RULE * sizeof(WCHAR);
// Here we need to read a wide string because this is our packed structure
// that will eventually get returned to the client and these are WCHAR always.
lTemp = TAPIRegQueryValueExW(
hKey,
gszSameAreaRuleW,
NULL,
&dwType,
pVarOffset,
&dwSize
);
if ( ERROR_SUCCESS == lTemp )
{
pce->dwSameAreaRuleOffset = (DWORD) (pVarOffset - pcl);
pce->dwSameAreaRuleSize = dwSize;
pVarOffset += dwSize;
}
dwSize = MAXLEN_RULE * sizeof(WCHAR);
// Here we need to read a wide string because this is our packed structure
// that will eventually get returned to the client and these are WCHAR always.
lTemp = TAPIRegQueryValueExW(
hKey,
gszLongDistanceRuleW,
NULL,
&dwType,
pVarOffset,
&dwSize
);
if ( ERROR_SUCCESS == lTemp )
{
pce->dwLongDistanceRuleOffset = (DWORD) (pVarOffset - pcl);
pce->dwLongDistanceRuleSize = dwSize;
pVarOffset += dwSize;
}
dwSize = MAXLEN_RULE * sizeof(WCHAR);
// Here we need to read a wide string because this is our packed structure
// that will eventually get returned to the client and these are WCHAR always.
lTemp = TAPIRegQueryValueExW(
hKey,
gszInternationalRuleW,
NULL,
&dwType,
pVarOffset,
&dwSize
);
if ( ERROR_SUCCESS == lTemp )
{
pce->dwInternationalRuleOffset = (DWORD) (pVarOffset - pcl);
pce->dwInternationalRuleSize = dwSize;
pVarOffset += dwSize;
}
*ppVarOffset = pVarOffset;
}
return TRUE;
}
BOOL
BuildCountryRegistryListFromRCW(
void
)
{
HKEY hKey = NULL, hKey2;
DWORD dwDisposition, dwNextCountryID, dw, dwNextCountryGroup, dwCountryGroupID;
TCHAR sz[256];
TCHAR sz1[256];
LONG err;
if (RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
gszRegKeyTelephony,
0,
KEY_READ,
&hKey2
) != ERROR_SUCCESS)
{
goto ExitHere;
}
err = RegCreateKeyEx(
hKey2,
TEXT("Country List"),
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hKey,
&dwDisposition
);
RegCloseKey (hKey2);
if (err != ERROR_SUCCESS)
{
goto ExitHere;
}
dwNextCountryID = 1;
while (dwNextCountryID)
{
if (LoadString(
ghInstance,
RC_COUNTRY_ID_BASE + dwNextCountryID,
sz,
ARRAYSIZE(sz)
) > 0 &&
LoadString(
ghInstance,
RC_COUNTRY_NAME_BASE + dwNextCountryID,
sz1,
ARRAYSIZE(sz1)
) > 0
)
{
TCHAR szCountryKey[20];
PTSTR p;
PTSTR p2;
wsprintf( szCountryKey, TEXT("%ld"), dwNextCountryID );
if (RegCreateKeyEx(
hKey,
szCountryKey,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hKey2,
&dwDisposition
) != ERROR_SUCCESS)
{
goto ExitHere;
}
//
// Set the country name and resource ID in registry
//
RegSetValueEx(
hKey2,
gszNameW,
0,
REG_SZ,
(LPBYTE) sz1,
(DWORD) ( (_tcslen(sz1) + 1) * sizeof(TCHAR) )
);
dw = RC_COUNTRY_NAME_BASE + dwNextCountryID;
RegSetValueEx(
hKey2,
gszNameResW,
0,
REG_DWORD,
(LPBYTE) &dw,
sizeof(DWORD)
);
//RC_COUNTRY_ID_BASE + 1 "1,101,""G"","" 1FG"",""011EFG"""
p = sz;
//
// Get the countryID
//
dw = _ttol (p);
RegSetValueEx(
hKey2,
TEXT("CountryCode"),
0,
REG_DWORD,
(LPBYTE)&dw,
sizeof(DWORD)
);
p = _tcschr( p, TEXT(',') ) + 1;
dwNextCountryID = _ttol( p );
p = _tcschr( p, TEXT('"') ) + 1; // Point to start of rule
p2 = _tcschr( p, TEXT('"') ); // Point to end of rule
*p2 = TEXT('\0');
RegSetValueEx(
hKey2,
gszSameAreaRuleW,
0,
REG_SZ,
(LPBYTE) p,
(DWORD) ((PBYTE) p2 - (PBYTE) p) + sizeof(TCHAR)
);
p = _tcschr( p2 + 1, TEXT('"') ) + 1; // Point to start of rule
p2 = _tcschr( p, TEXT('"') ); // Point to end of rule
*p2 = TEXT('\0');
RegSetValueEx(
hKey2,
gszLongDistanceRuleW,
0,
REG_SZ,
(LPBYTE) p,
(DWORD) ((PBYTE) p2 - (PBYTE) p) + sizeof(TCHAR)
);
p = _tcschr( p2 + 1, TEXT('"') ) + 1; // Point to start of rule
p2 = _tcschr( p, TEXT('"') ); // Point to end of rule
*p2 = TEXT('\0');
RegSetValueEx(
hKey2,
gszInternationalRuleW,
0,
REG_SZ,
(LPBYTE) p,
(DWORD) ((PBYTE) p2 - (PBYTE) p) + sizeof(TCHAR)
);
RegCloseKey(hKey2);
}
else
{
dwNextCountryID = 0;
}
}
//
// Get the Country Groups
//
//RC_COUNTRY_GROUP_BASE + 1 "1,0,""594,590,596,262,33"""
dwNextCountryGroup = 1;
while (dwNextCountryGroup)
{
if (LoadString(
ghInstance,
RC_COUNTRY_GROUP_BASE + dwNextCountryGroup,
sz,
ARRAYSIZE(sz)
) > 0)
{
TCHAR szCountryKey[20];
PTSTR p;
PTSTR p2;
p = sz;
//
// Get the country group ID
//
dwCountryGroupID = _ttol (p);
p = _tcschr( p, TEXT(',') ) + 1;
dwNextCountryGroup = _ttol( p );
p = _tcschr( p, TEXT('"') );
p2 = _tcschr( p+1, TEXT('"') );
*p2 = TEXT('\0');
while( NULL != p && p+1 < p2)
{
wsprintf( szCountryKey, TEXT("%ld"), _ttol (p+1) );
if (RegOpenKeyEx(
hKey,
szCountryKey,
0,
KEY_ALL_ACCESS,
&hKey2
) != ERROR_SUCCESS)
{
goto ExitHere;
}
RegSetValueEx(
hKey2,
gszCountryGroupW,
0,
REG_DWORD,
(LPBYTE)&dwCountryGroupID,
sizeof(DWORD)
);
RegCloseKey(hKey2);
p = _tcschr( p+1, TEXT(',') );
}
}
else
{
dwNextCountryGroup = 0;
}
}
//
// Write the country list version to the registry
//
{
DWORD dwCountryListVersion = TAPI_CURRENT_COUNTRY_LIST_VERSION;
RegSetValueEx(
hKey,
gszCountryListVersionW,
0,
REG_DWORD,
(LPBYTE) &dwCountryListVersion,
(DWORD) sizeof (dwCountryListVersion)
);
}
ExitHere:
if (hKey)
{
RegCloseKey (hKey);
}
return TRUE;
}
BOOL
DeleteAllSubkeys(
HKEY hKey,
DWORD dwRecursionCount
)
{
//
// Build a MULTISZ-style list of all the subkey names,
// then delete them all. This is because NT won't
// let us (do it the easy way and) delete the parent key
// while subkeys still exist. Note also that we're not
// allowed to delete subkeys while enumerating them.
//
HKEY hSubkey;
DWORD i, dwTotalChars = 2048, dwUsedChars = 0;
TCHAR *p, *p2;
//
// If we're nested more than a few levels deep then someone
// is probably doing some malicious registry munging to
// see if we blow up - don't recurse any further.
//
if (dwRecursionCount > 5)
{
return TRUE;
}
//
// Alloc a buffer to store subkey names
//
if (!(p = ServerAlloc (dwTotalChars * sizeof (TCHAR))))
{
return FALSE;
}
//
// Build the list
//
for (i = 0;; i++)
{
DWORD dwNumChars = dwTotalChars - dwUsedChars;
FILETIME fileTime;
//
// See if we need to grow the buffer first
//
if (dwNumChars < 256)
{
dwTotalChars *= 2;
if (!(p2 = LocalAlloc (LPTR, dwTotalChars * sizeof (TCHAR))))
{
ServerFree (p);
return FALSE;
}
CopyMemory (p2, p, dwUsedChars * sizeof (TCHAR));
ServerFree (p);
p = p2;
}
if (RegEnumKeyEx(
hKey,
i,
p + dwUsedChars,
&dwNumChars,
NULL,
NULL,
NULL,
&fileTime
) != ERROR_SUCCESS)
{
p[dwUsedChars] = TEXT('\0'); // the final (double) NULL
break;
}
//
// Append a terminating NULL if there wasn't one
//
if (p[dwUsedChars + dwNumChars - 1] != TEXT('\0'))
{
p[dwUsedChars + dwNumChars] = TEXT('\0');
dwNumChars++;
}
dwUsedChars += dwNumChars;
}
//
// Now nuke all the subkeys in the list (make sure to nuke
// any sub-subkeys first)
//
for (p2 = p; *p2 != TEXT('\0'); p2 += lstrlen (p2) + 1)
{
if (RegOpenKeyEx(
hKey,
p2,
0,
KEY_ALL_ACCESS,
&hSubkey
) == ERROR_SUCCESS)
{
DeleteAllSubkeys (hSubkey, dwRecursionCount + 1);
RegCloseKey (hSubkey);
}
RegDeleteKey (hKey, p2);
}
ServerFree (p);
return TRUE;
}
BOOL
BuildCountryListCache(
void
)
{
//
// The following is our "last resort" country list, i.e. the one we
// use of we get errors trying to build the country list below
//
static LINECOUNTRYLIST defCountryList =
{
sizeof(LINECOUNTRYLIST), // dwTotalSize
sizeof(LINECOUNTRYLIST), // dwNeededSize
sizeof(LINECOUNTRYLIST), // dwUsedSize
0, // dwNumCountries
0, // dwCountryListSize
0 // dwCountryListOffset
};
BOOL bResult = TRUE;
UINT i;
if (!gpCountryList)
{
TCHAR sz[256];
DWORD dwSize;
DWORD dwListSize;
DWORD dwCountryId, dwCountryListVersion, dwType;
PBYTE pTempCountryList;
LPLINECOUNTRYENTRY pce;
LPLINECOUNTRYENTRY pcePrev = NULL;
HKEY hKey;
HKEY hKeyTemp;
UINT uNumCountries;
PBYTE pVarOffset;
#define INITIAL_COUNTRY_COUNT 256
dwListSize = sizeof(LINECOUNTRYLIST) +
INITIAL_COUNTRY_COUNT * (sizeof(LINECOUNTRYENTRY) + 64);
if ( NULL == (pTempCountryList = ServerAlloc(dwListSize)) )
{
bResult = FALSE;
LOG((TL_ERROR, "Mem alloc failed for country list!1 (0x%lx", dwListSize));
goto BuildCountryListCache_return;
}
//
// Make sure the list is more-or-less there first
//
if (RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
gszRegKeyTelephony,
0,
KEY_READ,
&hKey
) != ERROR_SUCCESS)
{
bResult = FALSE;
ServerFree (pTempCountryList);
goto BuildCountryListCache_return;
}
dwCountryListVersion = 0;
if (RegOpenKeyEx(
hKey,
TEXT("Country List"),
0,
KEY_READ,
&hKeyTemp
) == ERROR_SUCCESS)
{
dwSize = sizeof(DWORD);
TAPIRegQueryValueExW(
hKeyTemp,
gszCountryListVersionW,
NULL,
&dwType,
(LPBYTE) &dwCountryListVersion,
&dwSize
);
RegCloseKey (hKeyTemp);
}
//
// If the country list version is < the version in our resource
// file OR
// if a read on the key for country code 1 (these united states)
// fails, we'll assume the country list in the registry is toasted
//
if ((dwCountryListVersion < TAPI_CURRENT_COUNTRY_LIST_VERSION) ||
RegOpenKeyEx(
hKey,
TEXT("Country List\\1"),
0,
KEY_READ,
&hKeyTemp
))
{
//
// Nuke any existing subkeys & (re)create it
//
if (RegOpenKeyEx(
hKey,
TEXT("Country List"),
0,
KEY_ALL_ACCESS,
&hKeyTemp
) == ERROR_SUCCESS)
{
DeleteAllSubkeys (hKeyTemp, 0);
RegCloseKey (hKeyTemp);
}
BuildCountryRegistryListFromRCW();
}
else
{
RegCloseKey( hKeyTemp );
}
RegCloseKey( hKey );
//
// In any case, the list is now good
//
if (RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
gszRegKeyTelephony,
0,
KEY_READ,
&hKeyTemp
) != ERROR_SUCCESS)
{
bResult = FALSE;
ServerFree (pTempCountryList);
goto BuildCountryListCache_return;
}
if (RegOpenKeyEx(
hKeyTemp,
TEXT("Country List"),
0,
KEY_READ,
&hKey
) != ERROR_SUCCESS)
{
RegCloseKey( hKeyTemp );
bResult = FALSE;
ServerFree (pTempCountryList);
goto BuildCountryListCache_return;
}
RegCloseKey( hKeyTemp );
//
// Enum through the country keys and make sure there's enough room
// for all of the LINECOUNTRYENTRYs
//
pce = (LPLINECOUNTRYENTRY)(pTempCountryList +
sizeof(LINECOUNTRYLIST));
//
// Make pretend we already have a previous linecountryentry so we
// don't have to do an 'if' in the loop every time just for the
// special case of the first time. (The correct number gets put
// into the field the second time through the loop.)
//
pcePrev = pce;
dwSize = ARRAYSIZE(sz);
uNumCountries = 0;
while (RegEnumKeyEx(
hKey,
uNumCountries,
sz,
&dwSize,
NULL,
NULL,
NULL,
NULL
) == 0)
{
if ((sizeof(LINECOUNTRYLIST) +
(sizeof(LINECOUNTRYENTRY) * uNumCountries)) > dwListSize)
{
PBYTE p;
UINT uOldSize;
uOldSize = dwListSize;
//
// alloc a new space
//
dwListSize = sizeof(LINECOUNTRYLIST) +
(
(sizeof(LINECOUNTRYENTRY) + 64)
* (uNumCountries + 25)
);
p = ServerAlloc( dwListSize );
if ( NULL == p )
{
bResult = FALSE;
LOG((TL_ERROR, "Mem alloc failed for country list!2 (0x%lx", dwListSize));
ServerFree( pTempCountryList );
RegCloseKey (hKey);
goto BuildCountryListCache_return;
}
CopyMemory(
p,
pTempCountryList,
(LPBYTE)pce - pTempCountryList
);
ServerFree( pTempCountryList );
pTempCountryList = p;
pce = (LPLINECOUNTRYENTRY)((LPBYTE)p + uOldSize);
}
dwCountryId = _ttol( sz );
pce->dwCountryID = dwCountryId;
pcePrev->dwNextCountryID = dwCountryId;
// Prepare for next trip through the loop
pcePrev = pce;
pce++;
uNumCountries++;
dwSize = ARRAYSIZE(sz); // need to set every time :-(
}
// Allocate the country groups global
gpCountryGroups = (LPDWORD) ServerAlloc( uNumCountries * sizeof (DWORD) );
if (gpCountryGroups)
memset(gpCountryGroups, 0, uNumCountries * sizeof (DWORD));
pcePrev->dwNextCountryID = 0;
//
// Now go through and get all of the associated strings
//
pce = (LPLINECOUNTRYENTRY)
(pTempCountryList + sizeof(LINECOUNTRYLIST));
pVarOffset = pTempCountryList +
sizeof(LINECOUNTRYLIST) +
(sizeof(LINECOUNTRYENTRY) * uNumCountries);
i = 0;
while ( i < uNumCountries )
{
HKEY hKey2;
//--> if it can't fix MAX_SPACE, realloc it
if ( ((DWORD)(pVarOffset - pTempCountryList) +
((MAXLEN_NAME +
MAXLEN_RULE +
MAXLEN_RULE +
MAXLEN_RULE +
100) * sizeof(WCHAR))) // mmmm... fudge...
> dwListSize )
{
PBYTE p;
//
// alloc a new space
//
dwListSize += 1024;
p = ServerAlloc( dwListSize );
if ( NULL == p )
{
bResult = FALSE;
LOG((TL_ERROR, "Mem alloc failed for country list!3 (0x%lx", dwListSize));
ServerFree( pTempCountryList );
RegCloseKey (hKey);
goto BuildCountryListCache_return;
}
CopyMemory(
p,
pTempCountryList,
(LPBYTE)pce - pTempCountryList
);
pVarOffset = (LPVOID)(p +
(UINT)( pVarOffset - pTempCountryList));
ServerFree( pTempCountryList );
pTempCountryList = p;
pce = (LPLINECOUNTRYENTRY)
(pTempCountryList + sizeof(LINECOUNTRYLIST) +
( sizeof(LINECOUNTRYENTRY) * i ));
}
wsprintf( sz, TEXT("%ld"), pce->dwCountryID);
if (RegOpenKeyEx (hKey, sz, 0, KEY_READ, &hKey2) == ERROR_SUCCESS)
{
FillupACountryEntry(
hKey2,
pTempCountryList,
pce,
&pVarOffset
);
// fill the country group
if (gpCountryGroups)
{
DWORD dwType;
DWORD dwSize = sizeof (DWORD);
if (ERROR_SUCCESS != RegQueryValueEx(
hKey2,
gszCountryGroupW,
NULL,
&dwType,
(LPBYTE)(gpCountryGroups + i),
&dwSize
) ||
dwType != REG_DWORD
)
{
gpCountryGroups[ i ] = 0;
}
}
RegCloseKey (hKey2);
}
pce++;
i++;
}
RegCloseKey( hKey );
((LPLINECOUNTRYLIST)pTempCountryList)->dwTotalSize =
(DWORD)(pVarOffset - pTempCountryList);
((LPLINECOUNTRYLIST)pTempCountryList)->dwNeededSize =
(DWORD)(pVarOffset - pTempCountryList);
((LPLINECOUNTRYLIST)pTempCountryList)->dwUsedSize =
(DWORD)(pVarOffset - pTempCountryList);
((LPLINECOUNTRYLIST)pTempCountryList)->dwNumCountries = uNumCountries;
((LPLINECOUNTRYLIST)pTempCountryList)->dwCountryListSize =
uNumCountries * sizeof(LINECOUNTRYENTRY);
((LPLINECOUNTRYLIST)pTempCountryList)->dwCountryListOffset =
sizeof(LINECOUNTRYLIST);
gpCountryList = (LPLINECOUNTRYLIST)pTempCountryList;
}
BuildCountryListCache_return:
if (bResult == FALSE)
{
gpCountryList = &defCountryList;
ServerFree( gpCountryGroups );
gpCountryGroups = NULL;
}
return bResult;
}
LPLINECOUNTRYLIST
BuildCountryList(
void
)
{
LPLINECOUNTRYENTRY pCtryEntry, pCtryEntryGlobal;
LPLINECOUNTRYLIST pCtryList;
DWORD dwListSize;
DWORD dwIdx;
DWORD dwResourceId;
DWORD dwNameSize;
DWORD dwNeededSize;
DWORD dwTotalSize;
LPBYTE pVarOffset;
BOOL bResult = TRUE;
WCHAR sz[MAXLEN_NAME];
if (!gpCountryList)
{
return NULL;
}
//
// Allocate memory, make room for country names
//
dwTotalSize = gpCountryList->dwUsedSize +
gpCountryList->dwNumCountries *
( MAXLEN_NAME * sizeof(WCHAR) - sizeof(DWORD) );
pCtryList = ServerAlloc (dwTotalSize);
if (!pCtryList)
{
return NULL;
}
//
// Fill the buffer
//
pCtryEntry = (LPLINECOUNTRYENTRY)((LPBYTE) pCtryList + sizeof(LINECOUNTRYLIST));
pCtryEntryGlobal = (LPLINECOUNTRYENTRY)((LPBYTE) gpCountryList + sizeof(LINECOUNTRYLIST));
pVarOffset = (LPBYTE)pCtryList + sizeof(LINECOUNTRYLIST) +
sizeof(LINECOUNTRYENTRY) * gpCountryList->dwNumCountries;
dwNeededSize = sizeof(LINECOUNTRYLIST) +
sizeof(LINECOUNTRYENTRY) * gpCountryList->dwNumCountries;
for( dwIdx = 0; dwIdx < gpCountryList->dwNumCountries;
dwIdx++, pCtryEntry++, pCtryEntryGlobal++ )
{
pCtryEntry->dwCountryCode = pCtryEntryGlobal->dwCountryCode;
pCtryEntry->dwCountryID = pCtryEntryGlobal->dwCountryID;
pCtryEntry->dwNextCountryID = pCtryEntryGlobal->dwNextCountryID;
//
// The name field has the resource string ID
// Need to load the actual string
//
CopyMemory(
&dwResourceId,
(LPBYTE)gpCountryList + pCtryEntryGlobal->dwCountryNameOffset,
sizeof(DWORD)
);
if (0 == LoadStringW(
ghInstance,
dwResourceId,
sz,
ARRAYSIZE(sz)
)
)
{
bResult = FALSE;
break;
}
dwNameSize = (wcslen(sz) + 1) * sizeof(WCHAR);
CopyMemory(
pVarOffset,
(LPBYTE)sz,
dwNameSize
);
pCtryEntry->dwCountryNameSize = dwNameSize;
pCtryEntry->dwCountryNameOffset = (DWORD)(pVarOffset - (LPBYTE)pCtryList);
pVarOffset += dwNameSize;
dwNeededSize += dwNameSize;
CopyMemory(
pVarOffset,
(LPBYTE)gpCountryList + pCtryEntryGlobal->dwSameAreaRuleOffset,
pCtryEntryGlobal->dwSameAreaRuleSize
);
pCtryEntry->dwSameAreaRuleSize = pCtryEntryGlobal->dwSameAreaRuleSize;
pCtryEntry->dwSameAreaRuleOffset = (DWORD)(pVarOffset - (LPBYTE)pCtryList);
pVarOffset += pCtryEntryGlobal->dwSameAreaRuleSize;
dwNeededSize += pCtryEntryGlobal->dwSameAreaRuleSize;
CopyMemory(
pVarOffset,
(LPBYTE)gpCountryList + pCtryEntryGlobal->dwLongDistanceRuleOffset,
pCtryEntryGlobal->dwLongDistanceRuleSize
);
pCtryEntry->dwLongDistanceRuleSize = pCtryEntryGlobal->dwLongDistanceRuleSize;
pCtryEntry->dwLongDistanceRuleOffset = (DWORD)(pVarOffset - (LPBYTE)pCtryList);
pVarOffset += pCtryEntryGlobal->dwLongDistanceRuleSize;
dwNeededSize += pCtryEntryGlobal->dwLongDistanceRuleSize;
CopyMemory(
pVarOffset,
(LPBYTE)gpCountryList + pCtryEntryGlobal->dwInternationalRuleOffset,
pCtryEntryGlobal->dwInternationalRuleSize
);
pCtryEntry->dwInternationalRuleSize = pCtryEntryGlobal->dwInternationalRuleSize;
pCtryEntry->dwInternationalRuleOffset = (DWORD)(pVarOffset - (LPBYTE)pCtryList);
pVarOffset += pCtryEntryGlobal->dwInternationalRuleSize;
dwNeededSize += pCtryEntryGlobal->dwInternationalRuleSize;
}
if (!bResult)
{
ServerFree(pCtryList);
pCtryList = NULL;
}
else
{
pCtryList->dwNeededSize = dwNeededSize;
pCtryList->dwTotalSize = dwTotalSize;
pCtryList->dwUsedSize = dwNeededSize;
pCtryList->dwNumCountries = gpCountryList->dwNumCountries;
pCtryList->dwCountryListSize = sizeof(LINECOUNTRYENTRY) * gpCountryList->dwNumCountries;
pCtryList->dwCountryListOffset = sizeof(LINECOUNTRYLIST);
}
return pCtryList;
}
PTLINECLIENT
PASCAL
xxxGetHighestPriorityLineClient(
TPOINTERLIST *pLineClientList,
DWORD dwMediaModes,
DWORD dwAddressID,
WCHAR *pszPriorityList
)
{
BOOL bFoundOwnerInPriorityList = FALSE;
DWORD i;
WCHAR *pszAppInPriorityList = NULL;
WCHAR *pszAppInPriorityListPrev = (WCHAR *) LongToPtr(0xffffffff);
PTLINECLIENT ptHiPriLineClient = (PTLINECLIENT) NULL;
for (i = 0; i < pLineClientList->dwNumUsedEntries; i++)
{
PTLINECLIENT ptLineClient = (PTLINECLIENT)
pLineClientList->aEntries[i];
try
{
if (ptLineClient->dwPrivileges & LINECALLPRIVILEGE_OWNER)
{
BOOL bMatch;
bMatch = ((ptLineClient->dwMediaModes & dwMediaModes)
== dwMediaModes);
if ( bMatch &&
// most common case, line opened for all addrs
((ptLineClient->dwAddressID == 0xffffffff) ||
// line opened for single addr, check if match
(ptLineClient->dwAddressID == dwAddressID) ||
// called from lineHandoff, addr ID irrelevent
(dwAddressID == 0xffffffff)))
{
if (pszPriorityList &&
(pszAppInPriorityList = wcsstr(
pszPriorityList,
ptLineClient->ptLineApp->pszModuleName
)))
{
//
// See if this app has higher pri
// than the previous app we found,
// and if so save the info
//
if (pszAppInPriorityList <= pszAppInPriorityListPrev)
{
ptHiPriLineClient = ptLineClient;
pszAppInPriorityListPrev =
pszAppInPriorityList;
bFoundOwnerInPriorityList = TRUE;
}
}
else if (!bFoundOwnerInPriorityList)
{
ptHiPriLineClient = ptLineClient;
}
}
}
}
myexcept
{
// just continue
}
}
return ptHiPriLineClient;
}
WCHAR *
GetPriorityListForMediaModes(
DWORD dwMediaModes
)
{
DWORD dwCount;
WCHAR *pszPriorityList = NULL;
if (TapiGlobals.dwUsedPriorityLists != 0)
{
//
// Safely get a copy of the priority list (if any)
// for this media mode
//
EnterCriticalSection (&gPriorityListCritSec);
for(
dwCount = 0;
dwCount < TapiGlobals.dwUsedPriorityLists;
dwCount++
)
{
PRILISTSTRUCT PriList = TapiGlobals.pPriLists[dwCount];
if ((dwMediaModes & PriList.dwMediaModes) == dwMediaModes)
{
if (PriList.pszPriList)
{
if ((pszPriorityList = ServerAlloc( sizeof(WCHAR) *
(1 + lstrlenW(PriList.pszPriList))
)))
{
wcscpy (pszPriorityList, PriList.pszPriList);
}
}
break;
}
}
LeaveCriticalSection (&gPriorityListCritSec);
}
return pszPriorityList;
}
PTLINECLIENT
PASCAL
GetHighestPriorityLineClient(
PTLINE ptLine,
DWORD dwMediaModes,
DWORD dwAddressID
)
{
WCHAR *pszPriorityList = NULL;
TPOINTERLIST lineClientList, *pLineClientList = &lineClientList;
PTLINECLIENT ptHiPriLineClient = (PTLINECLIENT) NULL;
DWORD dwCount = 0, dwMask;
if (GetLineClientListFromLine (ptLine, &pLineClientList) != 0)
{
return NULL;
}
//
// If >1 media mode is specifed without the UNKNOWN bit being set
// then we first want to see if there's any exact matches available,
// that is, if there's an app which has opened the line with OWNER
// privileges for all the specfied media modes. If so, then we'll
// give privilege to that app immediately, rather than walking
// through the media mode bits one-by-one as done below (the original
// TAPI 1.x priority determination scheme).
//
if (!IsOnlyOneBitSetInDWORD (dwMediaModes) &&
!(dwMediaModes & LINEMEDIAMODE_UNKNOWN))
{
pszPriorityList = GetPriorityListForMediaModes (dwMediaModes);
ptHiPriLineClient = xxxGetHighestPriorityLineClient(
pLineClientList,
dwMediaModes,
dwAddressID,
pszPriorityList
);
if (pszPriorityList)
{
ServerFree (pszPriorityList);
}
}
//
// Step thru the list of line clients (youngest client at head
// of list, oldest at tail) and look for the oldest & highest
// priority owner. Position in pri list takes precedence
// over "age" of line client.
//
// To be considered for ownership a line client must have owner
// privileges and be registered for (one of) the call's media
// mode(s). In addition, if the line client was opened with
// the SINGLEADDRESS option and the calling function specified
// a valid address ID (not 0xffffffff), the line client's single
// address ID must match that which was passed in.
//
dwMask = LINEMEDIAMODE_UNKNOWN; // 0x00000002, smallest valid bit
while (!ptHiPriLineClient && dwMediaModes)
{
if (dwMask & dwMediaModes)
{
pszPriorityList = GetPriorityListForMediaModes (dwMask);
ptHiPriLineClient = xxxGetHighestPriorityLineClient(
pLineClientList,
dwMask,
dwAddressID,
pszPriorityList
);
if (pszPriorityList)
{
ServerFree (pszPriorityList);
}
}
dwMediaModes &= ~dwMask;
dwMask <<= 1;
}
//
// Free line client list iff appropriate
//
if (pLineClientList != &lineClientList)
{
ServerFree (pLineClientList);
}
return ptHiPriLineClient;
}
LONG
PASCAL
LineProlog(
PTCLIENT ptClient,
DWORD dwArgType,
DWORD dwArg,
LPVOID phdXxx,
DWORD dwPrivilege, // can be privilege or device id
HANDLE *phMutex,
BOOL *pbDupedMutex,
DWORD dwTSPIFuncIndex,
TSPIPROC *ppfnTSPI_lineXxx,
PASYNCREQUESTINFO *ppAsyncRequestInfo,
DWORD dwRemoteRequestID,
DWORD *pObjectToDereference,
LPVOID *pContext
#if DBG
,char *pszFuncName
#endif
)
{
LONG lResult = 0;
DWORD initContext;
DWORD openContext;
ULONG_PTR htXxx;
PTPROVIDER ptProvider;
#if DBG
LOG((TL_TRACE, "LineProlog: (line%s) enter", pszFuncName));
#else
LOG((TL_TRACE, "LineProlog: -- enter"));
#endif
LOG((TL_INFO, "LineProlog: dwArg %lx", dwArg));
if (phMutex)
{
*phMutex = NULL;
*pbDupedMutex = FALSE;
}
*pObjectToDereference = 0;
if (ppAsyncRequestInfo)
{
*ppAsyncRequestInfo = (PASYNCREQUESTINFO) NULL;
}
if (TapiGlobals.dwNumLineInits == 0)
{
lResult = LINEERR_UNINITIALIZED;
goto LineProlog_exit;
}
if (ptClient->phContext == (HANDLE) -1)
{
lResult = LINEERR_REINIT;
goto LineProlog_exit;
}
switch (dwArgType)
{
case ANY_RT_HCALL:
{
PTCALLCLIENT ptCallClient;
LOG((TL_INFO, "LineProlog: ANY_RT_HCALL "));
if ((ptCallClient = ReferenceObject(
ghHandleTable,
dwArg,
TCALLCLIENT_KEY
)))
{
LOG((TL_INFO, "LineProlog: ReferenceObject returned ptCallClient %p", ptCallClient));
if (ptCallClient->ptClient != ptClient)
{
lResult = LINEERR_INVALCALLHANDLE;
}
else if (ptCallClient->dwPrivilege < dwPrivilege)
{
lResult = LINEERR_NOTOWNER;
}
else
{
*pObjectToDereference = dwArg;
*pContext = ptCallClient;
try
{
ptProvider = ptCallClient->ptCall->ptProvider;
*((HDRVCALL *) phdXxx) = ptCallClient->ptCall->hdCall;
if (ppAsyncRequestInfo)
{
PTLINECLIENT ptLineClient =
ptCallClient->ptLineClient;
initContext = ptLineClient->ptLineApp->InitContext;
openContext = ptLineClient->OpenContext;
htXxx = (ULONG_PTR)ptLineClient->ptLine->hLine;
}
}
myexcept
{
LOG((TL_ERROR, "LineProlog: exception"));
lResult = LINEERR_INVALCALLHANDLE;
}
if (lResult || ptCallClient->dwKey != TCALLCLIENT_KEY)
{
lResult = LINEERR_INVALCALLHANDLE;
}
else if (phMutex &&
(ptProvider->dwTSPIOptions &
LINETSPIOPTION_NONREENTRANT))
{
if (!WaitForMutex(
ptProvider->hMutex,
phMutex,
pbDupedMutex,
ptProvider,
TPROVIDER_KEY,
INFINITE
))
{
lResult = LINEERR_OPERATIONFAILED;
}
}
}
}
else
{
lResult = LINEERR_INVALCALLHANDLE;
}
break;
}
case ANY_RT_HLINE:
{
PTLINECLIENT ptLineClient;
LOG((TL_INFO, "LineProlog: ANY_RT_HLINE"));
if ((ptLineClient = ReferenceObject(
ghHandleTable,
dwArg,
TLINECLIENT_KEY
)))
{
LOG((TL_INFO, "LineProlog: ReferenceObject returned ptLineClient %p", ptLineClient));
if (ptLineClient->ptClient != ptClient)
{
lResult = LINEERR_INVALLINEHANDLE;
}
else
{
*pObjectToDereference = dwArg;
*pContext = ptLineClient;
try
{
ptProvider = ptLineClient->ptLine->ptProvider;
*((HDRVLINE *) phdXxx) = ptLineClient->ptLine->hdLine;
if (ppAsyncRequestInfo)
{
initContext = ptLineClient->ptLineApp->InitContext;
openContext = ptLineClient->OpenContext;
htXxx = (ULONG_PTR)ptLineClient->ptLine->hLine;
}
}
myexcept
{
LOG((TL_ERROR, "LineProlog: exception"));
lResult = LINEERR_INVALLINEHANDLE;
}
if (lResult || ptLineClient->dwKey != TLINECLIENT_KEY)
{
lResult = LINEERR_INVALLINEHANDLE;
}
else if (phMutex &&
(ptProvider->dwTSPIOptions &
LINETSPIOPTION_NONREENTRANT))
{
if (!WaitForMutex(
ptProvider->hMutex,
phMutex,
pbDupedMutex,
ptProvider,
TPROVIDER_KEY,
INFINITE
))
{
LOG((TL_ERROR, "LineProlog: waitformutex failed"));
lResult = LINEERR_OPERATIONFAILED;
}
}
}
}
else
{
LOG((TL_ERROR, "LineProlog: ReferenceObject returned NULL"));
lResult = LINEERR_INVALLINEHANDLE;
}
break;
}
case DEVICE_ID:
{
PTLINEAPP ptLineApp = NULL;
PTLINELOOKUPENTRY pLineLookupEntry;
#if TELE_SERVER
//
// If it's a server, map the device id
//
if ((TapiGlobals.dwFlags & TAPIGLOBALS_SERVER) &&
!IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR))
{
try
{
if ((dwPrivilege >= ptClient->dwLineDevices) ||
(ptClient->pLineDevices[dwPrivilege] == 0xffffffff))
{
lResult = LINEERR_BADDEVICEID;
goto LineProlog_exit;
}
*((LPDWORD) phdXxx) = ptClient->pLineDevices[dwPrivilege];
}
myexcept
{
lResult = LINEERR_INVALLINEHANDLE;
goto LineProlog_exit;
}
}
else
#endif
{
*((LPDWORD)phdXxx) = dwPrivilege;
}
if (dwArg &&
!(ptLineApp = IsValidLineApp ((HLINEAPP) dwArg, ptClient)))
{
lResult = LINEERR_INVALAPPHANDLE;
}
if (ppAsyncRequestInfo)
{
try
{
initContext = ptLineApp->InitContext;
openContext = 0;
if (ptLineApp->dwKey != TLINEAPP_KEY)
{
lResult = LINEERR_INVALAPPHANDLE;
}
}
myexcept
{
lResult = LINEERR_INVALAPPHANDLE;
}
}
if (lResult != 0)
{
// do nothing
}
else if (!(pLineLookupEntry = GetLineLookupEntry (*(LPDWORD)phdXxx)))
{
lResult = LINEERR_BADDEVICEID;
}
else if (pLineLookupEntry->bRemoved)
{
lResult = LINEERR_NODEVICE;
}
else if (!(ptProvider = pLineLookupEntry->ptProvider))
{
lResult = LINEERR_NODRIVER;
}
else
{
*pContext = pLineLookupEntry;
if (phMutex &&
(ptProvider->dwTSPIOptions &
LINETSPIOPTION_NONREENTRANT))
{
if (!WaitForMutex(
ptProvider->hMutex,
phMutex,
pbDupedMutex,
ptProvider,
TPROVIDER_KEY,
INFINITE
))
{
lResult = LINEERR_OPERATIONFAILED;
}
}
}
break;
}
} // switch
if (lResult)
{
goto LineProlog_exit;
}
//
// Make sure that if caller wants a pointer to a TSPI proc that the
// func is exported by the provider
//
if (ppfnTSPI_lineXxx &&
!(*ppfnTSPI_lineXxx = ptProvider->apfn[dwTSPIFuncIndex]))
{
lResult = LINEERR_OPERATIONUNAVAIL;
goto LineProlog_exit;
}
//
// See if we need to alloc & init an ASYNCREQUESTINFO struct
//
if (ppAsyncRequestInfo)
{
PASYNCREQUESTINFO pAsyncRequestInfo;
if (!(pAsyncRequestInfo = ServerAlloc (sizeof(ASYNCREQUESTINFO))))
{
lResult = LINEERR_NOMEM;
goto LineProlog_exit;
}
pAsyncRequestInfo->dwLocalRequestID = (DWORD) NewObject(
ghHandleTable,
pAsyncRequestInfo,
NULL
);
if (pAsyncRequestInfo->dwLocalRequestID == 0)
{
ServerFree (pAsyncRequestInfo);
lResult = LINEERR_NOMEM;
goto LineProlog_exit;
}
pAsyncRequestInfo->dwKey = TASYNC_KEY;
pAsyncRequestInfo->ptClient = ptClient;
pAsyncRequestInfo->InitContext = initContext;
pAsyncRequestInfo->OpenContext = openContext;
pAsyncRequestInfo->htXxx = (dwArgType != DEVICE_ID ? htXxx :
pAsyncRequestInfo->dwLocalRequestID); // a +/- random #
LOG((TL_INFO, "LineProlog: OpenContext %p", openContext));
pAsyncRequestInfo->dwLineFlags = 1;
if (dwRemoteRequestID)
{
lResult = pAsyncRequestInfo->dwRemoteRequestID = dwRemoteRequestID;
}
else
{
lResult = pAsyncRequestInfo->dwRemoteRequestID =
pAsyncRequestInfo->dwLocalRequestID;
}
*ppAsyncRequestInfo = pAsyncRequestInfo;
}
LineProlog_exit:
#if DBG
{
char szResult[32];
LOG((TL_TRACE,
"LineProlog: (line%s) exit, result=%s",
pszFuncName,
MapResultCodeToText (lResult, szResult)
));
}
#else
LOG((TL_TRACE,
"LienProlog: exit, result = x%lx",
lResult
));
#endif
return lResult;
}
void
PASCAL
LineEpilogSync(
LONG *plResult,
HANDLE hMutex,
BOOL bCloseMutex,
DWORD ObjectToDereference
#if DBG
,char *pszFuncName
#endif
)
{
DereferenceObject (ghHandleTable, ObjectToDereference, 1);
if (hMutex)
{
MyReleaseMutex (hMutex, bCloseMutex);
}
#if DBG
{
char szResult[32];
LOG((TL_TRACE,
"LineEpilogSync: (line%s) exit, result=%s",
pszFuncName,
MapResultCodeToText (*plResult, szResult)
));
}
#else
LOG((TL_TRACE,
"LineEpilogSync: exit, result=x%x",
*plResult
));
#endif
}
void
PASCAL
LineEpilogAsync(
LONG *plResult,
LONG lRequestID,
HANDLE hMutex,
BOOL bCloseMutex,
PASYNCREQUESTINFO pAsyncRequestInfo,
DWORD ObjectToDereference
#if DBG
,char *pszFuncName
#endif
)
{
DereferenceObject (ghHandleTable, ObjectToDereference, 1);
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,
"LineEpilogAsync: (line%s) exit, result=%s",
pszFuncName,
MapResultCodeToText (lRequestID, szResult)
));
}
#else
LOG((TL_TRACE,
"LineEpilogAsyc: exit, result=x%lx",
lRequestID
));
#endif
}
void
PASCAL
LineEventProc(
HTAPILINE htLine,
HTAPICALL htCall,
DWORD dwMsg,
ULONG_PTR Param1,
ULONG_PTR Param2,
ULONG_PTR Param3
)
{
LOG((TL_TRACE, "LineEventProc"));
switch (dwMsg)
{
case LINE_ADDRESSSTATE:
case LINE_LINEDEVSTATE:
case LINE_DEVSPECIFIC:
case LINE_DEVSPECIFICFEATURE:
case LINE_PROXYSTATUS:
case LINE_AGENTSTATUS:
{
PTLINE ptLine;
if (!(ptLine = ReferenceObject(ghHandleTable, (HLINE)(ULONG_PTR)htLine, TLINE_KEY)))
{
return;
}
if (dwMsg == LINE_LINEDEVSTATE &&
htLine == 0 &&
Param1 & LINEDEVSTATE_REINIT)
{
SendReinitMsgToAllXxxApps();
}
else
{
SendMsgToLineClients(
ptLine,
NULL,
dwMsg,
DWORD_CAST(Param1,__FILE__,__LINE__),
DWORD_CAST(Param2,__FILE__,__LINE__),
DWORD_CAST(Param3,__FILE__,__LINE__)
);
}
DereferenceObject(ghHandleTable, (HLINE)(ULONG_PTR)htLine, 1);
break;
}
case LINE_AGENTSPECIFIC:
if (htCall)
{
PTCALL ptCall;
if (ptCall = ReferenceObject(ghHandleTable, (HCALL)(ULONG_PTR)htCall, TCALL_KEY))
{
SendMsgToCallClients(
ptCall,
NULL,
LINE_AGENTSPECIFIC,
DWORD_CAST(Param1,__FILE__,__LINE__),
DWORD_CAST(Param2,__FILE__,__LINE__),
DWORD_CAST(Param3,__FILE__,__LINE__)
);
DereferenceObject(ghHandleTable, (HCALL)(ULONG_PTR)htCall, 1);
}
}
else
{
PTLINE ptLine;
if(ptLine = ReferenceObject(ghHandleTable, (HLINE)(ULONG_PTR)htLine, TLINE_KEY))
{
SendMsgToLineClients(
ptLine,
NULL,
LINE_AGENTSPECIFIC,
DWORD_CAST(Param1,__FILE__,__LINE__),
DWORD_CAST(Param2,__FILE__,__LINE__),
DWORD_CAST(Param3,__FILE__,__LINE__)
);
DereferenceObject(ghHandleTable, (HLINE)(ULONG_PTR)htLine, 1);
}
}
break;
case LINE_CLOSE:
{
PTLINE ptLine;
if (!(ptLine = ReferenceObject(ghHandleTable, (HLINE)(ULONG_PTR)htLine, TLINE_KEY)))
{
break;
}
if (ptLine->dwKey == TINCOMPLETELINE_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)
//
LineEventProcSP (htLine, 0, LINE_CLOSE, 0, 0, 0xdeadbeef);
}
else if (ptLine->dwKey == TLINE_KEY)
{
DestroytLine (ptLine, TRUE); // unconditional destroy
}
DereferenceObject(ghHandleTable, (HLINE)(ULONG_PTR)htLine, 1);
break;
}
case LINE_CALLDEVSPECIFIC:
case LINE_CALLDEVSPECIFICFEATURE:
case LINE_CALLINFO:
{
PTCALL ptCall;
if (ptCall = ReferenceObject(ghHandleTable, (HCALL)(ULONG_PTR)htCall, TCALL_KEY))
{
switch (dwMsg)
{
case LINE_CALLDEVSPECIFIC:
dwMsg = LINE_DEVSPECIFIC;
break;
case LINE_CALLDEVSPECIFICFEATURE:
dwMsg = LINE_DEVSPECIFICFEATURE;
break;
case LINE_CALLINFO:
{
Param2 =
Param3 = 0;
if ((Param1 == LINECALLINFOSTATE_CALLID) ||
(Param1 == LINECALLINFOSTATE_RELATEDCALLID))
{
if ((WaitForExclusivetCallAccess (ptCall, TCALL_KEY)))
{
DWORD dwPreviousCallID = ptCall->dwCallID;
GetCallIDs (ptCall);
DoCallHubHashing (ptCall, dwPreviousCallID);
UNLOCKTCALL(ptCall);
}
}
break;
}
}
SendMsgToCallClients(
ptCall,
NULL,
dwMsg,
DWORD_CAST(Param1,__FILE__,__LINE__),
DWORD_CAST(Param2,__FILE__,__LINE__),
DWORD_CAST(Param3,__FILE__,__LINE__)
);
DereferenceObject(ghHandleTable, (HCALL)(ULONG_PTR)htCall, 1);
}
break;
}
case LINE_MONITORDIGITS:
case LINE_MONITORMEDIA:
{
PTCALL ptCall;
if (NULL == htCall)
{
return;
}
if (ptCall = ReferenceObject(ghHandleTable, (HCALL)(ULONG_PTR)htCall, TCALL_KEY))
{
SendMsgToCallClients(
ptCall,
NULL,
dwMsg,
DWORD_CAST(Param1,__FILE__,__LINE__),
DWORD_CAST(Param2,__FILE__,__LINE__),
(Param3 ? DWORD_CAST(Param3,__FILE__,__LINE__) : GetTickCount())
);
DereferenceObject(ghHandleTable, (HCALL)(ULONG_PTR)htCall, 1);
}
break;
}
case LINE_CALLSTATE:
{
BOOL fastPrivilegeList[DEF_NUM_PTR_LIST_ENTRIES],
*pPrivilegeList = fastPrivilegeList;
DWORD i, j, dwNumUsedEntries = 0,
dwNumTotalEntries= DEF_NUM_PTR_LIST_ENTRIES;
PTCALL ptCall;
TPOINTERLIST fastCallClientList,
*pCallClientList = &fastCallClientList;
TPOINTERLIST fastConfCallClientList,
*pConfCallClientList = NULL;
LOG((TL_EVENT, "LineEventProc: LINE_CALLSTATE event x%lx", Param1));
if(!(ptCall = ReferenceObject(ghHandleTable, (HCALL)(ULONG_PTR)htCall, TCALL_KEY)))
{
break;
}
if (WaitForExclusivetCallAccess (ptCall, TCALL_KEY))
{
PTCALLCLIENT ptCallClient = ptCall->ptCallClients;
ASYNCEVENTMSG msg[2];
if (Param1 == LINECALLSTATE_OFFERING)
{
ptCall->dwDrvCallFlags |= DCF_INCOMINGCALL;
PerfBlock.dwCurrentIncomingCalls++;
PerfBlock.dwTotalIncomingCalls++;
PerfBlock.dwCurrentOutgoingCalls--;
PerfBlock.dwTotalOutgoingCalls--;
}
if (ptCall->bAlertApps)
{
//
// This is the first state msg we've received for an incoming
// call. We need to determine who owns & who monitors it,
// and create the appropriate tCallClients
//
BOOL bFindOwner;
DWORD dwMediaModes = (DWORD) Param3,
dwSPIVersion = ptCall->ptLine->dwSPIVersion,
dwAddressID;
PTLINECLIENT ptLineClientOwner;
ptCall->bAlertApps = FALSE;
//
// If this is a remotesp call then Param2 points at a
// DWORD array, the 1st entry of which is the "real"
// Param2 for this message (i.e. the call state mode),
// the 2nd entry of which is the original privilege for
// this call, and the 3rd entry of which is htCall
// (which we use for call verification purposes)
//
if (ptCall->ptProvider != pRemoteSP)
{
bFindOwner = TRUE;
}
else
{
BOOL bBreak = FALSE;
PULONG_PTR pdwRealParam2 = (PULONG_PTR) Param2,
pdwPrivilege = (((PULONG_PTR) Param2) + 1);
LPHTAPICALL phtCall = (LPHTAPICALL)
(((LPDWORD) Param2) + 2);
try
{
Param2 = *pdwRealParam2;
bFindOwner = (*pdwPrivilege & LINECALLPRIVILEGE_OWNER ?
TRUE : FALSE);
bBreak = (*phtCall != htCall ? TRUE : FALSE);
}
myexcept
{
bBreak = TRUE;
}
if (bBreak)
{
UNLOCKTCALL(ptCall);
goto LINE_CALLSTATE_break;
}
}
//
// Retrieve call's address id, etc
//
GetCallIDs (ptCall);
dwAddressID = ptCall->dwAddressID;
UNLOCKTCALL(ptCall);
//
// Add the UNKNOWN bit if >1 bit set
// if version is <= 2.1
if ( ( (dwSPIVersion <= TAPI_VERSION2_1) &&
!IsOnlyOneBitSetInDWORD (dwMediaModes) ) ||
dwMediaModes == 0)
{
dwMediaModes |= LINEMEDIAMODE_UNKNOWN;
}
//
// Try to find an owner. If no owner found then destroy
// the tCall.
//
if (bFindOwner)
{
PTLINE ptLine;
ptLine = ReferenceObject(ghHandleTable, (HLINE)(ULONG_PTR)htLine, TLINE_KEY);
if (!ptLine)
{
//
// Line closed
//
DestroytCall (ptCall);
goto LINE_CALLSTATE_break;
}
LINE_CALLSTATE_findOwner:
if ((ptLineClientOwner = GetHighestPriorityLineClient(
ptLine,
dwMediaModes,
dwAddressID
)))
{
LONG lResult;
PTCALLCLIENT ptCallClientOwner;
if ((lResult = CreatetCallClient(
ptCall,
ptLineClientOwner,
LINECALLPRIVILEGE_OWNER,
TRUE,
FALSE,
&ptCallClientOwner,
TRUE
)) != 0)
{
if (lResult == LINEERR_INVALLINEHANDLE)
{
//
// The tLineClient was just closed, so jump
// up top & try to find another owner
//
goto LINE_CALLSTATE_findOwner;
}
else
{
//
// No mem, line closed, etc
//
DestroytCall (ptCall);
DereferenceObject(ghHandleTable, (HLINE)(ULONG_PTR)htLine, 1);
goto LINE_CALLSTATE_break;
}
}
}
DereferenceObject(ghHandleTable, (HLINE)(ULONG_PTR)htLine, 1);
}
else if (Param1 == LINECALLSTATE_UNKNOWN &&
Param2 == 0xa5a5a5a5)
{
//
// If here we're being called directly from
// remotesp!TSPI_lineGetID, who's being called
// by LGetNewCalls. We're not going to look
// for an owner of this call, but if we don't
// find any monitors we still don't want to
// tear the call down, because we want to give
// a handle to the app doing the lineGetNewCalls
// (which may not have MONITOR privileges).
//
// So we do the following to prevent the call
// from getting destroyed.
//
ptLineClientOwner = (PTLINECLIENT) 1;
Param2 = 0;
}
else
{
//
// Set ptLineClientOwner == NULL, becaue if there
// aren't any monitors we'll want to destroy this
// calls.
//
ptLineClientOwner = (PTLINECLIENT) NULL;
}
if (CreateCallMonitors (ptCall, TRUE) <= 0 &&
!ptLineClientOwner)
{
DestroytCall (ptCall);
goto LINE_CALLSTATE_break;
}
if (!WaitForExclusivetCallAccess (ptCall, TCALL_KEY))
{
goto LINE_CALLSTATE_break;
}
}
//
// NOTE: per bug #20545 we're no longer auto-dropping
// non-IDLE calls; figured this would be the wrong
// thing to do in a distributed system
//
// dankn 02/15/96
//
//
// SP-initiated conference
//
if (Param1 == LINECALLSTATE_CONFERENCED)
{
PTCALL ptConfCall;
if (!ptCall->pConfList)
{
PTCONFERENCELIST pConfList;
ptCall->pConfList = (LPVOID) LongToPtr(0xffffffff);
UNLOCKTCALL(ptCall);
if ((ptConfCall = (PTCALL) ReferenceObject(
ghHandleTable,
(HCALL)(ULONG_PTR)Param2,
TCALL_KEY
)))
{
if (WaitForExclusivetCallAccess(
ptConfCall,
TCALL_KEY
))
{
if (!ptConfCall->pConfList)
{
if ((pConfList = ServerAlloc(
sizeof (TCONFERENCELIST) +
sizeof(PTCALL) *
(DEF_NUM_CONF_LIST_ENTRIES - 1)
)))
{
pConfList->dwKey = TCONFLIST_KEY;
pConfList->dwNumTotalEntries =
DEF_NUM_CONF_LIST_ENTRIES;
pConfList->dwNumUsedEntries = 1;
pConfList->aptCalls[0] = ptConfCall;
ptConfCall->pConfList = pConfList;
}
}
pConfList = ptConfCall->pConfList;
pConfCallClientList = &fastConfCallClientList;
if (GetCallClientListFromCall(
ptConfCall,
&pConfCallClientList
) != 0)
{
pConfCallClientList = NULL;
}
UNLOCKTCALL(ptConfCall);
}
else
{
pConfList = NULL;
}
DereferenceObject (ghHandleTable, (HCALL)(ULONG_PTR)Param2, 1);
}
else
{
pConfList = NULL;
}
SetCallConfList (ptCall, pConfList, TRUE);
}
else
{
// Just get the existing call client list
UNLOCKTCALL(ptCall);
if ((ptConfCall = (PTCALL) ReferenceObject(
ghHandleTable,
(HCALL)(ULONG_PTR)Param2,
TCALL_KEY
)))
{
if (WaitForExclusivetCallAccess(
ptConfCall,
TCALL_KEY
))
{
pConfCallClientList = &fastConfCallClientList;
if (GetCallClientListFromCall(
ptConfCall,
&pConfCallClientList
) != 0)
{
pConfCallClientList = NULL;
}
UNLOCKTCALL(ptConfCall);
}
DereferenceObject (ghHandleTable, (HCALL)(ULONG_PTR)Param2, 1);
}
}
if (!WaitForExclusivetCallAccess (ptCall, TCALL_KEY))
{
if (pConfCallClientList &&
pConfCallClientList != &fastConfCallClientList)
{
ServerFree (pConfCallClientList);
}
goto LINE_CALLSTATE_break;
}
}
//
// If call is a conference child and the call state has
// changed then remove it from the conference
//
else if (ptCall->pConfList &&
ptCall->pConfList != (PTCONFERENCELIST) LongToPtr(0xffffffff))
{
try
{
if ( ptCall->pConfList->aptCalls[0] != ptCall)
{
SetCallConfList (ptCall, NULL, FALSE);
}
}
myexcept
{
}
}
//
// Record the call state & mode
//
ptCall->dwCallState = DWORD_CAST(Param1,__FILE__,__LINE__);
ptCall->dwCallStateMode = (LINECALLSTATE_CONFERENCED==Param1?0:DWORD_CAST(Param2,__FILE__,__LINE__));
//
// Build a list of call clients & their bIndicatePrivilege
// settings
//
if (GetCallClientListFromCall (ptCall, &pCallClientList) != 0)
{
//
// If here we know there's at least a few entries
// in the fastCallClientList (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
//
pCallClientList = &fastCallClientList;
fastCallClientList.dwNumUsedEntries = DEF_NUM_PTR_LIST_ENTRIES;
}
dwNumUsedEntries = pCallClientList->dwNumUsedEntries;
pPrivilegeList = (dwNumUsedEntries <= DEF_NUM_PTR_LIST_ENTRIES ?
fastPrivilegeList :
ServerAlloc (pCallClientList->dwNumUsedEntries * sizeof (BOOL))
);
if (!pPrivilegeList)
{
//
// Same as above - make due with the stack bufs
//
pPrivilegeList = fastPrivilegeList;
dwNumUsedEntries = DEF_NUM_PTR_LIST_ENTRIES;
}
for (i = 0; i < dwNumUsedEntries; i++)
{
ptCallClient = (PTCALLCLIENT) pCallClientList->aEntries[i];
if ((pPrivilegeList[i] =
(BOOL) ptCallClient->bIndicatePrivilege))
{
ptCallClient->bIndicatePrivilege = 0;
}
}
//
// It's now ok to unlock the tCall
//
UNLOCKTCALL(ptCall);
//
// Send the CALLSTATE msg to all the clients
//
msg->TotalSize = sizeof (ASYNCEVENTMSG) + sizeof(HCALLHUB);
msg->Msg = dwMsg;
msg->Param1 = DWORD_CAST(Param1,__FILE__,__LINE__);
for (i = 0; i < dwNumUsedEntries; i++)
{
ptCallClient = (PTCALLCLIENT) pCallClientList->aEntries[i];
LOG((TL_INFO, "LineEventProc: i = [%d] corresponding ptCallClient [%p]", i, ptCallClient));
try
{
PTLINECLIENT ptLineClient;
PTLINEAPP ptLineApp;
LOG((TL_INFO, "LineEventProc: ptCallClient->ptLineClient[%p]", ptCallClient->ptLineClient));
ptLineClient = ptCallClient->ptLineClient;
LOG((TL_INFO, "LineEventProc: ptLineClient->ptLineApp[%p]", ptLineClient->ptLineApp));
ptLineApp = ptLineClient->ptLineApp;
LOG((TL_INFO, "LineEventProc: setting msg->InitContext to ptLineApp[%p]->InitContext of [%p]", ptLineApp, ptLineApp->InitContext));
msg->InitContext = ptLineApp->InitContext;
msg->hDevice = ptCallClient->hCall;
LOG((TL_INFO, "LineEventProc: setting msg->OpenContext to [%p]", ptLineClient->OpenContext));
msg->OpenContext = ptLineClient->OpenContext;
//
// REMOTESP HACK: indicate the hRemoteLine in p4
//
msg->Param4 = ptLineClient->hRemoteLine;
*((LPHCALLHUB)(&msg->Param4 + 1)) =
(ptCallClient->ptCallHubClient)?
ptCallClient->ptCallHubClient->hCallHub :
(HCALLHUB)0;
if (pPrivilegeList[i])
{
//
// We're presenting the app with a new call handle;
// for 2.0 & newer apps we indicate this with an
// APPNEWCALL msg, while older apps just get the
// privilege field set in the call state msg.
//
if (ptLineApp->dwAPIVersion >= TAPI_VERSION2_0)
{
ASYNCEVENTMSG newCallMsg[2],
*pNewCallMsg = newCallMsg;
PTCONFERENCELIST pConfList;
BOOL bConfParent = FALSE;
if (!FMsgDisabled(
ptCallClient->ptLineClient->ptLineApp->dwAPIVersion,
ptCallClient->adwEventSubMasks,
LINE_APPNEWCALL,
0
))
{
pNewCallMsg->TotalSize =
sizeof (ASYNCEVENTMSG) + 3 * sizeof (DWORD);
pNewCallMsg->InitContext = msg->InitContext;
pNewCallMsg->hDevice =
ptLineClient->hRemoteLine;
pNewCallMsg->OpenContext = msg->OpenContext;
pNewCallMsg->fnPostProcessProcHandle = 0;
pNewCallMsg->Msg = LINE_APPNEWCALL;
pNewCallMsg->Param1 = ptCall->dwAddressID;
pNewCallMsg->Param2 = ptCallClient->hCall;
pNewCallMsg->Param3 = ptCallClient->dwPrivilege;
*(&pNewCallMsg->Param4 + 1) = ptCall->dwCallID;
*(&pNewCallMsg->Param4 + 2) =
ptCall->dwRelatedCallID;
if ((pConfList = ptCall->pConfList) &&
(pConfList != (PTCONFERENCELIST) LongToPtr(0xffffffff)) &&
(pConfList->aptCalls[0] == ptCall))
{
bConfParent = TRUE;
}
*(&pNewCallMsg->Param4 + 3) = (DWORD) bConfParent;
if (ptCallClient->dwKey == TCALLCLIENT_KEY)
{
LOG((TL_INFO, "LineEventProc: sending LINE_APPNEWCALL, ptClient[%p]", ptCallClient->ptClient));
WriteEventBuffer(
ptCallClient->ptClient,
pNewCallMsg
);
}
}
msg->Param3 = 0;
}
else
{
msg->Param3 = ptCallClient->dwPrivilege;
}
}
else
{
msg->Param3 = 0;
}
if (FMsgDisabled (
ptCallClient->ptLineClient->ptLineApp->dwAPIVersion,
ptCallClient->adwEventSubMasks,
(DWORD) msg->Msg,
(DWORD) msg->Param1
))
{
continue;
}
//
// Another special case for LINECALLSTATE_CONFERENCED -
// try to find the corresponding hConfCall (on same
// tLineClient) so we can set Param2 per spec
//
if (Param1 == LINECALLSTATE_CONFERENCED)
{
BOOL bDone = (pConfCallClientList ? FALSE : TRUE);
Param2 = 0;
while (!bDone)
{
try
{
for(
j = 0;
j < pConfCallClientList->dwNumUsedEntries;
j++
)
{
PTCALLCLIENT pConfCallClient;
pConfCallClient = (PTCALLCLIENT)
pConfCallClientList->aEntries[j];
if (pConfCallClient &&
pConfCallClient->ptLineClient ==
ptLineClient)
{
pConfCallClientList->aEntries[j] =
NULL;
Param2 = pConfCallClient->hCall;
break;
}
}
bDone = TRUE;
}
myexcept
{
//
// If here we presumbly blew up because
// an entry in the confCallClientList was
// bad. So we'll zero this entry & try
// again.
//
pConfCallClientList->aEntries[j] = NULL;
}
}
}
//
// REMOTESP HACK: If the client is remote(sp), then pass
// on the media mode the SP passed us in p3
// We also need the privilege - in p2
//
// Should have originally put the privilege
// in msg.pfnPostProcess (since it's not
// used for this msg in rmeotesp), because
// in tapi 2.1 we ended up losing Param2
// (the call state mode). So now we stick
// the original Param2 (the call state
// mode) in msg.pfnPostProcess to maintain
// compatibility.
//
if (IS_REMOTE_CLIENT (ptLineApp->ptClient))
{
msg->Param2 = ptCallClient->dwPrivilege;
msg->Param3 = DWORD_CAST(Param3,__FILE__,__LINE__);
msg->fnPostProcessProcHandle = DWORD_CAST(Param2,__FILE__,__LINE__);
}
else
{
msg->Param2 = DWORD_CAST(Param2,__FILE__,__LINE__);
msg->fnPostProcessProcHandle = 0;
}
if (ptCallClient->dwKey == TCALLCLIENT_KEY)
{
WriteEventBuffer (ptCallClient->ptClient, msg);
}
}
myexcept
{
// do nothing, just fall thru
}
}
if (pCallClientList != &fastCallClientList)
{
ServerFree (pCallClientList);
}
if (pPrivilegeList != fastPrivilegeList)
{
ServerFree (pPrivilegeList);
}
if (pConfCallClientList &&
pConfCallClientList != &fastConfCallClientList)
{
ServerFree (pConfCallClientList);
}
} // if ((ptCall = WaitForExclusivetCallAccess(
else
{
LOG((TL_ERROR,
"LINECALLSTATE: Failed call access for call= x%p",
ptCall
));
LOG((TL_INFO,
" Line=x%lx p1=x%lx p2=x%lx p3=x%lx",
htLine,
Param1,
Param2,
Param3
));
}
LINE_CALLSTATE_break:
DereferenceObject(ghHandleTable, (HCALL)(ULONG_PTR)htCall, 1);
break;
}
case LINE_GATHERDIGITS:
{
PASYNCREQUESTINFO pAsyncRequestInfo;
if (Param2 == 0) // dwEndToEndID
{
//
// The SP is notifying us of the completion of a cancel
// request (not a _canceled_ request), so we can just blow
// this off and not bother passing it on to the client
//
break;
}
if ((pAsyncRequestInfo = ReferenceObject(
ghHandleTable,
DWORD_CAST(Param2,__FILE__,__LINE__),
TASYNC_KEY
)))
{
LPWSTR lpsDigitsSrv = (LPWSTR)
(((LPBYTE) pAsyncRequestInfo) +
pAsyncRequestInfo->dwParam1);
DWORD hpsDigitsCli = DWORD_CAST(pAsyncRequestInfo->dwParam2,__FILE__,__LINE__);
DWORD dwNumDigits = DWORD_CAST(pAsyncRequestInfo->dwParam3,__FILE__,__LINE__),
dwNumDigitsTmp;
HCALL hCall = (HCALL) pAsyncRequestInfo->dwParam4;
DWORD dwEndToEndIDRemote = DWORD_CAST(
pAsyncRequestInfo->dwParam5,__FILE__,__LINE__);
PTCALLCLIENT ptCallClient;
ASYNCEVENTMSG *pMsg;
if (!(ptCallClient = (PTCALLCLIENT) ReferenceObject(
ghHandleTable,
hCall,
TCALLCLIENT_KEY
)))
{
goto LINE_GATHERDIGITS_dereferenceAsyncReqInfo;
break;
}
//
// 2 * sizeof ULONG_PTR is adding space to include the
// dwEndToEndID and hRemoteLine, both for remotesp
//
if (!(pMsg = ServerAlloc(
sizeof (ASYNCEVENTMSG) + (2 * sizeof(DWORD)) +
(dwNumDigits + 1) * sizeof (WCHAR) + TALIGN_COUNT
)))
{
goto LINE_GATHERDIGITS_dereferenceCall;
break;
}
//
// Note: We either have < dwNumDigits digits in the buffer,
// and they are null-terminated, or we have dwNumDigits
// digits in the buffer and they are NOT null-terminated
// (such is the implementation given the spec)
//
{
DWORD *pDW = (DWORD *) (pMsg + 1);
WCHAR *pBuf = (WCHAR *) (pDW + 2);
pDW[0] = dwEndToEndIDRemote;
try
{
pDW[1] = ptCallClient->ptLineClient->hRemoteLine;
}
myexcept
{
}
wcsncpy (pBuf, lpsDigitsSrv, dwNumDigits);
if ((dwNumDigitsTmp = lstrlenW (pBuf)) < dwNumDigits)
{
dwNumDigits = dwNumDigitsTmp + 1;
}
}
//
// Make sure total size is DWORD-aligned so client side doesn't
// incur an alignment fault
//
// sizeof(ULONG_PTR) is added to put the dwEndToEndID in the buf
//
pMsg->TotalSize = (sizeof (ASYNCEVENTMSG) +
2 * sizeof(DWORD) +
dwNumDigits * sizeof (WCHAR) + TALIGN_COUNT) & TALIGN_MASK;
pMsg->InitContext = pAsyncRequestInfo->InitContext;
pMsg->fnPostProcessProcHandle =
pAsyncRequestInfo->hfnClientPostProcessProc;
pMsg->hDevice = hCall;
pMsg->Msg = LINE_GATHERDIGITS;
pMsg->OpenContext = pAsyncRequestInfo->OpenContext;
pMsg->Param1 = DWORD_CAST(Param1,__FILE__,__LINE__);
pMsg->Param2 = hpsDigitsCli;
pMsg->Param3 = (Param3 ? DWORD_CAST(Param3,__FILE__,__LINE__) : GetTickCount());
pMsg->Param4 = dwNumDigits;
WriteEventBuffer (pAsyncRequestInfo->ptClient, pMsg);
ServerFree (pMsg);
LINE_GATHERDIGITS_dereferenceCall:
DereferenceObject (ghHandleTable, hCall, 1);
LINE_GATHERDIGITS_dereferenceAsyncReqInfo:
DereferenceObject (ghHandleTable, DWORD_CAST(Param2,__FILE__,__LINE__), 2); // by 2 to free
}
else
{
LOG((TL_ERROR,
"Bad Param2=x%lx in LINE_GATHERDIGITS msg!",
Param2
));
}
break;
}
case LINE_MONITORTONE:
{
//
// Note: Param2 (the dwToneListID) is really a ptCallClient
//
// Hack Alert!! : In the case of remotesp we'll get a special
// bogus Param2, in which case we really don't
// know who the appropriate call client is. So
// we'll call SendMsgtoCallClients() and let it
// figure out which apps have done tone monitoring
// on this call, and we'll forward to all of them.
// It's cheesey, but the alternative is keeping a
// bunch of context around in the client/server
// case, and i really don't want to deal with that.
// (Plus, i doubt there will be many, if any, cases
// of >1 app doing remote monitor on the same call.)
//
// DanKn, 06/06/98
//
PTCALLCLIENT ptCallClient;
if (Param2 == 0) // special remotesp hack
{
PTCALL ptCall;
if(ptCall = ReferenceObject(ghHandleTable, (HCALL)(ULONG_PTR)htCall, TCALL_KEY))
{
SendMsgToCallClients(
ptCall,
NULL,
dwMsg,
DWORD_CAST(Param1,__FILE__,__LINE__),
0,
DWORD_CAST(Param3,__FILE__,__LINE__)
);
DereferenceObject(ghHandleTable, (HCALL)(ULONG_PTR)htCall, 1);
}
break;
}
if (!(ptCallClient = (PTCALLCLIENT) ReferenceObject(
ghHandleTable,
DWORD_CAST(Param2,__FILE__,__LINE__), // dwToneListID == hCall
TCALLCLIENT_KEY
)))
{
break;
}
try
{
ASYNCEVENTMSG msg[2];
PTLINECLIENT ptLineClient = ptCallClient->ptLineClient;
ptLineClient = ptCallClient->ptLineClient;
msg->TotalSize = sizeof (ASYNCEVENTMSG) +
sizeof (HCALLHUB);
msg->InitContext = ptLineClient->ptLineApp->InitContext;
msg->fnPostProcessProcHandle = 0;
msg->hDevice = ptCallClient->hCall;
msg->Msg = dwMsg;
msg->OpenContext = ptLineClient->OpenContext;
msg->Param1 = DWORD_CAST(Param1,__FILE__,__LINE__);
msg->Param2 = 0;
msg->Param3 = (Param3 ? DWORD_CAST(Param3,__FILE__,__LINE__) : GetTickCount());
msg->Param4 = ptLineClient->hRemoteLine; // for RemoteSP
*((LPHCALLHUB)(&msg->Param4 + 1)) =
(ptCallClient->ptCallHubClient)?
ptCallClient->ptCallHubClient->hCallHub :
(HCALLHUB)0;
//
// Now a final check to make sure all the
// params are valid before sending the msg
//
{
PTCLIENT ptClient = ptCallClient->ptClient;
if (ptCallClient->dwKey == TCALLCLIENT_KEY)
{
WriteEventBuffer (ptClient, msg);
}
}
}
myexcept
{
// do nothing
}
DereferenceObject (ghHandleTable, DWORD_CAST(Param2,__FILE__,__LINE__), 1);
break;
}
case LINE_GENERATE:
{
//
// Note: Param2 id really a pointer to instance data containing
// ([0]) the hCall & ([1]) the dwEndToEndID or dwToneListID,
// the latter of which is only useful to remotesp
//
HCALL hCall;
DWORD dwEndToEndID;
LPDWORD pInstData;
PTCALLCLIENT ptCallClient;
if (!(pInstData = (LPDWORD) ReferenceObject(
ghHandleTable,
DWORD_CAST(Param2,__FILE__,__LINE__),
TASYNC_KEY
)))
{
break;
}
hCall = pInstData[1];
dwEndToEndID = pInstData[2];
DereferenceObject (ghHandleTable, DWORD_CAST(Param2,__FILE__,__LINE__), 2); // by 2 to free it
if (!(ptCallClient = (PTCALLCLIENT) ReferenceObject(
ghHandleTable,
hCall,
TCALLCLIENT_KEY
)))
{
break;
}
try
{
ASYNCEVENTMSG msg[2];
PTLINECLIENT ptLineClient = ptCallClient->ptLineClient;
msg->TotalSize = sizeof (ASYNCEVENTMSG) +
sizeof (HCALLHUB);
msg->InitContext = ptLineClient->ptLineApp->InitContext;
msg->fnPostProcessProcHandle = 0;
msg->hDevice = hCall;
msg->Msg = dwMsg;
msg->OpenContext = ptLineClient->OpenContext;
msg->Param1 = DWORD_CAST(Param1,__FILE__,__LINE__);
LOG((TL_INFO,
"LineEventProc: LINE_GENERATE OpenContext %p InitContext %p",
msg->OpenContext, msg->InitContext ));
//
// Indicate the endToEndID/toneListID for remotesp, and the
// hRemoteLine in p4 to make life easier for remotesp
//
msg->Param2 = dwEndToEndID;
msg->Param3 = (Param3 ? DWORD_CAST(Param3,__FILE__,__LINE__) : GetTickCount());
msg->Param4 = ptLineClient->hRemoteLine;
*((LPHCALLHUB)(&msg->Param4 + 1)) =
(ptCallClient->ptCallHubClient)?
ptCallClient->ptCallHubClient->hCallHub :
(HCALLHUB)0;
//
// Now a final check to make sure all the
// params are valid before sending the msg
//
{
PTCLIENT ptClient = ptCallClient->ptClient;
if (ptCallClient->dwKey == TCALLCLIENT_KEY)
{
WriteEventBuffer (ptClient, msg);
}
}
}
myexcept
{
// do nothing
}
DereferenceObject (ghHandleTable, hCall, 1);
break;
}
case LINE_NEWCALL:
{
//
// Create a tCall & set the bAlertApps field so we create the
// appropriate tCallClients on the first call state msg
//
PTCALL ptCall;
PTLINE ptLine;
HCALL hCall;
ptLine = ReferenceObject(ghHandleTable, (HLINE)(ULONG_PTR)htLine, TLINE_KEY);
if (NULL != ptLine)
{
if (CreatetCall(
ptLine,
TRUE,
(HDRVCALL) Param1,
&ptCall,
NULL,
&hCall,
NULL
) != 0)
{
hCall = 0;
}
DereferenceObject(ghHandleTable, (HLINE)(ULONG_PTR)htLine, 1);
}
else
{
hCall = 0;
}
*((LPHTAPICALL) Param2) = (HTAPICALL)(ULONG_PTR)hCall;
break;
}
case LINE_CREATE:
{
LONG lResult;
DWORD dwDeviceID;
TSPIPROC pfnTSPI_providerCreateLineDevice;
PTPROVIDER ptProvider = (PTPROVIDER) Param1;
PTLINELOOKUPTABLE pTable, pPrevTable;
PTLINELOOKUPENTRY pEntry;
PTPROVIDER ptProvider2;
TapiEnterCriticalSection (&TapiGlobals.CritSec);
//
// Check to see if ptProvider(Param1) is still valid, LINE_CREATE
// might got processed after the TSP has been removed
//
if (NULL == ptProvider)
{
TapiLeaveCriticalSection (&TapiGlobals.CritSec);
return;
}
ptProvider2 = TapiGlobals.ptProviders;
while (ptProvider2 && ptProvider2 != ptProvider)
{
ptProvider2 = ptProvider2->pNext;
}
if (ptProvider2 != ptProvider)
{
TapiLeaveCriticalSection (&TapiGlobals.CritSec);
return;
}
pfnTSPI_providerCreateLineDevice =
ptProvider->apfn[SP_PROVIDERCREATELINEDEVICE];
assert (pfnTSPI_providerCreateLineDevice != NULL);
//
// Search for a table entry (create a new table if we can't find
// a free entry in an existing table)
//
if (!gbQueueSPEvents)
{
//
// We're shutting down, so bail out
//
TapiLeaveCriticalSection (&TapiGlobals.CritSec);
return;
}
pTable = TapiGlobals.pLineLookup;
while (pTable &&
!(pTable->dwNumUsedEntries < pTable->dwNumTotalEntries))
{
pPrevTable = pTable;
pTable = pTable->pNext;
}
if (!pTable)
{
if (!(pTable = ServerAlloc(
sizeof (TLINELOOKUPTABLE) +
(2 * pPrevTable->dwNumTotalEntries - 1) *
sizeof (TLINELOOKUPENTRY)
)))
{
TapiLeaveCriticalSection (&TapiGlobals.CritSec);
break;
}
pPrevTable->pNext = pTable;
pTable->dwNumTotalEntries = 2 * pPrevTable->dwNumTotalEntries;
}
//
// Initialize the table entry
//
pEntry = pTable->aEntries + pTable->dwNumUsedEntries;
dwDeviceID = TapiGlobals.dwNumLines;
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_providerCreateLineDevice,
"providerCreateLineDevice",
SP_FUNC_SYNC,
(ULONG_PTR) Param2,
(DWORD) dwDeviceID
)) == 0)
{
TSPIPROC pfnTSPI_lineNegotiateTSPIVersion =
ptProvider->apfn[SP_LINENEGOTIATETSPIVERSION];
TPOINTERLIST clientList, *pClientList = &clientList;
if ((lResult = CallSP4(
pfnTSPI_lineNegotiateTSPIVersion,
"",
SP_FUNC_SYNC,
(DWORD) dwDeviceID,
(DWORD) TAPI_VERSION1_0,
(DWORD) TAPI_VERSION_CURRENT,
(ULONG_PTR) &pEntry->dwSPIVersion
)) == 0)
{
PTCLIENT ptClient;
ASYNCEVENTMSG msg;
GetPermLineIDAndInsertInTable(
ptProvider,
dwDeviceID,
pEntry->dwSPIVersion
);
pTable->dwNumUsedEntries++;
TapiGlobals.dwNumLines++;
TapiLeaveCriticalSection (&TapiGlobals.CritSec);
AppendNewDeviceInfo (TRUE, dwDeviceID);
TapiEnterCriticalSection (&TapiGlobals.CritSec);
// PERF ** Number of lines
PerfBlock.dwLines = TapiGlobals.dwNumLines;
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 lines have not changed.
//
if (TapiGlobals.dwFlags & TAPIGLOBALS_SERVER)
{
lResult = GetClientList (TRUE, &pClientList);
}
else
{
lResult = GetClientList (FALSE, &pClientList);
}
if (lResult == S_OK)
{
DWORD i;
PTLINEAPP ptLineApp;
for (i = 0; i < pClientList->dwNumUsedEntries; ++i)
{
ptClient = (PTCLIENT) pClientList->aEntries[i];
if (!WaitForExclusiveClientAccess (ptClient))
{
continue;
}
ptLineApp = ptClient->ptLineApps;
while (ptLineApp)
{
if (ptLineApp->dwAPIVersion == TAPI_VERSION1_0)
{
msg.Msg = LINE_LINEDEVSTATE;
msg.Param1 = LINEDEVSTATE_REINIT;
}
else
{
msg.Msg = LINE_CREATE;
msg.Param1 = dwDeviceID;
}
msg.InitContext = ptLineApp->InitContext;
if (!FMsgDisabled (
ptLineApp->dwAPIVersion,
ptLineApp->adwEventSubMasks,
(DWORD) msg.Msg,
(DWORD) msg.Param1
))
{
WriteEventBuffer (ptClient, &msg);
}
ptLineApp = ptLineApp->pNext;
}
UNLOCKTCLIENT (ptClient);
}
}
}
if (pClientList != &clientList)
{
ServerFree (pClientList);
}
}
if (lResult)
{
MyCloseMutex (pEntry->hMutex);
}
}
TapiLeaveCriticalSection (&TapiGlobals.CritSec);
break;
}
case LINE_CREATEDIALOGINSTANCE:
{
DWORD dwDataSize, dwAlignedDataSize,
dwAlignedUIDllNameSize,
dwTotalSize;
PTCLIENT ptClient;
PASYNCEVENTMSG pMsg;
PASYNCREQUESTINFO pAsyncReqInfo;
PTAPIDIALOGINSTANCE ptDlgInst;
LPTUISPICREATEDIALOGINSTANCEPARAMS pParams;
pParams = (LPTUISPICREATEDIALOGINSTANCEPARAMS) Param1;
//
// Verify the async request info struct
//
if (!(pAsyncReqInfo = (PASYNCREQUESTINFO) ReferenceObject(
ghHandleTable,
pParams->dwRequestID,
TASYNC_KEY
)))
{
pParams->htDlgInst = 0;
return;
}
ptClient = pAsyncReqInfo->ptClient;
DereferenceObject (ghHandleTable, pParams->dwRequestID, 1);
//
// Alloc bufs for the msg & dlg instance, careful to keep offsets
// & total msg size on 64-bit boundaries
//
dwDataSize = pParams->dwSize;
dwAlignedDataSize = (dwDataSize + 7) & 0xfffffff8;
dwAlignedUIDllNameSize = 0xfffffff8 & (7 +
((lstrlenW ((PWSTR) pParams->lpszUIDLLName) + 1)*sizeof (WCHAR)));
dwTotalSize = sizeof (ASYNCEVENTMSG) + dwAlignedDataSize +
dwAlignedUIDllNameSize;
if (!(pMsg = ServerAlloc (dwTotalSize)))
{
pParams->htDlgInst = 0;
return;
}
if (!(ptDlgInst = ServerAlloc (sizeof (TAPIDIALOGINSTANCE))))
{
ServerFree (pMsg);
pParams->htDlgInst = 0;
return;
}
ptDlgInst->htDlgInst = NewObject(ghHandleTable, ptDlgInst, NULL);
if (0 == ptDlgInst->htDlgInst)
{
ServerFree (pMsg);
ServerFree (ptDlgInst);
pParams->htDlgInst = 0;
return;
}
//
// Add the dlg inst to the tClient's list
//
LOCKTCLIENT (ptClient);
if ((ptDlgInst->pNext = ptClient->pGenericDlgInsts))
{
ptDlgInst->pNext->pPrev = ptDlgInst;
}
ptClient->pGenericDlgInsts = ptDlgInst;
UNLOCKTCLIENT (ptClient);
//
// Init dlg inst struct & send msg to client
//
ptDlgInst->dwKey = TDLGINST_KEY;
ptDlgInst->hdDlgInst = pParams->hdDlgInst;
ptDlgInst->ptClient = ptClient;
ptDlgInst->ptProvider = (PTPROVIDER) htLine;
pMsg->TotalSize = dwTotalSize;
pMsg->hDevice = ptDlgInst->htDlgInst;
try
{
if (ptClient->ptLineApps)
{
pMsg->InitContext = ptClient->ptLineApps->InitContext;
}
}
myexcept
{
pMsg->InitContext = 0;
}
pMsg->Msg = LINE_CREATEDIALOGINSTANCE;
pMsg->Param1 = sizeof (ASYNCEVENTMSG); // data offset
pMsg->Param2 = dwDataSize; // data size
pMsg->Param3 = sizeof (ASYNCEVENTMSG) + dwAlignedDataSize;
// name offset
CopyMemory ((LPBYTE)(pMsg + 1), pParams->lpParams, dwDataSize);
wcscpy(
(PWSTR) ((LPBYTE)(pMsg + 1) + dwAlignedDataSize),
(PWSTR) pParams->lpszUIDLLName
);
pParams->htDlgInst = ptDlgInst->htDlgInst;
WriteEventBuffer (ptClient, pMsg);
ServerFree (pMsg);
break;
}
case LINE_SENDDIALOGINSTANCEDATA:
{
DWORD dwDataSize, dwAlignedDataSize, dwTotalSize;
PTCLIENT ptClient;
PASYNCEVENTMSG pMsg;
PTAPIDIALOGINSTANCE ptDlgInst = ReferenceObject (ghHandleTable, DWORD_CAST((ULONG_PTR)htLine,__FILE__,__LINE__), TDLGINST_KEY);
//
// Verify the dlg inst
//
try
{
ptClient = ptDlgInst->ptClient;
if (ptDlgInst->dwKey != TDLGINST_KEY)
{
return;
}
}
myexcept
{
return;
}
DereferenceObject (ghHandleTable, DWORD_CAST((ULONG_PTR)htLine,__FILE__,__LINE__), 1);
//
// Careful to keep offsets & total msg size on 64-bit boundaries
//
dwDataSize = (DWORD) Param2;
dwAlignedDataSize = (dwDataSize + 7) & 0xfffffff8;
dwTotalSize = sizeof (ASYNCEVENTMSG) + dwAlignedDataSize;
if (!(pMsg = ServerAlloc (dwTotalSize)))
{
return;
}
//
// Send the msg to the client
//
pMsg->TotalSize = dwTotalSize;
pMsg->hDevice = ptDlgInst->htDlgInst;
try
{
if (ptClient->ptLineApps)
{
pMsg->InitContext = ptClient->ptLineApps->InitContext;
}
}
myexcept
{
pMsg->InitContext = 0;
}
pMsg->Msg = LINE_SENDDIALOGINSTANCEDATA;
pMsg->Param1 = sizeof (ASYNCEVENTMSG); // data offset
pMsg->Param2 = dwDataSize; // data size
CopyMemory ((LPBYTE)(pMsg + 1), (LPBYTE) Param1, dwDataSize);
WriteEventBuffer (ptClient, pMsg);
ServerFree (pMsg);
break;
}
case LINE_REMOVE:
{
PTLINELOOKUPENTRY pLookupEntry;
HANDLE hLookupEntryMutex = NULL;
BOOL bOK = FALSE;
TapiEnterCriticalSection (&TapiGlobals.CritSec);
if (!(pLookupEntry = GetLineLookupEntry ((DWORD) Param1)) ||
pLookupEntry->bRemoved)
{
TapiLeaveCriticalSection(&TapiGlobals.CritSec);
return;
}
if ( pLookupEntry->hMutex )
{
bOK = DuplicateHandle(
TapiGlobals.hProcess,
pLookupEntry->hMutex,
TapiGlobals.hProcess,
&hLookupEntryMutex,
0,
FALSE,
DUPLICATE_SAME_ACCESS
);
}
TapiLeaveCriticalSection(&TapiGlobals.CritSec);
if ( !bOK )
{
return;
}
//
// Wait for the LookupEntry's mutex on the duplicate handle
//
if (WaitForSingleObject (hLookupEntryMutex, INFINITE)
!= WAIT_OBJECT_0)
{
return;
}
//
// Mark the lookup table entry as removed
//
pLookupEntry->bRemoved = 1;
//
// Release the mutex and close the duplicate handle
//
ReleaseMutex (hLookupEntryMutex);
CloseHandle (hLookupEntryMutex);
hLookupEntryMutex = NULL;
if (pLookupEntry->ptLine)
{
DestroytLine (pLookupEntry->ptLine, TRUE); // unconditional destroy
}
TapiEnterCriticalSection (&TapiGlobals.CritSec);
//
// Close the mutex to reduce overall handle count
//
MyCloseMutex (pLookupEntry->hMutex);
pLookupEntry->hMutex = NULL;
RemoveDeviceInfoEntry (TRUE, (DWORD)Param1);
TapiLeaveCriticalSection(&TapiGlobals.CritSec);
SendAMsgToAllLineApps(
TAPI_VERSION2_0 | 0x80000000,
LINE_REMOVE,
DWORD_CAST(Param1,__FILE__,__LINE__),
0,
0
);
break;
}
case LINE_APPNEWCALLHUB:
case LINE_CALLHUBCLOSE:
{
//
// This msg gets queued/sent by our own internal
// DoCallHubHashing func. See comments there for
// more info.
//
ASYNCEVENTMSG msg;
PTCLIENT ptClient = NULL;
msg.TotalSize = sizeof (ASYNCEVENTMSG);
msg.InitContext = DWORD_CAST(Param2,__FILE__,__LINE__);
msg.fnPostProcessProcHandle = 0;
msg.hDevice = 0;
msg.Msg = dwMsg;
msg.OpenContext = 0;
msg.Param1 = DWORD_CAST(Param1,__FILE__,__LINE__);
msg.Param2 =
msg.Param3 = 0;
//
// try to recover the pointer to tClient from the 32-bit handle value
//
ptClient = (PTCLIENT) Param3;
if (NULL != ptClient)
{
WriteEventBuffer (ptClient, &msg);
}
else
{
LOG((TL_ERROR, "LineEventProc: LINE_APPNEWCALLHUB/LINE_CALLHUBCLOSE failed to recover ptClient"));
}
break;
}
case LINE_SENDMSPDATA:
{
PASYNCEVENTMSG pmsg;
PTLINECLIENT ptLineClient = NULL;
PTCALLCLIENT ptCallClient = NULL;
DWORD dwSize = (sizeof (ASYNCEVENTMSG) +
DWORD_CAST(Param3,__FILE__,__LINE__) + TALIGN_COUNT) &
TALIGN_MASK;
DWORD initContext;
PTCLIENT ptClient = NULL;
DWORD dwCount;
BOOL bFound = FALSE;
TPOINTERLIST clientList, *pClientList = &clientList;
PTCALL ptCall;
DWORD hLine = 0, hCall = 0;
if ( (0 == Param1) && (0 == htCall) )
{
return;
}
if ( 0 != Param1 )
{
if (!(ptLineClient = (PTLINECLIENT) ReferenceObject(
ghHandleTable,
DWORD_CAST(Param1,__FILE__,__LINE__),
TLINECLIENT_KEY
)))
{
return;
}
ptClient = ptLineClient->ptClient;
initContext = ptLineClient->ptLineApp->InitContext;
}
//
// If ptCall isn't NULL, try to find the call client
// corresponding to this line client
//
if (0 != htCall)
{
if (ptCall = ReferenceObject(ghHandleTable, (HCALL)(ULONG_PTR)htCall, TCALL_KEY))
{
if ( NULL == ptLineClient )
{
SendBufferMsgToCallClients(
ptCall,
NULL,
LINE_SENDMSPDATA,
0,
DWORD_CAST(Param3,__FILE__,__LINE__),
(LPBYTE)Param2
);
DereferenceObject(ghHandleTable, (HCALL)(ULONG_PTR)htCall, 1);
return;
}
if (GetCallClientListFromCall (ptCall, &pClientList) == 0)
{
for(
dwCount = 0;
dwCount < pClientList->dwNumUsedEntries;
dwCount++
)
{
ptCallClient = pClientList->aEntries[dwCount];
try
{
if ( ptCallClient->ptLineClient == ptLineClient )
{
bFound = TRUE;
break;
}
}
myexcept
{
// do nothing
}
}
if ( pClientList != &clientList )
{
ServerFree( pClientList );
}
}
DereferenceObject( ghHandleTable, (HCALL)(ULONG_PTR)htCall, 1);
}
if ( !bFound )
{
//
// Didn't find it for some reason
//
DereferenceObject( ghHandleTable, DWORD_CAST(Param1,__FILE__,__LINE__), 1 );
return;
}
}
if ( NULL != ptLineClient )
{
hLine = ptLineClient->hLine;
DereferenceObject( ghHandleTable, DWORD_CAST(Param1,__FILE__,__LINE__), 1 );
}
if ( NULL != ptCallClient )
{
hCall = ptCallClient->hCall;
}
pmsg = ( PASYNCEVENTMSG )ServerAlloc( dwSize );
if (NULL == pmsg)
{
LOG((TL_ERROR, "Alloc failed in LINE_SENDMSPDATA"));
return;
}
CopyMemory ((LPBYTE) (pmsg+1), (LPBYTE) Param2, Param3);
pmsg->TotalSize = dwSize;
pmsg->InitContext = initContext;
pmsg->fnPostProcessProcHandle = 0;
pmsg->hDevice = hLine;
pmsg->Msg = LINE_SENDMSPDATA;
pmsg->OpenContext = 0;
pmsg->Param1 = hCall;
pmsg->Param2 = DWORD_CAST(Param3,__FILE__,__LINE__);
pmsg->Param3 = 0;
WriteEventBuffer ( ptClient, pmsg );
ServerFree( pmsg );
break;
}
case LINE_QOSINFO:
{
ASYNCEVENTMSG msg;
PTCALL ptCall;
TPOINTERLIST clientList, *pclientList = &clientList;
int i;
ptCall = ReferenceObject(ghHandleTable, (HCALL)(ULONG_PTR)htCall, TCALL_KEY);
if (0 == ptCall)
{
break;
}
clientList.dwNumUsedEntries = 0;
if (GetCallClientListFromCall (ptCall, &pclientList) == 0)
{
PTCALLCLIENT ptCallClient;
msg.TotalSize = sizeof (ASYNCEVENTMSG);
msg.fnPostProcessProcHandle = 0;
msg.Msg = dwMsg;
msg.OpenContext = 0;
msg.Param1 = DWORD_CAST(Param1,__FILE__,__LINE__);
msg.Param2 = DWORD_CAST(Param2,__FILE__,__LINE__);
msg.Param3 = 0;
for (i = 0; i < (int)pclientList->dwNumUsedEntries; ++ i)
{
ptCallClient = (PTCALLCLIENT) pclientList->aEntries[i];
if (WaitForExclusivetCallAccess (ptCallClient->ptCall, TCALL_KEY))
{
BOOL b = FMsgDisabled(
ptCallClient->ptLineClient->ptLineApp->dwAPIVersion,
ptCallClient->adwEventSubMasks,
LINE_QOSINFO,
0
);
UNLOCKTCALL (ptCallClient->ptCall);
if (b)
{
continue;
}
}
msg.InitContext =
ptCallClient->ptLineClient->ptLineApp->InitContext;
msg.hDevice = ptCallClient->hCall;
WriteEventBuffer (ptCallClient->ptClient, &msg);
}
if (pclientList && (pclientList != &clientList))
{
ServerFree (pclientList);
}
}
DereferenceObject(ghHandleTable, (HCALL)(ULONG_PTR)htCall, 1);
break;
}
case LINE_DEVSPECIFICEX:
{
PTLINE ptLine;
ptLine = ReferenceObject(ghHandleTable, (HLINE)(ULONG_PTR)htLine, TLINE_KEY);
if(ptLine)
{
SendBufferMsgToLineClients(
ptLine,
NULL,
LINE_DEVSPECIFICEX,
DWORD_CAST(Param1,__FILE__,__LINE__),
DWORD_CAST(Param2,__FILE__,__LINE__),
(LPBYTE) Param3
);
DereferenceObject(ghHandleTable, (HLINE)(ULONG_PTR)htLine, 1);
}
break;
}
default:
// if DBG assert (unrecognized dwMsg)
break;
}
}
void
CALLBACK
LineEventProcSP(
HTAPILINE htLine,
HTAPICALL htCall,
DWORD dwMsg,
ULONG_PTR Param1,
ULONG_PTR Param2,
ULONG_PTR Param3
)
{
PSPEVENT pSPEvent;
#if DBG
if (gdwDebugLevel >= 3)
{
char *pszMsg;
static char szInvalMsgVal[] = "<inval msg value>";
static char *aszMsgs[] =
{
"LINE_ADDRESSSTATE",
"LINE_CALLINFO",
"LINE_CALLSTATE",
"LINE_CLOSE",
"LINE_DEVSPECIFIC",
"LINE_DEVSPECIFICFEATURE",
"LINE_GATHERDIGITS",
"LINE_GENERATE",
"LINE_LINEDEVSTATE",
"LINE_MONITORDIGITS",
"LINE_MONITORMEDIA",
"LINE_MONITORTONE",
szInvalMsgVal, // LINE_REPLY
szInvalMsgVal, // LINE_REQUEST
szInvalMsgVal, // PHONE_BUTTON
szInvalMsgVal, // PHONE_CLOSE
szInvalMsgVal, // PHONE_DEVSPECIFIC
szInvalMsgVal, // PHONE_REPLY
szInvalMsgVal, // PHONE_STATE
"LINE_CREATE",
szInvalMsgVal, // PHONE_CREATE
"LINE_AGENTSPECIFIC",
"LINE_AGENTSTATUS",
szInvalMsgVal, // LINE_APPNEWCALL
"LINE_PROXYREQUEST",
"LINE_REMOVE",
szInvalMsgVal, // PHONE_REMOVE
"LINE_NEWCALL",
"LINE_CALLDEVSPECIFIC",
"LINE_CALLDEVSPECIFICFEATURE",
"LINE_CREATEDIALOGINSTANCE",
"LINE_SENDDIALOGINSTANCEDATA"
};
if (dwMsg <= PHONE_REMOVE)
{
pszMsg = aszMsgs[dwMsg];
}
else if (dwMsg >= LINE_NEWCALL && dwMsg <= LINE_SENDDIALOGINSTANCEDATA)
{
pszMsg = aszMsgs[27 + dwMsg - TSPI_MESSAGE_BASE];
}
else
{
pszMsg = szInvalMsgVal;
}
LOG((TL_TRACE,
"LineEventProcSP: enter\n" \
"\t Msg=%s (x%x), htLine=x%x, htCall=x%x",
pszMsg,
dwMsg,
htLine,
htCall
));
if (dwMsg == LINE_CALLSTATE)
{
char *pszCallState;
static char szInvalCallStateVal[] = "<inval callstate value>";
static char *aszCallStates[] =
{
"IDLE",
"OFFERING",
"ACCEPTED",
"DIALTONE",
"DIALING",
"RINGBACK",
"BUSY",
"SPECIALINFO",
"CONNECTED",
"PROCEEDING",
"ONHOLD",
"CONFERENCED",
"ONHOLDPENDCONF",
"ONHOLDPENDTRANSFER",
"DISCONNECTED",
"UNKNOWN"
};
if (!IsOnlyOneBitSetInDWORD(Param1) ||
Param1 > LINECALLSTATE_UNKNOWN)
{
pszCallState = szInvalCallStateVal;
}
else
{
DWORD i, dwBitMask;
for(
i = 0, dwBitMask = 1;
Param1 != dwBitMask;
i++, dwBitMask <<= 1
);
pszCallState = aszCallStates[i];
}
LOG((TL_INFO,
" P1=%s (x%x), P2=x%x, P3=x%x",
pszCallState,
Param1,
Param2,
Param3
));
}
else
{
LOG((TL_INFO,
" P1=x%x, P2=x%x, P3=x%x",
Param1,
Param2,
Param3
));
}
}
#endif
LOG((TL_INFO,
"LineEventProcSP: HTapiLine=%p, HTapiCall=%p, msg=%lx, P1=x%x, P2=x%x, P3=x%x",
htLine,
htCall,
dwMsg,
Param1,
Param2,
Param3
));
switch (dwMsg)
{
case LINE_NEWCALL:
case LINE_CREATEDIALOGINSTANCE:
case LINE_SENDDIALOGINSTANCEDATA:
case LINE_DEVSPECIFICEX:
//
// These msgs need immediate attention, since they contain
// pointers that we need to play with which may not be
// available during async processing later
//
LineEventProc (htLine, htCall, dwMsg, Param1, Param2, Param3);
break;
case LINE_SENDMSPDATA:
if ((pSPEvent = (PSPEVENT) ServerAlloc ( sizeof (SPEVENT) + (DWORD)Param3)))
{
CopyMemory(
(LPBYTE)(pSPEvent+1),
(LPBYTE)Param2,
Param3
);
pSPEvent->dwType = SP_LINE_EVENT;
pSPEvent->htLine = htLine;
pSPEvent->htCall = htCall;
pSPEvent->dwMsg = dwMsg;
pSPEvent->dwParam1 = Param1;
pSPEvent->dwParam2 = (ULONG_PTR)(LPBYTE)(pSPEvent+1);
pSPEvent->dwParam3 = Param3;
if (!QueueSPEvent (pSPEvent))
{
ServerFree (pSPEvent);
}
break;
}
default:
if ((pSPEvent = (PSPEVENT) ServerAlloc (sizeof (SPEVENT))))
{
pSPEvent->dwType = SP_LINE_EVENT;
pSPEvent->htLine = htLine;
pSPEvent->htCall = htCall;
pSPEvent->dwMsg = dwMsg;
pSPEvent->dwParam1 = Param1;
pSPEvent->dwParam2 = Param2;
pSPEvent->dwParam3 = Param3;
if (!QueueSPEvent (pSPEvent))
{
ServerFree (pSPEvent);
}
}
else if (dwMsg != LINE_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)
//
LOG((TL_ERROR,
"LineEventProcSP: alloc failed, calling EventProc inline"
));
LineEventProc (htLine, htCall, dwMsg, Param1, Param2, Param3);
}
break;
}
}
void
WINAPI
LAccept(
PTCLIENT ptClient,
PLINEACCEPT_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
LONG lRequestID;
HANDLE hMutex;
HDRVCALL hdCall;
DWORD objectToDereference;
PTCALLCLIENT ptCallClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
TSPIPROC pfnTSPI_lineAccept;
//
// Verify size/offset/string params given our input buffer/size
//
if ((pParams->dwUserUserInfoOffset != TAPI_NO_DATA) &&
ISBADSIZEOFFSET(
dwParamsBufferSize,
0,
pParams->dwSize,
pParams->dwUserUserInfoOffset,
sizeof(DWORD),
"LAccept",
"pParams->UserUserInfo"
))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HCALL, // widget type
pParams->hCall, // client widget handle
(LPVOID) &hdCall, // provider widget handle
LINECALLPRIVILEGE_OWNER, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINEACCEPT, // provider func index
&pfnTSPI_lineAccept, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptCallClient, // context
"Accept" // func name
)) > 0)
{
DWORD dwAppNameSize;
LPVOID pszAppName = NULL;
PTCALL ptCall;
//
// Safely check to see if the app name associated with this call is
// NULL (meaning this is the first client to accept/answer the call),
// and if so save the app name
//
try
{
ptCall = (PTCALL) ptCallClient->ptCall;
if (ptCall->pszAppName == NULL)
{
PTLINEAPP ptLineApp;
ptLineApp = ptCallClient->ptLineClient->ptLineApp;
dwAppNameSize = ptLineApp->dwFriendlyNameSize;
if (ptLineApp->dwKey != TLINEAPP_KEY)
{
lRequestID = LINEERR_INVALCALLHANDLE;
goto LAccept_epilog;
}
if ((pszAppName = ServerAlloc (dwAppNameSize)))
{
CopyMemory(
pszAppName,
ptLineApp->pszFriendlyName,
dwAppNameSize
);
}
}
}
myexcept
{
ServerFree (pszAppName);
lRequestID = LINEERR_INVALCALLHANDLE;
goto LAccept_epilog;
}
if (pszAppName)
{
if (WaitForExclusivetCallAccess (ptCall, TCALL_KEY))
{
if (!ptCall->pszAppName)
{
ptCall->pszAppName = pszAppName;
ptCall->dwAppNameSize = dwAppNameSize;
pszAppName = NULL;
}
UNLOCKTCALL (ptCall);
ServerFree (pszAppName);
}
else
{
ServerFree (pszAppName);
lRequestID = LINEERR_INVALCALLHANDLE;
goto LAccept_epilog;
}
}
pParams->lResult = CallSP4(
pfnTSPI_lineAccept,
"lineAccept",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdCall,
(ULONG_PTR) (pParams->dwUserUserInfoOffset == TAPI_NO_DATA ? NULL :
pDataBuf + pParams->dwUserUserInfoOffset),
(DWORD) (pParams->dwUserUserInfoOffset == TAPI_NO_DATA ? 0 :
pParams->dwSize)
);
}
LAccept_epilog:
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"Accept"
);
}
void
LAddToConference_PostProcess(
PASYNCREQUESTINFO pAsyncRequestInfo,
PASYNCEVENTMSG pAsyncEventMsg,
LPVOID *ppBuf
)
{
PTCALL ptConsultCall = (PTCALL) pAsyncRequestInfo->dwParam1;
if (pAsyncEventMsg->Param2 == 0)
{
PTCONFERENCELIST pConfList = (PTCONFERENCELIST)
pAsyncRequestInfo->dwParam2;
SetCallConfList (ptConsultCall, pConfList, TRUE);
}
else
{
SetCallConfList (ptConsultCall, NULL, TRUE);
}
}
void
WINAPI
LAddToConference(
PTCLIENT ptClient,
PLINEADDTOCONFERENCE_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
LONG lRequestID;
HANDLE hMutex;
HDRVCALL hdConfCall;
DWORD objectToDereference;
PTCALLCLIENT ptConsultCallClient, ptConfCallClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
TSPIPROC pfnTSPI_lineAddToConference;
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HCALL, // widget type
(DWORD) pParams->hConfCall, // client widget handle
(LPVOID) &hdConfCall, // provider widget handle
LINECALLPRIVILEGE_OWNER, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINEADDTOCONFERENCE, // provider func index
&pfnTSPI_lineAddToConference, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptConfCallClient, // context
"AddToConference" // func name
)) > 0)
{
PTCALL ptConfCall, ptConsultCall;
HDRVCALL hdConsultCall;
PTCONFERENCELIST pConfList;
//
// Safely make sure that the conf call is really a conf parent
//
try
{
ptConfCall = ptConfCallClient->ptCall;
if (!(pConfList = ptConfCall->pConfList) ||
(pConfList->aptCalls[0] != ptConfCall))
{
lRequestID = LINEERR_INVALCONFCALLHANDLE;
goto LAddToConference_return;
}
}
myexcept
{
lRequestID = LINEERR_INVALCONFCALLHANDLE;
goto LAddToConference_return;
}
//
// Verify hConsultCall
//
if (!(ptConsultCallClient = ReferenceCall(
pParams->hConsultCall,
ptClient
)))
{
lRequestID = LINEERR_INVALCALLHANDLE;
goto LAddToConference_return;
}
//
// Safely make sure calls are on same tLineClient, that client has
// owner privilege for consult call, and that the consult call
// is neither a conf parent or child (call SetCallConfList
// with an inval list to temporarily mark the call as conf'd)
//
try
{
ptConsultCall = ptConsultCallClient->ptCall;
if (ptConsultCallClient->ptLineClient !=
ptConfCallClient->ptLineClient)
{
lRequestID = LINEERR_INVALCALLHANDLE;
goto LAddToConference_dereference;
}
if (!(ptConsultCallClient->dwPrivilege & LINECALLPRIVILEGE_OWNER))
{
lRequestID = LINEERR_NOTOWNER;
goto LAddToConference_dereference;
}
if (SetCallConfList(
ptConsultCall,
(PTCONFERENCELIST) LongToPtr(0xffffffff),
FALSE
))
{
lRequestID = (pConfList->aptCalls[0] == ptConsultCall ?
LINEERR_INVALCALLHANDLE : LINEERR_INVALCALLSTATE);
goto LAddToConference_dereference;
}
hdConsultCall = ptConsultCall->hdCall;
}
myexcept
{
lRequestID = LINEERR_INVALCALLHANDLE;
goto LAddToConference_dereference;
}
//
// Set up the async request struct & call the SP
//
pAsyncRequestInfo->pfnPostProcess = LAddToConference_PostProcess;
pAsyncRequestInfo->dwParam1 = (ULONG_PTR) ptConsultCall;
pAsyncRequestInfo->dwParam2 = (ULONG_PTR) pConfList;
pParams->lResult = CallSP3(
pfnTSPI_lineAddToConference,
"lineAddToConference",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdConfCall,
(ULONG_PTR) hdConsultCall
);
LAddToConference_dereference:
DereferenceObject (ghHandleTable, pParams->hConsultCall, 1);
}
LAddToConference_return:
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"AddToConference"
);
}
void
WINAPI
LAgentSpecific(
PTCLIENT ptClient,
PLINEAGENTSPECIFIC_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
LONG lRequestID;
HANDLE hMutex;
HDRVLINE hdLine;
DWORD objectToDereference;
PTLINECLIENT ptLineClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
//
// Verify size/offset/string params given our input buffer/size
//
if (ISBADSIZEOFFSET(
dwParamsBufferSize,
0,
pParams->dwParamsSize,
pParams->dwParamsOffset,
sizeof(DWORD),
"LAgentSpecific",
"pParams->Params"
))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HLINE, // widget type
(DWORD) pParams->hLine, // client widget handle
(LPVOID) &hdLine, // provider widget handle
0, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
0, // provider func index
NULL, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptLineClient, // context
"AgentSpecific" // func name
)) > 0)
{
LONG lResult;
DWORD dwDeviceID, dwParamsSize = pParams->dwParamsSize;
PTLINECLIENT pProxy;
if ((lResult = FindProxy(
ptLineClient,
pParams->dwAddressID,
LINEPROXYREQUEST_AGENTSPECIFIC,
&pProxy,
&dwDeviceID,
0 // API ver wasn't checked in 2.0
)))
{
lRequestID = lResult;
goto LAgentSpecific_epilog;
}
//
// Save the client's buf ptr & post processing proc ptr
//
pAsyncRequestInfo->dwParam1 = pParams->hpParams;
pAsyncRequestInfo->dwParam2 = dwParamsSize;
pAsyncRequestInfo->hfnClientPostProcessProc =
pParams->hfnPostProcessProc;
//
// First check to see if there's a (local) proxy registered
// for this type of request on this line. If so, build a
// request & send it to the proxy.
//
if (pProxy)
{
LONG lResult;
PPROXYREQUESTWRAPPER pProxyRequestWrapper;
if ((lResult = CreateProxyRequest(
pProxy,
LINEPROXYREQUEST_AGENTSPECIFIC,
3 * sizeof (DWORD) + dwParamsSize,
pAsyncRequestInfo,
&pProxyRequestWrapper
)))
{
lRequestID = lResult;
goto LAgentSpecific_epilog;
}
pProxyRequestWrapper->ProxyRequest.AgentSpecific.dwAddressID =
pParams->dwAddressID;
pProxyRequestWrapper->ProxyRequest.AgentSpecific.
dwAgentExtensionIDIndex = pParams->dwAgentExtensionIDIndex;
pProxyRequestWrapper->ProxyRequest.AgentSpecific.dwSize =
dwParamsSize;
CopyMemory(
pProxyRequestWrapper->ProxyRequest.AgentSpecific.Params,
pDataBuf + pParams->dwParamsOffset,
dwParamsSize
);
if ((lResult = SendProxyRequest(
pProxy,
pProxyRequestWrapper,
pAsyncRequestInfo
)))
{
lRequestID = lResult;
goto LAgentSpecific_epilog;
}
else // success
{
pParams->lResult = (LONG) pAsyncRequestInfo->dwLocalRequestID;
}
}
//
// There's no proxy, so check to see if line is remote and
// call remotesp if so
//
else if ((GetLineLookupEntry (dwDeviceID))->bRemote)
{
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(
sizeof (ASYNCEVENTMSG) + ((dwParamsSize + 7) & 0xfffffff8)
)))
{
lRequestID = LINEERR_NOMEM;
goto LAgentSpecific_epilog;
}
pAsyncRequestInfo->pfnPostProcess = LDevSpecific_PostProcess;
pAsyncRequestInfo->dwParam3 = (ULONG_PTR) pBuf;
CopyMemory(
pBuf + sizeof (ASYNCEVENTMSG),
pDataBuf + pParams->dwParamsOffset,
dwParamsSize
);
pParams->lResult = CallSP6(
pRemoteSP->apfn[SP_LINEAGENTSPECIFIC],
"lineAgentSpecific",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdLine,
(DWORD) pParams->dwAddressID,
(DWORD) pParams->dwAgentExtensionIDIndex,
(ULONG_PTR) (pBuf + sizeof (ASYNCEVENTMSG)),
(DWORD) dwParamsSize
);
}
//
// There's no registered proxy & line is not remote, so fail
//
else
{
lRequestID = LINEERR_OPERATIONUNAVAIL;
}
}
LAgentSpecific_epilog:
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"AgentSpecific"
);
}
void
WINAPI
LAnswer(
PTCLIENT ptClient,
PLINEANSWER_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
LONG lRequestID;
HANDLE hMutex;
HDRVCALL hdCall;
TSPIPROC pfnTSPI_lineAnswer;
DWORD objectToDereference;
PTCALLCLIENT ptCallClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
//
// Verify size/offset/string params given our input buffer/size
//
if ((pParams->dwUserUserInfoOffset != TAPI_NO_DATA) &&
ISBADSIZEOFFSET(
dwParamsBufferSize,
0,
pParams->dwUserUserInfoSize,
pParams->dwUserUserInfoOffset,
sizeof(DWORD),
"LAnswerReal",
"pParams->UserUserInfo"
))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HCALL, // widget type
(DWORD) pParams->hCall, // client widget handle
(LPVOID) &hdCall, // provider widget handle
LINECALLPRIVILEGE_OWNER, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINEANSWER, // provider func index
&pfnTSPI_lineAnswer, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptCallClient, // context
"Answer" // func name
)) > 0)
{
DWORD dwAppNameSize;
LPVOID pszAppName = NULL;
PTCALL ptCall;
//
// Safely check to see if the app name associated with this call is
// NULL (meaning this is the first client to accept/answer the call),
// and if so save the app name
//
try
{
ptCall = (PTCALL) ptCallClient->ptCall;
if (ptCall->pszAppName == NULL)
{
PTLINEAPP ptLineApp;
ptLineApp = ptCallClient->ptLineClient->ptLineApp;
dwAppNameSize = ptLineApp->dwFriendlyNameSize;
if (ptLineApp->dwKey != TLINEAPP_KEY)
{
lRequestID = LINEERR_INVALCALLHANDLE;
goto LAnswer_epilog;
}
if ((pszAppName = ServerAlloc (dwAppNameSize)))
{
CopyMemory(
pszAppName,
ptLineApp->pszFriendlyName,
dwAppNameSize
);
}
}
}
myexcept
{
ServerFree (pszAppName);
lRequestID = LINEERR_INVALCALLHANDLE;
goto LAnswer_epilog;
}
if (pszAppName)
{
if (WaitForExclusivetCallAccess (ptCall, TCALL_KEY))
{
if (!ptCall->pszAppName)
{
ptCall->pszAppName = pszAppName;
ptCall->dwAppNameSize = dwAppNameSize;
pszAppName = NULL;
}
UNLOCKTCALL (ptCall);
ServerFree (pszAppName);
}
else
{
ServerFree (pszAppName);
lRequestID = LINEERR_INVALCALLHANDLE;
goto LAnswer_epilog;
}
}
pParams->lResult = CallSP4(
pfnTSPI_lineAnswer,
"lineAnswer",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdCall,
(ULONG_PTR) (pParams->dwUserUserInfoOffset == TAPI_NO_DATA ?
NULL : pDataBuf + pParams->dwUserUserInfoOffset),
(DWORD) (pParams->dwUserUserInfoOffset == TAPI_NO_DATA ?
0 : pParams->dwUserUserInfoSize)
);
}
LAnswer_epilog:
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"Answer"
);
}
void
WINAPI
LBlindTransfer(
PTCLIENT ptClient,
PLINEBLINDTRANSFER_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
LONG lRequestID;
HANDLE hMutex;
HDRVCALL hdCall;
TSPIPROC pfnTSPI_lineBlindTransfer;
DWORD objectToDereference;
PTCALLCLIENT ptCallClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
//
// Verify size/offset/string params given our input buffer/size
//
if (IsBadStringParam(
dwParamsBufferSize,
pDataBuf,
pParams->dwDestAddressOffset
))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HCALL, // widget type
(DWORD) pParams->hCall, // client widget handle
(LPVOID) &hdCall, // provider widget handle
LINECALLPRIVILEGE_OWNER, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINEBLINDTRANSFER, // provider func index
&pfnTSPI_lineBlindTransfer, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptCallClient, // context
"BlindTransfer" // func name
)) > 0)
{
pParams->lResult = CallSP4(
pfnTSPI_lineBlindTransfer,
"lineBlindTransfer",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdCall,
(ULONG_PTR) (pDataBuf + pParams->dwDestAddressOffset),
(DWORD) pParams->dwCountryCode
);
}
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"BlindTransfer"
);
}
void
WINAPI
LClose(
PTCLIENT ptClient,
PLINECLOSE_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
HDRVLINE hdLine;
DWORD objectToDereference;
PTLINECLIENT ptLineClient;
if ((pParams->lResult = LINEPROLOG(
ptClient, // tClient
ANY_RT_HLINE, // widget type
(DWORD) pParams->hLine, // client widget handle
(LPVOID) &hdLine, // provider widget handle
0, // req'd privileges (call only)
NULL, // mutex handle
NULL, // close hMutex when finished
0, // provider func index
NULL, // provider func pointer
NULL, // async request info
0, // client async request ID
&objectToDereference, // object to dereference
&ptLineClient, // context
"Close" // func name
)) == 0)
{
if (NULL != ptLineClient)
{
pParams->dwCallbackInstance = ptLineClient->OpenContext;
}
DestroytLineClient ((HLINE) pParams->hLine);
}
LINEEPILOGSYNC(
&pParams->lResult,
NULL,
FALSE,
objectToDereference,
"Close"
);
LOG((TL_TRACE, "Leaving lineClose"));
}
void
WINAPI
LCloseMSPInstance(
PTCLIENT ptClient,
PLINECLOSEMSPINSTANCE_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
HANDLE hMutex;
HDRVLINE hdLine;
TSPIPROC pfnTSPI_lineCloseMSPInstance;
DWORD objectToDereference;
PTLINECLIENT ptLineClient;
if ((pParams->lResult = LINEPROLOG(
ptClient, // tClient
ANY_RT_HLINE, // widget type
(DWORD) pParams->hLine, // client widget handle
(LPVOID) &hdLine, // provider widget handle
0, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINECLOSEMSPINSTANCE, // provider func index
&pfnTSPI_lineCloseMSPInstance, // provider func pointer
NULL, // async request info
0, // client async request ID,
&objectToDereference,
&ptLineClient,
"CloseMSPInstance" // func name
)) == 0)
{
pParams->lResult = CallSP1(
pfnTSPI_lineCloseMSPInstance,
"lineCloseMSPInstance",
SP_FUNC_SYNC,
(ULONG_PTR) (ptLineClient->hdMSPLine)
);
}
LINEEPILOGSYNC(
&pParams->lResult,
hMutex,
bCloseMutex,
objectToDereference,
"CloseMSPInstance"
);
}
void
LCompleteCall_PostProcess(
PASYNCREQUESTINFO pAsyncRequestInfo,
PASYNCEVENTMSG pAsyncEventMsg,
LPVOID *ppBuf
)
{
pAsyncEventMsg->Param3 = DWORD_CAST(pAsyncRequestInfo->dwParam1,__FILE__,__LINE__);
pAsyncEventMsg->Param4 = DWORD_CAST(pAsyncRequestInfo->dwParam2,__FILE__,__LINE__);
}
void
WINAPI
LCompleteCall(
PTCLIENT ptClient,
PLINECOMPLETECALL_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
LONG lRequestID;
HANDLE hMutex;
HDRVCALL hdCall;
TSPIPROC pfnTSPI_lineCompleteCall;
DWORD objectToDereference;
PTCALLCLIENT ptCallClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HCALL, // widget type
(DWORD) pParams->hCall, // client widget handle
(LPVOID) &hdCall, // provider widget handle
LINECALLPRIVILEGE_OWNER, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINECOMPLETECALL, // provider func index
&pfnTSPI_lineCompleteCall, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptCallClient, // context
"CompleteCall" // func name
)) > 0)
{
if (!IsOnlyOneBitSetInDWORD (pParams->dwCompletionMode) ||
(pParams->dwCompletionMode & ~AllCallComplModes)
)
{
lRequestID = LINEERR_INVALCALLCOMPLMODE;
goto LCompleteCall_epilog;
}
pAsyncRequestInfo->pfnPostProcess = LCompleteCall_PostProcess;
pAsyncRequestInfo->dwParam2 = pParams->hpdwCompletionID;
pAsyncRequestInfo->hfnClientPostProcessProc =
pParams->hfnPostProcessProc;
pParams->lResult = CallSP5(
pfnTSPI_lineCompleteCall,
"lineCompleteCall",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdCall,
(ULONG_PTR) &pAsyncRequestInfo->dwParam1,
(DWORD) pParams->dwCompletionMode,
(DWORD) pParams->dwMessageID
);
}
LCompleteCall_epilog:
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"CompleteCall"
);
}
void
LCompleteTransfer_PostProcess(
PASYNCREQUESTINFO pAsyncRequestInfo,
PASYNCEVENTMSG pAsyncEventMsg,
LPVOID *ppBuf
)
{
PTCALL ptConfCall = (PTCALL) pAsyncRequestInfo->dwParam1;
DWORD hpConfCallHandle = DWORD_CAST(pAsyncRequestInfo->dwParam2,__FILE__,__LINE__);
PTCALLCLIENT ptConfCallClient;
if (WaitForExclusivetCallAccess (ptConfCall, TINCOMPLETECALL_KEY))
{
PTCALL ptCall = (PTCALL) pAsyncRequestInfo->dwParam3,
ptCallThen,
ptConsultCall = (PTCALL) pAsyncRequestInfo->dwParam4;
HCALL hCallThen = (HCALL)pAsyncRequestInfo->dwParam5;
//
// Check to make sure this is the call we think it is (that the
// pointer wasn't freed by a previous call to lineClose/Shutdown
// and realloc'd for use as a ptCall again)
//
if (ptConfCall->hCall != hCallThen)
{
UNLOCKTCALL(ptConfCall);
goto LCompleteTransfer_PostProcess_bad_ptConfCall;
}
ptConfCallClient = ptConfCall->ptCallClients;
if (pAsyncEventMsg->Param2 == 0) // success
{
//
// Check to see if the app closed the line & left us with
// 0 call clients (in which case it'll also be taking care of
// cleaning up this tCall too)
//
if (ptConfCall->ptCallClients == NULL)
{
UNLOCKTCALL(ptConfCall);
ptConfCallClient = (PTCALLCLIENT) NULL;
if (pAsyncEventMsg->Param2 == 0)
{
pAsyncEventMsg->Param2 = LINEERR_INVALLINEHANDLE;
}
goto LCompleteTransfer_PostProcess_initMsgParams;
}
//
// Retrieve the various call IDs, then check if call
// client was destroyed by another thread (due to
// lineClose/Shutdown) while we were getting the call ID.
// If so, we'll need to clean up the tCall, since we know
// the other thread didn't do it because GetCallIDs marks
// the call as a zombie.
//
GetCallIDs (ptConfCall);
if (ptConfCall->ptCallClients == NULL)
{
goto LCompleteTransfer_PostProcess_cleanupCalls;
}
//
// Stuff the various call IDs in the var data section
// of the ASYNCEVENTMSG.
//
// Make sure to increment the dwTotalSize of the ASYNCEVENTMSG
// as appropriate. We rely on the fact that CompletionProc()
// calls us with a AsyncEventMsg buffer which is big enough to
// handle a few extra DWORDs.
//
pAsyncEventMsg->Param3 = ptConfCallClient->hCall;
pAsyncEventMsg->TotalSize += 3 * sizeof (pAsyncEventMsg->Param4);
*(&pAsyncEventMsg->Param4 + 1) = ptConfCall->dwAddressID;
*(&pAsyncEventMsg->Param4 + 2) = ptConfCall->dwCallID;
*(&pAsyncEventMsg->Param4 + 3) = ptConfCall->dwRelatedCallID;
//
// Mark the calls & conf list as valid, the release the mutex.
//
ptConfCall->dwKey = TCALL_KEY;
ptConfCallClient->dwKey = TCALLCLIENT_KEY;
ptConfCall->pConfList->dwKey = TCONFLIST_KEY;
UNLOCKTCALL(ptConfCall);
//
// Create monitor tCallClients
//
if(ptCallThen = ReferenceObject(ghHandleTable, hCallThen, TCALL_KEY))
{
if (ptCallThen == ptConfCall)
{
CreateCallMonitors (ptConfCall, FALSE);
}
DereferenceObject(ghHandleTable, hCallThen, 1);
}
}
else // error
{
LCompleteTransfer_PostProcess_cleanupCalls:
//
// Invalidate the tCall, & if there's still a tCallClient
// (might have already been destroyed by a lineClose/Shutdown
// in another thread) invalidate it too. Then unlock the
// tCall & remove the object(s) from the list(s).
//
ptConfCall->dwKey =
ptConfCall->pConfList->dwKey = INVAL_KEY;
if (ptConfCall->ptCallClients)
{
ptConfCallClient->dwKey = INVAL_KEY;
ptConfCall->lActiveFastCallClients--;
}
else
{
ptConfCallClient = NULL;
}
UNLOCKTCALL(ptConfCall);
RemoveCallFromLineList (ptConfCall);
if (ptConfCallClient)
{
DereferenceObject (ghHandleTable, ptConfCallClient->hCall, 1);
RemoveCallClientFromLineClientList (ptConfCallClient);
}
SetCallConfList (ptCall, NULL, FALSE);
SetCallConfList (ptConsultCall, NULL, FALSE);
//
// Make sure all fast call clients cleaned up before free tCall
//
while (ptConfCall->lActiveFastCallClients != 0)
{
Sleep (5);
}
ServerFree (ptConfCall->pConfList);
FreetCall (ptConfCall);
}
}
else
{
//
// If here we can assume that the call was already destroyed
// and just fail the request
//
LCompleteTransfer_PostProcess_bad_ptConfCall:
ptConfCallClient = (PTCALLCLIENT) NULL;
if (pAsyncEventMsg->Param2 == 0)
{
pAsyncEventMsg->Param2 = LINEERR_OPERATIONFAILED;
}
}
//
// Fill in the params to pass to client (important to remotesp in both
// the success & fail cases so it can either init or clean up drvCall)
//
LCompleteTransfer_PostProcess_initMsgParams:
pAsyncEventMsg->Param4 = hpConfCallHandle;
}
void
WINAPI
LCompleteTransfer(
PTCLIENT ptClient,
PLINECOMPLETETRANSFER_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex, bDereferenceConsultCall = FALSE;
LONG lRequestID;
HANDLE hMutex;
HDRVCALL hdCall;
TSPIPROC pfnTSPI_lineCompleteTransfer;
DWORD objectToDereference;
PTCALLCLIENT ptCallClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HCALL, // widget type
(DWORD) pParams->hCall, // client widget handle
(LPVOID) &hdCall, // provider widget handle
LINECALLPRIVILEGE_OWNER, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINECOMPLETETRANSFER, // provider func index
&pfnTSPI_lineCompleteTransfer, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptCallClient, // context
"CompleteTransfer" // func name
)) > 0)
{
PTCALL ptConfCall = (PTCALL) NULL, ptCall, ptConsultCall;
HCALL hConfCall = 0;
PTCALLCLIENT ptConfCallClient, ptConsultCallClient;
//
// Validate the hConsultCall
//
if (!(ptConsultCallClient = ReferenceObject(
ghHandleTable,
pParams->hConsultCall,
TCALLCLIENT_KEY
)))
{
lRequestID = LINEERR_INVALCONSULTCALLHANDLE;
goto LCompleteTransfer_return;
}
bDereferenceConsultCall = TRUE;
if (ptConsultCallClient->ptClient != ptClient)
{
lRequestID = LINEERR_INVALCONSULTCALLHANDLE;
goto LCompleteTransfer_return;
}
//
// Verify that app has owner privilege for hConsultCall
//
if (ptConsultCallClient->dwPrivilege != LINECALLPRIVILEGE_OWNER)
{
lRequestID = LINEERR_NOTOWNER;
goto LCompleteTransfer_return;
}
//
// Safely verify hCall & hConsultCall are not the same call,
// and that they are on the same tLine
//
try
{
ptCall = ptCallClient->ptCall;
ptConsultCall = ptConsultCallClient->ptCall;
if ((ptCall == ptConsultCall) ||
(ptCallClient->ptLineClient->ptLine !=
ptConsultCallClient->ptLineClient->ptLine))
{
lRequestID = LINEERR_INVALCALLHANDLE;
goto LCompleteTransfer_return;
}
}
myexcept
{
lRequestID = LINEERR_INVALCALLHANDLE;
goto LCompleteTransfer_return;
}
if (pParams->dwTransferMode == LINETRANSFERMODE_CONFERENCE)
{
LONG lResult;
PTCONFERENCELIST pConfList;
//
// Create & init a conf list
//
if (!(pConfList = ServerAlloc(
sizeof (TCONFERENCELIST) + DEF_NUM_CONF_LIST_ENTRIES *
sizeof (PTCALL)
)))
{
lRequestID = LINEERR_NOMEM;
goto LCompleteTransfer_return;
}
pConfList->dwNumTotalEntries = DEF_NUM_CONF_LIST_ENTRIES + 1;
pConfList->dwNumUsedEntries = 1;
//
// Set the tCall & tConsultCall conf list, then create
// the tConfCall & tConfCallClient
//
if ((lResult = SetCallConfList (ptCall, pConfList, FALSE)) == 0)
{
if ((lResult = SetCallConfList(
ptConsultCall,
pConfList,
FALSE
)) == 0)
{
if ((lResult = CreatetCallAndClient(
ptCallClient->ptLineClient,
&ptConfCall,
&ptConfCallClient,
NULL,
&hConfCall,
NULL
)) == 0)
{
pAsyncRequestInfo->dwParam5 = (ULONG_PTR)hConfCall;
ptConfCall->pConfList = pConfList;
pConfList->aptCalls[0] = ptConfCall;
pAsyncRequestInfo->htXxx = (ULONG_PTR) ptConfCallClient->ptLineClient->ptLine->hLine;
pAsyncRequestInfo->dwParam1 = (ULONG_PTR) ptConfCall;
pAsyncRequestInfo->dwParam2 = (ULONG_PTR) pParams->hpConfCallHandle;
pAsyncRequestInfo->dwParam3 = (ULONG_PTR) ptCall;
pAsyncRequestInfo->dwParam4 = (ULONG_PTR) ptConsultCall;
pAsyncRequestInfo->pfnPostProcess =
LCompleteTransfer_PostProcess;
goto LCompleteTransfer_callSP;
}
SetCallConfList (ptConsultCall, NULL, FALSE);
}
SetCallConfList (ptCall, NULL, FALSE);
}
//
// If here an error occured
//
ServerFree (pConfList);
lRequestID = lResult;
goto LCompleteTransfer_return;
}
else if (pParams->dwTransferMode != LINETRANSFERMODE_TRANSFER)
{
lRequestID = LINEERR_INVALTRANSFERMODE;
goto LCompleteTransfer_return;
}
LCompleteTransfer_callSP:
pAsyncRequestInfo->hfnClientPostProcessProc =
pParams->hfnPostProcessProc;
pParams->lResult = CallSP6(
pfnTSPI_lineCompleteTransfer,
"lineCompleteTransfer",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdCall,
(ULONG_PTR) ptConsultCallClient->ptCall->hdCall,
(ULONG_PTR) hConfCall,
(ULONG_PTR) (ptConfCall ? &ptConfCall->hdCall : 0),
(DWORD) pParams->dwTransferMode
);
if (ptConfCall)
{
SetDrvCallFlags(
hConfCall,
DCF_SPIRETURNED | (IS_LRESULT_NOTERROR(pParams->lResult) ?
DCF_DRVCALLVALID : 0)
);
}
}
LCompleteTransfer_return:
if (bDereferenceConsultCall)
{
DereferenceObject (ghHandleTable, pParams->hConsultCall, 1);
}
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"CompleteTransfer"
);
}
void
WINAPI
LConditionalMediaDetection(
PTCLIENT ptClient,
PLINECONDITIONALMEDIADETECTION_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
HANDLE hMutex;
HDRVLINE hdLine;
TSPIPROC pfnTSPI_lineConditionalMediaDetection;
DWORD objectToDereference;
PTLINECLIENT ptLineClient;
//
// Verify size/offset/string params given our input buffer/size
//
if (IsBadStructParam(
dwParamsBufferSize,
pDataBuf,
pParams->dwCallParamsOffset
))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if ((pParams->lResult = LINEPROLOG(
ptClient, // tClient
ANY_RT_HLINE, // widget type
(DWORD) pParams->hLine, // client widget handle
(LPVOID) &hdLine, // provider widget handle
0, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINECONDITIONALMEDIADETECTION, // provider func index
&pfnTSPI_lineConditionalMediaDetection, // provider func pointer
NULL, // async request info
0, // client async request ID
&objectToDereference, // object to dereference
&ptLineClient, // context
"ConditionalMediaDetection" // func name
)) == 0)
{
DWORD dwAPIVersion, dwSPIVersion;
LPLINECALLPARAMS pCallParams;
//
// This func only gets called by RemoteSP. Since RemoteSP
// might be down-level, we need to compare API/SPI vers
// to see if we need to munge call params (and it's good
// to validate them anyway).
//
pCallParams = (LPLINECALLPARAMS)
(pDataBuf + pParams->dwCallParamsOffset);
try
{
dwAPIVersion = ptLineClient->dwAPIVersion;
dwSPIVersion = ptLineClient->ptLine-> dwSPIVersion;
if (ptLineClient->dwKey != TLINECLIENT_KEY)
{
pParams->lResult = LINEERR_INVALLINEHANDLE;
goto LConditionalMediaDetection_epilog;
}
}
myexcept
{
pParams->lResult = LINEERR_INVALLINEHANDLE;
goto LConditionalMediaDetection_epilog;
}
if ((pParams->lResult = ValidateCallParams(
pCallParams,
&pCallParams,
dwAPIVersion,
dwSPIVersion,
pParams->dwAsciiCallParamsCodePage
)) == 0)
{
pParams->lResult = CallSP3(
pfnTSPI_lineConditionalMediaDetection,
"lineConditionalMediaDetection",
SP_FUNC_SYNC,
(ULONG_PTR) hdLine,
(DWORD) pParams->dwMediaModes,
(ULONG_PTR) pCallParams
);
if (pCallParams != (LPLINECALLPARAMS)
(pDataBuf + pParams->dwCallParamsOffset))
{
ServerFree (pCallParams);
}
}
}
LConditionalMediaDetection_epilog:
LINEEPILOGSYNC(
&pParams->lResult,
hMutex,
bCloseMutex,
objectToDereference,
"ConditionalMediaDetection"
);
}
void
LCreateAgent_PostProcess(
PASYNCREQUESTINFO pAsyncRequestInfo,
PASYNCEVENTMSG pAsyncEventMsg,
LPVOID *ppBuf
)
{
PASYNCEVENTMSG pNewAsyncEventMsg = (PASYNCEVENTMSG)
pAsyncRequestInfo->dwParam3;
CopyMemory (pNewAsyncEventMsg, pAsyncEventMsg, sizeof (ASYNCEVENTMSG));
*ppBuf = pNewAsyncEventMsg;
if (pAsyncEventMsg->Param2 == 0) // success
{
pNewAsyncEventMsg->TotalSize += ((sizeof(HAGENT) + 7) & 0xFFFFFFF8);
//
// param1 must not exceed 32 bits. use DWORD_CAST to enforce this at
// least in runtime.
//
pNewAsyncEventMsg->Param3 = DWORD_CAST(pAsyncRequestInfo->dwParam1,__FILE__,__LINE__);
pNewAsyncEventMsg->Param4 = sizeof(HAGENT);
}
}
void
WINAPI
LCreateAgent(
PTCLIENT ptClient,
PLINECREATEAGENT_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
LONG lRequestID;
HANDLE hMutex;
HDRVLINE hdLine;
DWORD objectToDereference;
PTLINECLIENT ptLineClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
//
// Verify size/offset/string params given our input buffer/size
//
if (((pParams->dwAgentIDOffset != TAPI_NO_DATA) &&
IsBadStringParam(
dwParamsBufferSize,
pDataBuf,
pParams->dwAgentIDOffset
)) ||
((pParams->dwAgentPINOffset != TAPI_NO_DATA) &&
IsBadStringParam(
dwParamsBufferSize,
pDataBuf,
pParams->dwAgentPINOffset
)))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HLINE, // widget type
(DWORD) pParams->hLine, // client widget handle
(LPVOID) &hdLine, // provider widget handle
0, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
0, // provider func index
NULL, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptLineClient, // context
"CreateAgent" // func name
)) > 0)
{
LONG lResult;
DWORD dwDeviceID;
PTLINECLIENT pProxy;
if ((lResult = FindProxy(
ptLineClient,
0,
LINEPROXYREQUEST_CREATEAGENT,
&pProxy,
&dwDeviceID,
TAPI_VERSION2_2
)))
{
lRequestID = lResult;
goto LCreateAgent_epilog;
}
//
// Save client's buffer pointer and post processing proc
//
pAsyncRequestInfo->dwParam1 = pParams->hpAgent;
pAsyncRequestInfo->dwParam2 = sizeof(HAGENT);
pAsyncRequestInfo->hfnClientPostProcessProc =
pParams->hfnPostProcessProc;
//
// First check to see if there's a (local) proxy registered
// for this type of request on this line. If so, build a
// request & send it to the proxy.
//
if (pProxy)
{
LONG lResult;
PPROXYREQUESTWRAPPER pProxyRequestWrapper;
DWORD dwAgentIDSize = 0;
DWORD dwAgentPINSize = 0;
DWORD dwTotalSize = 0;
DWORD dwOffset = 0;
//
// Figure out the total size of info we are passing to the proxy
//
if (TAPI_NO_DATA != pParams->dwAgentIDOffset)
{
dwAgentIDSize =
(lstrlenW ((PWSTR)(pDataBuf + pParams->dwAgentIDOffset))
+ 1) * sizeof(WCHAR);
dwTotalSize += dwAgentIDSize;
}
if (TAPI_NO_DATA != pParams->dwAgentPINOffset)
{
dwAgentPINSize =
(lstrlenW ((PWSTR)(pDataBuf + pParams->dwAgentPINOffset))
+ 1) * sizeof(WCHAR);
dwTotalSize += dwAgentPINSize;
}
//
// Fixed part of union part of structure
//
dwTotalSize += 4 * sizeof(DWORD) + sizeof(HAGENT);
if (lResult = CreateProxyRequest(
pProxy,
LINEPROXYREQUEST_CREATEAGENT,
dwTotalSize,
pAsyncRequestInfo,
&pProxyRequestWrapper
))
{
lRequestID = lResult;
goto LCreateAgent_epilog;
}
//
// Save the info in the proxy request
//
//
// The offset is after the fixed size of the CreateAgent
// struct which has 4 dwords and an hAgent.
//
// This will require no extra alloc on the client side
// as the thing to be returned is the hAgent
//
dwOffset = 4 * sizeof(DWORD) + sizeof(HAGENT);
//
// Copy the id if exists
//
if (0 != dwAgentIDSize)
{
pProxyRequestWrapper->ProxyRequest.CreateAgent.
dwAgentIDSize = dwAgentIDSize;
pProxyRequestWrapper->ProxyRequest.CreateAgent.
dwAgentIDOffset = dwOffset;
wcscpy(
(PWSTR)((LPBYTE)(&(pProxyRequestWrapper->
ProxyRequest.CreateAgent)) + dwOffset),
(PWSTR)(pDataBuf + pParams->dwAgentIDOffset)
);
dwOffset += dwAgentIDSize;
}
//
// Copy the pin if exists
//
if (0 != dwAgentPINSize)
{
pProxyRequestWrapper->ProxyRequest.CreateAgent.
dwAgentPINSize = dwAgentPINSize;
pProxyRequestWrapper->ProxyRequest.CreateAgent.
dwAgentPINOffset = dwOffset;
wcscpy(
(PWSTR)((LPBYTE)(&(pProxyRequestWrapper->
ProxyRequest.CreateAgent)) + dwOffset),
(PWSTR)(pDataBuf + pParams->dwAgentPINOffset)
);
}
if ((lResult = SendProxyRequest(
pProxy,
pProxyRequestWrapper,
pAsyncRequestInfo
)))
{
lRequestID = lResult;
goto LCreateAgent_epilog;
}
else // success
{
pParams->lResult = (LONG) pAsyncRequestInfo->dwLocalRequestID;
}
}
//
// There's no proxy, so check to see if line is remote and
// call remotesp if so
//
else if ((GetLineLookupEntry (dwDeviceID))->bRemote)
{
LPBYTE pBuf;
pBuf = ServerAlloc (sizeof (ASYNCEVENTMSG) + sizeof (HAGENT));
if (!pBuf)
{
lRequestID = LINEERR_NOMEM;
goto LCreateAgent_epilog;
}
pAsyncRequestInfo->pfnPostProcess =
LCreateAgent_PostProcess;
pAsyncRequestInfo->dwParam3 = (ULONG_PTR) pBuf;
pParams->lResult = CallSP5(
pRemoteSP->apfn[SP_LINECREATEAGENT],
"CreateAgent",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdLine,
(ULONG_PTR) ((pParams->dwAgentIDOffset) == TAPI_NO_DATA ?
NULL : (pDataBuf + pParams->dwAgentIDOffset)),
(ULONG_PTR) ((pParams->dwAgentPINOffset) == TAPI_NO_DATA ?
NULL : (pDataBuf + pParams->dwAgentPINOffset)),
(ULONG_PTR) (pBuf + sizeof (ASYNCEVENTMSG))
);
}
//
// No proxy and not remote
//
else
{
lRequestID = LINEERR_OPERATIONUNAVAIL;
}
}
LCreateAgent_epilog:
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"CreateAgent"
);
}
void
WINAPI
LCreateAgentSession(
PTCLIENT ptClient,
PLINECREATEAGENTSESSION_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
LONG lRequestID;
HANDLE hMutex;
HDRVLINE hdLine;
DWORD objectToDereference;
PTLINECLIENT ptLineClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
//
// Verify size/offset/string params given our input buffer/size
//
if (((pParams->dwAgentPINOffset != TAPI_NO_DATA) &&
IsBadStringParam(
dwParamsBufferSize,
pDataBuf,
pParams->dwAgentPINOffset
)) ||
ISBADSIZEOFFSET(
dwParamsBufferSize,
0,
pParams->dwGroupIDSize,
pParams->dwGroupIDOffset,
sizeof(DWORD),
"LCreateAgentSession",
"pParams->GroupID"
))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HLINE, // widget type
(DWORD) pParams->hLine, // client widget handle
(LPVOID) &hdLine, // provider widget handle
0, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
0, // provider func index
NULL, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptLineClient, // context
"CreateAgentSession" // func name
)) > 0)
{
LONG lResult;
DWORD dwDeviceID;
PTLINECLIENT pProxy;
if ((lResult = FindProxy(
ptLineClient,
pParams->dwWorkingAddressID,
LINEPROXYREQUEST_CREATEAGENTSESSION,
&pProxy,
&dwDeviceID,
TAPI_VERSION2_2
)))
{
lRequestID = lResult;
goto LCreateAgentSession_epilog;
}
//
// save client's buffer pointer and
// post processing proc
//
pAsyncRequestInfo->dwParam1 = pParams->hpAgentSessionHandle;
pAsyncRequestInfo->dwParam2 = sizeof(HAGENTSESSION);
pAsyncRequestInfo->hfnClientPostProcessProc =
pParams->hfnPostProcessProc;
//
// First check to see if there's a (local) proxy registered
// for this type of request on this line. If so, build a
// request & send it to the proxy.
//
if (pProxy)
{
LONG lResult;
PPROXYREQUESTWRAPPER pProxyRequestWrapper;
DWORD dwAgentPINSize = 0;
DWORD dwTotalSize = 0;
DWORD dwOffset = 0;
//
// figure out the total size of information
// we are passing to the proxy
//
if (TAPI_NO_DATA != pParams->dwAgentPINOffset)
{
dwAgentPINSize =
(lstrlenW( (PWSTR)(pDataBuf + pParams->dwAgentPINOffset))
+ 1 ) * sizeof(WCHAR);
}
//
// Add the union part of the CreateAgentSession request
// which looks like:
//
// struct
// {
// HAGENTSESSION hAgentSession;
// DWORD dwAgentPINSize;
// DWORD dwAgentPINOffset;
// HAGENT hAgent;
// GUID GroupID;
// DWORD dwWorkingAddressID;
//
// } CreateAgentSession;
//
dwOffset = ( 3 * sizeof(DWORD) ) + sizeof(GUID) +
sizeof(HAGENTSESSION) + sizeof(HAGENT);
dwTotalSize = dwOffset + dwAgentPINSize;
if (lResult = CreateProxyRequest(
pProxy,
LINEPROXYREQUEST_CREATEAGENTSESSION,
dwTotalSize,
pAsyncRequestInfo,
&pProxyRequestWrapper
))
{
lRequestID = lResult;
goto LCreateAgentSession_epilog;
}
//
// Save the info in the proxy request - copy the pin if exists
//
if ( 0 != dwAgentPINSize )
{
pProxyRequestWrapper->ProxyRequest.CreateAgentSession.
dwAgentPINSize = dwAgentPINSize;
pProxyRequestWrapper->ProxyRequest.CreateAgentSession.
dwAgentPINOffset = dwOffset;
wcscpy(
(PWSTR)((LPBYTE)(&(pProxyRequestWrapper->
ProxyRequest.CreateAgentSession)) + dwOffset),
(PWSTR)(pDataBuf + pParams->dwAgentPINOffset)
);
}
CopyMemory(
&(pProxyRequestWrapper->
ProxyRequest.CreateAgentSession.GroupID),
pDataBuf + pParams->dwGroupIDOffset,
sizeof( GUID )
);
pProxyRequestWrapper->ProxyRequest.CreateAgentSession.
dwWorkingAddressID = pParams->dwWorkingAddressID;
pProxyRequestWrapper->ProxyRequest.CreateAgentSession.
hAgent = pParams->hAgent;
if ((lResult = SendProxyRequest(
pProxy,
pProxyRequestWrapper,
pAsyncRequestInfo
)))
{
lRequestID = lResult;
goto LCreateAgentSession_epilog;
}
else // success
{
pParams->lResult = (LONG) pAsyncRequestInfo->dwLocalRequestID;
}
}
//
// There's no proxy, so check to see if line is remote and
// call remotesp if so
//
else if ((GetLineLookupEntry (dwDeviceID))->bRemote)
{
LPBYTE pBuf;
pBuf = ServerAlloc(sizeof(ASYNCEVENTMSG) + sizeof (HAGENTSESSION));
if ( NULL == pBuf )
{
lRequestID = LINEERR_NOMEM;
goto LCreateAgentSession_epilog;
}
pAsyncRequestInfo->pfnPostProcess =
LCreateAgent_PostProcess;
pAsyncRequestInfo->dwParam3 = (ULONG_PTR) pBuf;
pParams->lResult = CallSP7(
pRemoteSP->apfn[SP_LINECREATEAGENTSESSION],
"CreateAgentSession",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdLine,
(DWORD) pParams->hAgent,
(ULONG_PTR) ((pParams->dwAgentPINOffset) == TAPI_NO_DATA ?
NULL : (pDataBuf + pParams->dwAgentPINOffset)),
(DWORD) pParams->dwWorkingAddressID,
(ULONG_PTR) (pDataBuf + pParams->dwGroupIDOffset),
(ULONG_PTR) (pBuf + sizeof (ASYNCEVENTMSG))
);
}
//
// no proxy and not remote
//
else
{
lRequestID = LINEERR_OPERATIONUNAVAIL;
}
}
LCreateAgentSession_epilog:
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"CreateAgentSession"
);
}
void
WINAPI
LCreateMSPInstance(
PTCLIENT ptClient,
PLINECREATEMSPINSTANCE_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
HANDLE hMutex;
HDRVLINE hdLine;
TSPIPROC pfnTSPI_lineCreateMSPInstance;
DWORD objectToDereference;
PTLINECLIENT ptLineClient;
if ((pParams->lResult = LINEPROLOG(
ptClient, // tClient
ANY_RT_HLINE, // widget type
(DWORD) pParams->hLine, // client widget handle
(LPVOID) &hdLine, // provider widget handle
0, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINECREATEMSPINSTANCE, // provider func index
&pfnTSPI_lineCreateMSPInstance, // provider func pointer
NULL, // async request info
0, // client async request ID
&objectToDereference,
&ptLineClient,
"CreateMSPInstance" // func name
)) == 0)
{
pParams->lResult = CallSP4(
pfnTSPI_lineCreateMSPInstance,
"lineCreateMSPInstance",
SP_FUNC_SYNC,
(ULONG_PTR) hdLine,
(DWORD) pParams->dwAddressID,
(DWORD) ptLineClient->hLine,
(ULONG_PTR) &ptLineClient->hdMSPLine
);
if ( 0 == pParams->lResult )
{
*pdwNumBytesReturned = sizeof( LINECREATEMSPINSTANCE_PARAMS );
}
}
LINEEPILOGSYNC(
&pParams->lResult,
hMutex,
bCloseMutex,
objectToDereference,
"CreateMSPInstance"
);
}
void
WINAPI
LDeallocateCall(
PTCLIENT ptClient,
PLINEDEALLOCATECALL_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
HANDLE hMutex;
HDRVCALL hdCall;
DWORD objectToDereference;
PTCALLCLIENT ptCallClient;
if ((pParams->lResult = LINEPROLOG(
ptClient, // tClient
ANY_RT_HCALL, // widget type
(DWORD) pParams->hCall, // client widget handle
(LPVOID) &hdCall, // provider widget handle
LINECALLPRIVILEGE_MONITOR, // req'd privileges (call only)
&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
&objectToDereference, // object to dereference
&ptCallClient, // context
"DeallocateCall" // func name
)) == 0)
{
//
// Per nt bug #20546 we're now allowing the last owner to dealloc
// a non-IDLE call. Decided to do this based on distributed call
// ownership issues. dankn 02/13/96
//
DestroytCallClient (ptCallClient);
}
LINEEPILOGSYNC(
&pParams->lResult,
hMutex,
bCloseMutex,
objectToDereference,
"DeallocateCall"
);
}
void
LDevSpecific_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;
//
// need to be at most 32-bit. use dword_cast to ensure this in
// runtime
//
pNewAsyncEventMsg->Param3 = DWORD_CAST(pAsyncRequestInfo->dwParam1,__FILE__,__LINE__); // lpParams
pNewAsyncEventMsg->Param4 = DWORD_CAST(pAsyncRequestInfo->dwParam2,__FILE__,__LINE__); // dwSize
}
}
void
WINAPI
LDevSpecific(
PTCLIENT ptClient,
PLINEDEVSPECIFIC_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex, bDereferenceLineClient = FALSE;
LONG lRequestID;
DWORD dwWidgetType, hWidget;
DWORD dwPrivilege = LINECALLPRIVILEGE_MONITOR;
HANDLE hMutex;
TSPIPROC pfnTSPI_lineDevSpecific;
DWORD objectToDereference;
ULONG_PTR hdWidget;
PTCALLCLIENT ptXxxClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
//
// Verify size/offset/string params given our input buffer/size
//
if (ISBADSIZEOFFSET(
dwParamsBufferSize,
0,
pParams->dwParamsSize,
pParams->dwParamsOffset,
sizeof(DWORD),
"LDevSpecific",
"pParams->Params"
))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if (pParams->hCall)
{
dwWidgetType = ANY_RT_HCALL;
hWidget = (DWORD) pParams->hCall;
}
else
{
dwWidgetType = ANY_RT_HLINE;
hWidget = (DWORD) pParams->hLine;
}
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
dwWidgetType, // widget type
hWidget, // client widget handle
(LPVOID) &hdWidget, // provider widget handle
(pParams->hCall ? (dwPrivilege) : 0),
// req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINEDEVSPECIFIC, // provider func index
&pfnTSPI_lineDevSpecific, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptXxxClient, // context
"DevSpecific" // func name
)) > 0)
{
LPBYTE pBuf;
HDRVCALL hdCall;
HDRVLINE hdLine;
//
// If an hCall was specified verify the hLine &
// make sure the call is on the specified hLine
//
if (dwWidgetType == ANY_RT_HCALL)
{
LONG lResult;
PTLINECLIENT ptLineClient;
if (!(ptLineClient = ReferenceObject(
ghHandleTable,
pParams->hLine,
TLINECLIENT_KEY
)))
{
lRequestID = LINEERR_INVALLINEHANDLE;
goto LDevSpecific_epilog;
}
bDereferenceLineClient = TRUE;
if (ptLineClient->ptClient != ptClient)
{
lRequestID = LINEERR_INVALLINEHANDLE;
goto LDevSpecific_epilog;
}
try
{
lResult = LINEERR_INVALLINEHANDLE;
hdLine = ptLineClient->ptLine->hdLine;
lResult = LINEERR_INVALCALLHANDLE;
if (ptLineClient != ptXxxClient->ptLineClient)
{
LOG((TL_ERROR,
"LDevSpecific: error, hCall=x%x not related " \
"to hLine=x%x",
pParams->hCall,
pParams->hLine
));
lRequestID = LINEERR_INVALCALLHANDLE;
goto LDevSpecific_epilog;
}
}
myexcept
{
lRequestID = lResult;
goto LDevSpecific_epilog;
}
hdCall = (HDRVCALL) hdWidget;
}
else
{
hdLine = (HDRVLINE) hdWidget;
hdCall = 0;
}
//
// 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 = LINEERR_NOMEM;
goto LDevSpecific_epilog;
}
CopyMemory(
pBuf + sizeof (ASYNCEVENTMSG),
pDataBuf + pParams->dwParamsOffset,
pParams->dwParamsSize
);
pAsyncRequestInfo->pfnPostProcess = LDevSpecific_PostProcess;
pAsyncRequestInfo->dwParam1 = pParams->hpParams;
pAsyncRequestInfo->dwParam2 = pParams->dwParamsSize;
pAsyncRequestInfo->dwParam3 = (ULONG_PTR) pBuf;
pAsyncRequestInfo->hfnClientPostProcessProc =
pParams->hfnPostProcessProc;
pParams->lResult = CallSP6(
pfnTSPI_lineDevSpecific,
"lineDevSpecific",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdLine,
(DWORD) pParams->dwAddressID,
(ULONG_PTR) hdCall,
(ULONG_PTR) (pParams->dwParamsSize ?
pBuf + sizeof (ASYNCEVENTMSG) : NULL),
(DWORD) pParams->dwParamsSize
);
}
LDevSpecific_epilog:
if (bDereferenceLineClient)
{
DereferenceObject (ghHandleTable, pParams->hLine, 1);
}
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"DevSpecific"
);
}
void
WINAPI
LDevSpecificEx(
PTCLIENT ptClient,
PLINEDEVSPECIFICEX_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
LONG lRequestID;
DWORD dwWidgetType, hWidget;
DWORD dwPrivilege = LINECALLPRIVILEGE_MONITOR;
DWORD dwCallHubID = 0;
HANDLE hMutex;
LPVOID context;
TSPIPROC pfnTSPI_lineDevSpecificEx;
DWORD objectToDereference;
ULONG_PTR hdWidget;
PASYNCREQUESTINFO pAsyncRequestInfo;
//
// Verify size/offset/string params given our input buffer/size
//
if (ISBADSIZEOFFSET(
dwParamsBufferSize,
0,
pParams->dwParamsSize,
pParams->dwParamsOffset,
sizeof(DWORD),
"LDevSpecificEx",
"pParams->Params"
))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
switch (pParams->dwSelect)
{
case LINECALLSELECT_DEVICEID:
case LINECALLSELECT_ADDRESS:
dwWidgetType = DEVICE_ID;
hWidget = pParams->dwDeviceID;
break;
case LINECALLSELECT_CALLID:
{
PTCALLHUBCLIENT ptCallHubClient;
if (ptCallHubClient = IsValidCallHub(
pParams->hCallHub,
ptClient
))
{
try
{
dwCallHubID = ptCallHubClient->dwCallHubID;
if (ptCallHubClient->dwKey != TCALLHUBCLIENT_KEY)
{
pParams->lResult = LINEERR_INVALCALLHANDLE;
return;
}
}
myexcept
{
pParams->lResult = LINEERR_INVALCALLSELECT;
return;
}
}
}
// fall through
case LINECALLSELECT_CALL:
dwWidgetType = ANY_RT_HCALL;
hWidget = (DWORD) pParams->hCall;
break;
case LINECALLSELECT_LINE:
default:
pParams->lResult = LINEERR_INVALCALLSELECT;
return;
}
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
dwWidgetType, // widget type
hWidget, // client widget handle
(LPVOID) &hdWidget, // provider widget handle
(pParams->hCall ? (dwPrivilege) : 0),
// req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINEDEVSPECIFICEX, // provider func index
&pfnTSPI_lineDevSpecificEx, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&context, // context
"DevSpecificEx" // func name
)) > 0)
{
DWORD dwDeviceID = 0;
LPBYTE pBuf;
HDRVCALL hdCall = 0;
switch (pParams->dwSelect)
{
case LINECALLSELECT_DEVICEID:
case LINECALLSELECT_ADDRESS:
dwDeviceID = (DWORD) hdWidget;
break;
case LINECALLSELECT_CALLID:
case LINECALLSELECT_CALL:
hdCall = (HDRVCALL) hdWidget;
break;
default:
lRequestID = LINEERR_INVALCALLSELECT;
goto LDevSpecificEx_epilog;
}
//
// 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 = LINEERR_NOMEM;
goto LDevSpecificEx_epilog;
}
CopyMemory(
pBuf + sizeof (ASYNCEVENTMSG),
pDataBuf + pParams->dwParamsOffset,
pParams->dwParamsSize
);
pAsyncRequestInfo->pfnPostProcess = LDevSpecific_PostProcess;
pAsyncRequestInfo->dwParam1 = pParams->hpParams;
pAsyncRequestInfo->dwParam2 = pParams->dwParamsSize;
pAsyncRequestInfo->dwParam3 = (ULONG_PTR) pBuf;
pAsyncRequestInfo->hfnClientPostProcessProc =
pParams->hfnPostProcessProc;
pParams->lResult = CallSP8(
pfnTSPI_lineDevSpecificEx,
"lineDevSpecificEx",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(DWORD) dwDeviceID,
(DWORD) pParams->dwAddressID,
(ULONG_PTR) hdCall,
(DWORD) dwCallHubID,
(DWORD) pParams->dwSelect,
(ULONG_PTR) (pParams->dwParamsSize ?
pBuf + sizeof (ASYNCEVENTMSG) : NULL),
(DWORD) pParams->dwParamsSize
);
}
LDevSpecificEx_epilog:
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"DevSpecific"
);
}
void
WINAPI
LDevSpecificFeature(
PTCLIENT ptClient,
PLINEDEVSPECIFICFEATURE_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
LONG lRequestID;
HANDLE hMutex;
HDRVLINE hdLine;
TSPIPROC pfnTSPI_lineDevSpecificFeature;
DWORD objectToDereference;
PTLINECLIENT ptLineClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
//
// Verify size/offset/string params given our input buffer/size
//
if (ISBADSIZEOFFSET(
dwParamsBufferSize,
0,
pParams->dwParamsSize,
pParams->dwParamsOffset,
sizeof(DWORD),
"LDevSpecificFeature",
"pParams->Params"
))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HLINE, // widget type
(DWORD) pParams->hLine, // client widget handle
(LPVOID) &hdLine, // provider widget handle
0, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINEDEVSPECIFICFEATURE, // provider func index
&pfnTSPI_lineDevSpecificFeature,// provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptLineClient, // context
"DevSpecificFeature" // func name
)) > 0)
{
LPBYTE pBuf;
if (pParams->dwFeature > PHONEBUTTONFUNCTION_NONE &&
(pParams->dwFeature & 0x80000000) == 0)
{
lRequestID = LINEERR_INVALFEATURE;
goto LDevSpecificFeature_epilog;
}
//
// 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 = LINEERR_NOMEM;
goto LDevSpecificFeature_epilog;
}
CopyMemory(
pBuf + sizeof (ASYNCEVENTMSG),
pDataBuf + pParams->dwParamsOffset,
pParams->dwParamsSize
);
pAsyncRequestInfo->pfnPostProcess = LDevSpecific_PostProcess;
pAsyncRequestInfo->dwParam1 = pParams->hpParams;
pAsyncRequestInfo->dwParam2 = pParams->dwParamsSize;
pAsyncRequestInfo->dwParam3 = (ULONG_PTR) pBuf;
pAsyncRequestInfo->hfnClientPostProcessProc =
pParams->hfnPostProcessProc;
pParams->lResult = CallSP5(
pfnTSPI_lineDevSpecificFeature,
"lineDevSpecificFeature",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdLine,
(DWORD) pParams->dwFeature,
(ULONG_PTR) (pParams->dwParamsSize ?
pBuf + sizeof (ASYNCEVENTMSG) : NULL),
(DWORD) pParams->dwParamsSize
);
}
LDevSpecificFeature_epilog:
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"DevSpecificFeature"
);
}
void
WINAPI
LDial(
PTCLIENT ptClient,
PLINEDIAL_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
LONG lRequestID;
HANDLE hMutex;
HDRVCALL hdCall;
TSPIPROC pfnTSPI_lineDial;
DWORD objectToDereference;
PTCALLCLIENT ptCallClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
//
// Verify size/offset/string params given our input buffer/size
//
if (IsBadStringParam(
dwParamsBufferSize,
pDataBuf,
pParams->dwDestAddressOffset
))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HCALL, // widget type
(DWORD) pParams->hCall, // client widget handle
(LPVOID) &hdCall, // provider widget handle
LINECALLPRIVILEGE_OWNER, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINEDIAL, // provider func index
&pfnTSPI_lineDial, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptCallClient, // context
"Dial" // func name
)) > 0)
{
pParams->lResult = CallSP4(
pfnTSPI_lineDial,
"lineDial",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdCall,
(ULONG_PTR) (pDataBuf + pParams->dwDestAddressOffset),
(DWORD) pParams->dwCountryCode
);
}
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"Dial"
);
}
void
WINAPI
LDrop(
PTCLIENT ptClient,
PLINEDROP_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
LONG lRequestID;
HANDLE hMutex;
HDRVCALL hdCall;
TSPIPROC pfnTSPI_lineDrop;
DWORD objectToDereference;
PTCALLCLIENT ptCallClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
//
// Verify size/offset/string params given our input buffer/size
//
if ((pParams->dwUserUserInfoOffset != TAPI_NO_DATA) &&
ISBADSIZEOFFSET(
dwParamsBufferSize,
0,
pParams->dwSize,
pParams->dwUserUserInfoOffset,
sizeof(DWORD),
"LDrop",
"pParams->UserUserInfo"
))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HCALL, // widget type
(DWORD) pParams->hCall, // client widget handle
(LPVOID) &hdCall, // provider widget handle
LINECALLPRIVILEGE_OWNER, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINEDROP, // provider func index
&pfnTSPI_lineDrop, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptCallClient, // context
"Drop" // func name
)) > 0)
{
pParams->lResult = CallSP4(
pfnTSPI_lineDrop,
"lineDrop",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdCall,
(ULONG_PTR) (pParams->dwUserUserInfoOffset == TAPI_NO_DATA ? NULL :
pDataBuf + pParams->dwUserUserInfoOffset),
(DWORD) (pParams->dwUserUserInfoOffset == TAPI_NO_DATA ? 0 :
pParams->dwSize)
);
}
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"Drop"
);
}
LPBYTE
NewToOldLineforwardlist(
LPLINEFORWARDLIST pFwdList3_1
);
LPLINEFORWARDLIST
OldToNewLineforwardlist(
LPLINEFORWARDLIST pFwdList3_0
);
void
WINAPI
LForward(
PTCLIENT ptClient,
PLINEFORWARD_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
LONG lRequestID;
HANDLE hMutex;
HDRVLINE hdLine;
TSPIPROC pfnTSPI_lineForward;
DWORD objectToDereference;
PTLINECLIENT ptLineClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
DWORD dwSizeofLFwdList = sizeof (LINEFORWARDLIST);
DWORD dwSizeofLFwd = sizeof (LINEFORWARD);
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HLINE, // widget type
(DWORD) pParams->hLine, // client widget handle
(LPVOID) &hdLine, // provider widget handle
0, // privileges or device ID
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINEFORWARD, // provider func index
&pfnTSPI_lineForward, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptLineClient, // context
"Forward" // func name
)) > 0)
{
LONG lResult;
DWORD dwAPIVersion, dwSPIVersion;
PTCALL ptConsultCall;
HCALL hConsultCall = 0;
PTCALLCLIENT ptConsultCallClient;
LPLINECALLPARAMS pCallParamsApp, pCallParamsSP;
LPLINEFORWARDLIST pFwdList = (LPLINEFORWARDLIST)
(pParams->dwForwardListOffset == TAPI_NO_DATA ?
NULL :pDataBuf + pParams->dwForwardListOffset),
pTmpFwdList = NULL,
pTmpFwdList1 = NULL;
//
// Verify size/offset/string params given our input buffer/size
//
if (((pParams->dwForwardListOffset != TAPI_NO_DATA) &&
IsBadStructParam(
dwParamsBufferSize,
pDataBuf,
pParams->dwForwardListOffset
)) ||
((pParams->dwCallParamsOffset != TAPI_NO_DATA) &&
IsBadStructParam(
dwParamsBufferSize,
pDataBuf,
pParams->dwCallParamsOffset
)))
{
lRequestID = LINEERR_STRUCTURETOOSMALL;
goto LForward_epilog;
}
//
// Validate the params
//
if (GetLineVersions (ptLineClient, &dwAPIVersion, &dwSPIVersion) != 0)
{
lRequestID = LINEERR_INVALLINEHANDLE;
goto LForward_epilog;
}
//
// Check if the client app. is < 3.1 ===> uses old LINEFORWARD structure
//
if ( ptLineClient->ptLineApp->dwAPIVersion < TAPI_VERSION3_1 )
{
dwSizeofLFwdList -= 2 * sizeof (DWORD);
dwSizeofLFwd -= 2 * sizeof (DWORD);
}
if (pFwdList)
{
DWORD dwTotalSize = pFwdList->dwTotalSize, dwFixedSize,
dwNumEntries, i, dwInvalidForwardModes;
LPLINEFORWARD pFwdEntry = pFwdList->ForwardList;
if (dwTotalSize < dwSizeofLFwdList)
{
lRequestID = LINEERR_STRUCTURETOOSMALL;
goto LForward_epilog;
}
//
// Note: dwNumEntries == 0 is the same as pFwdList == NULL
//
dwNumEntries = pFwdList->dwNumEntries;
if (dwNumEntries & 0xffff0000)
{
lRequestID = LINEERR_INVALPARAM;
goto LForward_epilog;
}
dwFixedSize = dwSizeofLFwdList + dwSizeofLFwd *
(dwNumEntries == 0 ? 0 : dwNumEntries - 1);
if (dwFixedSize > dwTotalSize)
{
lRequestID = LINEERR_INVALPARAM;
goto LForward_epilog;
}
dwInvalidForwardModes = (dwAPIVersion < TAPI_VERSION1_4 ?
~AllForwardModes1_0 : ~AllForwardModes1_4);
for (i = 0; i < dwNumEntries; i++)
{
if (!IsOnlyOneBitSetInDWORD (pFwdEntry->dwForwardMode) ||
pFwdEntry->dwForwardMode & dwInvalidForwardModes)
{
LOG((TL_ERROR,
"LFoward: bad dwForwardMode, x%x",
pFwdEntry->dwForwardMode
));
lRequestID = LINEERR_INVALPARAM;
goto LForward_epilog;
}
if (ISBADSIZEOFFSET(
dwTotalSize,
dwFixedSize,
pFwdEntry->dwCallerAddressSize,
pFwdEntry->dwCallerAddressOffset,
0,
"LFoward",
"CallerAddress"
) ||
ISBADSIZEOFFSET(
dwTotalSize,
dwFixedSize,
pFwdEntry->dwDestAddressSize,
pFwdEntry->dwDestAddressOffset,
0,
"LFoward",
"CallerAddress"
))
{
lRequestID = LINEERR_INVALPARAM;
goto LForward_epilog;
}
// don't bother validating country code right now
pFwdEntry = (LPLINEFORWARD) ((LPBYTE)pFwdEntry + dwSizeofLFwd);
}
//
// See if we need to convert an ascii fwd list to unicode
//
if (pParams->dwAsciiCallParamsCodePage != 0xffffffff &&
dwNumEntries != 0)
{
DWORD dwXxxOffset;
//
// Alloc a temporary buffer for storing the converted
// data (sizeof(WCHAR) * dwTotalSize to insure buffer
// is large enough for all ascii->unicode conversions)
//
if (!(pTmpFwdList = ServerAlloc (sizeof(WCHAR) * dwTotalSize)))
{
lRequestID = LINEERR_NOMEM;
goto LForward_epilog;
}
dwXxxOffset = dwSizeofLFwdList +
(dwNumEntries - 1) * dwSizeofLFwd;
pFwdEntry = pTmpFwdList->ForwardList;
CopyMemory (pTmpFwdList, pFwdList, dwXxxOffset);
pTmpFwdList->dwTotalSize *= sizeof (WCHAR);
for (i = 0; i < dwNumEntries; i++)
{
if (pFwdEntry->dwCallerAddressSize)
{
MultiByteToWideChar(
pParams->dwAsciiCallParamsCodePage,
MB_PRECOMPOSED,
(LPCSTR) (((LPBYTE) pFwdList) +
pFwdEntry->dwCallerAddressOffset),
pFwdEntry->dwCallerAddressSize,
(LPWSTR) (((LPBYTE) pTmpFwdList) + dwXxxOffset),
pFwdEntry->dwCallerAddressSize
);
pFwdEntry->dwCallerAddressOffset = dwXxxOffset;
dwXxxOffset += (pFwdEntry->dwCallerAddressSize *=
sizeof (WCHAR));
}
if (pFwdEntry->dwDestAddressSize)
{
MultiByteToWideChar(
pParams->dwAsciiCallParamsCodePage,
MB_PRECOMPOSED,
(LPCSTR) (((LPBYTE) pFwdList) +
pFwdEntry->dwDestAddressOffset),
pFwdEntry->dwDestAddressSize,
(LPWSTR) (((LPBYTE) pTmpFwdList) + dwXxxOffset),
pFwdEntry->dwDestAddressSize
);
pFwdEntry->dwDestAddressOffset = dwXxxOffset;
dwXxxOffset += (pFwdEntry->dwDestAddressSize *=
sizeof (WCHAR));
}
pFwdEntry = (LPLINEFORWARD) ((LPBYTE)pFwdEntry + dwSizeofLFwd);
}
pFwdList = pTmpFwdList;
}
}
//
// Check if we need LINEFORWARDLIST conversion new to old
// if the TSP is < 3.1 ===> expects old LINEFORWARDLIST structure
// and the App is >= 3.1 ===> sent over new LINEFORWARDLIST structure
//
if ( pFwdList &&
dwSPIVersion < TAPI_VERSION3_1 &&
ptLineClient->ptLineApp->dwAPIVersion >= TAPI_VERSION3_1 )
{
if (!(pTmpFwdList1 = ( LPLINEFORWARDLIST ) NewToOldLineforwardlist (pFwdList)))
{
lRequestID = LINEERR_NOMEM;
goto LForward_freeFwdList;
}
pFwdList = pTmpFwdList1;
}
//
// Check if we need LINEFORWARDLIST conversion old to new
// if the TSP is >= 3.1 ===> expects new LINEFORWARDLIST structure
// and the App is < 3.1 ===> sent over old LINEFORWARDLIST structure
//
if ( pFwdList &&
dwSPIVersion >= TAPI_VERSION3_1 &&
ptLineClient->ptLineApp->dwAPIVersion < TAPI_VERSION3_1 )
{
if (!(pTmpFwdList1 = OldToNewLineforwardlist (pFwdList)))
{
lRequestID = LINEERR_NOMEM;
goto LForward_freeFwdList;
}
pFwdList = pTmpFwdList1;
}
pCallParamsApp = (LPLINECALLPARAMS)
(pParams->dwCallParamsOffset == TAPI_NO_DATA ? NULL :
pDataBuf + pParams->dwCallParamsOffset);
if (pCallParamsApp)
{
if ((lResult = ValidateCallParams(
pCallParamsApp,
&pCallParamsSP,
dwAPIVersion,
dwSPIVersion,
pParams->dwAsciiCallParamsCodePage
)) != 0)
{
lRequestID = lResult;
goto LForward_freeFwdList1;
}
}
else
{
pCallParamsSP = (LPLINECALLPARAMS) NULL;
}
if (CreatetCallAndClient(
ptLineClient,
&ptConsultCall,
&ptConsultCallClient,
pCallParamsSP,
&hConsultCall,
NULL
) != 0)
{
lRequestID = LINEERR_NOMEM;
goto LForward_freeCallParams;
}
//htConsultCall = ptConsultCall->htCall;
pAsyncRequestInfo->pfnPostProcess = LMakeCall_PostProcess;
pAsyncRequestInfo->htXxx = (ULONG_PTR)ptConsultCallClient->ptLineClient->ptLine->hLine;
pAsyncRequestInfo->dwParam1 = (ULONG_PTR) ptConsultCall;
pAsyncRequestInfo->dwParam2 = pParams->hpConsultCall;
pAsyncRequestInfo->dwParam3 = 1; // special case for post-process proc
pAsyncRequestInfo->dwParam5 = (ULONG_PTR)hConsultCall;
pAsyncRequestInfo->hfnClientPostProcessProc =
pParams->hfnPostProcessProc;
pParams->lResult = CallSP9(
pfnTSPI_lineForward,
"lineForward",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdLine,
(DWORD) pParams->bAllAddresses,
(DWORD) pParams->dwAddressID,
(ULONG_PTR) pFwdList,
(DWORD) pParams->dwNumRingsNoAnswer,
(ULONG_PTR) hConsultCall,
(ULONG_PTR) &ptConsultCall->hdCall,
(ULONG_PTR) pCallParamsSP
);
SetDrvCallFlags(
hConsultCall,
DCF_SPIRETURNED | (IS_LRESULT_NOTERROR(pParams->lResult) ?
DCF_DRVCALLVALID : 0)
);
LForward_freeCallParams:
if (pCallParamsSP != pCallParamsApp)
{
ServerFree (pCallParamsSP);
}
LForward_freeFwdList1:
if (pTmpFwdList1)
{
ServerFree (pTmpFwdList1);
}
LForward_freeFwdList:
if (pTmpFwdList)
{
ServerFree (pTmpFwdList);
}
}
LForward_epilog:
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"Forward"
);
}
void
WINAPI
LGatherDigits(
PTCLIENT ptClient,
PLINEGATHERDIGITS_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
HANDLE hMutex;
HDRVCALL hdCall;
TSPIPROC pfnTSPI_lineGatherDigits;
DWORD objectToDereference;
PTCALLCLIENT ptCallClient;
//
// Verify size/offset/string params given our input buffer/size
//
if ((pParams->dwTerminationDigitsOffset != TAPI_NO_DATA) &&
IsBadStringParam(
dwParamsBufferSize,
pDataBuf,
pParams->dwTerminationDigitsOffset
))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if ((pParams->lResult = LINEPROLOG(
ptClient, // tClient
ANY_RT_HCALL, // widget type
(DWORD) pParams->hCall, // client widget handle
(LPVOID) &hdCall, // provider widget handle
LINECALLPRIVILEGE_OWNER, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINEGATHERDIGITS, // provider func index
&pfnTSPI_lineGatherDigits, // provider func pointer
NULL, // async request info
0, // client async request ID
&objectToDereference, // object to dereference
&ptCallClient, // context
"GatherDigits" // func name
)) == 0)
{
DWORD dwDigitModes = pParams->dwDigitModes;
LPWSTR lpsDigits;
PASYNCREQUESTINFO pAsyncRequestInfo;
#define AllGatherDigitsModes (LINEDIGITMODE_PULSE | LINEDIGITMODE_DTMF)
if (!(dwDigitModes & AllGatherDigitsModes) ||
(dwDigitModes & ~AllGatherDigitsModes))
{
pParams->lResult = LINEERR_INVALDIGITMODE;
goto LGatherDigits_epilog;
}
if (pParams->hpsDigits)
{
//
// The client passed us a non-null digits buffer so we'll
// alloc an async request info buf with extra space at the
// end for the temporary digits buf for use by the sp
// (faster than two two allocs & two frees for separate
// async request & digits bufs). Use the pointer as the
// dwEndToEndID we pass to the sp.
//
PTLINECLIENT ptLineClient;
if (pParams->dwNumDigits == 0)
{
pParams->lResult = LINEERR_INVALPARAM;
goto LGatherDigits_epilog;
}
if (!(pAsyncRequestInfo = ServerAlloc(
sizeof (ASYNCREQUESTINFO) +
(pParams->dwNumDigits * sizeof (WCHAR))
)))
{
pParams->lResult = LINEERR_NOMEM;
goto LGatherDigits_epilog;
}
lpsDigits = (LPWSTR) (pAsyncRequestInfo + 1);
ptLineClient = ptCallClient->ptLineClient;
pAsyncRequestInfo->dwKey = TASYNC_KEY;
pAsyncRequestInfo->ptClient = ptClient;
try
{
pAsyncRequestInfo->InitContext =
ptLineClient->ptLineApp->InitContext;
pAsyncRequestInfo->OpenContext = ptLineClient->OpenContext;
}
myexcept
{
ServerFree (pAsyncRequestInfo);
pParams->lResult = LINEERR_INVALCALLHANDLE;
goto LGatherDigits_epilog;
}
pAsyncRequestInfo->dwParam1 = sizeof (ASYNCREQUESTINFO);
pAsyncRequestInfo->dwParam2 = DWORD_CAST(pParams->hpsDigits,__FILE__,__LINE__);
pAsyncRequestInfo->dwParam3 = pParams->dwNumDigits;
pAsyncRequestInfo->dwParam4 = pParams->hCall;
pAsyncRequestInfo->dwParam5 = (ULONG_PTR)pParams->dwEndToEndID;
pAsyncRequestInfo->hfnClientPostProcessProc =
pParams->hfnPostProcessProc;
pAsyncRequestInfo->dwLocalRequestID = (DWORD) NewObject(
ghHandleTable,
pAsyncRequestInfo,
NULL
);
}
else
{
//
// Client wants to cancel gathering, so just set these two to null
//
lpsDigits = NULL;
pAsyncRequestInfo = NULL;
}
if ((pParams->lResult = CallSP8(
pfnTSPI_lineGatherDigits,
"lineGatherDigits",
SP_FUNC_SYNC,
(ULONG_PTR) hdCall,
(DWORD) (pAsyncRequestInfo ?
pAsyncRequestInfo->dwLocalRequestID : 0),
(DWORD) dwDigitModes,
(ULONG_PTR) lpsDigits,
(DWORD) pParams->dwNumDigits,
(ULONG_PTR) (pParams->dwTerminationDigitsOffset ==TAPI_NO_DATA?
0 : (pDataBuf + pParams->dwTerminationDigitsOffset)),
(DWORD) pParams->dwFirstDigitTimeout,
(DWORD) pParams->dwInterDigitTimeout
)) != 0)
{
if (pAsyncRequestInfo)
{
DereferenceObject(
ghHandleTable,
pAsyncRequestInfo->dwLocalRequestID,
1
);
}
}
}
LGatherDigits_epilog:
LINEEPILOGSYNC(
&pParams->lResult,
hMutex,
bCloseMutex,
objectToDereference,
"GatherDigits"
);
}
void
WINAPI
LGenerateDigits(
PTCLIENT ptClient,
PLINEGENERATEDIGITS_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
HANDLE hMutex;
HDRVCALL hdCall;
TSPIPROC pfnTSPI_lineGenerateDigits;
DWORD objectToDereference;
PTCALLCLIENT ptCallClient;
//
// Verify size/offset/string params given our input buffer/size
//
if ((pParams->dwDigitsOffset != TAPI_NO_DATA) &&
IsBadStringParam(
dwParamsBufferSize,
pDataBuf,
pParams->dwDigitsOffset
))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if ((pParams->lResult = LINEPROLOG(
ptClient, // tClient
ANY_RT_HCALL, // widget type
(DWORD) pParams->hCall, // client widget handle
(LPVOID) &hdCall, // provider widget handle
LINECALLPRIVILEGE_OWNER, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINEGENERATEDIGITS, // provider func index
&pfnTSPI_lineGenerateDigits,// provider func pointer
NULL, // async request info
0, // client async request ID
&objectToDereference, // object to dereference
&ptCallClient, // context
"GenerateDigits" // func name
)) == 0)
{
DWORD dwDigitMode = pParams->dwDigitMode, *pInstData, dwEndToEndID = 0;
if (dwDigitMode != LINEDIGITMODE_PULSE &&
dwDigitMode != LINEDIGITMODE_DTMF)
{
pParams->lResult = LINEERR_INVALDIGITMODE;
goto LGenerateDigits_epilog;
}
if (pParams->dwDigitsOffset != TAPI_NO_DATA)
{
if (!(pInstData = ServerAlloc (3 * sizeof (DWORD))))
{
pParams->lResult = LINEERR_NOMEM;
goto LGenerateDigits_epilog;
}
pInstData[0] = TASYNC_KEY;
pInstData[1] = (DWORD) pParams->hCall;
pInstData[2] = pParams->dwEndToEndID;
dwEndToEndID = (DWORD) NewObject (ghHandleTable, pInstData, 0);
}
pParams->lResult = CallSP5(
pfnTSPI_lineGenerateDigits,
"lineGenerateDigits",
SP_FUNC_SYNC,
(ULONG_PTR) hdCall,
(DWORD) dwEndToEndID,
(DWORD) dwDigitMode,
(ULONG_PTR) (pParams->dwDigitsOffset == TAPI_NO_DATA ?
NULL : pDataBuf + pParams->dwDigitsOffset),
(DWORD) pParams->dwDuration
);
if (pParams->lResult != 0 && dwEndToEndID != 0)
{
DereferenceObject (ghHandleTable, dwEndToEndID, 1);
}
}
LGenerateDigits_epilog:
LINEEPILOGSYNC(
&pParams->lResult,
hMutex,
bCloseMutex,
objectToDereference,
"GenerateDigits"
);
}
void
WINAPI
LGenerateTone(
PTCLIENT ptClient,
PLINEGENERATETONE_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
HANDLE hMutex;
HDRVCALL hdCall;
TSPIPROC pfnTSPI_lineGenerateTone;
DWORD objectToDereference;
PTCALLCLIENT ptCallClient;
//
// Verify size/offset/string params given our input buffer/size
//
if ((pParams->dwToneMode == LINETONEMODE_CUSTOM) &&
ISBADSIZEOFFSET(
dwParamsBufferSize,
0,
pParams->dwNumTones * sizeof (LINEGENERATETONE),
pParams->dwTonesOffset,
sizeof(DWORD),
"LGenerateTone",
"pParams->Tones"
))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if ((pParams->lResult = LINEPROLOG(
ptClient, // tClient
ANY_RT_HCALL, // widget type
(DWORD) pParams->hCall, // client widget handle
(LPVOID) &hdCall, // provider widget handle
LINECALLPRIVILEGE_OWNER, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINEGENERATETONE, // provider func index
&pfnTSPI_lineGenerateTone, // provider func pointer
NULL, // async request info
0, // client async request ID
&objectToDereference, // object to dereference
&ptCallClient, // context
"GenerateTone" // func name
)) == 0)
{
DWORD dwToneMode = pParams->dwToneMode, *pInstData, dwEndToEndID;
if (dwToneMode != 0)
{
if (!(dwToneMode & AllToneModes) ||
!IsOnlyOneBitSetInDWORD (dwToneMode))
{
pParams->lResult = LINEERR_INVALTONEMODE;
goto LGenerateTone_epilog;
}
else if (!(pInstData = ServerAlloc (3 * sizeof (DWORD))))
{
pParams->lResult = LINEERR_NOMEM;
goto LGenerateTone_epilog;
}
pInstData[0] = TASYNC_KEY;
pInstData[1] = (DWORD) pParams->hCall;
pInstData[2] = pParams->dwEndToEndID;
dwEndToEndID = (DWORD) NewObject (ghHandleTable, pInstData, 0);
}
else
{
dwEndToEndID = 0;
}
pParams->lResult = CallSP6(
pfnTSPI_lineGenerateTone,
"lineGenerateTone",
SP_FUNC_SYNC,
(ULONG_PTR) hdCall,
(DWORD) dwEndToEndID,
(DWORD) pParams->dwToneMode,
(DWORD) pParams->dwDuration,
(DWORD) pParams->dwNumTones,
(ULONG_PTR) (pDataBuf + pParams->dwTonesOffset)
);
if (pParams->lResult != 0 && dwEndToEndID != 0)
{
DereferenceObject (ghHandleTable, dwEndToEndID, 1);
}
}
LGenerateTone_epilog:
LINEEPILOGSYNC(
&pParams->lResult,
hMutex,
bCloseMutex,
objectToDereference,
"GenerateTone"
);
}
void
WINAPI
LGetAddressCaps(
PTCLIENT ptClient,
PLINEGETADDRESSCAPS_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
DWORD dwDeviceID;
HANDLE hMutex;
TSPIPROC pfnTSPI_lineGetAddressCaps;
DWORD objectToDereference;
PTLINELOOKUPENTRY pLookupEntry;
//
// Verify size/offset/string params given our input buffer/size
//
if (pParams->dwAddressCapsTotalSize > dwParamsBufferSize)
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if ((pParams->lResult = LINEPROLOG(
ptClient, // tClient
DEVICE_ID, // widget type
(DWORD) pParams->hLineApp, // client widget handle
&dwDeviceID, // provider widget handle
pParams->dwDeviceID, // privileges or device ID
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINEGETADDRESSCAPS, // provider func index
&pfnTSPI_lineGetAddressCaps,// provider func pointer
NULL, // async request info
0, // client async request ID
&objectToDereference, // object to dereference
&pLookupEntry, // context
"GetAddressCaps" // func name
)) == 0)
{
DWORD dwAPIVersion, dwSPIVersion, dwTotalSize,
dwFixedSizeClient, dwFixedSizeSP;
LPLINEADDRESSCAPS pAddrCaps = (LPLINEADDRESSCAPS) pDataBuf,
pAddrCaps2 = (LPLINEADDRESSCAPS) NULL;
//
// Verify API & SPI version compatibility
//
dwAPIVersion = pParams->dwAPIVersion;
dwSPIVersion = pLookupEntry->dwSPIVersion;
if (!IsAPIVersionInRange (dwAPIVersion, dwSPIVersion))
{
pParams->lResult = LINEERR_INCOMPATIBLEAPIVERSION;
goto LGetAddressCaps_epilog;
}
//
// Verify Ext version compatibility
//
if (!IsValidLineExtVersion (dwDeviceID, pParams->dwExtVersion))
{
pParams->lResult = LINEERR_INCOMPATIBLEEXTVERSION;
goto LGetAddressCaps_epilog;
}
//
// Determine the fixed siize of the structure for the specified API
// version, verify client's buffer is big enough
//
dwTotalSize = pParams->dwAddressCapsTotalSize;
switch (dwAPIVersion)
{
case TAPI_VERSION1_0:
dwFixedSizeClient = 176; // 44 * sizeof (DWORD);
break;
case TAPI_VERSION1_4:
dwFixedSizeClient = 180; // 45 * sizeof (DWORD);
break;
default: // (fix ppc build wrn) case TAPI_VERSION_CURRENT:
dwFixedSizeClient = sizeof (LINEADDRESSCAPS);
break;
}
if (dwTotalSize < dwFixedSizeClient)
{
pParams->lResult = LINEERR_STRUCTURETOOSMALL;
goto LGetAddressCaps_epilog;
}
//
// Determine the fixed size of the structure expected by the SP
//
switch (dwSPIVersion)
{
case TAPI_VERSION1_0:
dwFixedSizeSP = 176; // 44 * sizeof (DWORD);
break;
case TAPI_VERSION1_4:
dwFixedSizeSP = 180; // 45 * sizeof (DWORD);
break;
default: // (fix ppc build wrn) case TAPI_VERSION_CURRENT:
dwFixedSizeSP = sizeof (LINEADDRESSCAPS);
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 (!(pAddrCaps2 = ServerAlloc (dwFixedSizeSP)))
{
pParams->lResult = LINEERR_NOMEM;
goto LGetAddressCaps_epilog;
}
pAddrCaps = pAddrCaps2;
dwTotalSize = dwFixedSizeSP;
}
InitTapiStruct(
pAddrCaps,
dwTotalSize,
dwFixedSizeSP,
(pAddrCaps2 == NULL ? TRUE : FALSE)
);
if ((pParams->lResult = CallSP5(
pfnTSPI_lineGetAddressCaps,
"lineGetAddressCaps",
SP_FUNC_SYNC,
(DWORD) dwDeviceID,
(DWORD) pParams->dwAddressID,
(DWORD) dwSPIVersion,
(DWORD) pParams->dwExtVersion,
(ULONG_PTR) pAddrCaps
)) == 0)
{
#if DBG
//
// Verify the info returned by the provider
//
#endif
//
// Add the fields we're responsible for
//
pAddrCaps->dwCallInfoStates |= LINECALLINFOSTATE_NUMOWNERINCR |
LINECALLINFOSTATE_NUMOWNERDECR |
LINECALLINFOSTATE_NUMMONITORS;
pAddrCaps->dwCallStates |= LINECALLSTATE_UNKNOWN;
pAddrCaps->dwLineDeviceID = pParams->dwDeviceID;
//
// Munge fields where appropriate for old apps (don't want to
// pass back flags that they won't understand)
//
if ((dwAPIVersion == TAPI_VERSION1_0) &&
(pAddrCaps->dwForwardModes &
(LINEFORWARDMODE_UNKNOWN | LINEFORWARDMODE_UNAVAIL)))
{
pAddrCaps->dwForwardModes &=
~(LINEFORWARDMODE_UNKNOWN |
LINEFORWARDMODE_UNAVAIL);
pAddrCaps->dwForwardModes |= LINEFORWARDMODE_UNCOND;
}
if ((dwAPIVersion == TAPI_VERSION2_0) &&
(pAddrCaps->dwAvailableMediaModes & LINEMEDIAMODE_VIDEO))
{
pAddrCaps->dwAvailableMediaModes = LINEMEDIAMODE_UNKNOWN |
(pAddrCaps->dwAvailableMediaModes & ~LINEMEDIAMODE_VIDEO);
}
//
// 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 (pAddrCaps == pAddrCaps2)
{
pAddrCaps = (LPLINEADDRESSCAPS) pDataBuf;
CopyMemory (pAddrCaps, pAddrCaps2, dwFixedSizeClient);
ServerFree (pAddrCaps2);
pAddrCaps->dwTotalSize = pParams->dwAddressCapsTotalSize;
pAddrCaps->dwUsedSize = dwFixedSizeClient;
}
//
// Indicate the offset & how many bytes of data we're passing back
//
pParams->dwAddressCapsOffset = 0;
*pdwNumBytesReturned = sizeof (TAPI32_MSG) +
pAddrCaps->dwUsedSize;
}
}
LGetAddressCaps_epilog:
LINEEPILOGSYNC(
&pParams->lResult,
hMutex,
bCloseMutex,
objectToDereference,
"GetAddressCaps"
);
}
void
WINAPI
LGetAddressID(
PTCLIENT ptClient,
PLINEGETADDRESSID_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
HANDLE hMutex;
HDRVLINE hdLine;
TSPIPROC pfnTSPI_lineGetAddressID;
DWORD objectToDereference;
PTLINECLIENT ptLineClient;
//
// Verify size/offset/string params given our input buffer/size
//
if (ISBADSIZEOFFSET(
dwParamsBufferSize,
0,
pParams->dwSize,
pParams->dwAddressOffset,
sizeof(DWORD),
"LGetAddressID",
"pParams->Address"
))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if ((pParams->lResult = LINEPROLOG(
ptClient, // tClient
ANY_RT_HLINE, // widget type
(DWORD) pParams->hLine, // client widget handle
(LPVOID) &hdLine, // provider widget handle
0, // privileges or device ID
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINEGETADDRESSID, // provider func index
&pfnTSPI_lineGetAddressID, // provider func pointer
NULL, // async request info
0, // client async request ID
&objectToDereference, // object to dereference
&ptLineClient, // context
"GetAddressID" // func name
)) == 0)
{
if (pParams->dwAddressMode == LINEADDRESSMODE_DIALABLEADDR)
{
pParams->lResult = CallSP5(
pfnTSPI_lineGetAddressID,
"lineGetAddressID",
SP_FUNC_SYNC,
(ULONG_PTR) hdLine,
(ULONG_PTR) &pParams->dwAddressID,
(DWORD) pParams->dwAddressMode,
(ULONG_PTR) (pDataBuf + pParams->dwAddressOffset),
(DWORD) pParams->dwSize
);
*pdwNumBytesReturned = sizeof (LINEGETADDRESSID_PARAMS);
}
else
{
pParams->lResult = LINEERR_INVALADDRESSMODE;
}
}
LINEEPILOGSYNC(
&pParams->lResult,
hMutex,
bCloseMutex,
objectToDereference,
"GetAddressID"
);
}
void
WINAPI
LGetAddressStatus(
PTCLIENT ptClient,
PLINEGETADDRESSSTATUS_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
HANDLE hMutex;
HDRVLINE hdLine;
TSPIPROC pfnTSPI_lineGetAddressStatus;
DWORD objectToDereference;
PTLINECLIENT ptLineClient;
//
// Verify size/offset/string params given our input buffer/size
//
if (pParams->dwAddressStatusTotalSize > dwParamsBufferSize)
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if ((pParams->lResult = LINEPROLOG(
ptClient, // tClient
ANY_RT_HLINE, // widget type
(DWORD) pParams->hLine, // client widget handle
(LPVOID) &hdLine, // provider widget handle
0, // privileges or device ID
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINEGETADDRESSSTATUS, // provider func index
&pfnTSPI_lineGetAddressStatus, // provider func pointer
NULL, // async request info
0, // client async request ID
&objectToDereference, // object to dereference
&ptLineClient, // context
"GetAddressStatus" // func name
)) == 0)
{
DWORD dwAPIVersion, dwSPIVersion, dwTotalSize,
dwFixedSizeClient, dwFixedSizeSP;
LPLINEADDRESSSTATUS pAddrStatus = (LPLINEADDRESSSTATUS) pDataBuf,
pAddrStatus2 = (LPLINEADDRESSSTATUS) NULL;
//
// Safely retrieve the API & SPI versions
//
if (GetLineVersions (ptLineClient, &dwAPIVersion, &dwSPIVersion) != 0)
{
pParams->lResult = LINEERR_INVALLINEHANDLE;
goto LGetAddressStatus_epilog;
}
//
// Determine the fixed size of the structure for the specified API
// version, verify client's buffer is big enough
//
dwTotalSize = pParams->dwAddressStatusTotalSize;
switch (dwAPIVersion)
{
case TAPI_VERSION1_0:
case TAPI_VERSION1_4:
dwFixedSizeClient = 64; // 16 * sizeof (DWORD)
break;
default: // (fix ppc build wrn) case TAPI_VERSION_CURRENT:
dwFixedSizeClient = sizeof (LINEADDRESSSTATUS);
break;
}
if (dwTotalSize < dwFixedSizeClient)
{
pParams->lResult = LINEERR_STRUCTURETOOSMALL;
goto LGetAddressStatus_epilog;
}
//
// Determine the fixed size of the structure expected by the SP
//
switch (dwSPIVersion)
{
case TAPI_VERSION1_0:
case TAPI_VERSION1_4:
dwFixedSizeSP = 64; // 16 * sizeof (DWORD)
break;
default: // (fix ppc build wrn) case TAPI_VERSION_CURRENT:
dwFixedSizeSP = sizeof (LINEADDRESSSTATUS);
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 (!(pAddrStatus2 = ServerAlloc (dwFixedSizeSP)))
{
pParams->lResult = LINEERR_NOMEM;
goto LGetAddressStatus_epilog;
}
pAddrStatus = pAddrStatus2;
dwTotalSize = dwFixedSizeSP;
}
InitTapiStruct(
pAddrStatus,
dwTotalSize,
dwFixedSizeSP,
(pAddrStatus2 == NULL ? TRUE : FALSE)
);
if ((pParams->lResult = CallSP3(
pfnTSPI_lineGetAddressStatus,
"lineGetAddressStatus",
SP_FUNC_SYNC,
(ULONG_PTR) hdLine,
(DWORD) pParams->dwAddressID,
(ULONG_PTR) pAddrStatus
)) == 0)
{
DWORD dwForwardNumEntries;
#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 ((dwAPIVersion == TAPI_VERSION1_0) &&
(dwForwardNumEntries = pAddrStatus->dwForwardNumEntries))
{
DWORD i;
LPLINEFORWARD pLineForward;
pLineForward = (LPLINEFORWARD) (((LPBYTE) pAddrStatus) +
pAddrStatus->dwForwardOffset);
for (i = 0; i < dwForwardNumEntries; i++, pLineForward++)
{
if (pLineForward->dwForwardMode &
(LINEFORWARDMODE_UNKNOWN | LINEFORWARDMODE_UNAVAIL))
{
pLineForward->dwForwardMode &=
~(LINEFORWARDMODE_UNKNOWN |
LINEFORWARDMODE_UNAVAIL);
pLineForward->dwForwardMode |= LINEFORWARDMODE_UNCOND;
}
}
}
//
// 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 (pAddrStatus == pAddrStatus2)
{
pAddrStatus = (LPLINEADDRESSSTATUS) pDataBuf;
CopyMemory (pAddrStatus, pAddrStatus2, dwFixedSizeClient);
ServerFree (pAddrStatus2);
pAddrStatus->dwTotalSize =
pParams->dwAddressStatusTotalSize;
pAddrStatus->dwUsedSize = dwFixedSizeClient;
}
//
// Indicate the offset & how many bytes of data we're passing back
//
pParams->dwAddressStatusOffset = 0;
*pdwNumBytesReturned = sizeof (TAPI32_MSG) +
pAddrStatus->dwUsedSize;
}
}
LGetAddressStatus_epilog:
LINEEPILOGSYNC(
&pParams->lResult,
hMutex,
bCloseMutex,
objectToDereference,
"GetAddressStatus"
);
}
void
LGetAgentXxx_PostProcess(
PASYNCREQUESTINFO pAsyncRequestInfo,
PASYNCEVENTMSG pAsyncEventMsg,
LPVOID *ppBuf
)
{
PASYNCEVENTMSG pNewAsyncEventMsg = (PASYNCEVENTMSG)
pAsyncRequestInfo->dwParam3;
CopyMemory (pNewAsyncEventMsg, pAsyncEventMsg, sizeof (ASYNCEVENTMSG));
*ppBuf = pNewAsyncEventMsg;
if (pAsyncEventMsg->Param2 == 0) // success
{
LPLINEAGENTACTIVITYLIST pActivityList = (LPLINEAGENTACTIVITYLIST)
(pNewAsyncEventMsg + 1);
pNewAsyncEventMsg->TotalSize +=
((pActivityList->dwUsedSize + 7) & 0xFFFFFFF8);
//
// param 1 must not exceed 32-bits. use DWORD_CAST to insure this in
// runtime
//
pNewAsyncEventMsg->Param3 = DWORD_CAST(pAsyncRequestInfo->dwParam1,__FILE__,__LINE__);
pNewAsyncEventMsg->Param4 = DWORD_CAST(pActivityList->dwUsedSize,__FILE__,__LINE__);
}
}
#if DBG
void
PASCAL
LGetAgentXxx(
PTCLIENT ptClient,
PLINEGETAGENTACTIVITYLIST_PARAMS pParams,
DWORD dwParamsBufferSize,
DWORD dwRequestType,
DWORD dwSPIOrdinal,
DWORD dwFixedStructSize,
char *pszFuncName
)
#else
void
PASCAL
LGetAgentXxx(
PTCLIENT ptClient,
PLINEGETAGENTACTIVITYLIST_PARAMS pParams,
DWORD dwParamsBufferSize,
DWORD dwRequestType,
DWORD dwSPIOrdinal,
DWORD dwFixedStructSize
)
#endif
{
//
// Since LGetAgentActivityList, LGetAgentGroupList, and LGetAgentStatus
// all do the same thing (& the params are more or less identical) we
// can safely condense all the functionality into this one procedure
//
BOOL bCloseMutex;
LONG lRequestID;
HANDLE hMutex;
HDRVLINE hdLine;
DWORD objectToDereference;
PTLINECLIENT ptLineClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
//
// Verify size/offset/string params given our input buffer/size
//
if (pParams->dwActivityListTotalSize > 0x40000)
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HLINE, // widget type
(DWORD) pParams->hLine, // client widget handle
(LPVOID) &hdLine, // provider widget handle
0, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
0, // provider func index
NULL, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptLineClient, // context
pszFuncName // func name
)) > 0)
{
LONG lResult;
DWORD dwDeviceID,
dwTotalSize = pParams->dwActivityListTotalSize;
PTLINECLIENT pProxy;
if (dwTotalSize < dwFixedStructSize)
{
lRequestID = LINEERR_STRUCTURETOOSMALL;
goto LGetAgentXxx_epilog;
}
if ((lResult = FindProxy(
ptLineClient,
pParams->dwAddressID,
dwRequestType,
&pProxy,
&dwDeviceID,
0 // API ver wasn't checked in 2.0
)))
{
lRequestID = lResult;
goto LGetAgentXxx_epilog;
}
//
// Save the client's buf ptr & post processing proc ptr
//
pAsyncRequestInfo->dwParam1 = pParams->hpAgentActivityList;
pAsyncRequestInfo->dwParam2 = dwTotalSize;
pAsyncRequestInfo->hfnClientPostProcessProc =
pParams->hfnPostProcessProc;
//
// First check to see if there's a (local) proxy registered
// for this type of request on this line. If so, build a
// request & send it to the proxy.
//
if (pProxy)
{
LONG lResult;
PPROXYREQUESTWRAPPER pProxyRequestWrapper;
if ((lResult = CreateProxyRequest(
pProxy,
dwRequestType,
2 * sizeof (DWORD),
pAsyncRequestInfo,
&pProxyRequestWrapper
)))
{
lRequestID = lResult;
goto LGetAgentXxx_epilog;
}
pProxyRequestWrapper->ProxyRequest.GetAgentActivityList.
dwAddressID = pParams->dwAddressID;
pProxyRequestWrapper->ProxyRequest.GetAgentActivityList.
ActivityList.dwTotalSize = dwTotalSize;
if ((lResult = SendProxyRequest(
pProxy,
pProxyRequestWrapper,
pAsyncRequestInfo
)))
{
lRequestID = lResult;
goto LGetAgentXxx_epilog;
}
else // success
{
pParams->lResult = (LONG) pAsyncRequestInfo->dwLocalRequestID;
}
}
//
// There's no proxy, so check to see if line is remote and
// call remotesp if so
//
else if ((GetLineLookupEntry (dwDeviceID))->bRemote)
{
LPBYTE pBuf;
LPLINEAGENTACTIVITYLIST pActivityList;
//
// 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(
sizeof (ASYNCEVENTMSG) + ((dwTotalSize + 7) & 0xfffffff8)
)))
{
lRequestID = LINEERR_NOMEM;
goto LGetAgentXxx_epilog;
}
pAsyncRequestInfo->pfnPostProcess =
LGetAgentXxx_PostProcess;
pAsyncRequestInfo->dwParam3 = (ULONG_PTR) pBuf;
pActivityList = (LPLINEAGENTACTIVITYLIST)
(pBuf + sizeof (ASYNCEVENTMSG));
pActivityList->dwTotalSize = dwTotalSize;
pParams->lResult = CallSP4(
pRemoteSP->apfn[dwSPIOrdinal],
pszFuncName,
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdLine,
(DWORD) pParams->dwAddressID,
(ULONG_PTR) pActivityList
);
}
//
// There's no registered proxy & line is not remote, so fail
//
else
{
lRequestID = LINEERR_OPERATIONUNAVAIL;
}
}
LGetAgentXxx_epilog:
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
pszFuncName
);
}
#if DBG
void
PASCAL
LGetAgentWithoutAddressIDXxx(
PTCLIENT ptClient,
PLINEGETAGENTINFO_PARAMS pParams,
DWORD dwParamsBufferSize,
DWORD dwRequestType,
DWORD dwSPIOrdinal,
DWORD dwFixedStructSize,
char *pszFuncName
)
#else
void
PASCAL
LGetAgentWithoutAddressIDXxx(
PTCLIENT ptClient,
PLINEGETAGENTINFO_PARAMS pParams,
DWORD dwParamsBufferSize,
DWORD dwRequestType,
DWORD dwSPIOrdinal,
DWORD dwFixedStructSize
)
#endif
{
BOOL bCloseMutex;
LONG lRequestID;
HANDLE hMutex;
HDRVLINE hdLine;
DWORD objectToDereference;
PTLINECLIENT ptLineClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
//
// Verify size/offset/string params given our input buffer/size
//
if (pParams->dwAgentInfoTotalSize > 0x40000)
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HLINE, // widget type
(DWORD) pParams->hLine, // client widget handle
(LPVOID) &hdLine, // provider widget handle
0, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
0, // provider func index
NULL, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptLineClient, // context
pszFuncName // func name
)) > 0)
{
LONG lResult;
DWORD dwDeviceID,
dwTotalSize = pParams->dwAgentInfoTotalSize;
PTLINECLIENT pProxy;
if (dwTotalSize < dwFixedStructSize)
{
lRequestID = LINEERR_STRUCTURETOOSMALL;
goto LGetAgentWithoutAddressIDXxx_epilog;
}
if ((lResult = FindProxy(
ptLineClient,
0,
dwRequestType,
&pProxy,
&dwDeviceID,
TAPI_VERSION2_2
)))
{
lRequestID = lResult;
goto LGetAgentWithoutAddressIDXxx_epilog;
}
//
// Save the client's buf ptr & post processing proc ptr
//
pAsyncRequestInfo->dwParam1 = pParams->hpAgentInfo;
pAsyncRequestInfo->dwParam2 = dwTotalSize;
pAsyncRequestInfo->hfnClientPostProcessProc =
pParams->hfnPostProcessProc;
//
// First check to see if there's a (local) proxy registered
// for this type of request on this line. If so, build a
// request & send it to the proxy.
//
if (pProxy)
{
LONG lResult;
PPROXYREQUESTWRAPPER pProxyRequestWrapper;
if ((lResult = CreateProxyRequest(
pProxy,
dwRequestType,
2 * sizeof (DWORD),
pAsyncRequestInfo,
&pProxyRequestWrapper
)))
{
lRequestID = lResult;
goto LGetAgentWithoutAddressIDXxx_epilog;
}
pProxyRequestWrapper->ProxyRequest.GetAgentInfo.
hAgent = pParams->hAgent;
pProxyRequestWrapper->ProxyRequest.GetAgentInfo.
AgentInfo.dwTotalSize = dwTotalSize;
if ((lResult = SendProxyRequest(
pProxy,
pProxyRequestWrapper,
pAsyncRequestInfo
)))
{
lRequestID = lResult;
goto LGetAgentWithoutAddressIDXxx_epilog;
}
else // success
{
pParams->lResult = (LONG) pAsyncRequestInfo->dwLocalRequestID;
}
}
//
// There's no proxy, so check to see if line is remote and
// call remotesp if so
//
else if ((GetLineLookupEntry (dwDeviceID))->bRemote)
{
LPBYTE pBuf;
LPLINEAGENTINFO pAgentInfo;
//
// 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(
sizeof (ASYNCEVENTMSG) + ((dwTotalSize + 7) & 0xfffffff8)
)))
{
lRequestID = LINEERR_NOMEM;
goto LGetAgentWithoutAddressIDXxx_epilog;
}
pAsyncRequestInfo->pfnPostProcess =
LGetAgentXxx_PostProcess;
pAsyncRequestInfo->dwParam3 = (ULONG_PTR) pBuf;
pAgentInfo = (LPLINEAGENTINFO)
(pBuf + sizeof (ASYNCEVENTMSG));
pAgentInfo->dwTotalSize = dwTotalSize;
pParams->lResult = CallSP4(
pRemoteSP->apfn[dwSPIOrdinal],
pszFuncName,
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdLine,
(DWORD) pParams->hAgent,
(ULONG_PTR) pAgentInfo
);
}
//
// There's no registered proxy & line is not remote, so fail
//
else
{
lRequestID = LINEERR_OPERATIONUNAVAIL;
}
}
LGetAgentWithoutAddressIDXxx_epilog:
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
pszFuncName
);
}
void
WINAPI
LGetAgentActivityList(
PTCLIENT ptClient,
PLINEGETAGENTACTIVITYLIST_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
LGetAgentXxx(
ptClient,
pParams,
dwParamsBufferSize,
LINEPROXYREQUEST_GETAGENTACTIVITYLIST,
SP_LINEGETAGENTACTIVITYLIST,
sizeof (LINEAGENTACTIVITYLIST)
#if DBG
,
"GetAgentActivityList"
#endif
);
}
void
WINAPI
LGetAgentCaps(
PTCLIENT ptClient,
PLINEGETAGENTCAPS_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex, bProxy = FALSE;
LONG lRequestID;
DWORD dwDeviceID;
HANDLE hMutex;
DWORD objectToDereference;
PTLINELOOKUPENTRY pLookupEntry;
PASYNCREQUESTINFO pAsyncRequestInfo;
//
// Verify size/offset/string params given our input buffer/size
//
if (pParams->dwAgentCapsTotalSize > dwParamsBufferSize)
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
DEVICE_ID, // widget type
(DWORD) pParams->hLineApp, // client widget handle
&dwDeviceID, // provider widget handle
pParams->dwDeviceID, // privileges or device ID
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
0, // provider func index
NULL, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&pLookupEntry, // context
"GetAgentCaps" // func name
)) > 0)
{
DWORD dwTotalSize = pParams->dwAgentCapsTotalSize;
PTLINE ptLine;
PTLINECLIENT pProxy = NULL;
DWORD dwFixedSize = 0;
switch (pParams->dwAppAPIVersion)
{
case TAPI_VERSION2_0:
case TAPI_VERSION2_1:
dwFixedSize = 14 * sizeof(DWORD);
break;
case TAPI_VERSION2_2:
case TAPI_VERSION3_0:
case TAPI_VERSION3_1:
dwFixedSize = sizeof(LINEAGENTCAPS);
break;
default:
//
// Any other version is too low or invalid
//
lRequestID = LINEERR_INCOMPATIBLEAPIVERSION;
goto LGetAgentCaps_epilog;
}
if (dwTotalSize < dwFixedSize)
{
lRequestID = LINEERR_STRUCTURETOOSMALL;
goto LGetAgentCaps_epilog;
}
//
// Save the client's buf ptr & post processing proc ptr
//
pAsyncRequestInfo->dwParam1 = pParams->hpAgentCaps;
pAsyncRequestInfo->dwParam2 = dwTotalSize;
pAsyncRequestInfo->hfnClientPostProcessProc =
pParams->hfnPostProcessProc;
try
{
if (!(ptLine = pLookupEntry->ptLine))
{
// If ptLine is NULL, the line has not been
// open by any app on the local machine; this means
// that there's no proxy on the local machine; however,
// if the line is a remote one (i.e., exposed by remotesp),
// there could be a proxy on another machine. So get out
// of this try block and continue to check for remote line
// (pProxy is already initialized to NULL).
leave;
}
pProxy = ptLine->apProxys[LINEPROXYREQUEST_GETAGENTCAPS];
if (pParams->dwAddressID >= ptLine->dwNumAddresses)
{
lRequestID = LINEERR_INVALADDRESSID;
goto LGetAgentCaps_epilog;
}
if (ptLine->dwKey != TLINE_KEY)
{
lRequestID = LINEERR_INVALLINEHANDLE;
goto LGetAgentCaps_epilog;
}
}
myexcept
{
lRequestID = LINEERR_OPERATIONUNAVAIL;
goto LGetAgentCaps_epilog;
}
if (pProxy)
{
LONG lResult;
PPROXYREQUESTWRAPPER pProxyRequestWrapper;
bProxy = TRUE;
if ((lResult = CreateProxyRequest(
pProxy,
LINEPROXYREQUEST_GETAGENTCAPS,
2 * sizeof(DWORD),
pAsyncRequestInfo,
&pProxyRequestWrapper
)))
{
lRequestID = lResult;
goto LGetAgentCaps_epilog;
}
pProxyRequestWrapper->ProxyRequest.GetAgentCaps.dwAddressID =
pParams->dwAddressID;
pProxyRequestWrapper->ProxyRequest.GetAgentCaps.
AgentCaps.dwTotalSize = dwTotalSize;
if ((lResult = SendProxyRequest(
pProxy,
pProxyRequestWrapper,
pAsyncRequestInfo
)))
{
lRequestID = lResult;
goto LGetAgentCaps_epilog;
}
else // success
{
pParams->lResult = (LONG)
pAsyncRequestInfo->dwLocalRequestID;
}
}
else if (pLookupEntry->bRemote)
{
LPBYTE pBuf;
LPLINEAGENTCAPS pCaps;
bProxy = TRUE;
//
// 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(
sizeof (ASYNCEVENTMSG) + ((dwTotalSize + 7) & 0xfffffff8)
)))
{
lRequestID = LINEERR_NOMEM;
goto LGetAgentCaps_epilog;
}
pAsyncRequestInfo->pfnPostProcess =
LGetAgentXxx_PostProcess;
pAsyncRequestInfo->dwParam3 = (ULONG_PTR) pBuf;
pCaps = (LPLINEAGENTCAPS) (pBuf + sizeof (ASYNCEVENTMSG));
pCaps->dwTotalSize = dwTotalSize;
// Note: RemoteSP comes up with it's own hLineApp
pParams->lResult = CallSP5(
pRemoteSP->apfn[SP_LINEGETAGENTCAPS],
"lineGetAgentCaps",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(DWORD) dwDeviceID,
(DWORD) pParams->dwAddressID,
(DWORD) pParams->dwAppAPIVersion,
(ULONG_PTR) pCaps
);
}
//
// There's no registered proxy & line is not remote, so fail
//
if (!bProxy)
{
lRequestID = LINEERR_OPERATIONUNAVAIL;
}
}
LGetAgentCaps_epilog:
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"GetAgentCaps"
);
}
void
WINAPI
LGetAgentGroupList(
PTCLIENT ptClient,
PLINEGETAGENTGROUPLIST_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
LGetAgentXxx(
ptClient,
(PLINEGETAGENTACTIVITYLIST_PARAMS) pParams,
dwParamsBufferSize,
LINEPROXYREQUEST_GETAGENTGROUPLIST,
SP_LINEGETAGENTGROUPLIST,
sizeof (LINEAGENTGROUPLIST)
#if DBG
,
"GetAgentGroupList"
#endif
);
}
void
WINAPI
LGetAgentInfo(
PTCLIENT ptClient,
PLINEGETAGENTINFO_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
LGetAgentWithoutAddressIDXxx(
ptClient,
pParams,
dwParamsBufferSize,
LINEPROXYREQUEST_GETAGENTINFO,
SP_LINEGETAGENTINFO,
sizeof (LINEAGENTINFO)
#if DBG
,
"GetAgentInfo"
#endif
);
}
void
WINAPI
LGetAgentSessionInfo(
PTCLIENT ptClient,
PLINEGETAGENTSESSIONINFO_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
LGetAgentWithoutAddressIDXxx(
ptClient,
(PLINEGETAGENTINFO_PARAMS) pParams,
dwParamsBufferSize,
LINEPROXYREQUEST_GETAGENTSESSIONINFO,
SP_LINEGETAGENTSESSIONINFO,
sizeof (LINEAGENTSESSIONINFO)
#if DBG
,
"GetAgentSessionInfo"
#endif
);
}
void
WINAPI
LGetAgentSessionList(
PTCLIENT ptClient,
PLINEGETAGENTSESSIONLIST_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
LGetAgentWithoutAddressIDXxx(
ptClient,
(PLINEGETAGENTINFO_PARAMS) pParams,
dwParamsBufferSize,
LINEPROXYREQUEST_GETAGENTSESSIONLIST,
SP_LINEGETAGENTSESSIONLIST,
sizeof (LINEAGENTSESSIONLIST)
#if DBG
,
"GetAgentSessionList"
#endif
);
}
void
WINAPI
LGetAgentStatus(
PTCLIENT ptClient,
PLINEGETAGENTSTATUS_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
LGetAgentXxx(
ptClient,
(PLINEGETAGENTACTIVITYLIST_PARAMS) pParams,
dwParamsBufferSize,
LINEPROXYREQUEST_GETAGENTSTATUS,
SP_LINEGETAGENTSTATUS,
sizeof (LINEAGENTSTATUS)
#if DBG
,
"GetAgentStatus"
#endif
);
}
void
WINAPI
LGetAppPriority(
PTCLIENT ptClient,
PLINEGETAPPPRIORITY_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
DWORD dwMediaMode = pParams->dwMediaMode,
dwRequestMode = pParams->dwRequestMode;
DWORD dwCount;
//
// Verify size/offset/string params given our input buffer/size
//
if (IsBadStringParam(
dwParamsBufferSize,
pDataBuf,
pParams->dwAppNameOffset
) ||
((pParams->dwExtensionIDOffset != TAPI_NO_DATA) &&
((pParams->dwExtensionIDOffset + sizeof (LINEEXTENSIONID)) >
dwParamsBufferSize)) ||
((pParams->dwExtensionNameTotalSize != TAPI_NO_DATA) &&
(pParams->dwExtensionNameTotalSize > dwParamsBufferSize)))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if (dwMediaMode == 0)
{
if ((dwRequestMode != LINEREQUESTMODE_MAKECALL) &&
(dwRequestMode != LINEREQUESTMODE_MEDIACALL))
{
pParams->lResult = LINEERR_INVALREQUESTMODE;
goto LGetAppPriority_return;
}
}
else if ( 0xFF000000 & dwMediaMode )
{
// ignore
}
else if ( dwMediaMode & ~AllMediaModes2_1 )
{
pParams->lResult = LINEERR_INVALMEDIAMODE;
goto LGetAppPriority_return;
}
if ((dwMediaMode & 0x00ffffff) || (dwMediaMode == 0))
{
WCHAR szModuleName[MAX_PATH];
WCHAR *pszCurrentPriorityList = NULL;
WCHAR *pszLocationInPriorityList;
szModuleName[0] = '"';
wcsncpy(szModuleName + 1,
(PWSTR)(pDataBuf + pParams->dwAppNameOffset),
MAX_PATH - 2);
szModuleName[MAX_PATH - 1] = '\0';
_wcsupr( szModuleName + 1 );
//
// Enter the pri list critical section before we start looking
//
EnterCriticalSection (&gPriorityListCritSec);
//
// Determine which of the priority lists we want to look at
//
if (dwMediaMode)
{
for(
dwCount = 0;
dwCount < TapiGlobals.dwUsedPriorityLists;
dwCount++
)
{
if (dwMediaMode == TapiGlobals.pPriLists[dwCount].dwMediaModes)
{
pszCurrentPriorityList =
TapiGlobals.pPriLists[dwCount].pszPriList;
break;
}
}
}
else
{
pszCurrentPriorityList = (dwRequestMode == LINEREQUESTMODE_MAKECALL
? TapiGlobals.pszReqMakeCallPriList :
TapiGlobals.pszReqMediaCallPriList);
}
if (pszCurrentPriorityList &&
(pszLocationInPriorityList = wcsstr(
pszCurrentPriorityList,
szModuleName
)))
{
//
// App is in pri list, determine it's position
//
WCHAR *p = pszCurrentPriorityList + 1; // skip first '"'
DWORD i;
for (i = 1; pszLocationInPriorityList > p; i++)
{
p = wcschr(p, '"');
p++;
}
pParams->dwPriority = i;
}
else
{
//
// App not listed in formal priority list, so just return 0
//
// Note: TAPI 1.4 said that if app was in soft pri list
// (i.e. had line open with OWNER priv for specified
// media mode) then we'd return -1 instead of 0.
// But that's a pain to figure out, & we figured no
// one was going to use that info anyway, so we settled
// for always returning 0.
//
pParams->dwPriority = 0;
}
//
// Leave list critical section now that we're done
//
LeaveCriticalSection (&gPriorityListCritSec);
*pdwNumBytesReturned = sizeof (LINEGETAPPPRIORITY_PARAMS);
}
LGetAppPriority_return:
LOG((TL_TRACE,
"LineEpilogSync (lineGetAppPriority) exit, returning x%x",
pParams->lResult
));
}
void
WINAPI
LGetCallAddressID(
PTCLIENT ptClient,
PLINEGETCALLADDRESSID_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
PTCALLCLIENT ptCallClient;
if (TapiGlobals.dwNumLineInits == 0)
{
pParams->lResult = LINEERR_UNINITIALIZED;
goto LGetCallAddressID_exit;
}
if (!(ptCallClient = ReferenceCall (pParams->hCall, ptClient)))
{
pParams->lResult = LINEERR_INVALCALLHANDLE;
goto LGetCallAddressID_exit;
}
try
{
pParams->dwAddressID = ptCallClient->ptCall->dwAddressID;
if (ptCallClient->dwKey != TCALLCLIENT_KEY)
{
pParams->lResult = LINEERR_INVALCALLHANDLE;
}
}
except (EXCEPTION_EXECUTE_HANDLER)
{
pParams->lResult = LINEERR_INVALCALLHANDLE;
}
DereferenceObject (ghHandleTable, pParams->hCall, 1);
if (pParams->lResult == 0)
{
*pdwNumBytesReturned = sizeof (LINEGETCALLADDRESSID_PARAMS);
}
LGetCallAddressID_exit:
#if DBG
{
char szResult[32];
LOG((TL_TRACE,
"lineGetCallAddressID: exit, result=%s",
MapResultCodeToText (pParams->lResult, szResult)
));
}
#else
LOG((TL_TRACE,
"lineGetCallAddressID: exit, result=x%x",
pParams->lResult
));
#endif
return;
}
void
WINAPI
LGetCallHubTracking(
PTCLIENT ptClient,
PLINEGETCALLHUBTRACKING_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
HANDLE hMutex;
HDRVLINE hdLine;
TSPIPROC pfnTSPI_lineGetCallHubTracking;
DWORD objectToDereference;
PTLINECLIENT ptLineClient;
//
// Verify size/offset/string params given our input buffer/size
//
if (pParams->dwTrackingInfoTotalSize > dwParamsBufferSize)
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if ((pParams->lResult = LINEPROLOG(
ptClient, // tClient
ANY_RT_HLINE, // widget type
(DWORD) pParams->hLine, // client widget handle
(LPVOID) &hdLine, // provider widget handle
0, // privileges or device ID
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINEGETCALLHUBTRACKING, // provider func index
&pfnTSPI_lineGetCallHubTracking,// provider func pointer
NULL, // async request info
0, // client async request ID
&objectToDereference, // object to dereference
&ptLineClient, // context
"GetCallHubTracking" // func name
)) == 0 ||
(pParams->lResult == LINEERR_OPERATIONUNAVAIL))
{
LPLINECALLHUBTRACKINGINFO pTrackingInfo =
(LPLINECALLHUBTRACKINGINFO) pDataBuf;
if (pParams->lResult == LINEERR_OPERATIONUNAVAIL)
{
pParams->lResult = 0;
pfnTSPI_lineGetCallHubTracking = (TSPIPROC) NULL;
}
if (pParams->dwTrackingInfoTotalSize <
sizeof (LINECALLHUBTRACKINGINFO))
{
pParams->lResult = LINEERR_STRUCTURETOOSMALL;
goto LGetCallHubTracking_epilog;
}
InitTapiStruct(
pTrackingInfo,
pParams->dwTrackingInfoTotalSize,
sizeof (LINECALLHUBTRACKINGINFO),
TRUE
);
if (!pfnTSPI_lineGetCallHubTracking ||
(pParams->lResult = CallSP2(
pfnTSPI_lineGetCallHubTracking,
"lineGetCallHubTracking",
SP_FUNC_SYNC,
(ULONG_PTR) hdLine,
(ULONG_PTR) pTrackingInfo
)) == 0)
{
try
{
pTrackingInfo->dwCurrentTracking =
ptLineClient->dwCurrentTracking;
}
except (EXCEPTION_EXECUTE_HANDLER)
{
pParams->lResult = LINEERR_INVALLINEHANDLE;
goto LGetCallHubTracking_epilog;
}
pTrackingInfo->dwAvailableTracking |=
LINECALLHUBTRACKING_ALLCALLS;
pParams->dwTrackingInfoOffset = 0;
*pdwNumBytesReturned = sizeof (TAPI32_MSG) +
pTrackingInfo->dwUsedSize;
}
}
LGetCallHubTracking_epilog:
LINEEPILOGSYNC(
&pParams->lResult,
hMutex,
bCloseMutex,
objectToDereference,
"GetCallHubTracking"
);
}
void
WINAPI
LGetCallIDs(
PTCLIENT ptClient,
PLINEGETCALLIDS_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
PTCALLCLIENT ptCallClient;
if (TapiGlobals.dwNumLineInits == 0)
{
pParams->lResult = LINEERR_UNINITIALIZED;
goto LGetCallIDs_exit;
}
if (!(ptCallClient = ReferenceCall (pParams->hCall, ptClient)))
{
pParams->lResult = LINEERR_INVALCALLHANDLE;
goto LGetCallIDs_exit;
}
try
{
pParams->dwAddressID = ptCallClient->ptCall->dwAddressID;
pParams->dwCallID = ptCallClient->ptCall->dwCallID;
pParams->dwRelatedCallID = ptCallClient->ptCall->dwRelatedCallID;
if (ptCallClient->dwKey != TCALLCLIENT_KEY)
{
pParams->lResult = LINEERR_INVALCALLHANDLE;
}
}
except (EXCEPTION_EXECUTE_HANDLER)
{
pParams->lResult = LINEERR_INVALCALLHANDLE;
}
DereferenceObject (ghHandleTable, pParams->hCall, 1);
if (pParams->lResult == 0)
{
*pdwNumBytesReturned = sizeof (LINEGETCALLIDS_PARAMS);
}
LGetCallIDs_exit:
#if DBG
{
char szResult[32];
LOG((TL_TRACE,
"lineGetCallIDs: exit, result=%s",
MapResultCodeToText (pParams->lResult, szResult)
));
}
#else
LOG((TL_TRACE,
"lineGetCallIDs: exit, result=x%x",
pParams->lResult
));
#endif
return;
}
void
WINAPI
LGetCallInfo(
PTCLIENT ptClient,
PLINEGETCALLINFO_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
HANDLE hMutex;
HDRVCALL hdCall;
TSPIPROC pfnTSPI_lineGetCallInfo;
DWORD objectToDereference;
PTCALLCLIENT ptCallClient;
//
// Verify size/offset/string params given our input buffer/size
//
if (pParams->dwCallInfoTotalSize > dwParamsBufferSize)
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if ((pParams->lResult = LINEPROLOG(
ptClient, // tClient
ANY_RT_HCALL, // widget type
(DWORD) pParams->hCall, // client widget handle
(LPVOID) &hdCall, // provider widget handle
LINECALLPRIVILEGE_MONITOR, // privileges or device ID
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINEGETCALLINFO, // provider func index
&pfnTSPI_lineGetCallInfo, // provider func pointer
NULL, // async request info
0, // client async request ID
&objectToDereference, // object to dereference
&ptCallClient, // context
"GetCallInfo" // func name
)) == 0)
{
DWORD dwAPIVersion, dwSPIVersion, dwTotalSize,
dwFixedSizeClient, dwFixedSizeSP;
PTCALL ptCall;
LPLINECALLINFO pCallInfo = (LPLINECALLINFO) pDataBuf,
pCallInfo2 = (LPLINECALLINFO) NULL;
//
// Safely retrieve the API & SPI versions, etc
//
try
{
ptCall = ptCallClient->ptCall;
dwAPIVersion = ptCallClient->ptLineClient->dwAPIVersion;
dwSPIVersion = ((PTLINE) ptCallClient->ptLineClient->ptLine)
->dwSPIVersion;
if (ptCallClient->dwKey != TCALLCLIENT_KEY)
{
pParams->lResult = LINEERR_INVALCALLHANDLE;
goto LGetCallInfo_epilog;
}
}
myexcept
{
pParams->lResult = LINEERR_INVALCALLHANDLE;
goto LGetCallInfo_epilog;
}
//
// Determine the fixed size of the structure for the specified API
// version, verify client's buffer is big enough
//
dwTotalSize = pParams->dwCallInfoTotalSize;
switch (dwAPIVersion)
{
case TAPI_VERSION1_0:
case TAPI_VERSION1_4:
dwFixedSizeClient = 296; // 69 * sizeof(DWORD) + sizeof (HLINE)
// + sizeof (LINEDIALPARAMS)
break;
case TAPI_VERSION2_0:
case TAPI_VERSION2_1:
case TAPI_VERSION2_2:
dwFixedSizeClient = 324; // 76 * sizeof(DWORD) + sizeof (HLINE)
// + sizeof (LINEDIALPARAMS)
break;
default: // (fix ppc build wrn) case TAPI_VERSION_CURRENT:
dwFixedSizeClient = sizeof (LINECALLINFO);
break;
}
if (dwTotalSize < dwFixedSizeClient)
{
pParams->lResult = LINEERR_STRUCTURETOOSMALL;
goto LGetCallInfo_epilog;
}
//
// Determine the fixed size of the structure expected by the SP
//
switch (dwSPIVersion)
{
case TAPI_VERSION1_0:
case TAPI_VERSION1_4:
dwFixedSizeSP = 296; // 69 * sizeof(DWORD) + sizeof (HLINE)
// + sizeof (LINEDIALPARAMS)
break;
case TAPI_VERSION2_0:
case TAPI_VERSION2_1:
case TAPI_VERSION2_2:
dwFixedSizeSP = 324; // 76 * sizeof(DWORD) + sizeof (HLINE)
// + sizeof (LINEDIALPARAMS)
break;
default: // (fix ppc build wrn) case TAPI_VERSION_CURRENT:
dwFixedSizeSP = sizeof (LINECALLINFO);
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 (!(pCallInfo2 = ServerAlloc (dwFixedSizeSP)))
{
pParams->lResult = LINEERR_NOMEM;
goto LGetCallInfo_epilog;
}
pCallInfo = pCallInfo2;
dwTotalSize = dwFixedSizeSP;
}
InitTapiStruct(
pCallInfo,
dwTotalSize,
dwFixedSizeSP,
(pCallInfo2 == NULL ? TRUE : FALSE)
);
if ((pParams->lResult = CallSP2(
pfnTSPI_lineGetCallInfo,
"lineGetCallInfo",
SP_FUNC_SYNC,
(ULONG_PTR) hdCall,
(ULONG_PTR) pCallInfo
)) == 0)
{
//
// Safely add the fields we're responsible for
//
try
{
pCallInfo->hLine = (HLINE) ptCallClient->ptLineClient->hLine;
pCallInfo->dwMonitorDigitModes =
ptCallClient->dwMonitorDigitModes;
pCallInfo->dwMonitorMediaModes =
ptCallClient->dwMonitorMediaModes;
pCallInfo->dwNumOwners = ptCall->dwNumOwners;
pCallInfo->dwNumMonitors = ptCall->dwNumMonitors;
InsertVarData(
pCallInfo,
&pCallInfo->dwAppNameSize,
ptCall->pszAppName,
ptCall->dwAppNameSize
);
InsertVarData(
pCallInfo,
&pCallInfo->dwDisplayableAddressSize,
ptCall->pszDisplayableAddress,
ptCall->dwDisplayableAddressSize
);
InsertVarData(
pCallInfo,
&pCallInfo->dwCalledPartySize,
ptCall->pszCalledParty,
ptCall->dwCalledPartySize
);
InsertVarData(
pCallInfo,
&pCallInfo->dwCommentSize,
ptCall->pszComment,
ptCall->dwCommentSize
);
if (ptCallClient->dwKey != TCALLCLIENT_KEY)
{
pParams->lResult = LINEERR_INVALCALLHANDLE;
}
}
myexcept
{
pParams->lResult = LINEERR_INVALCALLHANDLE;
}
pCallInfo->dwCallStates |= LINECALLSTATE_UNKNOWN;
#if TELE_SERVER
// if it's a server, map the device id
if ((TapiGlobals.dwFlags & TAPIGLOBALS_SERVER) &&
!IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR))
{
DWORD dwCount;
// if we fall out of this for loop, the id just
// doesn't get updated
for(
dwCount = 0;
dwCount < ptClient->dwLineDevices;
dwCount++
)
{
if (ptClient->pLineDevices[dwCount] ==
pCallInfo->dwLineDeviceID)
{
pCallInfo->dwLineDeviceID = dwCount;
break;
}
}
}
#endif
//
// Munge fields where appropriate for old apps (don't want to
// pass back flags that they won't understand)
//
if (dwAPIVersion == TAPI_VERSION1_0)
{
if (pCallInfo->dwOrigin & LINECALLORIGIN_INBOUND)
{
pCallInfo->dwOrigin = LINECALLORIGIN_UNAVAIL;
}
if ((pCallInfo->dwReason &
(LINECALLREASON_INTRUDE | LINECALLREASON_PARKED)))
{
pCallInfo->dwReason = LINECALLREASON_UNAVAIL;
}
}
//
// 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 (pCallInfo == pCallInfo2)
{
pCallInfo = (LPLINECALLINFO) pDataBuf;
CopyMemory (pCallInfo, pCallInfo2, dwFixedSizeClient);
ServerFree (pCallInfo2);
pCallInfo->dwTotalSize = pParams->dwCallInfoTotalSize;
pCallInfo->dwUsedSize = dwFixedSizeClient;
}
//
// Indicate the offset & how many bytes of data we're passing back
//
if (pParams->lResult == 0)
{
pParams->dwCallInfoOffset = 0;
*pdwNumBytesReturned = sizeof (TAPI32_MSG) +
pCallInfo->dwUsedSize;
}
}
}
LGetCallInfo_epilog:
LINEEPILOGSYNC(
&pParams->lResult,
hMutex,
bCloseMutex,
objectToDereference,
"GetCallInfo"
);
}
void
WINAPI
LGetCallStatus(
PTCLIENT ptClient,
PLINEGETCALLSTATUS_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
HANDLE hMutex;
HDRVCALL hdCall;
TSPIPROC pfnTSPI_lineGetCallStatus;
DWORD objectToDereference;
PTCALLCLIENT ptCallClient;
//
// Verify size/offset/string params given our input buffer/size
//
if (pParams->dwCallStatusTotalSize > dwParamsBufferSize)
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if ((pParams->lResult = LINEPROLOG(
ptClient, // tClient
ANY_RT_HCALL, // widget type
(DWORD) pParams->hCall, // client widget handle
(LPVOID) &hdCall, // provider widget handle
LINECALLPRIVILEGE_MONITOR, // privileges or device ID
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINEGETCALLSTATUS, // provider func index
&pfnTSPI_lineGetCallStatus, // provider func pointer
NULL, // async request info
0, // client async request ID
&objectToDereference, // object to dereference
&ptCallClient, // context
"GetCallStatus" // func name
)) == 0)
{
DWORD dwAPIVersion, dwSPIVersion, dwTotalSize,
dwFixedSizeClient, dwFixedSizeSP, dwPrivilege;
LPLINECALLSTATUS pCallStatus = (LPLINECALLSTATUS) pDataBuf,
pCallStatus2 = (LPLINECALLSTATUS) NULL;
//
// Safely retrieve the API & SPI versions
//
try
{
dwAPIVersion = ptCallClient->ptLineClient->dwAPIVersion;
dwSPIVersion = ((PTLINE) ptCallClient->ptLineClient->ptLine)
->dwSPIVersion;
dwPrivilege = ptCallClient->dwPrivilege;
if (ptCallClient->dwKey != TCALLCLIENT_KEY)
{
pParams->lResult = LINEERR_INVALCALLHANDLE;
goto LGetCallStatus_epilog;
}
}
myexcept
{
pParams->lResult = LINEERR_INVALCALLHANDLE;
goto LGetCallStatus_epilog;
}
//
// Determine the fixed siize of the structure for the specified API
// version, verify client's buffer is big enough
//
dwTotalSize = pParams->dwCallStatusTotalSize;
switch (dwAPIVersion)
{
case TAPI_VERSION1_0:
case TAPI_VERSION1_4:
dwFixedSizeClient = 36; // 9 * sizeof (DWORD)
break;
default: // (fix ppc build wrn) case TAPI_VERSION_CURRENT:
dwFixedSizeClient = sizeof (LINECALLSTATUS);
break;
}
if (dwTotalSize < dwFixedSizeClient)
{
pParams->lResult = LINEERR_STRUCTURETOOSMALL;
goto LGetCallStatus_epilog;
}
//
// Determine the fixed size of the structure expected by the SP
//
switch (dwSPIVersion)
{
case TAPI_VERSION1_0:
case TAPI_VERSION1_4:
dwFixedSizeSP = 36; // 9 * sizeof (DWORD)
break;
default: // (fix ppc build wrn) case TAPI_VERSION_CURRENT:
dwFixedSizeSP = sizeof (LINECALLSTATUS);
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 (!(pCallStatus2 = ServerAlloc (dwFixedSizeSP)))
{
pParams->lResult = LINEERR_NOMEM;
goto LGetCallStatus_epilog;
}
pCallStatus = pCallStatus2;
dwTotalSize = dwFixedSizeSP;
}
InitTapiStruct(
pCallStatus,
dwTotalSize,
dwFixedSizeSP,
(pCallStatus2 == NULL ? TRUE : FALSE)
);
if ((pParams->lResult = CallSP2(
pfnTSPI_lineGetCallStatus,
"lineGetCallStatus",
SP_FUNC_SYNC,
(ULONG_PTR) hdCall,
(ULONG_PTR) pCallStatus
)) == 0)
{
#if DBG
//
// Verify the info returned by the provider
//
#endif
//
// Add the fields we're responsible for
//
pCallStatus->dwCallPrivilege = dwPrivilege;
if (dwSPIVersion < TAPI_VERSION2_0 &&
dwAPIVersion >= TAPI_VERSION2_0)
{
GetSystemTime (&pCallStatus->tStateEntryTime);
}
//
// 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 (pCallStatus == pCallStatus2)
{
pCallStatus = (LPLINECALLSTATUS) pDataBuf;
CopyMemory (pCallStatus, pCallStatus2, dwFixedSizeClient);
ServerFree (pCallStatus2);
pCallStatus->dwTotalSize = pParams->dwCallStatusTotalSize;
pCallStatus->dwUsedSize = dwFixedSizeClient;
}
//
// Indicate the offset & how many bytes of data we're passing back
//
pParams->dwCallStatusOffset = 0;
*pdwNumBytesReturned = sizeof (TAPI32_MSG) +
pCallStatus->dwUsedSize;
}
}
LGetCallStatus_epilog:
LINEEPILOGSYNC(
&pParams->lResult,
hMutex,
bCloseMutex,
objectToDereference,
"GetCallStatus"
);
}
void
WINAPI
LGetConfRelatedCalls(
PTCLIENT ptClient,
PLINEGETCONFRELATEDCALLS_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
DWORD dwTotalSize = pParams->dwCallListTotalSize;
PTCALLCLIENT ptCallClient;
PTLINECLIENT ptLineClient;
LPLINECALLLIST pCallList = (LPLINECALLLIST) pDataBuf;
TPOINTERLIST confCallList, *pConfCallList = &confCallList;
PTCONFERENCELIST pConfList;
//
// Verify size/offset/string params given our input buffer/size
//
if (pParams->dwCallListTotalSize > dwParamsBufferSize)
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if (TapiGlobals.dwNumLineInits == 0)
{
pParams->lResult = LINEERR_UNINITIALIZED;
return;
}
if (dwTotalSize < sizeof (LINECALLLIST))
{
pParams->lResult = LINEERR_STRUCTURETOOSMALL;
return;
}
if (!(ptCallClient = ReferenceCall (pParams->hCall, ptClient)))
{
pParams->lResult = LINEERR_INVALCALLHANDLE;
return;
}
try
{
ptLineClient = ptCallClient->ptLineClient;
if (!(pConfList = ptCallClient->ptCall->pConfList) ||
(pConfList == (PTCONFERENCELIST) LongToPtr(0xffffffff)))
{
pParams->lResult = LINEERR_NOCONFERENCE;
}
}
myexcept
{
pParams->lResult = LINEERR_INVALCALLHANDLE;
}
DereferenceObject (ghHandleTable, pParams->hCall, 1);
if (pParams->lResult != 0)
{
return;
}
if ((pParams->lResult = GetConfCallListFromConf(
pConfList,
&pConfCallList
)) != 0)
{
return;
}
{
DWORD dwNeededSize = sizeof (LINECALLLIST) +
pConfCallList->dwNumUsedEntries * sizeof (HCALL);
if (dwTotalSize < dwNeededSize)
{
pCallList->dwNeededSize = dwNeededSize;
pCallList->dwUsedSize = sizeof (LINECALLLIST);
FillMemory (&pCallList->dwCallsNumEntries, 3 * sizeof (DWORD), 0);
goto LGetConfRelatedCalls_fillInList;
}
}
//
// For each call in the conf list see if the app has a
// call client (if not create one w/ monitor privileges)
// and add it to the list
//
{
DWORD dwNumCallsInList = 0, i;
LPHCALL lphCallsInList = (LPHCALL) (pCallList + 1);
for (i = 0; i < pConfCallList->dwNumUsedEntries; i++)
{
PTCALL ptCall = pConfCallList->aEntries[i];
if (WaitForExclusivetCallAccess (ptCall, TCALL_KEY))
{
ptCallClient = ptCall->ptCallClients;
while (ptCallClient &&
(ptCallClient->ptLineClient != ptLineClient))
{
ptCallClient = ptCallClient->pNextSametCall;
}
if (!ptCallClient)
{
LONG lResult;
if ((lResult = CreatetCallClient(
ptCall,
ptLineClient,
LINECALLPRIVILEGE_MONITOR,
TRUE,
TRUE,
&ptCallClient,
FALSE
)))
{
// Skip...
UNLOCKTCALL(ptCall);
continue;
}
}
*(lphCallsInList++) = ptCallClient->hCall;
dwNumCallsInList++;
UNLOCKTCALL(ptCall);
}
}
pCallList->dwUsedSize =
pCallList->dwNeededSize = sizeof (LINECALLLIST) +
dwNumCallsInList * sizeof (HCALL);
pCallList->dwCallsNumEntries = dwNumCallsInList;
pCallList->dwCallsSize = dwNumCallsInList * sizeof (HCALL);
pCallList->dwCallsOffset = sizeof (LINECALLLIST);
}
LGetConfRelatedCalls_fillInList:
if (pConfCallList != &confCallList)
{
ServerFree (pConfCallList);
}
pCallList->dwTotalSize = dwTotalSize;
pParams->dwCallListOffset = 0;
*pdwNumBytesReturned = sizeof (TAPI32_MSG) + pCallList->dwUsedSize;
#if DBG
{
char szResult[32];
LOG((TL_TRACE,
"lineGetConfRelatedCalls: exit, result=%s",
MapResultCodeToText (pParams->lResult, szResult)
));
}
#else
LOG((TL_TRACE,
"lineGetConfRelatedCalls: exit, result=x%x",
pParams->lResult
));
#endif
}
void
WINAPI
LGetCountry(
PTCLIENT ptClient,
PLINEGETCOUNTRY_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
LPLINECOUNTRYLIST pCountryList = (LPLINECOUNTRYLIST) pDataBuf;
LPLINECOUNTRYLIST pCountries = NULL;
//
// Verify size/offset/string params given our input buffer/size
//
if (pParams->dwCountryListTotalSize > dwParamsBufferSize)
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if (pParams->dwCountryListTotalSize < sizeof (LINECOUNTRYLIST))
{
pParams->lResult = LINEERR_STRUCTURETOOSMALL;
}
else
{
BuildCountryListCache();
if (pParams->dwCountryID == 0)
{
//
// Client wants entire country list
//
if (RPC_S_OK != RpcImpersonateClient(0))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
pCountries = BuildCountryList();
RpcRevertToSelf();
if (NULL == pCountries)
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if (pParams->dwCountryListTotalSize >= pCountries->dwNeededSize)
{
CopyMemory(
pCountryList,
pCountries,
pCountries->dwUsedSize
);
}
else
{
pCountryList->dwNeededSize = pCountries->dwNeededSize;
pCountryList->dwUsedSize = sizeof(LINECOUNTRYLIST);
pCountryList->dwNumCountries = 0;
pCountryList->dwCountryListSize = 0;
pCountryList->dwCountryListOffset = 0;
}
*pdwNumBytesReturned = sizeof (TAPI32_MSG) +
pCountryList->dwUsedSize;
pCountryList->dwTotalSize = pParams->dwCountryListTotalSize;
ServerFree(pCountries);
}
else
{
//
// Caller wants single country
//
LPLINECOUNTRYLIST pBuildCountryList;
if ( NULL == ( pBuildCountryList = ServerAlloc( sizeof(LINECOUNTRYLIST) +
sizeof(LINECOUNTRYENTRY) +
((MAXLEN_NAME +
MAXLEN_RULE +
MAXLEN_RULE +
MAXLEN_RULE +
100) * sizeof(WCHAR))
) ) )
{
LOG((TL_ERROR, "Alloc failed for countrylist"));
pParams->lResult = LINEERR_NOMEM;
}
else
{
LPLINECOUNTRYENTRY pCountryEntrySource;
LPLINECOUNTRYENTRY pCountryEntryDest;
pCountryEntryDest = (LPLINECOUNTRYENTRY)((PBYTE)pBuildCountryList +
sizeof(LINECOUNTRYLIST));
//
// search through the gpCountryList looking for the entry
//
pCountryEntrySource = (LPLINECOUNTRYENTRY)((PBYTE)gpCountryList +
sizeof(LINECOUNTRYLIST));
while (
(pCountryEntrySource->dwCountryID != pParams->dwCountryID )
&&
(pCountryEntrySource->dwNextCountryID)
)
{
pCountryEntrySource++;
}
if ( pCountryEntrySource->dwCountryID != pParams->dwCountryID )
{
LOG((TL_ERROR, "Invalid Countrycode (%ld) in lineGetCountry",
pParams->dwCountryID));
pParams->lResult = LINEERR_INVALCOUNTRYCODE;
}
else
{
PBYTE pCountryListToUse;
PBYTE pVarOffset;
PBYTE pOverrideList = NULL;
DWORD dwNeededSize;
DWORD dwResourceId;
DWORD dwNameSize;
WCHAR sz[MAXLEN_NAME];
//
// Is the caller calling a specific country that there might be
// an override for?
//
if ( pParams->dwDestCountryID != 0 )
{
HKEY hKey;
HKEY hKey2;
TCHAR p[256];
wsprintf(
p,
TEXT("Country List\\%ld\\Exceptions\\%ld"),
pParams->dwCountryID,
pParams->dwDestCountryID
);
//
// Is there an exception?
//
if (0 == RegOpenKeyEx (HKEY_LOCAL_MACHINE, gszRegKeyTelephony, 0, KEY_READ, &hKey2) &&
0 == RegOpenKeyEx (hKey2, p, 0, KEY_READ, &hKey))
{
PBYTE pVarOffset;
pOverrideList = ServerAlloc(
sizeof(LINECOUNTRYLIST) +
sizeof(LINECOUNTRYENTRY) +
((MAXLEN_NAME +
MAXLEN_RULE +
MAXLEN_RULE +
MAXLEN_RULE +
100) * sizeof(WCHAR))
);
if (!pOverrideList)
{
ServerFree (pBuildCountryList);
RegCloseKey (hKey2);
RegCloseKey (hKey);
pParams->lResult = LINEERR_NOMEM;
return;
}
pCountryListToUse = pOverrideList;
pCountryEntrySource = (LPLINECOUNTRYENTRY)
(pOverrideList +
sizeof(LINECOUNTRYLIST));
pVarOffset = pOverrideList +
sizeof(LINECOUNTRYLIST) +
sizeof(LINECOUNTRYENTRY);
FillupACountryEntry(
hKey,
pCountryListToUse,
pCountryEntrySource,
&pVarOffset
);
RegCloseKey( hKey );
}
else
{
//
// No, we tried, but there was no exception.
//
pCountryListToUse = (PBYTE)gpCountryList;
}
RegCloseKey( hKey2);
}
else
{
pCountryListToUse = (PBYTE)gpCountryList;
}
//
// Fill in the buffer
//
dwNeededSize = sizeof(LINECOUNTRYLIST) +
sizeof(LINECOUNTRYENTRY);
pVarOffset = (LPBYTE)pCountryEntryDest +
sizeof(LINECOUNTRYENTRY);
//
// The name field has the resource string ID
// Need to load the actual string based on current user's language
//
CopyMemory(
&dwResourceId,
pCountryListToUse + pCountryEntrySource->dwCountryNameOffset,
sizeof(DWORD)
);
if (RPC_S_OK != RpcImpersonateClient(0))
{
ServerFree (pBuildCountryList);
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if (0 == LoadStringW(
ghInstance,
dwResourceId,
sz,
ARRAYSIZE(sz)
)
)
{
RpcRevertToSelf();
ServerFree (pBuildCountryList);
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
RpcRevertToSelf();
dwNameSize = (wcslen(sz) + 1) * sizeof(WCHAR);
CopyMemory(
pVarOffset,
(LPBYTE)sz,
dwNameSize
);
pCountryEntryDest->dwCountryNameSize = dwNameSize;
pCountryEntryDest->dwCountryNameOffset =
(DWORD) (pVarOffset - (LPBYTE) pBuildCountryList);
pVarOffset += dwNameSize;
dwNeededSize += dwNameSize;
CopyMemory(
pVarOffset,
pCountryListToUse +
pCountryEntrySource->dwSameAreaRuleOffset,
pCountryEntrySource->dwSameAreaRuleSize
);
pCountryEntryDest->dwSameAreaRuleSize =
pCountryEntrySource->dwSameAreaRuleSize;
pCountryEntryDest->dwSameAreaRuleOffset =
(DWORD) (pVarOffset - (LPBYTE) pBuildCountryList);
pVarOffset += pCountryEntrySource->dwSameAreaRuleSize;
dwNeededSize += pCountryEntrySource->dwSameAreaRuleSize;
CopyMemory(
pVarOffset,
pCountryListToUse +
pCountryEntrySource->dwLongDistanceRuleOffset,
pCountryEntrySource->dwLongDistanceRuleSize
);
pCountryEntryDest->dwLongDistanceRuleSize =
pCountryEntrySource->dwLongDistanceRuleSize;
pCountryEntryDest->dwLongDistanceRuleOffset =
(DWORD) (pVarOffset - (LPBYTE) pBuildCountryList);
pVarOffset += pCountryEntrySource->dwLongDistanceRuleSize;
dwNeededSize += pCountryEntrySource->dwLongDistanceRuleSize;
CopyMemory(
pVarOffset,
pCountryListToUse +
pCountryEntrySource->dwInternationalRuleOffset,
pCountryEntrySource->dwInternationalRuleSize
);
pCountryEntryDest->dwInternationalRuleSize =
pCountryEntrySource->dwInternationalRuleSize;
pCountryEntryDest->dwInternationalRuleOffset =
(DWORD) (pVarOffset - (LPBYTE) pBuildCountryList);
pVarOffset += pCountryEntrySource->dwInternationalRuleSize;
dwNeededSize += pCountryEntrySource->dwInternationalRuleSize;
//
// Is there room to put this country's info?
//
if (pParams->dwCountryListTotalSize >= dwNeededSize)
{
pCountryList->dwUsedSize = dwNeededSize;
pCountryList->dwNumCountries = 1;
pCountryList->dwCountryListSize = sizeof(LINECOUNTRYENTRY);
pCountryList->dwCountryListOffset = sizeof(LINECOUNTRYLIST);
pCountryEntryDest->dwCountryID = pParams->dwCountryID;
pCountryEntryDest->dwCountryCode =
pCountryEntrySource->dwCountryCode;
pCountryEntryDest->dwNextCountryID =
pCountryEntrySource->dwNextCountryID;
CopyMemory(
(LPBYTE)pCountryList + sizeof(LINECOUNTRYLIST),
(LPBYTE)pBuildCountryList + sizeof(LINECOUNTRYLIST),
pCountryList->dwUsedSize - sizeof(LINECOUNTRYLIST)
);
}
else
{
//
// Buffer not large enough
//
pCountryList->dwUsedSize = sizeof(LINECOUNTRYLIST);
pCountryList->dwNumCountries = 0;
pCountryList->dwCountryListSize = 0;
pCountryList->dwCountryListOffset = 0;
}
pCountryList->dwNeededSize = dwNeededSize;
pCountryList->dwTotalSize = pParams->dwCountryListTotalSize;
*pdwNumBytesReturned = sizeof (TAPI32_MSG) +
pCountryList->dwUsedSize;
//
// Did we have a "special" case?
//
if ( pOverrideList )
{
ServerFree( pOverrideList );
}
}
ServerFree( pBuildCountryList );
}
}
}
pParams->dwCountryListOffset = 0;
#if DBG
{
char szResult[32];
LOG((TL_TRACE,
"lineGetCountry: exit, result=%s",
MapResultCodeToText (pParams->lResult, szResult)
));
}
#else
LOG((TL_TRACE,
"lineGetCountry: exit, result=x%x",
pParams->lResult
));
#endif
}
void
WINAPI
LGetCountryGroups(
PTCLIENT ptClient,
PLINEGETCOUNTRYGROUP_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
DWORD dwCount, dwIdx, dwIdx1;
BOOL bFoundAll = TRUE;
DWORD * pCountryGroups = NULL;
DWORD * pCountryID;
LPLINECOUNTRYENTRY pCountryEntry;
//
// Verify size/offset/string params given our input buffer/size
//
if (pParams->dwCountryIdSize > dwParamsBufferSize ||
0 == pParams->dwCountryIdSize ||
pParams->dwCountryIdSize > pParams->dwCountryGroupSize
)
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
dwCount = pParams->dwCountryIdSize / sizeof(DWORD);
BuildCountryListCache();
if (NULL == gpCountryGroups)
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
ASSERT( NULL != gpCountryList );
pCountryGroups = ServerAlloc (pParams->dwCountryIdSize);
if (NULL == pCountryGroups)
{
pParams->lResult = LINEERR_NOMEM;
return;
}
pCountryID = (DWORD*)(pDataBuf + pParams->dwCountryIdOffset);
for( dwIdx = 0; dwIdx < dwCount; dwIdx++, pCountryID++ )
{
// find the country
pCountryEntry = (LPLINECOUNTRYENTRY)
((LPBYTE) gpCountryList + gpCountryList->dwCountryListOffset);
for( dwIdx1 = 0; dwIdx1 < gpCountryList->dwNumCountries; dwIdx1++, pCountryEntry++ )
{
if (pCountryEntry->dwCountryID == *pCountryID)
{
pCountryGroups[ dwIdx ] = gpCountryGroups[ dwIdx1 ];
break;
}
}
if (dwIdx1 == gpCountryList->dwNumCountries)
{
LOG((TL_ERROR, "Invalid CountryID (%ld) in lineGetCountryGroup",
pCountryEntry->dwCountryID));
bFoundAll = FALSE;
break;
}
}
if (bFoundAll)
{
pParams->dwCountryGroupOffset = pParams->dwCountryIdOffset;
pParams->dwCountryGroupSize = pParams->dwCountryIdSize;
memset( pDataBuf + pParams->dwCountryGroupOffset, 0, pParams->dwCountryGroupSize );
CopyMemory(
pDataBuf + pParams->dwCountryGroupOffset,
pCountryGroups,
pParams->dwCountryIdSize
);
*pdwNumBytesReturned = sizeof (TAPI32_MSG) +
pParams->dwCountryGroupOffset +
pParams->dwCountryGroupSize;
}
else
{
pParams->lResult = LINEERR_OPERATIONFAILED;
}
ServerFree (pCountryGroups);
#if DBG
{
char szResult[32];
LOG((TL_TRACE,
"LGetCountryGroups: exit, result=%s",
MapResultCodeToText (pParams->lResult, szResult)
));
}
#else
LOG((TL_TRACE,
"LGetCountryGroups: exit, result=x%x",
pParams->lResult
));
#endif
}
void
WINAPI
LGetDevCaps(
PTCLIENT ptClient,
PLINEGETDEVCAPS_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
DWORD dwDeviceID;
HANDLE hMutex;
TSPIPROC pfnTSPI_lineGetDevCaps;
DWORD objectToDereference;
PTLINELOOKUPENTRY pLookupEntry;
//
// Verify size/offset/string params given our input buffer/size
//
if (pParams->dwDevCapsTotalSize > dwParamsBufferSize)
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if ((pParams->lResult = LINEPROLOG(
ptClient, // tClient
DEVICE_ID, // widget type
(DWORD) pParams->hLineApp, // client widget handle
&dwDeviceID, // provider widget handle
pParams->dwDeviceID, // privileges or device ID
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINEGETDEVCAPS, // provider func index
&pfnTSPI_lineGetDevCaps, // provider func pointer
NULL, // async request info
0, // client async request ID
&objectToDereference, // object to dereference
&pLookupEntry, // context
"GetDevCaps" // func name
)) == 0)
{
DWORD dwAPIVersion, dwSPIVersion, dwTotalSize,
dwFixedSizeClient, dwFixedSizeSP;
LPLINEDEVCAPS pDevCaps = (LPLINEDEVCAPS) pDataBuf,
pDevCaps2 = (LPLINEDEVCAPS) NULL;
//
// Verify API & SPI version compatibility
//
dwAPIVersion = pParams->dwAPIVersion;
dwSPIVersion = pLookupEntry->dwSPIVersion;
if (!IsAPIVersionInRange (dwAPIVersion, dwSPIVersion))
{
pParams->lResult = LINEERR_INCOMPATIBLEAPIVERSION;
goto LGetDevCaps_epilog;
}
//
// Verify Ext version compatibility
//
if (!IsValidLineExtVersion (dwDeviceID, pParams->dwExtVersion))
{
pParams->lResult = LINEERR_INCOMPATIBLEEXTVERSION;
goto LGetDevCaps_epilog;
}
//
// Determine the fixed size of the structure for the specified API
// version, verify client's buffer is big enough
//
dwTotalSize = pParams->dwDevCapsTotalSize;
switch (dwAPIVersion)
{
case TAPI_VERSION1_0:
dwFixedSizeClient = 236; // 47 * sizeof (DWORD) +
// 3 * sizeof (LINEDIALPARAMS)
break;
case TAPI_VERSION1_4:
dwFixedSizeClient = 240; // 48 * sizeof (DWORD) +
// 3 * sizeof (LINEDIALPARAMS)
break;
case TAPI_VERSION2_0:
case TAPI_VERSION2_1:
dwFixedSizeClient = 252; // 51 * sizeof (DWORD) +
// 3 * sizeof (LINEDIALPARAMS)
break;
case TAPI_VERSION2_2:
dwFixedSizeClient = 268; // 51 * sizeof (DWORD) +
// 3 * sizeof (LINEDIALPARAMS) +
// sizeof (GUID)
break;
default: // (fix ppc build wrn) case TAPI_VERSION_CURRENT:
dwFixedSizeClient = sizeof (LINEDEVCAPS);
break;
}
if (dwTotalSize < dwFixedSizeClient)
{
pParams->lResult = LINEERR_STRUCTURETOOSMALL;
goto LGetDevCaps_epilog;
}
//
// Determine the fixed size of the structure expected by the SP
//
switch (dwSPIVersion)
{
case TAPI_VERSION1_0:
dwFixedSizeSP = 236; // 47 * sizeof (DWORD) +
// 3 * sizeof (LINEDIALPARAMS)
break;
case TAPI_VERSION1_4:
dwFixedSizeSP = 240; // 48 * sizeof (DWORD) +
// 3 * sizeof (LINEDIALPARAMS)
break;
case TAPI_VERSION2_0:
case TAPI_VERSION2_1:
dwFixedSizeSP = 252; // 51 * sizeof (DWORD) +
// 3 * sizeof (LINEDIALPARAMS)
break;
case TAPI_VERSION2_2:
dwFixedSizeSP = 268; // 51 * sizeof (DWORD) +
// 3 * sizeof (LINEDIALPARAMS) +
// sizeof (GUID)
break;
default: // (fix ppc build wrn) case TAPI_VERSION_CURRENT:
dwFixedSizeSP = sizeof (LINEDEVCAPS);
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 (!(pDevCaps2 = ServerAlloc (dwFixedSizeSP)))
{
pParams->lResult = LINEERR_NOMEM;
goto LGetDevCaps_epilog;
}
pDevCaps = pDevCaps2;
dwTotalSize = dwFixedSizeSP;
}
InitTapiStruct(
pDevCaps,
dwTotalSize,
dwFixedSizeSP,
(pDevCaps2 == NULL ? TRUE : FALSE)
);
if (pLookupEntry->bRemoved)
{
ServerFree (pDevCaps2);
pParams->lResult = LINEERR_NODEVICE;
}
else if ((pParams->lResult = CallSP4(
pfnTSPI_lineGetDevCaps,
"lineGetDevCaps",
SP_FUNC_SYNC,
(DWORD) dwDeviceID,
(DWORD) dwSPIVersion,
(DWORD) pParams->dwExtVersion,
(ULONG_PTR) pDevCaps
)) == 0)
{
#if DBG
//
// Verify the info returned by the provider
//
#endif
//
// Add the fields we're responsible for
//
pDevCaps->dwLineStates |= LINEDEVSTATE_OPEN |
LINEDEVSTATE_CLOSE |
LINEDEVSTATE_REINIT |
LINEDEVSTATE_TRANSLATECHANGE;
if (dwAPIVersion >= TAPI_VERSION3_0)
{
pDevCaps->dwAvailableTracking |=
LINECALLHUBTRACKING_ALLCALLS;
}
//
// Munge fields where appropriate for old apps (don't want to
// pass back flags that they won't understand)
//
if ((dwAPIVersion == TAPI_VERSION1_0) &&
(pDevCaps->dwMediaModes & LINEMEDIAMODE_VOICEVIEW))
{
pDevCaps->dwMediaModes = LINEMEDIAMODE_UNKNOWN |
(pDevCaps->dwMediaModes & ~LINEMEDIAMODE_VOICEVIEW);
}
if ((dwAPIVersion < TAPI_VERSION2_1) &&
(pDevCaps->dwMediaModes & LINEMEDIAMODE_VIDEO))
{
pDevCaps->dwMediaModes = LINEMEDIAMODE_UNKNOWN |
(pDevCaps->dwMediaModes & ~LINEMEDIAMODE_VIDEO);
}
//
// 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 (pDevCaps == pDevCaps2)
{
pDevCaps = (LPLINEDEVCAPS) pDataBuf;
CopyMemory (pDevCaps, pDevCaps2, dwFixedSizeClient);
ServerFree (pDevCaps2);
pDevCaps->dwTotalSize = pParams->dwDevCapsTotalSize;
pDevCaps->dwUsedSize = dwFixedSizeClient;
}
//
// Indicate the offset & how many bytes of data we're passing back
//
pParams->dwDevCapsOffset = 0;
*pdwNumBytesReturned = sizeof (TAPI32_MSG) +
pDevCaps->dwUsedSize;
}
else
{
ServerFree (pDevCaps2);
}
}
LGetDevCaps_epilog:
LINEEPILOGSYNC(
&pParams->lResult,
hMutex,
bCloseMutex,
objectToDereference,
"GetDevCaps"
);
}
void
WINAPI
LGetDevConfig(
PTCLIENT ptClient,
PLINEGETDEVCONFIG_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
DWORD dwDeviceID;
HANDLE hMutex;
TSPIPROC pfnTSPI_lineGetDevConfig;
DWORD objectToDereference;
PTLINELOOKUPENTRY pLookupEntry;
//
// Verify size/offset/string params given our input buffer/size
//
if ((pParams->dwDeviceConfigTotalSize > dwParamsBufferSize) ||
IsBadStringParam(
dwParamsBufferSize,
pDataBuf,
pParams->dwDeviceClassOffset
))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if ((pParams->lResult = LINEPROLOG(
ptClient, // tClient
DEVICE_ID, // widget type
0, // client widget handle
&dwDeviceID, // provider widget handle
pParams->dwDeviceID, // privileges or device ID
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINEGETDEVCONFIG, // provider func index
&pfnTSPI_lineGetDevConfig, // provider func pointer
NULL, // async request info
0, // client async request ID
&objectToDereference, // object to dereference
&pLookupEntry, // context
"GetDevConfig" // func name
)) == 0)
{
WCHAR *pszDeviceClass;
LPVARSTRING pConfig = (LPVARSTRING) pDataBuf;
//
// Alloc a temporary buf for the dev class, since we'll be using
// the existing buffer for output
//
if (!(pszDeviceClass = (WCHAR *) ServerAlloc( sizeof(WCHAR) * ( 1 +
lstrlenW((PWSTR)(pDataBuf + pParams->dwDeviceClassOffset)))
)))
{
pParams->lResult = LINEERR_NOMEM;
goto LGetDevConfig_epilog;
}
wcscpy(
pszDeviceClass,
(PWSTR)(pDataBuf + pParams->dwDeviceClassOffset)
);
if (!InitTapiStruct(
pConfig,
pParams->dwDeviceConfigTotalSize,
sizeof (VARSTRING),
TRUE
))
{
ServerFree (pszDeviceClass);
pParams->lResult = LINEERR_STRUCTURETOOSMALL;
goto LGetDevConfig_epilog;
}
if (pLookupEntry->bRemoved)
{
ServerFree (pszDeviceClass);
pParams->lResult = LINEERR_NODEVICE;
goto LGetDevConfig_epilog;
}
if ((pParams->lResult = CallSP3(
pfnTSPI_lineGetDevConfig,
"lineGetDevConfig",
SP_FUNC_SYNC,
(DWORD) dwDeviceID,
(ULONG_PTR) pConfig,
(ULONG_PTR) pszDeviceClass
)) == 0)
{
//
// Indicate how many bytes of data we're passing back
//
pParams->dwDeviceConfigOffset = 0;
*pdwNumBytesReturned = sizeof (TAPI32_MSG) +
pConfig->dwUsedSize;
}
ServerFree (pszDeviceClass);
}
LGetDevConfig_epilog:
LINEEPILOGSYNC(
&pParams->lResult,
hMutex,
bCloseMutex,
objectToDereference,
"GetDevConfig"
);
}
void
WINAPI
LGetGroupList(
PTCLIENT ptClient,
PLINEGETGROUPLIST_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
//
// note: can't use lgetagentxxx because
// pparams don't match
//
BOOL bCloseMutex;
LONG lRequestID;
HANDLE hMutex;
HDRVLINE hdLine;
DWORD objectToDereference;
PTLINECLIENT ptLineClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HLINE, // widget type
(DWORD) pParams->hLine, // client widget handle
(LPVOID) &hdLine, // provider widget handle
0, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
0, // provider func index
NULL, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptLineClient, // context
"GetGroupList" // func name
)) > 0)
{
LONG lResult;
DWORD dwDeviceID, dwTotalSize =pParams->dwGroupListTotalSize;
PTLINECLIENT pProxy;
if (dwTotalSize < sizeof(LINEAGENTGROUPLIST))
{
lRequestID = LINEERR_STRUCTURETOOSMALL;
goto LGetGroupList_epilog;
}
if ((lResult = FindProxy(
ptLineClient,
0,
LINEPROXYREQUEST_GETGROUPLIST,
&pProxy,
&dwDeviceID,
TAPI_VERSION2_2
)))
{
lRequestID = lResult;
goto LGetGroupList_epilog;
}
//
// Save the client's buf ptr & post processing proc ptr
//
pAsyncRequestInfo->dwParam1 = pParams->hpGroupList;
pAsyncRequestInfo->dwParam2 = dwTotalSize;
pAsyncRequestInfo->hfnClientPostProcessProc =
pParams->hfnPostProcessProc;
//
// First check to see if there's a (local) proxy registered
// for this type of request on this line. If so, build a
// request & send it to the proxy.
//
if (pProxy)
{
LONG lResult;
PPROXYREQUESTWRAPPER pProxyRequestWrapper;
if ((lResult = CreateProxyRequest(
pProxy,
LINEPROXYREQUEST_GETGROUPLIST,
dwTotalSize,
pAsyncRequestInfo,
&pProxyRequestWrapper
)))
{
lRequestID = lResult;
goto LGetGroupList_epilog;
}
pProxyRequestWrapper->ProxyRequest.GetGroupList.
GroupList.dwTotalSize = dwTotalSize;
if ((lResult = SendProxyRequest(
pProxy,
pProxyRequestWrapper,
pAsyncRequestInfo
)))
{
lRequestID = lResult;
goto LGetGroupList_epilog;
}
else // success
{
pParams->lResult = (LONG) pAsyncRequestInfo->dwLocalRequestID;
}
}
//
// There's no proxy, so check to see if line is remote and
// call remotesp if so
//
else if ((GetLineLookupEntry (dwDeviceID))->bRemote)
{
LPBYTE pBuf;
LPLINEAGENTGROUPLIST pGroupList;
//
// 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(
sizeof (ASYNCEVENTMSG) + ((dwTotalSize + 7) & 0xfffffff8)
)))
{
lRequestID = LINEERR_NOMEM;
goto LGetGroupList_epilog;
}
pAsyncRequestInfo->pfnPostProcess =
LGetAgentXxx_PostProcess;
pAsyncRequestInfo->dwParam3 = (ULONG_PTR) pBuf;
pGroupList = (LPLINEAGENTGROUPLIST)
(pBuf + sizeof (ASYNCEVENTMSG));
pGroupList->dwTotalSize = dwTotalSize;
pParams->lResult = CallSP3(
pRemoteSP->apfn[SP_LINEGETGROUPLIST],
"GetGroupList",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdLine,
(ULONG_PTR) pGroupList
);
}
//
// There's no registered proxy & line is not remote, so fail
//
else
{
lRequestID = LINEERR_OPERATIONUNAVAIL;
}
}
LGetGroupList_epilog:
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"GetGroupList"
);
}
void
WINAPI
LGetHubRelatedCalls(
PTCLIENT ptClient,
PLINEGETHUBRELATEDCALLS_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
DWORD dwTotalSize = pParams->dwCallListTotalSize,
dwNeededSize, dwUsedSize, dwCallHubID, i, j;
PTCALL ptCall;
PTLINEAPP ptLineApp;
PTPROVIDER ptProvider;
TPOINTERLIST fastCallList = {0}, *pCallList = &fastCallList;
PTCALLCLIENT ptCallClient;
PTCALLHUBCLIENT ptCallHubClient;
PTHASHTABLEENTRY pEntry;
//
// Verify size/offset/string params given our input buffer/size
//
if (pParams->dwCallListTotalSize > dwParamsBufferSize)
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
//
// State/param validation
//
if (TapiGlobals.dwNumLineInits == 0)
{
pParams->lResult = LINEERR_UNINITIALIZED;
goto LGetHubRelatedCalls_exit;
}
if (dwTotalSize < sizeof (LINECALLLIST))
{
pParams->lResult = LINEERR_STRUCTURETOOSMALL;
goto LGetHubRelatedCalls_exit;
}
//
// Determine the associated tProvider, call hub id, & tLineApp
// (assume failure, resetting lResult to 0 only when we're sure
// we're ok)
//
pParams->lResult = LINEERR_INVALCALLHANDLE;
if (pParams->hCallHub)
{
if (!pParams->hCall &&
(ptCallHubClient = IsValidCallHub(
pParams->hCallHub,
ptClient
)))
{
try
{
ptProvider = ptCallHubClient->ptProvider;
dwCallHubID = ptCallHubClient->dwCallHubID;
ptLineApp = ptCallHubClient->ptLineApp;
if (ptCallHubClient->dwKey == TCALLHUBCLIENT_KEY)
{
pParams->lResult = 0;
}
}
except (EXCEPTION_EXECUTE_HANDLER)
{
// do nothing, error handled below
}
}
}
else
{
if ((ptCallClient = ReferenceCall(
pParams->hCall,
ptClient
)))
{
try
{
if ((dwCallHubID = ptCallClient->ptCall->dwCallID))
{
ptProvider = ptCallClient->ptCall->ptProvider;
ptLineApp = ptCallClient->ptLineClient->ptLineApp;
if (ptCallClient->dwKey == TCALLCLIENT_KEY)
{
pParams->lResult = 0;
ptCallHubClient = NULL;
}
}
}
except (EXCEPTION_EXECUTE_HANDLER)
{
// do nothing, error handled below
}
DereferenceObject (ghHandleTable, pParams->hCall, 1);
}
}
if (pParams->lResult != 0)
{
goto LGetHubRelatedCalls_exit;
}
//
// Get the list of tCall's for this tProvider/CallHubID. Also, if
// the tCallHubClient is not already known then try to find it.
//
pEntry = AcquireHashTableEntryLock (ptProvider, dwCallHubID);
if (!pEntry)
{
pParams->lResult = LINEERR_INVALCALLHANDLE;
goto LGetHubRelatedCalls_exit;
}
if (pEntry->dwCallHubID != dwCallHubID)
{
ReleaseHashTableEntryLock (ptProvider, pEntry);
pParams->lResult = LINEERR_INVALCALLHANDLE;
goto LGetHubRelatedCalls_exit;
}
if (!ptCallHubClient)
{
ptCallHubClient = pEntry->ptCallHubClients;
while (ptCallHubClient && ptCallHubClient->ptLineApp != ptLineApp)
{
ptCallHubClient = ptCallHubClient->pNext;
}
//
// If there's no tCallHubClient then there's no call hub as far
// as this app is concerned
//
if (!ptCallHubClient)
{
ReleaseHashTableEntryLock (ptProvider, pEntry);
pParams->lResult = LINEERR_INVALCALLHANDLE;
goto LGetHubRelatedCalls_exit;
}
}
GetList (&pEntry->CallHubList, &pCallList);
ReleaseHashTableEntryLock (ptProvider, pEntry);
//
// Insert the hCallHub at the front of the call list
//
dwNeededSize = sizeof (LINECALLLIST) + sizeof (HCALLHUB);
if (dwNeededSize <= dwTotalSize)
{
*((LPHCALLHUB)(pDataBuf + sizeof (LINECALLLIST))) =
ptCallHubClient->hCallHub;
dwUsedSize = dwNeededSize;
}
else
{
dwUsedSize = sizeof (LINECALLLIST);
}
//
// For each of the tCall in the list get the list of tCallClients,
// then for each tCallClient see if it's on the same tLineApp
// as the specified call/hub, & if so add it to the list
//
for (i = 0; i < pCallList->dwNumUsedEntries; i++)
{
TPOINTERLIST fastCallClientList,
*pCallClientList = &fastCallClientList;
ptCall = CONTAINING_RECORD(
pCallList->aEntries[i],
TCALL,
CallHubList
);
if (GetCallClientListFromCall (ptCall, &pCallClientList) != 0)
{
continue;
}
for (j = 0; j < pCallClientList->dwNumUsedEntries; j++)
{
PTCALLCLIENT ptCallClient = pCallClientList->aEntries[j];
try
{
if ((ptCallClient->ptLineClient->ptLineApp == ptLineApp) &&
(ptCallClient->dwKey == TCALLCLIENT_KEY))
{
if (!ptCallClient->ptCallHubClient)
{
ptCallClient->ptCallHubClient = ptCallHubClient;
}
if ((dwUsedSize + sizeof(HCALL)) <= dwTotalSize)
{
*((LPHCALL)(pDataBuf + dwUsedSize)) =
ptCallClient->hCall;
dwUsedSize += sizeof(HCALL);
}
dwNeededSize += sizeof(HCALL);
}
}
except (EXCEPTION_EXECUTE_HANDLER)
{
// do nothing, this call not included in list
}
}
if (pCallClientList != &fastCallClientList)
{
ServerFree (pCallClientList);
}
}
if (pCallList != &fastCallList)
{
ServerFree (pCallList);
}
((LPLINECALLLIST) pDataBuf)->dwTotalSize = dwTotalSize;
((LPLINECALLLIST) pDataBuf)->dwNeededSize = dwNeededSize;
((LPLINECALLLIST) pDataBuf)->dwUsedSize = dwUsedSize;
((LPLINECALLLIST) pDataBuf)->dwCallsSize = dwUsedSize -
sizeof (LINECALLLIST);
((LPLINECALLLIST) pDataBuf)->dwCallsNumEntries =
((LPLINECALLLIST) pDataBuf)->dwCallsSize / sizeof (HCALL);
((LPLINECALLLIST) pDataBuf)->dwCallsOffset = sizeof (LINECALLLIST);
pParams->dwCallListOffset = 0;
*pdwNumBytesReturned = sizeof (TAPI32_MSG) +
((LPLINECALLLIST) pDataBuf)->dwUsedSize;
LGetHubRelatedCalls_exit:
#if DBG
{
char szResult[32];
LOG((TL_TRACE,
"lineGetHubRelatedCalls: exit, result=%s",
MapResultCodeToText (pParams->lResult, szResult)
));
}
#else
LOG((TL_TRACE,
"lineGetHubRelatedCalls: exit, result=x%x",
pParams->lResult
));
#endif
return;
}
void
WINAPI
LGetIcon(
PTCLIENT ptClient,
PLINEGETICON_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
//
// Note: Icons are Windows NT User Objects, so. HICONs are public to
// all processes, and do not need to be dup'd.
//
BOOL bCloseMutex;
WCHAR *pszDeviceClass;
DWORD dwDeviceID;
HANDLE hMutex;
TSPIPROC pfnTSPI_lineGetIcon;
DWORD objectToDereference;
PTLINELOOKUPENTRY pLookupEntry;
//
// Verify size/offset/string params given our input buffer/size
//
if ((pParams->dwDeviceClassOffset != TAPI_NO_DATA) &&
IsBadStringParam(
dwParamsBufferSize,
pDataBuf,
pParams->dwDeviceClassOffset
))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
pszDeviceClass = (WCHAR *) (pParams->dwDeviceClassOffset == TAPI_NO_DATA ?
NULL : pDataBuf + pParams->dwDeviceClassOffset);
if ((pParams->lResult = LINEPROLOG(
ptClient, // tClient
DEVICE_ID, // widget type
0, // client widget handle
&dwDeviceID, // provider widget handle
pParams->dwDeviceID, // privileges or device ID
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINEGETICON, // provider func index
&pfnTSPI_lineGetIcon, // provider func pointer
NULL, // async request info
0, // client async request ID
&objectToDereference, // object to dereference
&pLookupEntry, // context
"GetIcon" // func name
)) == 0)
{
if ((pParams->lResult = CallSP3(
pfnTSPI_lineGetIcon,
"lineGetIcon",
SP_FUNC_SYNC,
(DWORD) dwDeviceID,
(ULONG_PTR) pszDeviceClass,
(ULONG_PTR) &pParams->hIcon
)) == 0)
{
*pdwNumBytesReturned = sizeof (LINEGETICON_PARAMS);
}
}
else if (pParams->lResult == LINEERR_OPERATIONUNAVAIL)
{
if ((pszDeviceClass == NULL) ||
(_wcsicmp(pszDeviceClass, L"tapi/line") == 0))
{
pParams->hIcon = TapiGlobals.hLineIcon;
pParams->lResult = 0;
*pdwNumBytesReturned = sizeof (LINEGETICON_PARAMS);
}
else
{
pParams->lResult = LINEERR_INVALDEVICECLASS;
}
}
LINEEPILOGSYNC(
&pParams->lResult,
hMutex,
bCloseMutex,
objectToDereference,
"GetIcon"
);
}
void
WINAPI
LGetIDEx(
PTCLIENT ptClient,
PLINEGETID_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, "LGetIDEx: failed to allocate DeviceClassCopy"));
pParams->lResult = LINEERR_NOMEM;
}
wcscpy(pDeviceClassCopy, (LPWSTR)pDeviceClass);
//
// First call LGetID
//
LGetID( ptClient,
pParams,
dwParamsBufferSize,
pDataBuf,
pdwNumBytesReturned);
//
// if LGetID 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, "LGetIDEx: WaveDeviceIdToStringId failed"));
pParams->lResult = LINEERR_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, "LGetIDEx: WaveDeviceIdToStringId failed"));
pParams->lResult = LINEERR_OPERATIONFAILED;
}
ServerFree(szStringId1);
ServerFree(szStringId2);
}
}
ServerFree(pDeviceClassCopy);
}
void
WINAPI
LGetID(
PTCLIENT ptClient,
PLINEGETID_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex, bSPITooLow = FALSE;
DWORD dwWidgetType, hWidget, dwPrivilege;
HANDLE hMutex;
ULONG_PTR hdWidget;
LPVOID context;
TSPIPROC pfnTSPI_lineGetID;
DWORD objectToDereference;
//
// Verify size/offset/string params given our input buffer/size
//
if ((pParams->dwDeviceIDTotalSize > dwParamsBufferSize) ||
IsBadStringParam(
dwParamsBufferSize,
pDataBuf,
pParams->dwDeviceClassOffset
))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
switch ( pParams->dwSelect )
{
case LINECALLSELECT_CALL:
{
dwWidgetType = ANY_RT_HCALL;
hWidget = pParams->hCall;
dwPrivilege = LINECALLPRIVILEGE_MONITOR;
break;
}
case LINECALLSELECT_DEVICEID:
{
PTLINEAPP ptLineApp;
BOOL bVersion = FALSE;
PTLINELOOKUPENTRY ptLineLookup;
LOG((TL_INFO, "lineGetID: LINECALLSELECT_DEVICEID. ptClient %p", ptClient));
if (WaitForExclusiveClientAccess (ptClient))
{
ptLineApp = ptClient->ptLineApps;
// see if any line app is > version 2.0
while (ptLineApp)
{
LOG((TL_INFO, "lineGetID: ptLineApp->dwAPIVersion %lx, TAPI_VERSION2_0 %lx", ptLineApp->dwAPIVersion, TAPI_VERSION2_0));
if (ptLineApp->dwAPIVersion > TAPI_VERSION2_0)
{
bVersion = TRUE;
break;
}
ptLineApp = ptLineApp->pNext;
}
UNLOCKTCLIENT (ptClient);
}
else
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if (!bVersion)
{
LOG((TL_ERROR, "lineGetID failed with invalid call select"));
pParams->lResult = LINEERR_INVALCALLSELECT;
return;
}
// check the spi version
ptLineLookup = GetLineLookupEntry (pParams->dwAddressID);
if (!ptLineLookup)
{
LOG((TL_ERROR, "lineGetID failed with invalid device id"));
pParams->lResult = LINEERR_BADDEVICEID;
return;
}
if (ptLineLookup->ptProvider->dwSPIVersion <= TAPI_VERSION2_0)
{
bSPITooLow = TRUE;
}
dwWidgetType = DEVICE_ID;
hWidget = 0;
dwPrivilege = pParams->dwAddressID;
break;
}
case LINECALLSELECT_ADDRESS:
case LINECALLSELECT_LINE:
{
dwWidgetType = ANY_RT_HLINE;
hWidget = pParams->hLine;
dwPrivilege = 0;
break;
}
default:
LOG((TL_ERROR, "lineGetID failed with invalid call select"));
pParams->lResult = LINEERR_INVALCALLSELECT;
return;
}
if ((pParams->lResult = LINEPROLOG(
ptClient, // tClient
dwWidgetType, // widget type
hWidget, // client widget handle
&hdWidget, // provider widget handle
dwPrivilege, // privileges or device ID
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINEGETID, // provider func index
&pfnTSPI_lineGetID, // provider func pointer
NULL, // async request info
0, // client async request ID
&objectToDereference, // object to dereference
&context, // context
"GetID" // func name
)) == 0 || pParams->lResult == LINEERR_OPERATIONUNAVAIL)
{
WCHAR *pszDeviceClass;
LPVARSTRING pID = (LPVARSTRING) pDataBuf;
//
// We'll handle the "tapi/line" class right here rather than
// burden every single driver with having to support it
//
if (_wcsicmp(
(PWSTR)(pDataBuf + pParams->dwDeviceClassOffset),
L"tapi/line"
) == 0)
{
if (!InitTapiStruct(
pID,
pParams->dwDeviceIDTotalSize,
sizeof (VARSTRING),
TRUE
))
{
pParams->lResult = LINEERR_STRUCTURETOOSMALL;
goto LGetID_epilog;
}
pID->dwNeededSize += sizeof (DWORD);
if (pID->dwTotalSize >= pID->dwNeededSize)
{
try
{
switch (pParams->dwSelect)
{
case LINECALLSELECT_ADDRESS:
{
if (pParams->dwAddressID >= ((PTLINECLIENT)
context)->ptLine->dwNumAddresses)
{
pParams->lResult = LINEERR_INVALADDRESSID;
goto LGetID_epilog;
}
*((LPDWORD)(pID + 1)) = ((PTLINECLIENT)
context)->ptLine->dwDeviceID;
break;
}
case LINECALLSELECT_CALL:
{
*((LPDWORD)(pID + 1)) = ((PTCALLCLIENT)
context)->ptCall->ptLine->dwDeviceID;
break;
}
case LINECALLSELECT_LINE:
{
*((LPDWORD)(pID + 1)) = ((PTLINECLIENT)
context)->ptLine->dwDeviceID;
break;
}
case LINECALLSELECT_DEVICEID:
{
*((LPDWORD)(pID + 1)) = pParams->dwAddressID;
break;
}
} // switch
}
myexcept
{
switch (pParams->dwSelect)
{
case LINECALLSELECT_CALL:
pParams->lResult = LINEERR_INVALCALLHANDLE;
break;
case LINECALLSELECT_LINE:
case LINECALLSELECT_ADDRESS:
pParams->lResult = LINEERR_INVALLINEHANDLE;
break;
case LINECALLSELECT_DEVICEID:
pParams->lResult = LINEERR_BADDEVICEID;
break;
}
goto LGetID_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 LGetID_epilog;
}
// see if they want the provider id
if (_wcsicmp(
(PWSTR)(pDataBuf + pParams->dwDeviceClassOffset),
L"tapi/providerid"
) == 0)
{
if (!InitTapiStruct(
pID,
pParams->dwDeviceIDTotalSize,
sizeof (VARSTRING),
TRUE
))
{
pParams->lResult = LINEERR_STRUCTURETOOSMALL;
goto LGetID_epilog;
}
pID->dwNeededSize += sizeof (DWORD);
if (pID->dwTotalSize >= pID->dwNeededSize)
{
try
{
switch (pParams->dwSelect)
{
case LINECALLSELECT_ADDRESS:
{
if (pParams->dwAddressID >= ((PTLINECLIENT)
context)->ptLine->dwNumAddresses)
{
pParams->lResult = LINEERR_INVALADDRESSID;
goto LGetID_epilog;
}
*((LPDWORD)(pID + 1)) = ((PTLINECLIENT)
context)->ptLine->ptProvider->
dwPermanentProviderID;
break;
}
case LINECALLSELECT_DEVICEID:
{
*((LPDWORD)(pID + 1)) = ((PTLINELOOKUPENTRY)
context)->ptProvider->dwPermanentProviderID;
break;
}
case LINECALLSELECT_CALL:
{
PTCALLCLIENT ptCallClient = (PTCALLCLIENT)
context;
*((LPDWORD)(pID + 1)) = ptCallClient->ptLineClient->
ptLine->ptProvider->dwPermanentProviderID;
break;
}
case LINECALLSELECT_LINE:
{
*((LPDWORD)(pID + 1)) = ((PTLINECLIENT)
context)->ptLine->ptProvider->
dwPermanentProviderID;
break;
}
default:
// we've already verified the call select flags above.
break;
}
}
myexcept
{
switch (pParams->dwSelect)
{
case LINECALLSELECT_CALL:
pParams->lResult = LINEERR_INVALCALLHANDLE;
break;
case LINECALLSELECT_LINE:
case LINECALLSELECT_ADDRESS:
pParams->lResult = LINEERR_INVALLINEHANDLE;
break;
case LINECALLSELECT_DEVICEID:
pParams->lResult = LINEERR_BADDEVICEID;
break;
}
goto LGetID_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 LGetID_epilog;
}
if (pParams->lResult == LINEERR_OPERATIONUNAVAIL)
{
goto LGetID_epilog;
}
if (bSPITooLow)
{
pParams->lResult = LINEERR_INVALCALLSELECT;
goto LGetID_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)
{
LOG((TL_ERROR, "Bad string size (0) in lineGetID!"));
pParams->lResult = LINEERR_INVALPARAM;
goto LGetID_epilog;
}
if (!(pszDeviceClass = (WCHAR *) ServerAlloc (nStringSize)))
{
LOG((TL_ERROR, "Mem failed in lineGetID!"));
pParams->lResult = LINEERR_NOMEM;
goto LGetID_epilog;
}
}
wcscpy(
pszDeviceClass,
(PWSTR)(pDataBuf + pParams->dwDeviceClassOffset)
);
if (!InitTapiStruct(
pID,
pParams->dwDeviceIDTotalSize,
sizeof (VARSTRING),
TRUE
))
{
ServerFree (pszDeviceClass);
pParams->lResult = LINEERR_STRUCTURETOOSMALL;
goto LGetID_epilog;
}
{
ULONG_PTR dwCallWidgetHold = 0,
dwLineWidgetHold = 0;
DWORD dwDeviceIDHold = 0;
switch (pParams->dwSelect)
{
case LINECALLSELECT_ADDRESS:
dwDeviceIDHold = pParams->dwAddressID;
//fall through
case LINECALLSELECT_LINE:
dwLineWidgetHold = hdWidget;
break;
case LINECALLSELECT_DEVICEID:
// this is the mapped id.
dwDeviceIDHold = DWORD_CAST(hdWidget,__FILE__,__LINE__);
break;
case LINECALLSELECT_CALL:
dwCallWidgetHold = hdWidget;
break;
default:
break;
}
if ((pParams->lResult = CallSP7(
pfnTSPI_lineGetID,
"lineGetID",
SP_FUNC_SYNC,
(ULONG_PTR) dwLineWidgetHold,
(DWORD) dwDeviceIDHold,
(ULONG_PTR) dwCallWidgetHold,
(DWORD) pParams->dwSelect,
(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/phone" &
// the dwUsedSize indicates that a phone id was
// (likely) copied to the buffer
// then
// try to map the retrieved phone 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/phone") == 0) &&
!IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR) &&
(pID->dwUsedSize >= (sizeof (*pID) + sizeof (DWORD))))
{
DWORD i;
LPDWORD pdwPhoneID = (LPDWORD)
(((LPBYTE) pID) + pID->dwStringOffset);
for (i = 0; i < ptClient->dwPhoneDevices; i++)
{
if (*pdwPhoneID == ptClient->pPhoneDevices[i])
{
*pdwPhoneID = i;
break;
}
}
if (i >= ptClient->dwPhoneDevices)
{
pParams->lResult = LINEERR_OPERATIONFAILED;
}
}
#endif
//
// Indicate offset & how many bytes of data we're passing back
//
pParams->dwDeviceIDOffset = 0;
*pdwNumBytesReturned = sizeof (TAPI32_MSG) + pID->dwUsedSize;
}
}
ServerFree (pszDeviceClass);
}
LGetID_epilog:
LINEEPILOGSYNC(
&pParams->lResult,
hMutex,
bCloseMutex,
objectToDereference,
"GetID"
);
}
void
WINAPI
LGetLineDevStatus(
PTCLIENT ptClient,
PLINEGETLINEDEVSTATUS_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
HANDLE hMutex;
HDRVLINE hdLine;
TSPIPROC pfnTSPI_lineGetLineDevStatus;
DWORD objectToDereference;
PTLINECLIENT ptLineClient;
//
// Verify size/offset/string params given our input buffer/size
//
if (pParams->dwLineDevStatusTotalSize > dwParamsBufferSize)
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if ((pParams->lResult = LINEPROLOG(
ptClient, // tClient
ANY_RT_HLINE, // widget type
pParams->hLine, // client widget handle
(LPVOID) &hdLine, // provider widget handle
0, // privileges or device ID
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINEGETLINEDEVSTATUS, // provider func index
&pfnTSPI_lineGetLineDevStatus, // provider func pointer
NULL, // async request info
0, // client async request ID
&objectToDereference, // object to dereference
&ptLineClient, // context
"GetLineDevStatus" // func name
)) == 0)
{
DWORD dwAPIVersion, dwSPIVersion, dwTotalSize,
dwFixedSizeClient, dwFixedSizeSP, dwNumOpens,
dwOpenMediaModes;
PTLINE ptLine;
LPLINEDEVSTATUS pDevStatus = (LPLINEDEVSTATUS) pDataBuf,
pDevStatus2 = (LPLINEDEVSTATUS) NULL;
//
// Safely retrieve the API & SPI versions, also some other info
//
try
{
dwAPIVersion = ptLineClient->dwAPIVersion;
ptLine = ptLineClient->ptLine;
dwSPIVersion = ptLine->dwSPIVersion;
dwNumOpens = ptLine->dwNumOpens;
dwOpenMediaModes = ptLine->dwOpenMediaModes;
if (ptLineClient->dwKey != TLINECLIENT_KEY)
{
pParams->lResult = LINEERR_INVALLINEHANDLE;
goto LGetLineDevStatus_epilog;
}
}
myexcept
{
pParams->lResult = LINEERR_INVALLINEHANDLE;
goto LGetLineDevStatus_epilog;
}
//
// Determine the fixed size of the structure for the specified API
// version, verify client's buffer is big enough
//
dwTotalSize = pParams->dwLineDevStatusTotalSize;
switch (dwAPIVersion)
{
case TAPI_VERSION1_0:
case TAPI_VERSION1_4:
dwFixedSizeClient = 76; // 19 * sizeof (DWORD)
break;
default: // (fix ppc build wrn) case TAPI_VERSION_CURRENT:
dwFixedSizeClient = sizeof (LINEDEVSTATUS);
break;
}
if (dwTotalSize < dwFixedSizeClient)
{
pParams->lResult = LINEERR_STRUCTURETOOSMALL;
goto LGetLineDevStatus_epilog;
}
//
// Determine the fixed size of the structure expected by the SP
//
switch (dwSPIVersion)
{
case TAPI_VERSION1_0:
case TAPI_VERSION1_4:
dwFixedSizeSP = 76; // 19 * sizeof (DWORD)
break;
default: // (fix ppc build wrn) case TAPI_VERSION_CURRENT:
dwFixedSizeSP = sizeof (LINEDEVSTATUS);
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 (!(pDevStatus2 = ServerAlloc (dwFixedSizeSP)))
{
pParams->lResult = LINEERR_NOMEM;
goto LGetLineDevStatus_epilog;
}
pDevStatus = pDevStatus2;
dwTotalSize = dwFixedSizeSP;
}
InitTapiStruct(
pDevStatus,
dwTotalSize,
dwFixedSizeSP,
(pDevStatus2 == NULL ? TRUE : FALSE)
);
if ((pParams->lResult = CallSP2(
pfnTSPI_lineGetLineDevStatus,
"lineGetLineDevStatus",
SP_FUNC_SYNC,
(ULONG_PTR) hdLine,
(ULONG_PTR) pDevStatus
)) == 0)
{
//
// Add the fields we're responsible for
//
pDevStatus->dwNumOpens = dwNumOpens;
pDevStatus->dwOpenMediaModes = dwOpenMediaModes;
if (dwAPIVersion >= TAPI_VERSION2_0)
{
DWORD dwAppInfoTotalSize, dwNumOpens, dwXxxOffset, i;
TPOINTERLIST clientList, *pClientList = &clientList;
LPLINEAPPINFO pAppInfo;
//
// Reset the num opens to 0 in case we return prior to
// filling in the app info list (so tapi32.dll doesn't
// blow up trying to do unicode->ascii conversion on
// bad data)
//
pDevStatus->dwNumOpens = 0;
//
// Retrieve the list of line clients & determine how big
// of a buffer we need to hold all the related app info
// data. Do it safely in case one of the widgets is
// destroyed while we're reading it's data.
//
if (GetLineClientListFromLine (ptLine, &pClientList) != 0)
{
goto LGetLineDevStatus_copyTmpBuffer;
}
dwAppInfoTotalSize = pClientList->dwNumUsedEntries *
sizeof (LINEAPPINFO);
for (i = 0; i < pClientList->dwNumUsedEntries; i++)
{
PTLINECLIENT ptLineClient = (PTLINECLIENT)
pClientList->aEntries[i];
try
{
DWORD d;
d = ptLineClient->ptClient->dwComputerNameSize;
d += ptLineClient->ptClient->dwUserNameSize;
// don't include preceding '"'
d += ptLineClient->ptLineApp->dwModuleNameSize -
sizeof (WCHAR);
d += ptLineClient->ptLineApp->dwFriendlyNameSize;
if (ptLineClient->dwKey == TLINECLIENT_KEY)
{
dwAppInfoTotalSize += d;
}
else
{
pClientList->aEntries[i] = 0;
}
}
myexcept
{
pClientList->aEntries[i] = 0;
}
}
dwAppInfoTotalSize += 3; // add 3 to guarantee DWORD alignment
pDevStatus->dwNeededSize += dwAppInfoTotalSize;
//
// Check to see if there's enough room in the app buffer
// for all the app info data
//
if ((pDevStatus->dwTotalSize - pDevStatus->dwUsedSize) <
dwAppInfoTotalSize)
{
goto LGetLineDevStatus_freeClientList;
}
//
// Now figure out where the app info goes & safely fill
// it in
//
pDevStatus->dwAppInfoSize = pClientList->dwNumUsedEntries *
sizeof (LINEAPPINFO);
pDevStatus->dwAppInfoOffset = (pDevStatus->dwUsedSize + 3) &
0xfffffffc;
pDevStatus->dwUsedSize += dwAppInfoTotalSize;
pAppInfo = (LPLINEAPPINFO) (((LPBYTE) pDevStatus) +
pDevStatus->dwAppInfoOffset);
dwXxxOffset = pDevStatus->dwAppInfoSize +
pDevStatus->dwAppInfoOffset;
dwNumOpens = 0;
for (i = 0; i < pClientList->dwNumUsedEntries; i++)
{
PTLINECLIENT ptLineClient = (PTLINECLIENT)
pClientList->aEntries[i];
if (ptLineClient == NULL)
{
continue;
}
try
{
DWORD d = dwXxxOffset;
PTCLIENT ptClient = ptLineClient->ptClient;
PTLINEAPP ptLineApp = ptLineClient->ptLineApp;
pAppInfo->dwMachineNameSize =
ptClient->dwComputerNameSize;
pAppInfo->dwUserNameSize =
ptClient->dwUserNameSize;
if (ptClient->dwKey != TCLIENT_KEY)
{
continue;
}
pAppInfo->dwModuleFilenameSize =
ptLineApp->dwModuleNameSize - sizeof (WCHAR);
pAppInfo->dwFriendlyNameSize =
ptLineApp->dwFriendlyNameSize;
if (ptLineApp->dwKey != TLINEAPP_KEY)
{
continue;
}
pAppInfo->dwMachineNameOffset = d;
if (pAppInfo->dwMachineNameSize)
{
wcsncpy(
(LPWSTR) (((LPBYTE) pDevStatus) + d),
ptClient->pszComputerName,
pAppInfo->dwMachineNameSize / sizeof (WCHAR)
);
d += pAppInfo->dwMachineNameSize;
}
pAppInfo->dwUserNameOffset = d;
if (pAppInfo->dwUserNameSize)
{
wcsncpy(
(LPWSTR) (((LPBYTE) pDevStatus) + d),
ptClient->pszUserName,
pAppInfo->dwUserNameSize / sizeof (WCHAR)
);
d += pAppInfo->dwUserNameSize;
}
pAppInfo->dwModuleFilenameOffset = d;
if (pAppInfo->dwModuleFilenameSize)
{
// don't include preceding '"'
wcsncpy(
(LPWSTR) (((LPBYTE) pDevStatus) + d),
&ptLineApp->pszModuleName[1],
pAppInfo->dwModuleFilenameSize / sizeof (WCHAR)
);
d += pAppInfo->dwModuleFilenameSize;
}
pAppInfo->dwFriendlyNameOffset = d;
if (pAppInfo->dwFriendlyNameSize)
{
wcsncpy(
(LPWSTR) (((LPBYTE) pDevStatus) + d),
ptLineApp->pszFriendlyName,
pAppInfo->dwFriendlyNameSize / sizeof (WCHAR)
);
d += pAppInfo->dwFriendlyNameSize;
}
pAppInfo->dwMediaModes = ptLineClient->dwMediaModes;
pAppInfo->dwAddressID = ptLineClient->dwAddressID;
//
// Finally, make sure the tLineClient is still good
// so we know all the info above is kosher, &
// if so inc the appropriate vars
//
if (ptLineClient->dwKey == TLINECLIENT_KEY)
{
pAppInfo++;
dwNumOpens++;
dwXxxOffset = d;
}
}
myexcept
{
// do nothing, just continue to loop
}
}
pDevStatus->dwNumOpens = dwNumOpens;
pDevStatus->dwAppInfoSize = dwNumOpens * sizeof (LINEAPPINFO);
LGetLineDevStatus_freeClientList:
if (pClientList != &clientList)
{
ServerFree (pClientList);
}
}
//
// 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.
//
LGetLineDevStatus_copyTmpBuffer:
if (pDevStatus == pDevStatus2)
{
pDevStatus = (LPLINEDEVSTATUS) pDataBuf;
CopyMemory (pDevStatus, pDevStatus2, dwFixedSizeClient);
ServerFree (pDevStatus2);
pDevStatus->dwTotalSize = pParams->dwLineDevStatusTotalSize;
pDevStatus->dwUsedSize = dwFixedSizeClient;
}
//
// Indicate the API version of the hLine so tapi32.dll knows
// which strings to munge from ascii to unicode
//
pParams->dwAPIVersion = dwAPIVersion;
//
// Indicate the offset & how many bytes of data we're passing back
//
pParams->dwLineDevStatusOffset = 0;
*pdwNumBytesReturned = sizeof (TAPI32_MSG) +
pDevStatus->dwUsedSize;
}
}
LGetLineDevStatus_epilog:
LINEEPILOGSYNC(
&pParams->lResult,
hMutex,
bCloseMutex,
objectToDereference,
"GetLineDevStatus"
);
}
void
WINAPI
LGetNewCalls(
PTCLIENT ptClient,
PLINEGETNEWCALLS_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
LONG lResult = 0;
DWORD dwTotalSize = pParams->dwCallListTotalSize, dwAddressID,
dwNumNewCalls, i, j, dwSelect = pParams->dwSelect;
PTLINE ptLine;
HDRVLINE hdLine;
PTLINECLIENT ptLineClient;
TPOINTERLIST callList, *pCallList = &callList;
LPLINECALLLIST pAppCallList = (LPLINECALLLIST) pDataBuf;
//
// Verify size/offset/string params given our input buffer/size
//
if (pParams->dwCallListTotalSize > dwParamsBufferSize)
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
//
// Verify params
//
if (TapiGlobals.dwNumLineInits == 0)
{
pParams->lResult = LINEERR_UNINITIALIZED;
goto LGetNewCalls_return;
}
if (dwSelect == LINECALLSELECT_ADDRESS)
{
dwAddressID = pParams->dwAddressID;
}
else if (dwSelect != LINECALLSELECT_LINE)
{
pParams->lResult = LINEERR_INVALCALLSELECT;
goto LGetNewCalls_return;
}
if (dwTotalSize < sizeof (LINECALLLIST))
{
pParams->lResult = LINEERR_STRUCTURETOOSMALL;
goto LGetNewCalls_return;
}
if (!(ptLineClient = ReferenceObject(
ghHandleTable,
pParams->hLine,
TLINECLIENT_KEY
)))
{
pParams->lResult = LINEERR_INVALLINEHANDLE;
goto LGetNewCalls_return;
}
if (ptLineClient->ptClient != ptClient)
{
pParams->lResult = LINEERR_INVALLINEHANDLE;
goto LGetNewCalls_dereference;
}
ptLine = ptLineClient->ptLine;
//
// HACK ALERT!
//
// GetNewCalls did not work on remote lines in tapi 2.1,
// win98 gold, or nt4sp4.
//
// The way we get it to work here for remote lines is to do a
// TSPI_lineGetID down to remotesp, specifying the device class
// of "GetNewCalls", and passing it the pointer to our real
// LineEventProc, not the LineEventProcSP which queues msgs,
// so it can process LINE_CALLSTATE msgs inline (this allows
// the initial/requisite monitor handles to be created, etc,
// before we might do so below).
//
try
{
hdLine = (ptLine->ptProvider == pRemoteSP ? ptLine->hdLine : 0);
if (ptLine->dwKey != TLINE_KEY)
{
pParams->lResult = LINEERR_INVALLINEHANDLE;
goto LGetNewCalls_dereference;
}
}
myexcept
{
pParams->lResult = LINEERR_INVALLINEHANDLE;
goto LGetNewCalls_dereference;
}
if (hdLine && pRemoteSP->apfn[SP_LINEGETID])
{
CallSP7(
pRemoteSP->apfn[SP_LINEGETID],
"lineGetID(GetNewCalls)",
SP_FUNC_SYNC,
(ULONG_PTR) hdLine,
(DWORD) dwAddressID,
(ULONG_PTR) 0, // hdCall
(DWORD) dwSelect,
(ULONG_PTR) 0, // lpDeviceID
(ULONG_PTR) L"GetNewCalls", // lpszDeviceClass
(ULONG_PTR) LineEventProc // hTargetProcess
);
}
//
// Get list of tCalls on the tLine
//
if ((lResult = GetCallListFromLine (ptLine, &pCallList)) != 0)
{
pParams->lResult = lResult;
goto LGetNewCalls_dereference;
}
//
// Assume worst case scenario- that we have to create a new call
// client for each tCall on the tLine- and make sure the app's call
// list is large enough to hold them all
//
pAppCallList->dwTotalSize = dwTotalSize;
if (dwTotalSize < (sizeof (LINECALLLIST) +
pCallList->dwNumUsedEntries * sizeof(HCALL)))
{
pAppCallList->dwNeededSize = sizeof (LINECALLLIST) +
pCallList->dwNumUsedEntries * sizeof(HCALL);
pAppCallList->dwUsedSize = sizeof (LINECALLLIST);
FillMemory (&pAppCallList->dwCallsNumEntries, 3 * sizeof (DWORD), 0);
goto LGetNewCalls_cleanup;
}
//
// Check to see if there's a call client for the specified
// line client for each of the calls on the line/address,
// create one with monitor privilege if not
//
dwNumNewCalls = 0;
for (i = 0; i < pCallList->dwNumUsedEntries; i++)
{
BOOL bContinue = FALSE;
PTCALL ptCall = (PTCALL) pCallList->aEntries[i];
TPOINTERLIST callClientList, *pCallClientList = &callClientList;
//
// Check to see if the post-processing routine (for outgoing calls)
// or the CALLSTATE msg handler in the LineEventProc (for incoming
// calls) has already created the list of monitors for this tCall.
//
try
{
if (ptCall->bCreatedInitialMonitors == FALSE)
{
bContinue = TRUE;
}
}
myexcept
{
bContinue = TRUE;
}
if (dwSelect == LINECALLSELECT_ADDRESS)
{
try
{
if (dwAddressID != ptCall->dwAddressID)
{
bContinue = TRUE;
}
}
myexcept
{
bContinue = TRUE;
}
}
if (bContinue)
{
continue;
}
if (GetCallClientListFromCall (ptCall, &pCallClientList) != 0)
{
continue;
}
for (j = 0; j < pCallClientList->dwNumUsedEntries; j++)
{
try
{
if (((PTCALLCLIENT)(pCallClientList->aEntries[j]))
->ptLineClient == ptLineClient)
{
break;
}
}
myexcept
{
// just continue
}
}
if (j == pCallClientList->dwNumUsedEntries)
{
PTCALLCLIENT pNewCallClient;
//
// (Similar remotesp hack in CreateCallMonitors)
//
// NOTE: If client is remote(sp) then create the call client
// with OWNER privileges so client can still do everything.
// The remote tapisrv will deal with all the remote
// privilege issues.
//
// This scheme might end up confusing other apps since
// a LINE_CALLINFO\NUMOWNERINCR (not NUMMONITORS) msgs
// get sent, but it certainly beats what we had in tapi 2.1 -
// that is, if a remote client did not initially have owner
// privilege then it could *never* get owner privilege.
//
if ((lResult = CreatetCallClient(
ptCall,
ptLineClient,
(IS_REMOTE_CLIENT (ptClient) ?
LINECALLPRIVILEGE_OWNER : LINECALLPRIVILEGE_MONITOR),
TRUE,
TRUE,
&pNewCallClient,
FALSE
)) == 0)
{
try
{
*(((LPHCALL)(pAppCallList + 1)) + dwNumNewCalls) =
pNewCallClient->hCall;
}
myexcept
{
//
// If here the call got torn down, meaning the line
// is going down too
//
pParams->lResult = LINEERR_INVALLINEHANDLE;
i = 0xfffffffe;
break;
}
dwNumNewCalls++;
}
else
{
// specfied tCall might have been closed, not a fatal error
}
}
if (pCallClientList != &callClientList)
{
ServerFree (pCallClientList);
}
}
{
DWORD dwCallsSize = dwNumNewCalls * sizeof (HCALL);
pAppCallList->dwUsedSize =
pAppCallList->dwNeededSize = sizeof (LINECALLLIST) + dwCallsSize;
pAppCallList->dwCallsNumEntries = dwNumNewCalls;
pAppCallList->dwCallsSize = dwCallsSize;
pAppCallList->dwCallsOffset = sizeof (LINECALLLIST);
}
LGetNewCalls_cleanup:
if (pCallList != &callList)
{
ServerFree (pCallList);
}
pParams->dwCallListOffset = 0;
*pdwNumBytesReturned = sizeof (TAPI32_MSG) + pAppCallList->dwUsedSize;
LGetNewCalls_dereference:
DereferenceObject (ghHandleTable, pParams->hLine, 1);
LGetNewCalls_return:
#if DBG
{
char szResult[32];
LOG((TL_TRACE,
"lineGetNewCalls: exit, result=%s",
MapResultCodeToText (pParams->lResult, szResult)
));
}
#else
LOG((TL_TRACE,
"lineGetNewCalls: exit, result=x%x",
pParams->lResult
));
#endif
return;
}
void
WINAPI
LGetNumAddressIDs(
PTCLIENT ptClient,
PLINEGETNUMADDRESSIDS_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
HANDLE hMutex;
HDRVLINE hdLine;
DWORD objectToDereference;
PTLINECLIENT ptLineClient;
if ((pParams->lResult = LINEPROLOG(
ptClient, // tClient
ANY_RT_HLINE, // widget type
(DWORD) pParams->hLine, // client widget handle
(LPVOID) &hdLine, // provider widget handle
0, // req'd privileges (call only)
&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
&objectToDereference, // object to dereference
&ptLineClient, // context
"GetNumAddressIDs" // func name
)) == 0)
{
try
{
pParams->dwNumAddresses = ptLineClient->ptLine->dwNumAddresses;
*pdwNumBytesReturned = sizeof (LINEGETNUMADDRESSIDS_PARAMS);
}
myexcept
{
pParams->lResult = LINEERR_INVALLINEHANDLE;
}
}
LINEEPILOGSYNC(
&pParams->lResult,
hMutex,
bCloseMutex,
objectToDereference,
"GetNumAddressIDs"
);
}
void
WINAPI
LGetNumRings(
PTCLIENT ptClient,
PLINEGETNUMRINGS_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
HANDLE hMutex;
HDRVLINE hdLine;
DWORD objectToDereference;
PTLINECLIENT ptLineClient;
if ((pParams->lResult = LINEPROLOG(
ptClient, // tClient
ANY_RT_HLINE, // widget type
(DWORD) pParams->hLine, // client widget handle
(LPVOID) &hdLine, // provider widget handle
0, // privileges or device ID
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_NONE, // provider func index
NULL, // provider func pointer
NULL, // async request info
0, // client async request ID
&objectToDereference, // object to dereference
&ptLineClient, // context
"GetNumRings" // func name
)) == 0)
{
DWORD i, dwNumRings = 0xffffffff,
dwAddressID = pParams->dwAddressID;
PTLINE ptLine;
TPOINTERLIST lineClientList, *pLineClientList = &lineClientList;
try
{
ptLine = ptLineClient->ptLine;
if (dwAddressID >= ptLine->dwNumAddresses)
{
pParams->lResult = LINEERR_INVALADDRESSID;
goto LGetNumRings_epilog;
}
}
myexcept
{
pParams->lResult = LINEERR_INVALLINEHANDLE;
goto LGetNumRings_epilog;
}
{
LONG lResult;
if ((lResult = GetLineClientListFromLine(
ptLine,
&pLineClientList
)) != 0)
{
pParams->lResult = LINEERR_INVALLINEHANDLE;
goto LGetNumRings_epilog;
}
}
for (i = 0; i < pLineClientList->dwNumUsedEntries; i++)
{
ptLineClient = (PTLINECLIENT) pLineClientList->aEntries[i];
try
{
if (ptLineClient->aNumRings == NULL)
{
continue;
}
else if (ptLineClient->aNumRings[dwAddressID] < dwNumRings)
{
DWORD dwNumRingsTmp =
ptLineClient->aNumRings[dwAddressID];
if (ptLineClient->dwKey == TLINECLIENT_KEY)
{
dwNumRings = dwNumRingsTmp;
}
}
}
myexcept
{
// just continue
}
}
if (pLineClientList != &lineClientList)
{
ServerFree (pLineClientList);
}
pParams->dwNumRings = dwNumRings;
*pdwNumBytesReturned = sizeof (LINEGETNUMRINGS_PARAMS);
}
LGetNumRings_epilog:
LINEEPILOGSYNC(
&pParams->lResult,
hMutex,
bCloseMutex,
objectToDereference,
"GetNumRings"
);
}
void
WINAPI
LGetProviderList(
PTCLIENT ptClient,
PLINEGETPROVIDERLIST_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
DWORD iNumProviders = 0, i;
WCHAR *bufw;
DWORD dwFixedSizeClient, dwTotalSize, dwNeededSize;
LPBYTE pVarData;
LPLINEPROVIDERLIST pProviderList;
LPLINEPROVIDERENTRY pProviderEntry;
HKEY hKey;
DWORD dwDataSize;
DWORD dwDataType;
//
// Verify size/offset/string params given our input buffer/size
//
if (pParams->dwProviderListTotalSize > dwParamsBufferSize)
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
switch (pParams->dwAPIVersion)
{
case TAPI_VERSION1_0:
case TAPI_VERSION1_4:
case TAPI_VERSION2_0:
case TAPI_VERSION2_1:
case TAPI_VERSION2_2:
case TAPI_VERSION3_0:
case TAPI_VERSION_CURRENT:
dwFixedSizeClient = sizeof (LINEPROVIDERLIST);
break;
default:
pParams->lResult = LINEERR_INCOMPATIBLEAPIVERSION;
goto LGetProviderList_epilog;
}
if ((dwTotalSize = pParams->dwProviderListTotalSize) < dwFixedSizeClient)
{
pParams->lResult = LINEERR_STRUCTURETOOSMALL;
goto LGetProviderList_epilog;
}
if (ERROR_SUCCESS ==
RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
gszRegKeyProviders,
0,
KEY_ALL_ACCESS,
&hKey
))
{
dwDataSize = sizeof(iNumProviders);
iNumProviders = 0;
RegQueryValueEx(
hKey,
gszNumProviders,
0,
&dwDataType,
(LPBYTE)&iNumProviders,
&dwDataSize
);
}
dwNeededSize = dwFixedSizeClient +
(iNumProviders * sizeof (LINEPROVIDERENTRY));
pProviderList = (LPLINEPROVIDERLIST) pDataBuf;
pProviderEntry = (LPLINEPROVIDERENTRY) (pDataBuf + dwFixedSizeClient);
pVarData = pDataBuf + dwNeededSize;
bufw = ServerAlloc (MAX_PATH*sizeof(WCHAR)); // enough for complete path
if ( !bufw )
{
pParams->lResult = LINEERR_NOMEM;
goto LGetProviderList_epilog;
}
for (i = 0; i < iNumProviders; i++)
{
TCHAR szProviderXxxN[32];
DWORD dwNameLen;
DWORD dwNewSize;
wsprintf (szProviderXxxN, TEXT("%s%d"), gszProviderFilename, i);
dwNameLen = MAX_PATH*sizeof(WCHAR);
if (TAPIRegQueryValueExW(
hKey,
szProviderXxxN,
0,
&dwDataType,
(LPBYTE)bufw,
&dwNameLen
) != ERROR_SUCCESS)
{
bufw[0] = 0;
}
dwNewSize = (lstrlenW(bufw)+1) * sizeof(WCHAR);
dwNeededSize += dwNewSize;
if (dwTotalSize >= dwNeededSize)
{
wsprintf(szProviderXxxN, TEXT("%s%d"), gszProviderID, i);
dwDataSize = sizeof(pProviderEntry->dwPermanentProviderID);
pProviderEntry->dwPermanentProviderID = 0;
RegQueryValueEx(
hKey,
szProviderXxxN,
0,
&dwDataType,
(LPBYTE)&(pProviderEntry->dwPermanentProviderID),
&dwDataSize
);
pProviderEntry->dwProviderFilenameSize = dwNewSize;
pProviderEntry->dwProviderFilenameOffset =
(DWORD) (pVarData - ((LPBYTE) pProviderList));
CopyMemory (pVarData, bufw, dwNewSize);
pVarData += dwNewSize;
pProviderEntry++;
}
}
ServerFree (bufw);
pProviderList->dwTotalSize = dwTotalSize;
pProviderList->dwNeededSize = dwNeededSize;
if (dwTotalSize >= dwNeededSize)
{
pProviderList->dwUsedSize = dwNeededSize;
pProviderList->dwNumProviders = (DWORD) iNumProviders;
pProviderList->dwProviderListSize =
(DWORD) (iNumProviders * sizeof (LINEPROVIDERENTRY));
pProviderList->dwProviderListOffset = dwFixedSizeClient;
}
else
{
pProviderList->dwUsedSize = dwFixedSizeClient;
pProviderList->dwNumProviders =
pProviderList->dwProviderListSize =
pProviderList->dwProviderListOffset = 0;
}
pParams->dwProviderListOffset = 0;
*pdwNumBytesReturned = sizeof (TAPI32_MSG) + pProviderList->dwUsedSize;
RegCloseKey (hKey);
LGetProviderList_epilog:
#if DBG
{
char szResult[32];
LOG((TL_TRACE,
"lineGetProviderList: exit, result=%s",
MapResultCodeToText (pParams->lResult, szResult)
));
}
#else
LOG((TL_TRACE,
"lineGetProviderList: exit, result=x%x",
pParams->lResult
));
#endif
return;
}
void
WINAPI
LGetProxyStatus(
PTCLIENT ptClient,
PLINEGETPROXYSTATUS_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
DWORD dwDeviceID;
HANDLE hMutex;
DWORD objectToDereference;
PTLINELOOKUPENTRY pLookupEntry;
//
// Verify size/offset/string params given our input buffer/size
//
if (pParams->dwProxyStatusTotalSize > dwParamsBufferSize)
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
switch (pParams->dwAppAPIVersion)
{
case TAPI_VERSION1_0:
case TAPI_VERSION1_4:
case TAPI_VERSION2_0:
case TAPI_VERSION2_1:
case TAPI_VERSION2_2:
case TAPI_VERSION3_0:
case TAPI_VERSION_CURRENT:
break;
default:
pParams->lResult = LINEERR_INCOMPATIBLEAPIVERSION;
return;
}
if ((pParams->lResult = LINEPROLOG(
ptClient, // tClient
DEVICE_ID, // widget type
(DWORD) pParams->hLineApp, // client widget handle
(LPVOID) &dwDeviceID, // provider widget handle
pParams->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
&objectToDereference, // object to dereference
&pLookupEntry, // context
"GetProxyStatus" // func name
)) == 0)
{
DWORD dwAPIVersion = 0;
DWORD dwTotalSize = 0;
DWORD dwFixedSizeClient = 0;
//
// Determine the fixed size of the structure for the
// specified API version
//
dwAPIVersion = pParams->dwAppAPIVersion;
dwFixedSizeClient = sizeof (LINEPROXYREQUESTLIST);
//
// Will it fit ?
//
dwTotalSize = pParams->dwProxyStatusTotalSize;
if (dwTotalSize >= dwFixedSizeClient)
{
//
// OK, buffer's large enough for fixed part.
//
// Is this line remote ?
//
if (pLookupEntry->bRemote)
{
LPLINEPROXYREQUESTLIST pProxyReqList =
(LPLINEPROXYREQUESTLIST) pDataBuf;
InitTapiStruct(
pProxyReqList,
dwTotalSize,
dwFixedSizeClient,
TRUE
);
pParams->lResult = CallSP3(
pRemoteSP->apfn[SP_LINEGETPROXYSTATUS],
"LineGetProxyStatus",
SP_FUNC_SYNC,
(DWORD) dwDeviceID,
(DWORD) dwAPIVersion,
(ULONG_PTR) pProxyReqList
);
//
// Set the return values
//
pParams->dwAPIVersion = dwAPIVersion;
pParams->dwProxyStatusOffset = 0;
*pdwNumBytesReturned = sizeof (TAPI32_MSG) +
pProxyReqList->dwUsedSize;
}
else // it's a local line
{
DWORD i;
DWORD dwNeededSize;
LPDWORD pListEntry;
PTLINE ptLine = pLookupEntry->ptLine;
LPLINEPROXYREQUESTLIST pProxyReqList =
(LPLINEPROXYREQUESTLIST) pDataBuf;
if (ptLine != NULL)
{
//
// how much space is needed for the list ?
//
dwNeededSize = sizeof (LINEPROXYREQUESTLIST);
pProxyReqList->dwNumEntries = 0;
for(
i = LINEPROXYREQUEST_SETAGENTGROUP;
i <= LINEPROXYREQUEST_LASTVALUE;
i++
)
{
try // Just in case the line gets closed
{
if (ptLine->apProxys[i] != NULL)
{
//
// So there's a proxy associated with
// this proxy request type, add on space
// requirement for it's list entry
//
dwNeededSize += sizeof(DWORD);
}
}
myexcept
{
pParams->lResult = LINEERR_OPERATIONUNAVAIL;
goto LGetProxyStatus_epilog;
}
}
//
// Will it fit ?
//
if (dwTotalSize >= dwNeededSize)
{
//
// enough room , so fill in list
//
pProxyReqList->dwListSize = 0;
pProxyReqList->dwNumEntries = 0;
pProxyReqList->dwListOffset =
sizeof(LINEPROXYREQUESTLIST);
pListEntry = (LPDWORD) ((BYTE *) pProxyReqList +
sizeof (LINEPROXYREQUESTLIST));
for(
i = LINEPROXYREQUEST_SETAGENTGROUP;
i <= LINEPROXYREQUEST_LASTVALUE;
i++
)
{
try // Just in case the line gets closed
{
if (ptLine->apProxys[i] != NULL)
{
//
// So there's a proxy associated with
// this proxy request type, add on space
// requirement for entry to list size
//
pProxyReqList->dwListSize += sizeof(DWORD);
//
// Incr number of entries in the list
//
pProxyReqList->dwNumEntries++;
//
// Proxy reqest type is ..
//
*pListEntry++ = i;
}
}
myexcept
{
pParams->lResult = LINEERR_OPERATIONUNAVAIL;
goto LGetProxyStatus_epilog;
}
}
//
// set the total, used & need sizes
//
pProxyReqList->dwTotalSize = dwTotalSize;
pProxyReqList->dwUsedSize = dwNeededSize;
pProxyReqList->dwNeededSize = dwNeededSize;
//
// Set the return values
//
pParams->dwAPIVersion = dwAPIVersion;
pParams->dwProxyStatusOffset = 0;
*pdwNumBytesReturned = sizeof (TAPI32_MSG) +
pProxyReqList->dwUsedSize;
}
else // Buffer too small for the list, so return an error
{
pParams->lResult = LINEERR_STRUCTURETOOSMALL;
}
}
else // (ptLine == NULL) - No line open, so no proxies !
{
pParams->lResult = LINEERR_OPERATIONFAILED;
LOG((TL_ERROR, "lineGetProxyStatus - no line open"));
}
} // endif bRemote
}
else // Buffer too small
{
pParams->lResult = LINEERR_STRUCTURETOOSMALL;
}
} // endif LINEPROLOG
LGetProxyStatus_epilog:
LINEEPILOGSYNC(
&pParams->lResult,
hMutex,
bCloseMutex,
objectToDereference,
"GetLineProxyStatus"
);
}
void
WINAPI
LGetQueueInfo(
PTCLIENT ptClient,
PLINEGETQUEUEINFO_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
LGetAgentWithoutAddressIDXxx(
ptClient,
(PLINEGETAGENTINFO_PARAMS) pParams,
dwParamsBufferSize,
LINEPROXYREQUEST_GETQUEUEINFO,
SP_LINEGETQUEUEINFO,
sizeof (LINEQUEUEINFO)
#if DBG
,
"GetQueueInfo"
#endif
);
}
void
WINAPI
LGetQueueList(
PTCLIENT ptClient,
PLINEGETQUEUELIST_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
LONG lRequestID;
HANDLE hMutex;
HDRVLINE hdLine;
DWORD objectToDereference;
PTLINECLIENT ptLineClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
//
// Verify size/offset/string params given our input buffer/size
//
if (ISBADSIZEOFFSET(
dwParamsBufferSize,
0,
pParams->dwGroupIDSize,
pParams->dwGroupIDOffset,
sizeof(DWORD),
"LGetQueueList",
"pParams->GroupID"
))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HLINE, // widget type
(DWORD) pParams->hLine, // client widget handle
(LPVOID) &hdLine, // provider widget handle
0, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
0, // provider func index
NULL, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptLineClient, // context
"GetQueueList" // func name
)) > 0)
{
LONG lResult;
DWORD dwDeviceID,
dwTotalSize = pParams->dwQueueListTotalSize;
PTLINECLIENT pProxy;
if (dwTotalSize < sizeof( LINEQUEUELIST ) )
{
lRequestID = LINEERR_STRUCTURETOOSMALL;
goto LGetQueueList_epilog;
}
if ((lResult = FindProxy(
ptLineClient,
0,
LINEPROXYREQUEST_GETQUEUELIST,
&pProxy,
&dwDeviceID,
TAPI_VERSION2_2
)))
{
lRequestID = lResult;
goto LGetQueueList_epilog;
}
//
// Save the client's buf ptr & post processing proc ptr
//
pAsyncRequestInfo->dwParam1 = pParams->hpQueueList;
pAsyncRequestInfo->dwParam2 = dwTotalSize;
pAsyncRequestInfo->hfnClientPostProcessProc =
pParams->hfnPostProcessProc;
//
// First check to see if there's a (local) proxy registered
// for this type of request on this line. If so, build a
// request & send it to the proxy.
//
if (pProxy)
{
LONG lResult;
PPROXYREQUESTWRAPPER pProxyRequestWrapper;
if ((lResult = CreateProxyRequest(
pProxy,
LINEPROXYREQUEST_GETQUEUELIST,
sizeof(GUID) + sizeof(DWORD),
pAsyncRequestInfo,
&pProxyRequestWrapper
)))
{
lRequestID = lResult;
goto LGetQueueList_epilog;
}
CopyMemory(
&(pProxyRequestWrapper->ProxyRequest.GetQueueList.GroupID),
pDataBuf + pParams->dwGroupIDOffset,
sizeof(GUID)
);
pProxyRequestWrapper->ProxyRequest.GetQueueList.
QueueList.dwTotalSize = dwTotalSize;
if ((lResult = SendProxyRequest(
pProxy,
pProxyRequestWrapper,
pAsyncRequestInfo
)))
{
lRequestID = lResult;
goto LGetQueueList_epilog;
}
else // success
{
pParams->lResult = (LONG) pAsyncRequestInfo->dwLocalRequestID;
}
}
//
// There's no proxy, so check to see if line is remote and
// call remotesp if so
//
else if ((GetLineLookupEntry (dwDeviceID))->bRemote)
{
LPBYTE pBuf;
LPLINEAGENTINFO pAgentInfo;
//
// 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(
sizeof (ASYNCEVENTMSG) + ((dwTotalSize + 7) & 0xfffffff8)
)))
{
lRequestID = LINEERR_NOMEM;
goto LGetQueueList_epilog;
}
pAsyncRequestInfo->pfnPostProcess =
LGetAgentXxx_PostProcess;
pAsyncRequestInfo->dwParam3 = (ULONG_PTR) pBuf;
pAgentInfo = (LPLINEAGENTINFO)
(pBuf + sizeof (ASYNCEVENTMSG));
pAgentInfo->dwTotalSize = dwTotalSize;
pParams->lResult = CallSP4(
pRemoteSP->apfn[SP_LINEGETQUEUELIST],
"LineGetQueueList",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdLine,
(ULONG_PTR) (pDataBuf + pParams->dwGroupIDOffset),
(ULONG_PTR) pAgentInfo
);
}
//
// There's no registered proxy & line is not remote, so fail
//
else
{
lRequestID = LINEERR_OPERATIONUNAVAIL;
}
}
LGetQueueList_epilog:
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"GetQueueList"
);
}
void
WINAPI
LGetRequest(
PTCLIENT ptClient,
PLINEGETREQUEST_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
PTLINEAPP ptLineApp;
PTREQUESTMAKECALL pRequestMakeCall;
//
// Verify size/offset/string params given our input buffer/size
//
if (dwParamsBufferSize < sizeof (LINEREQMAKECALLW))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if ((ptLineApp = WaitForExclusiveLineAppAccess(
pParams->hLineApp,
ptClient
)))
{
if (pParams->dwRequestMode == LINEREQUESTMODE_MAKECALL)
{
if (!ptLineApp->pRequestRecipient)
{
pParams->lResult = LINEERR_NOTREGISTERED;
goto LGetRequest_releaseMutex;
}
EnterCriticalSection (&gPriorityListCritSec);
// note: if here guaranteed to be >=1 reqRecip obj in global list
if (_wcsicmp(
ptLineApp->pszModuleName,
TapiGlobals.pHighestPriorityRequestRecipient->
ptLineApp->pszModuleName
) == 0)
{
if ((pRequestMakeCall = TapiGlobals.pRequestMakeCallList))
{
CopyMemory(
pDataBuf,
&pRequestMakeCall->LineReqMakeCall,
sizeof (LINEREQMAKECALLW)
);
LOG((TL_INFO, "Getting request: 0x%p", pRequestMakeCall));
LOG((TL_INFO, " DestAddress: [%ls]",
pRequestMakeCall->LineReqMakeCall.szDestAddress));
LOG((TL_INFO, " AppName: [%ls]",
pRequestMakeCall->LineReqMakeCall.szAppName));
LOG((TL_INFO, " CalledParty: [%ls]",
pRequestMakeCall->LineReqMakeCall.szCalledParty));
LOG((TL_INFO, " Comment: [%ls]",
pRequestMakeCall->LineReqMakeCall.szComment));
pParams->dwRequestBufferOffset = 0;
pParams->dwSize = sizeof (LINEREQMAKECALLW);
*pdwNumBytesReturned = sizeof (TAPI32_MSG) +
sizeof (LINEREQMAKECALLW);
if (!(TapiGlobals.pRequestMakeCallList =
pRequestMakeCall->pNext))
{
TapiGlobals.pRequestMakeCallListEnd = NULL;
}
ServerFree (pRequestMakeCall);
}
else
{
pParams->lResult = LINEERR_NOREQUEST;
}
}
else
{
pParams->lResult = LINEERR_NOREQUEST;
}
LeaveCriticalSection (&gPriorityListCritSec);
}
else if (pParams->dwRequestMode == LINEREQUESTMODE_MEDIACALL)
{
pParams->lResult = (ptLineApp->bReqMediaCallRecipient ?
LINEERR_NOREQUEST : LINEERR_NOTREGISTERED);
}
else
{
pParams->lResult = LINEERR_INVALREQUESTMODE;
}
LGetRequest_releaseMutex:
UNLOCKTLINEAPP(ptLineApp);
}
else
{
pParams->lResult = (TapiGlobals.dwNumLineInits == 0 ?
LINEERR_UNINITIALIZED : LINEERR_INVALAPPHANDLE);
}
#if DBG
{
char szResult[32];
LOG((TL_TRACE,
"lineGetRequest: exit, result=%s",
MapResultCodeToText (pParams->lResult, szResult)
));
}
#else
LOG((TL_TRACE,
"lineGetRequest: exit, result=x%x",
pParams->lResult
));
#endif
return;
}
void
WINAPI
LGetStatusMessages(
PTCLIENT ptClient,
PLINEGETSTATUSMESSAGES_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
PTLINECLIENT ptLineClient;
if ((ptLineClient = ReferenceObject(
ghHandleTable,
pParams->hLine,
TLINECLIENT_KEY
)))
{
if (ptLineClient->ptClient == ptClient)
{
pParams->dwLineStates = ptLineClient->dwLineStates;
pParams->dwAddressStates = ptLineClient->dwAddressStates;
*pdwNumBytesReturned = sizeof (LINEGETSTATUSMESSAGES_PARAMS);
}
else
{
pParams->lResult = (TapiGlobals.dwNumLineInits ?
LINEERR_INVALLINEHANDLE : LINEERR_UNINITIALIZED);
}
DereferenceObject (ghHandleTable, pParams->hLine, 1);
}
else
{
pParams->lResult = (TapiGlobals.dwNumLineInits ?
LINEERR_INVALLINEHANDLE : LINEERR_UNINITIALIZED);
}
#if DBG
{
char szResult[32];
LOG((TL_TRACE,
"lineGetStatusMessages: exit, result=%s",
MapResultCodeToText (pParams->lResult, szResult)
));
}
#else
LOG((TL_TRACE,
"lineGetStatusMessages: exit, result=x%x",
pParams->lResult
));
#endif
}
void
WINAPI
LHandoff(
PTCLIENT ptClient,
PLINEHANDOFF_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
HANDLE hMutex;
HDRVCALL hdCall;
DWORD objectToDereference;
PTCALLCLIENT ptCallClientApp;
TPOINTERLIST xxxClientList, *pXxxClientList = &xxxClientList;
//
// Verify size/offset/string params given our input buffer/size
//
if ((pParams->dwFileNameOffset != TAPI_NO_DATA) &&
IsBadStringParam(
dwParamsBufferSize,
pDataBuf,
pParams->dwFileNameOffset
))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if ((pParams->lResult = LINEPROLOG(
ptClient, // tClient
ANY_RT_HCALL, // widget type
(DWORD) pParams->hCall, // client widget handle
(LPVOID) &hdCall, // provider widget handle
LINECALLPRIVILEGE_OWNER, // req'd privileges (call only)
&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
&objectToDereference, // object to dereference
&ptCallClientApp, // context
"Handoff" // func name
)) == 0)
{
LONG lResult;
DWORD dwAPIVersion, dwValidMediaModes, i,
dwMediaMode = pParams->dwMediaMode;
WCHAR *pszFileName = (pParams->dwFileNameOffset==TAPI_NO_DATA
? NULL :
(PWSTR)(pDataBuf + pParams->dwFileNameOffset));
PTLINE ptLine;
PTCALL ptCall;
PTLINECLIENT ptLineClientApp, ptLineClientTarget, ptLineClientTmp;
HCALL hCall;
HLINE hLine;
//
// Safely retrieve all the object pointers needed below, then get
// a list of line clients
//
try
{
ptCall = ptCallClientApp->ptCall;
ptLineClientApp = ptCallClientApp->ptLineClient;
ptLine = ptLineClientApp->ptLine;
dwAPIVersion = ptLineClientApp->dwAPIVersion;
hCall = ptCall->hCall;
hLine = ptLine->hLine;
}
myexcept
{
pParams->lResult = LINEERR_INVALCALLHANDLE;
goto LHandoff_epilog;
}
if ((lResult = GetLineClientListFromLine (ptLine, &pXxxClientList)))
{
pParams->lResult = lResult;
goto LHandoff_epilog;
}
if (pszFileName)
{
//
// "Directed" handoff
//
// Walk thru the list of clients on this line & find the oldest
// one (that's an owner) with an app name that matches the
// specified app name
//
// Note: It's possible that a target app who opened the line
// with OWNER privilege for only DATAMODEM calls will be a
// target of a directed handoff for calls of a different media
// mode, i.e. G3FAX. TNixon decided that it was desirable
// to maintain this behavior for existing apps which may rely
// on it. (10/24/95)
//
_wcsupr(pszFileName);
ptLineClientTarget = NULL;
for (i = 0; i < pXxxClientList->dwNumUsedEntries; i++)
{
ptLineClientTmp = (PTLINECLIENT) pXxxClientList->aEntries[i];
try
{
//
// Recall that all app names start with '"'
//
LOG((TL_INFO,
"LHandoff: Looking for [%ls] list entry [%ls]",
pszFileName,
ptLineClientTmp->ptLineApp->pszModuleName
));
if ((_wcsicmp(
pszFileName,
ptLineClientTmp->ptLineApp->pszModuleName + 1
) == 0) &&
(ptLineClientTmp->dwPrivileges &
LINECALLPRIVILEGE_OWNER))
{
ptLineClientTarget = ptLineClientTmp;
}
}
myexcept
{
// just continue
}
}
if (ptLineClientTarget == NULL)
{
pParams->lResult = LINEERR_TARGETNOTFOUND;
goto LHandoff_freeXxxClientList;
}
else if (ptLineClientTarget == ptLineClientApp)
{
pParams->lResult = LINEERR_TARGETSELF;
goto LHandoff_freeXxxClientList;
}
}
else
{
//
// "Non-directed" handoff
//
// Validate the media mode, then walk thru the list of line
// clients and find the highest pri one with owner privileges
// that wants calls of the specified media mode
//
switch (dwAPIVersion)
{
case TAPI_VERSION1_0:
dwValidMediaModes = AllMediaModes1_0;
break;
case TAPI_VERSION1_4:
case TAPI_VERSION2_0:
dwValidMediaModes = AllMediaModes1_4;
break;
//case TAPI_VERSION2_1:
//case TAPI_VERSION2_2:
default: //case TAPI_VERSION_CURRENT:
dwValidMediaModes = AllMediaModes2_1;
break;
}
if ((dwMediaMode == 0) ||
(dwAPIVersion <= TAPI_VERSION2_1 ) &&
!IsOnlyOneBitSetInDWORD(dwMediaMode) ||
(dwMediaMode & (dwValidMediaModes ^ 0x00ffffff)))
{
pParams->lResult = LINEERR_INVALMEDIAMODE;
goto LHandoff_freeXxxClientList;
}
if ((ptLineClientTarget = GetHighestPriorityLineClient(
ptLine,
dwMediaMode,
0xffffffff
)) == NULL)
{
pParams->lResult = LINEERR_TARGETNOTFOUND;
goto LHandoff_freeXxxClientList;
}
else if (ptLineClientTarget == ptLineClientApp)
{
pParams->lResult = LINEERR_TARGETSELF;
goto LHandoff_freeXxxClientList;
}
}
//
// We've found a target tLineClient. See if it already has a
// tCallClient for this call, and if not create one. Then set
// the privilege on the target's tCallClient to OWNER & send
// the appropriate msgs.
//
if (pXxxClientList != &xxxClientList)
{
ServerFree (pXxxClientList);
}
if ((lResult = GetCallClientListFromCall(
ptCall,
&pXxxClientList
)))
{
pParams->lResult = lResult;
goto LHandoff_epilog;
}
{
BOOL bCreatedtCallClient,
bTargetAlreadyOwner = FALSE;
HANDLE hMutex;
PTCALLCLIENT ptCallClientTarget = NULL, ptCallClientTmp;
for (i = 0; i < pXxxClientList->dwNumUsedEntries; i++)
{
ptCallClientTmp = (PTCALLCLIENT) pXxxClientList->aEntries[i];
try
{
if (ptCallClientTmp->ptLineClient == ptLineClientTarget)
{
ptCallClientTarget = ptCallClientTmp;
break;
}
}
myexcept
{
// just continue
}
}
if (!ptCallClientTarget)
{
if ((lResult = CreatetCallClient(
ptCall,
ptLineClientTarget,
LINECALLPRIVILEGE_OWNER,
TRUE,
TRUE,
&ptCallClientTarget,
FALSE
)) != 0)
{
pParams->lResult = lResult;
goto LHandoff_freeXxxClientList;
}
bCreatedtCallClient = TRUE;
}
else
{
bCreatedtCallClient = FALSE;
}
if (WaitForExclusivetCallAccess (ptCall, TCALL_KEY))
{
DWORD dwCallInfoState, dwCallState, dwCallStateMode;
if (bCreatedtCallClient)
{
//
// CreatetCallClient will have already sent out the
// appropriate CALLINFO msgs & updated NumOwners field
//
dwCallInfoState = 0;
}
else if (ptCallClientTarget->dwPrivilege ==
LINECALLPRIVILEGE_MONITOR)
{
ptCallClientTarget->dwPrivilege = LINECALLPRIVILEGE_OWNER;
ptCall->dwNumOwners++;
ptCall->dwNumMonitors--;
dwCallInfoState = LINECALLINFOSTATE_NUMOWNERINCR |
LINECALLINFOSTATE_NUMMONITORS;
}
else
{
//
// Ideally we should just be able to exit at this point.
// However, TAPI 1.x will send a CALLSTATE msg with
// dwParam3 == OWNER to the target app even though it
// already is an OWNER. Some Intel app relies on this
// behavior, so we'll preserve it for now...
//
bTargetAlreadyOwner = TRUE;
dwCallInfoState = 0;
}
dwCallState = ptCall->dwCallState;
dwCallStateMode = ptCall->dwCallStateMode;
UNLOCKTCALL(ptCall);
if (dwCallInfoState ||
bCreatedtCallClient ||
bTargetAlreadyOwner)
{
BOOL bIndicatePrivilege = TRUE;
PTCLIENT ptClientTarget;
ASYNCEVENTMSG msg[2];
if (bCreatedtCallClient)
{
try
{
if (ptLineClientTarget->dwAPIVersion >=
TAPI_VERSION2_0 &&
!FMsgDisabled(
ptLineClientTarget->ptLineApp->dwAPIVersion,
ptLineClientTarget->adwEventSubMasks,
LINE_APPNEWCALL,
0
))
{
ASYNCEVENTMSG newCallMsg[2],
*pNewCallMsg = newCallMsg;
PTCONFERENCELIST pConfList;
BOOL bConfParent = FALSE;
pNewCallMsg->TotalSize =
sizeof (ASYNCEVENTMSG) + 3*sizeof (DWORD);
pNewCallMsg->fnPostProcessProcHandle = 0;
pNewCallMsg->hDevice =
ptLineClientTarget->hRemoteLine;
pNewCallMsg->Msg = LINE_APPNEWCALL;
pNewCallMsg->Param1 =
ptCall->dwAddressID;
pNewCallMsg->Param2 =
ptCallClientTarget->hCall;
pNewCallMsg->Param3 =
LINECALLPRIVILEGE_OWNER;
*(&pNewCallMsg->Param4 + 1) =
ptCall->dwCallID;
*(&pNewCallMsg->Param4 + 2) =
ptCall->dwRelatedCallID;
if ((pConfList = ptCall->pConfList) &&
(pConfList != (PTCONFERENCELIST) LongToPtr(0xffffffff)) &&
(pConfList->aptCalls[0] == ptCall))
{
bConfParent = TRUE;
}
*(&pNewCallMsg->Param4 + 3) = (DWORD) bConfParent;
pNewCallMsg->InitContext =
ptLineClientTarget->ptLineApp->
InitContext;
pNewCallMsg->OpenContext =
ptLineClientTarget->OpenContext;
ptClientTarget = ptCallClientTarget->ptClient;
if (ptCallClientTarget->dwKey ==
TCALLCLIENT_KEY)
{
bIndicatePrivilege = FALSE;
WriteEventBuffer(
ptClientTarget,
pNewCallMsg
);
}
}
}
myexcept
{
}
}
msg->TotalSize = sizeof (ASYNCEVENTMSG) +
sizeof (HCALLHUB);
msg->fnPostProcessProcHandle = 0;
msg->Msg = LINE_CALLSTATE;
msg->Param1 = dwCallState;
msg->Param2 = dwCallStateMode;
msg->Param3 = (bIndicatePrivilege ?
LINECALLPRIVILEGE_OWNER : 0);
try
{
msg->hDevice = ptCallClientTarget->hCall;
msg->InitContext =
ptLineClientTarget->ptLineApp->InitContext;
msg->OpenContext =
ptLineClientTarget->OpenContext;
*((LPHCALLHUB)(&msg->Param4 + 1)) =
(ptCallClientTarget->ptCallHubClient)?
ptCallClientTarget->ptCallHubClient->hCallHub :
(HCALLHUB)(ULONG_PTR)NULL;
ptClientTarget = ptCallClientTarget->ptClient;
if (ptCallClientTarget->dwKey == TCALLCLIENT_KEY &&
!FMsgDisabled (
ptCallClientTarget->ptLineClient->ptLineApp->dwAPIVersion,
ptCallClientTarget->adwEventSubMasks,
LINE_CALLSTATE,
dwCallState
))
{
WriteEventBuffer (ptClientTarget, msg);
}
}
myexcept
{
}
if (dwCallInfoState != 0)
{
LineEventProc(
(HTAPILINE)(ULONG_PTR)hLine,
(HTAPICALL)(ULONG_PTR)hCall,
LINE_CALLINFO,
dwCallInfoState,
0,
0
);
}
if (bCreatedtCallClient)
{
UpdateCallHubHashing(ptCall);
}
}
}
}
LHandoff_freeXxxClientList:
if (pXxxClientList != &xxxClientList)
{
ServerFree (pXxxClientList);
}
}
LHandoff_epilog:
LINEEPILOGSYNC(
&pParams->lResult,
hMutex,
bCloseMutex,
objectToDereference,
"Handoff"
);
}
void
WINAPI
LHold(
PTCLIENT ptClient,
PLINEHOLD_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
LONG lRequestID;
HANDLE hMutex;
HDRVCALL hdCall;
TSPIPROC pfnTSPI_lineHold;
DWORD objectToDereference;
PTCALLCLIENT ptCallClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HCALL, // widget type
pParams->hCall, // client widget handle
(LPVOID) &hdCall, // provider widget handle
LINECALLPRIVILEGE_OWNER, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINEHOLD, // provider func index
&pfnTSPI_lineHold, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptCallClient, // context
"Hold" // func name
)) > 0)
{
pParams->lResult = CallSP2(
pfnTSPI_lineHold,
"lineHold",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdCall
);
}
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"Hold"
);
}
void
WINAPI
LInitialize(
PTCLIENT ptClient,
PLINEINITIALIZE_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bInitClient = FALSE;
DWORD dwFriendlyNameSize, dwModuleNameSize;
PTLINEAPP ptLineApp;
//
// Verify size/offset/string params given our input buffer/size
//
if (IsBadStringParam(
dwParamsBufferSize,
pDataBuf,
pParams->dwFriendlyNameOffset
) ||
IsBadStringParam(
dwParamsBufferSize,
pDataBuf,
pParams->dwModuleNameOffset
))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
//
// Alloc & init a new tLineApp
//
dwFriendlyNameSize = sizeof(WCHAR) * (1 + lstrlenW(
(PWSTR)(pDataBuf + pParams->dwFriendlyNameOffset))
);
dwModuleNameSize = sizeof(WCHAR) * (2 + lstrlenW(
(PWSTR)(pDataBuf + pParams->dwModuleNameOffset))
);
if (!(ptLineApp = ServerAlloc(
sizeof(TLINEAPP) +
dwFriendlyNameSize +
dwModuleNameSize
)))
{
pParams->lResult = LINEERR_NOMEM;
goto LInitialize_return;
}
LOG((TL_INFO, "LInitialize: calling NewObject ptLineApp %p, pParams->InitContext %lx", ptLineApp, pParams->InitContext));
if (!(ptLineApp->hLineApp = (HLINEAPP) NewObject(
ghHandleTable,
ptLineApp,
NULL
)))
{
pParams->lResult = LINEERR_NOMEM;
ServerFree (ptLineApp);
goto LInitialize_return;
}
LOG((TL_INFO, "LInitialize: NewObject returned hLineApp %lx", ptLineApp->hLineApp));
ptLineApp->dwKey = TLINEAPP_KEY;
ptLineApp->ptClient = ptClient;
LOG((TL_INFO, "LInitialize: initializing ptLineApp->InitContext with %lx", pParams->InitContext));
ptLineApp->InitContext = pParams->InitContext;
ptLineApp->dwAPIVersion = pParams->dwAPIVersion;
LOG((TL_INFO, "LInitialize: initialized ptLineApp->dwAPIVersion with %lx", pParams->dwAPIVersion));
ptLineApp->dwFriendlyNameSize = dwFriendlyNameSize;
ptLineApp->pszFriendlyName = (WCHAR *) (ptLineApp + 1);
wcscpy(
ptLineApp->pszFriendlyName,
(PWSTR)(pDataBuf + pParams->dwFriendlyNameOffset)
);
//
// Note: we prepend the '"' char to the saved module name to aid in
// priority determination for incoming calls
//
ptLineApp->dwModuleNameSize = dwModuleNameSize;
ptLineApp->pszModuleName = (WCHAR *)((LPBYTE)(ptLineApp + 1) +
dwFriendlyNameSize);
ptLineApp->pszModuleName[0] = '"';
wcscpy(
&ptLineApp->pszModuleName[1],
(WCHAR *)(pDataBuf + pParams->dwModuleNameOffset)
);
_wcsupr (&ptLineApp->pszModuleName[1]);
//
// Safely insert new tLineApp at front of tClient's tLineApp list
//
if (ptClient->ptLineApps == NULL)
{
bInitClient = TRUE;
}
if (WaitForExclusiveClientAccess (ptClient))
{
if (ptLineApp->dwAPIVersion <= TAPI_VERSION3_0)
{
FillMemory (
ptLineApp->adwEventSubMasks,
sizeof(DWORD) * EM_NUM_MASKS,
(BYTE) 0xff
);
}
else
{
CopyMemory (
ptLineApp->adwEventSubMasks,
ptClient->adwEventSubMasks,
sizeof(DWORD) * EM_NUM_MASKS
);
}
if ((ptLineApp->pNext = ptClient->ptLineApps))
{
ptLineApp->pNext->pPrev = ptLineApp;
}
ptClient->ptLineApps = ptLineApp;
UNLOCKTCLIENT (ptClient);
}
else
{
pParams->lResult = LINEERR_OPERATIONFAILED;
goto LInitialize_error1;
}
//
// Check if global reinit flag set
//
if (TapiGlobals.dwFlags & TAPIGLOBALS_REINIT)
{
pParams->lResult = LINEERR_REINIT;
goto LInitialize_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 LInitialize_error2;
}
gbServerInited = TRUE;
}
#if TELE_SERVER
if (bInitClient)
{
if (pParams->lResult = InitializeClient(ptClient))
{
TapiLeaveCriticalSection (&TapiGlobals.CritSec);
goto LInitialize_error2;
}
}
#else
pParams->lResult = 0; // That's what happens if it's not a tele_server...
#endif
//
// Fill in the return values
//
pParams->hLineApp = ptLineApp->hLineApp;
LOG((TL_INFO, "LInitialize: returning pParams->hLineApp %p", pParams->hLineApp));
pParams->dwNumDevs = TapiGlobals.dwNumLines;
LOG((TL_INFO, "LInitialize: returning pParams->dwNumDevs %p", pParams->dwNumDevs));
#if TELE_SERVER
if ((TapiGlobals.dwFlags & TAPIGLOBALS_SERVER) &&
!IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR))
{
pParams->dwNumDevs = ptClient->dwLineDevices;
LOG((TL_TRACE, "LInitialize: returning pParams->dwNumDevs %p (again)", pParams->dwNumDevs));
}
#endif
//
// Increment total num line inits
//
TapiGlobals.dwNumLineInits++;
*pdwNumBytesReturned = sizeof (LINEINITIALIZE_PARAMS);
TapiLeaveCriticalSection (&TapiGlobals.CritSec);
goto LInitialize_return;
LInitialize_error2:
if (WaitForExclusiveClientAccess (ptClient))
{
if (ptLineApp->pNext)
{
ptLineApp->pNext->pPrev = ptLineApp->pPrev;
}
if (ptLineApp->pPrev)
{
ptLineApp->pPrev->pNext = ptLineApp->pNext;
}
else
{
ptClient->ptLineApps = ptLineApp->pNext;
}
UNLOCKTCLIENT (ptClient);
}
LInitialize_error1:
DereferenceObject (ghHandleTable, ptLineApp->hLineApp, 1);
LInitialize_return:
#if DBG
{
char szResult[32];
LOG((TL_TRACE,
"lineInitialize: exit, result=%s",
MapResultCodeToText (pParams->lResult, szResult)
));
}
#else
LOG((TL_TRACE,
"lineInitialize: exit, result=x%x",
pParams->lResult
));
#endif
return;
}
void
LMakeCall_PostProcess(
PASYNCREQUESTINFO pAsyncRequestInfo,
PASYNCEVENTMSG pAsyncEventMsg,
LPVOID *ppBuf
)
{
PTCALL ptCall = (PTCALL) pAsyncRequestInfo->dwParam1;
DWORD hpCallHandle = DWORD_CAST(pAsyncRequestInfo->dwParam2,__FILE__,__LINE__);
PTCALLCLIENT ptCallClient;
if (WaitForExclusivetCallAccess (ptCall, TINCOMPLETECALL_KEY))
{
PTCALL ptCallThen;
HCALL hCallThen = (HCALL)pAsyncRequestInfo->dwParam5;
//
// Check to make sure this is the call we think it is (that the
// pointer wasn't freed by a previous call to lineClose/Shutdown
// and realloc'd for use as a ptCall again)
//
if (ptCall->hCall != hCallThen)
{
UNLOCKTCALL(ptCall);
goto LMakeCall_PostProcess_bad_ptCall;
}
ptCallClient = ptCall->ptCallClients;
if (pAsyncEventMsg->Param2 == 0) // success
{
//
// In general it's ok with us if service providers want to
// specify NULL as their hdCall (could be an index in an
// array). But in the TSPI_lineForward case, the spec says
// that a NULL hdCall value following successful completion
// indicates that no call was created, so in that case we
// want to nuke the tCall & tCallClient we created, and
// indicate a NULL call handle to the client. A non-zero
// pAsyncRequestInfo->dwParam3 tells us that we are
// post-processing a lineForward request, otherwise it's a
// make call or similar (non-Forward) request.
//
if (pAsyncRequestInfo->dwParam3 && !ptCall->hdCall)
{
goto LMakeCall_PostProcess_cleanupCalls;
}
//
// Check to see if the app closed the line & left us with
// 0 call clients (in which case it'll also be taking care of
// cleaning up this tCall too)
//
if (ptCall->ptCallClients == NULL)
{
UNLOCKTCALL(ptCall);
ptCallClient = (PTCALLCLIENT) NULL;
if (pAsyncEventMsg->Param2 == 0)
{
pAsyncEventMsg->Param2 = LINEERR_INVALLINEHANDLE;
}
goto LMakeCall_PostProcess_initMsgParams;
}
//
// Retrieve the various call IDs, then check if call
// client was destroyed by another thread (due to
// lineClose/Shutdown) while we were getting the call ID.
// If so, we'll need to clean up the tCall, since we know
// the other thread didn't do it because GetCallIDs marks
// the call as a zombie.
//
GetCallIDs (ptCall);
if (ptCall->ptCallClients == NULL)
{
goto LMakeCall_PostProcess_cleanupCalls;
}
//
// Stuff the various call IDs in the var data section
// of the ASYNCEVENTMSG.
//
// Make sure to increment the dwTotalSize of the ASYNCEVENTMSG
// as appropriate. We rely on the fact that CompletionProc()
// calls us with a AsyncEventMsg buffer which is big enough to
// handle a few extra DWORDs.
//
pAsyncEventMsg->Param3 = ptCallClient->hCall;
pAsyncEventMsg->TotalSize +=
3 * sizeof (pAsyncEventMsg->Param1);
*(&pAsyncEventMsg->Param4 + 1) = ptCall->dwAddressID;
*(&pAsyncEventMsg->Param4 + 2) = ptCall->dwCallID;
*(&pAsyncEventMsg->Param4 + 3) = ptCall->dwRelatedCallID;
//
// Mark the calls as valid, the release the mutex.
//
ptCall->dwKey = TCALL_KEY;
ptCallClient->dwKey = TCALLCLIENT_KEY;
UNLOCKTCALL(ptCall);
//
// Create monitor tCallClients
//
if (ptCallThen = ReferenceObject(ghHandleTable, hCallThen, TCALL_KEY))
{
if (ptCallThen == ptCall)
{
CreateCallMonitors (ptCall, FALSE);
}
DereferenceObject(ghHandleTable, hCallThen, 1);
}
}
else // error
{
LMakeCall_PostProcess_cleanupCalls:
//
// Invalidate the tCall, & if there's still a tCallClient
// (might have already been destroyed by a lineClose/Shutdown
// in another thread) invalidate it too. Then unlock the
// tCall & remove the object(s) from the list(s).
//
ptCall->dwKey = INVAL_KEY;
if (ptCall->ptCallClients)
{
ptCallClient->dwKey = INVAL_KEY;
ptCall->lActiveFastCallClients--;
}
else
{
ptCallClient = NULL;
}
UNLOCKTCALL(ptCall);
RemoveCallFromLineList (ptCall);
if (ptCallClient)
{
DereferenceObject (ghHandleTable, ptCallClient->hCall, 1);
RemoveCallClientFromLineClientList (ptCallClient);
}
//
// Make sure all fast call clients cleaned up before free tCall
//
while (ptCall->lActiveFastCallClients != 0)
{
Sleep (5);
}
FreetCall (ptCall);
ptCallClient = NULL;
}
}
else
{
//
// If here we can assume that the call was already destroyed
// and just fail the request
//
LMakeCall_PostProcess_bad_ptCall:
ptCallClient = (PTCALLCLIENT) NULL;
if (pAsyncEventMsg->Param2 == 0)
{
pAsyncEventMsg->Param2 = LINEERR_OPERATIONFAILED;
}
}
LMakeCall_PostProcess_initMsgParams:
//
// Fill in the params to pass to client (important to remotesp in both
// the success & fail cases so it can either init or clean up drvCall)
//
pAsyncEventMsg->Param4 = hpCallHandle;
}
void
WINAPI
LMakeCall(
PTCLIENT ptClient,
PLINEMAKECALL_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
LONG lRequestID;
HANDLE hMutex;
HDRVLINE hdLine;
TSPIPROC pfnTSPI_lineMakeCall;
DWORD objectToDereference;
PTLINECLIENT ptLineClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HLINE, // widget type
(DWORD) pParams->hLine, // client widget handle
(LPVOID) &hdLine, // provider widget handle
0, // privileges or device ID
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINEMAKECALL, // provider func index
&pfnTSPI_lineMakeCall, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptLineClient, // context
"MakeCall" // func name
)) > 0)
{
LONG lResult;
PTCALL ptCall;
LPWSTR lpszDestAddress;
HCALL hCall;
PTCALLCLIENT ptCallClient;
LPLINECALLPARAMS pCallParamsApp, pCallParamsSP;
LOG((TL_INFO, "LMakeCall: LINEPROLOG succeeded ."));
//
// Verify size/offset/string params given our input buffer/size
//
if (((pParams->dwDestAddressOffset != TAPI_NO_DATA) &&
IsBadStringParam(
dwParamsBufferSize,
pDataBuf,
pParams->dwDestAddressOffset
)) ||
((pParams->dwCallParamsOffset != TAPI_NO_DATA) &&
IsBadStructParam(
dwParamsBufferSize,
pDataBuf,
pParams->dwCallParamsOffset
)))
{
LOG((TL_INFO, "LMakeCall: LINEERR_STRUCTURETOOSMALL."));
//
// Note: Passing back ERR_STRUCTURETOOSMALL handles the case
// where app has passed in a bad size in the callparams,
// and does so in a spec-friendly manner. The only
// other reason we'd end up here would be an rpc attack,
// and in that case it's just important that we fail.
//
lRequestID = LINEERR_STRUCTURETOOSMALL;
goto LMakeCall_return;
}
pCallParamsApp = (LPLINECALLPARAMS)
(pParams->dwCallParamsOffset == TAPI_NO_DATA ?
0 : (pDataBuf + pParams->dwCallParamsOffset));
LOG((TL_INFO, "LMakeCall: pCallParamsApp %p.", pCallParamsApp));
if (pCallParamsApp)
{
DWORD dwAPIVersion, dwSPIVersion;
if (GetLineVersions(
ptLineClient,
&dwAPIVersion,
&dwSPIVersion
) != 0)
{
LOG((TL_ERROR, "LMakeCall: GetLineVersions failed. LINEERR_INVALLINEHANDLE"));
lRequestID = LINEERR_INVALLINEHANDLE;
goto LMakeCall_return;
}
if ((lResult = ValidateCallParams(
pCallParamsApp,
&pCallParamsSP,
dwAPIVersion,
dwSPIVersion,
pParams->dwAsciiCallParamsCodePage
)) != 0)
{
LOG((TL_ERROR, "LMakeCall: ValidateCallParams failed. %lx", lResult));
lRequestID = lResult;
goto LMakeCall_return;
}
}
else
{
pCallParamsSP = (LPLINECALLPARAMS) NULL;
}
if (CreatetCallAndClient(
ptLineClient,
&ptCall,
&ptCallClient,
pCallParamsSP,
&hCall,
NULL
) != 0)
{
LOG((TL_ERROR, "LMakeCall: CreatetCallAndClient failed. LINEERR_NOMEM"));
lRequestID = LINEERR_NOMEM;
goto LMakeCall_freeCallParams;
}
pAsyncRequestInfo->pfnPostProcess = LMakeCall_PostProcess;
pAsyncRequestInfo->htXxx = (ULONG_PTR)ptCallClient->ptLineClient->ptLine->hLine;
pAsyncRequestInfo->dwParam1 = (ULONG_PTR) ptCall;
pAsyncRequestInfo->dwParam2 = pParams->hpCall;
pAsyncRequestInfo->dwParam5 = (ULONG_PTR)hCall;
pAsyncRequestInfo->hfnClientPostProcessProc =
pParams->hfnPostProcessProc;
if (pParams->dwDestAddressOffset == TAPI_NO_DATA)
{
LOG((TL_ERROR, "LMakeCall: pParams->dwDestAddressOffset == TAPI_NO_DATA"));
lpszDestAddress = NULL;
}
else
{
lpszDestAddress = (LPWSTR)(pDataBuf +pParams->dwDestAddressOffset);
}
LOG((TL_TRACE, "LMakeCall: calling CallSP7"));
pParams->lResult = CallSP7(
pfnTSPI_lineMakeCall,
"lineMakeCall",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdLine,
(ULONG_PTR) hCall,
(ULONG_PTR) &ptCall->hdCall,
(ULONG_PTR) lpszDestAddress,
(DWORD) pParams->dwCountryCode,
(ULONG_PTR) pCallParamsSP
);
LOG((TL_INFO, "LMakeCall: CallSP7 returnded %lx", pParams->lResult));
SetDrvCallFlags(
hCall,
DCF_SPIRETURNED | (IS_LRESULT_NOTERROR(pParams->lResult) ?
DCF_DRVCALLVALID : 0)
);
LMakeCall_freeCallParams:
if (pCallParamsSP != pCallParamsApp)
{
ServerFree (pCallParamsSP);
}
}
LMakeCall_return:
LOG((TL_TRACE, "LMakeCall: calling LINEEPILOGASYNC"));
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"MakeCall"
);
LOG((TL_TRACE, "LMakeCall: LINEEPILOGASYNC returned"));
}
void
WINAPI
LMonitorDigits(
PTCLIENT ptClient,
PLINEMONITORDIGITS_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
HANDLE hMutex;
HDRVCALL hdCall;
TSPIPROC pfnTSPI_lineMonitorDigits;
DWORD objectToDereference;
PTCALLCLIENT ptCallClient, ptCallClient2;
if ((pParams->lResult = LINEPROLOG(
ptClient, // tClient
ANY_RT_HCALL, // widget type
(DWORD) pParams->hCall, // client widget handle
(LPVOID) &hdCall, // provider widget handle
LINECALLPRIVILEGE_MONITOR, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINEMONITORDIGITS, // provider func index
&pfnTSPI_lineMonitorDigits, // provider func pointer
NULL, // async request info
0, // client async request ID
&objectToDereference, // object to dereference
&ptCallClient, // context
"MonitorDigits" // func name
)) == 0)
{
DWORD dwUnionDigitModes;
PTCALL ptCall;
if ((pParams->dwDigitModes & (~AllDigitModes)))
{
pParams->lResult = LINEERR_INVALDIGITMODE;
goto LMonitorDigits_epilog;
}
//
// Determine the new union of modes
//
dwUnionDigitModes = pParams->dwDigitModes;
try
{
ptCall = ptCallClient->ptCall;
}
myexcept
{
pParams->lResult = LINEERR_INVALCALLHANDLE;
goto LMonitorDigits_epilog;
}
if (WaitForExclusivetCallAccess (ptCall, TCALL_KEY))
{
ptCallClient2 = ptCall->ptCallClients;
while (ptCallClient2)
{
if (ptCallClient2 != ptCallClient)
{
dwUnionDigitModes |=
ptCallClient2->dwMonitorDigitModes;
}
ptCallClient2 = ptCallClient2->pNextSametCall;
}
UNLOCKTCALL (ptCall);
}
else
{
pParams->lResult = LINEERR_INVALCALLHANDLE;
goto LMonitorDigits_epilog;
}
if ((pParams->lResult = CallSP2(
pfnTSPI_lineMonitorDigits,
"lineMonitorDigits",
SP_FUNC_SYNC,
(ULONG_PTR) hdCall,
(DWORD) dwUnionDigitModes
)) == 0)
{
ptCallClient->dwMonitorDigitModes = pParams->dwDigitModes;
}
}
LMonitorDigits_epilog:
LINEEPILOGSYNC(
&pParams->lResult,
hMutex,
bCloseMutex,
objectToDereference,
"MonitorDigits"
);
}
void
WINAPI
LMonitorMedia(
PTCLIENT ptClient,
PLINEMONITORMEDIA_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
HANDLE hMutex;
HDRVCALL hdCall;
TSPIPROC pfnTSPI_lineMonitorMedia;
DWORD objectToDereference;
PTCALLCLIENT ptCallClient, ptCallClient2;
if ((pParams->lResult = LINEPROLOG(
ptClient, // tClient
ANY_RT_HCALL, // widget type
(DWORD) pParams->hCall, // client widget handle
(LPVOID) &hdCall, // provider widget handle
LINECALLPRIVILEGE_MONITOR, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINEMONITORMEDIA, // provider func index
&pfnTSPI_lineMonitorMedia, // provider func pointer
NULL, // async request info
0, // client async request ID
&objectToDereference, // object to dereference
&ptCallClient, // context
"MonitorMedia" // func name
)) == 0)
{
DWORD dwAPIVersion, dwValidMediaModes, dwUnionMediaModes;
PTCALL ptCall;
//
// Validate the specified modes
//
try
{
ptCall = ptCallClient->ptCall;
dwAPIVersion = ptCallClient->ptLineClient->dwAPIVersion;
if (ptCallClient->dwKey != TCALLCLIENT_KEY)
{
pParams->lResult = LINEERR_INVALCALLHANDLE;
goto LMonitorMedia_epilog;
}
}
myexcept
{
pParams->lResult = LINEERR_INVALCALLHANDLE;
goto LMonitorMedia_epilog;
}
switch (dwAPIVersion)
{
case TAPI_VERSION1_0:
dwValidMediaModes = AllMediaModes1_0;
break;
case TAPI_VERSION1_4:
case TAPI_VERSION2_0:
dwValidMediaModes = AllMediaModes1_4;
break;
//case TAPI_VERSION2_1:
//case TAPI_VERSION2_2:
//case TAPI_VERSION_CURRENT:
default:
dwValidMediaModes = AllMediaModes2_1;
break;
}
if (pParams->dwMediaModes & (~dwValidMediaModes & 0x00FFFFFF))
{
pParams->lResult = LINEERR_INVALMEDIAMODE;
goto LMonitorMedia_epilog;
}
//
// Determine the new union of modes
//
dwUnionMediaModes = pParams->dwMediaModes;
if (WaitForExclusivetCallAccess (ptCall, TCALL_KEY))
{
ptCallClient2 = ptCall->ptCallClients;
while (ptCallClient2)
{
if (ptCallClient2 != ptCallClient)
{
dwUnionMediaModes |=
ptCallClient2->dwMonitorMediaModes;
}
ptCallClient2 = ptCallClient2->pNextSametCall;
}
UNLOCKTCALL (ptCall);
}
else
{
pParams->lResult = LINEERR_INVALCALLHANDLE;
goto LMonitorMedia_epilog;
}
if ((pParams->lResult = CallSP2(
pfnTSPI_lineMonitorMedia,
"lineMonitorMedia",
SP_FUNC_SYNC,
(ULONG_PTR) hdCall,
(DWORD) dwUnionMediaModes
)) == 0)
{
ptCallClient->dwMonitorMediaModes = pParams->dwMediaModes;
}
}
LMonitorMedia_epilog:
LINEEPILOGSYNC(
&pParams->lResult,
hMutex,
bCloseMutex,
objectToDereference,
"MonitorMedia"
);
}
void
WINAPI
LMonitorTones(
PTCLIENT ptClient,
PLINEMONITORTONES_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
HANDLE hMutex;
HDRVCALL hdCall;
TSPIPROC pfnTSPI_lineMonitorTones;
DWORD objectToDereference;
PTCALLCLIENT ptCallClient, ptCallClient2;
//
// Verify size/offset/string params given our input buffer/size
//
if ((pParams->dwTonesOffset != TAPI_NO_DATA) &&
ISBADSIZEOFFSET(
dwParamsBufferSize,
0,
pParams->dwNumEntries, // really dwNumEntries *
// sizeof(LINEMONITORTONE)
pParams->dwTonesOffset,
sizeof(DWORD),
"LMonitorTones",
"pParams->MSPBuffer"
))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if ((pParams->lResult = LINEPROLOG(
ptClient, // tClient
ANY_RT_HCALL, // widget type
(DWORD) pParams->hCall, // client widget handle
(LPVOID) &hdCall, // provider widget handle
LINECALLPRIVILEGE_MONITOR, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINEMONITORTONES, // provider func index
&pfnTSPI_lineMonitorTones, // provider func pointer
NULL, // async request info
0, // client async request ID
&objectToDereference, // object to dereference
&ptCallClient, // context
"MonitorTones" // func name
)) == 0)
{
//
// If this is a remotesp call then we want to mark the
// tCallClient as being interested in LINE_MONITORTONES
// messages (due to our kludgy handling of this msg, see
// comments in the msg handler in LineEventProc()).
//
PTCALL ptCall;
try
{
ptCall = ptCallClient->ptCall;
if (ptCall->ptProvider != pRemoteSP)
{
ptCall = NULL;
}
}
myexcept
{
pParams->lResult = LINEERR_INVALCALLHANDLE;
goto LMonitorTones_epilog;
}
if (ptCall)
{
if (WaitForExclusivetCallAccess (ptCall, TCALL_KEY))
{
for(
ptCallClient2 = ptCall->ptCallClients;
(ptCallClient2 && (ptCallClient2 != ptCallClient));
ptCallClient2 = ptCallClient2->pNextSametCall
);
if (ptCallClient2 == ptCallClient)
{
ptCallClient->bMonitoringTones =
(pParams->dwTonesOffset == TAPI_NO_DATA ? 0 : 1);
}
UNLOCKTCALL (ptCall);
if (!ptCallClient2)
{
pParams->lResult = LINEERR_INVALCALLHANDLE;
goto LMonitorTones_epilog;
}
}
else
{
pParams->lResult = LINEERR_INVALCALLHANDLE;
goto LMonitorTones_epilog;
}
}
pParams->lResult = CallSP4(
pfnTSPI_lineMonitorTones,
"lineMonitorTones",
SP_FUNC_SYNC,
(ULONG_PTR) hdCall,
(DWORD) pParams->hCall,
(ULONG_PTR) (pParams->dwTonesOffset == TAPI_NO_DATA ? 0 :
pDataBuf + pParams->dwTonesOffset),
(DWORD) pParams->dwNumEntries / sizeof (LINEMONITORTONE)
);
}
LMonitorTones_epilog:
LINEEPILOGSYNC(
&pParams->lResult,
hMutex,
bCloseMutex,
objectToDereference,
"MonitorTones"
);
}
void
WINAPI
LNegotiateAPIVersion(
PTCLIENT ptClient,
PLINENEGOTIATEAPIVERSION_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
//
// Note: TAPI_VERSION1_0 <= dwNegotiatedAPIVersion <= dwSPIVersion
//
DWORD dwDeviceID = pParams->dwDeviceID;
LOG((TL_TRACE, "LNegotiateAPIVersion: started. dwDeviceID %lx, dwAPILowVersion %lx dwAPIHighVersion %lx",
pParams->dwDeviceID, pParams->dwAPILowVersion, pParams->dwAPIHighVersion));
//
// Verify size/offset/string params given our input buffer/size
//
if (dwParamsBufferSize < sizeof (LINEEXTENSIONID))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if (TapiGlobals.dwNumLineInits == 0)
{
pParams->lResult = LINEERR_UNINITIALIZED;
goto LNegotiateAPIVersion_exit;
}
#if TELE_SERVER
if ((TapiGlobals.dwFlags & TAPIGLOBALS_SERVER) &&
!IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR))
{
try
{
if (dwDeviceID >= ptClient->dwLineDevices)
{
pParams->lResult = LINEERR_BADDEVICEID;
goto LNegotiateAPIVersion_exit;
}
dwDeviceID = ptClient->pLineDevices[dwDeviceID];
}
myexcept
{
LOG((TL_ERROR, "ptClient excepted in LineNegotiateAPIVersion"));
pParams->lResult = LINEERR_INVALLINEHANDLE;
goto LNegotiateAPIVersion_exit;
}
}
#endif
if (dwDeviceID < TapiGlobals.dwNumLines)
{
DWORD dwAPIHighVersion = pParams->dwAPIHighVersion,
dwAPILowVersion = pParams->dwAPILowVersion,
dwHighestValidAPIVersion;
PTLINEAPP ptLineApp;
//
// Do a minimax test on the specified lo/hi values
//
if ((dwAPILowVersion > dwAPIHighVersion) ||
(dwAPILowVersion > TAPI_VERSION_CURRENT) ||
(dwAPIHighVersion < TAPI_VERSION1_0))
{
LOG((TL_ERROR, "LNegotiateAPIVersion: LINEERR_INCOMPATIBLEAPIVERSION1"));
pParams->lResult = LINEERR_INCOMPATIBLEAPIVERSION;
goto LNegotiateAPIVersion_exit;
}
//
// HACKALERT! Some dumb apps like SmarTerm negotiate specifying
// a dwHighVersion of 0x7fffffff or higher, which can really
// cause them problems (like when they try to pass down structures
// of a size that was fine in the TAPI version under which the app
// was built, but which were enlarged in subsequent versions of
// TAPI, and the result is lots of LINEERR_STRUCTURETOOSMALL
// errors).
//
// Since we're nice, accomodating people we'll try to munge the
// dwHighVersion in these cases to be a value that makes sense, so
// we don't end up negotiating a version that the app can't handle.
//
if (dwAPIHighVersion & 0xc0000000)
{
dwAPIHighVersion = (dwAPILowVersion > TAPI_VERSION1_0 ?
dwAPILowVersion : TAPI_VERSION1_0);
}
//
// 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, "LNegotiateAPIVersion: LINEERR_INCOMPATIBLEAPIVERSION2"));
pParams->lResult = LINEERR_INCOMPATIBLEAPIVERSION;
goto LNegotiateAPIVersion_exit;
}
}
else
{
dwHighestValidAPIVersion = TAPI_VERSION_CURRENT;
}
//
// WARNING!!! WARNING!!! WARNING!!! WARNING!!!
// This code overwrites ptLineApp and later invalidates it.
// Do NOT use ptLineApp after the MyReleaseMutex call.
//
if ((ptLineApp = WaitForExclusiveLineAppAccess(
pParams->hLineApp,
ptClient
)))
{
LOG((TL_INFO,
"LNegotiateAPIVersion WaitForExclusiveLineAppAccess succeeded returned ptLineApp %p for hLineApp %p",
ptLineApp, pParams->hLineApp));
//
// Is this app trying to negotiate something valid?
//
// If an app has called lineInitalize (as opposed to
// lineInitializeEx), we'll clamp the max APIVersion they can
// negotiate to 1.4.
//
if ( ptLineApp->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 > ptLineApp->dwAPIVersion)
{
ptLineApp->dwAPIVersion = dwHighestValidAPIVersion;
}
UNLOCKTLINEAPP(ptLineApp);
}
else
{
LOG((TL_ERROR, "LNegotiateAPIVersion WaitForExclusiveLineAppAccess returned NULL"));
pParams->lResult = LINEERR_INVALAPPHANDLE;
goto LNegotiateAPIVersion_exit;
}
//
// See if there's a valid match with the SPI ver
//
{
DWORD dwSPIVersion;
PTLINELOOKUPENTRY pLookupEntry;
pLookupEntry = GetLineLookupEntry (dwDeviceID);
if (NULL == pLookupEntry)
{
pParams->lResult = LINEERR_INVALAPPHANDLE;
goto LNegotiateAPIVersion_exit;
}
dwSPIVersion = pLookupEntry->dwSPIVersion;
if (pLookupEntry->bRemoved)
{
pParams->lResult = LINEERR_NODEVICE;
goto LNegotiateAPIVersion_exit;
}
if (pLookupEntry->ptProvider == NULL)
{
pParams->lResult = LINEERR_NODRIVER;
goto LNegotiateAPIVersion_exit;
}
if (dwAPILowVersion <= dwSPIVersion)
{
pParams->dwAPIVersion =
(dwHighestValidAPIVersion > dwSPIVersion ?
dwSPIVersion : dwHighestValidAPIVersion);
//
// Retrieve ext id (indicate no exts if GetExtID not exported)
//
if ((pLookupEntry->ptProvider->apfn[SP_LINEGETEXTENSIONID]))
{
pParams->lResult = CallSP3(
pLookupEntry->ptProvider->
apfn[SP_LINEGETEXTENSIONID],
"lineGetExtensionID",
SP_FUNC_SYNC,
(DWORD) dwDeviceID,
(DWORD) dwSPIVersion,
(ULONG_PTR) pDataBuf
);
// the sp returned operationunavail. we don't want
// to return that, so we just indicate that
// there are no extensions
if (pParams->lResult == LINEERR_OPERATIONUNAVAIL)
{
pParams->lResult = 0;
FillMemory (pDataBuf, sizeof (LINEEXTENSIONID), 0);
}
}
else
{
// doesn't export it, so fill in with zeros
pParams->lResult = 0;
FillMemory (pDataBuf, sizeof (LINEEXTENSIONID), 0);
}
}
else
{
LOG((TL_ERROR, "LNegotiateAPIVersion: LINEERR_INCOMPATIBLEAPIVERSION3"));
pParams->lResult = LINEERR_INCOMPATIBLEAPIVERSION;
goto LNegotiateAPIVersion_exit;
}
}
pParams->dwExtensionIDOffset = 0;
pParams->dwSize = sizeof (LINEEXTENSIONID);
*pdwNumBytesReturned = sizeof (LINEEXTENSIONID) + sizeof (TAPI32_MSG);
}
else
{
pParams->lResult = LINEERR_BADDEVICEID;
}
LNegotiateAPIVersion_exit:
#if DBG
{
char szResult[32];
LOG((TL_TRACE,
"lineNegotiateAPIVersion: exit, result=%s",
MapResultCodeToText (pParams->lResult, szResult)
));
}
#else
LOG((TL_TRACE,
"lineNegotiateAPIVersion: exit, result=x%x",
pParams->lResult
));
#endif
return;
}
void
WINAPI
NegotiateAPIVersionForAllDevices(
PTCLIENT ptClient,
PNEGOTIATEAPIVERSIONFORALLDEVICES_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
#if TELE_SERVER
//
// Note: TAPI_VERSION1_0 <= dwNegotiatedAPIVersion <= dwSPIVersion
//
DWORD i,
dwNumLineDevices = pParams->dwNumLineDevices,
dwNumPhoneDevices = pParams->dwNumPhoneDevices,
dwAPIHighVersion = pParams->dwAPIHighVersion,
dwAPILowVersion = TAPI_VERSION1_0,
dwHighestValidAPIVersion, *pdwAPIVersion;
LPLINEEXTENSIONID pExtID;
//
// Verify size/offset/string params given our input buffer/size
//
i = pParams->dwLineAPIVersionListSize +
pParams->dwLineExtensionIDListSize +
pParams->dwPhoneAPIVersionListSize +
pParams->dwPhoneExtensionIDListSize;
if ((pParams->dwLineAPIVersionListSize & 0xc0000000) ||
(pParams->dwLineExtensionIDListSize & 0xc0000000) ||
(pParams->dwPhoneAPIVersionListSize & 0xc0000000) ||
(pParams->dwPhoneExtensionIDListSize & 0xc0000000) ||
(i > dwParamsBufferSize))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
//
// Verify the specified dwNumLine/PhonesDevices
//
if (IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR))
{
if ((pParams->dwNumLineDevices > TapiGlobals.dwNumLines) ||
(pParams->dwNumPhoneDevices > TapiGlobals.dwNumPhones))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
}
else
{
if ((pParams->dwNumLineDevices > ptClient->dwLineDevices) ||
(pParams->dwNumPhoneDevices > ptClient->dwPhoneDevices))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
}
//
//
//
if (TapiGlobals.dwNumLineInits == 0)
{
pParams->lResult = LINEERR_UNINITIALIZED;
goto NegotiateAPIVersionForAllDevices_exit;
}
//
// Do a minimax test on the specified lo/hi values
//
if ((dwAPILowVersion > dwAPIHighVersion) ||
(dwAPILowVersion > TAPI_VERSION_CURRENT) ||
(dwAPIHighVersion < TAPI_VERSION1_0))
{
pParams->lResult = LINEERR_INCOMPATIBLEAPIVERSION;
goto NegotiateAPIVersionForAllDevices_exit;
}
//
// 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
{
pParams->lResult = LINEERR_INCOMPATIBLEAPIVERSION;
goto NegotiateAPIVersionForAllDevices_exit;
}
}
else
{
dwHighestValidAPIVersion = TAPI_VERSION_CURRENT;
}
//
// Now for each line device do negotiation
//
pdwAPIVersion = (LPDWORD) pDataBuf;
pExtID = (LPLINEEXTENSIONID)
(pDataBuf + pParams->dwLineAPIVersionListSize);
for (i = 0; i < dwNumLineDevices; i++, pdwAPIVersion++, pExtID++)
{
DWORD dwDeviceID, dwSPIVersion;
PTLINELOOKUPENTRY pLookupEntry;
if (!IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR))
{
dwDeviceID = ptClient->pLineDevices[i];
}
else
{
dwDeviceID = i;
}
pLookupEntry = GetLineLookupEntry (dwDeviceID);
if (NULL == pLookupEntry)
{
// Something is wrong with this device ID;
// skip it.
continue;
}
dwSPIVersion = pLookupEntry->dwSPIVersion;
if ((dwAPILowVersion <= dwSPIVersion) &&
!pLookupEntry->bRemoved &&
(pLookupEntry->ptProvider != NULL))
{
*pdwAPIVersion =
(dwHighestValidAPIVersion > dwSPIVersion ?
dwSPIVersion : dwHighestValidAPIVersion);
//
// Retrieve ext id (indicate no exts if GetExtID not exported)
//
if (!(pLookupEntry->ptProvider->apfn[SP_LINEGETEXTENSIONID]) ||
CallSP3(
pLookupEntry->ptProvider->apfn[SP_LINEGETEXTENSIONID],
"lineGetExtensionID",
SP_FUNC_SYNC,
(DWORD) dwDeviceID,
(DWORD) dwSPIVersion,
(ULONG_PTR) pExtID
) != 0)
{
ZeroMemory (pExtID, sizeof (LINEEXTENSIONID));
}
}
else
{
*pdwAPIVersion = 0;
}
}
//
// Now for each phone device do negotiation
//
pdwAPIVersion = (LPDWORD) (pDataBuf +
pParams->dwLineAPIVersionListSize +
pParams->dwLineExtensionIDListSize);
pExtID = (LPLINEEXTENSIONID) (pDataBuf +
pParams->dwLineAPIVersionListSize +
pParams->dwLineExtensionIDListSize +
pParams->dwPhoneAPIVersionListSize);
for (i = 0; i < dwNumPhoneDevices; i++, pdwAPIVersion++, pExtID++)
{
DWORD dwDeviceID, dwSPIVersion;
PTPHONELOOKUPENTRY pLookupEntry;
if (!IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR))
{
dwDeviceID = ptClient->pPhoneDevices[i];
}
else
{
dwDeviceID = i;
}
pLookupEntry = GetPhoneLookupEntry (dwDeviceID);
if (NULL == pLookupEntry)
{
// Something wrong with this device;
// skip it.
continue;
}
dwSPIVersion = pLookupEntry->dwSPIVersion;
if ((dwAPILowVersion <= dwSPIVersion) &&
!pLookupEntry->bRemoved &&
(pLookupEntry->ptProvider != NULL))
{
*pdwAPIVersion =
(dwHighestValidAPIVersion > dwSPIVersion ?
dwSPIVersion : dwHighestValidAPIVersion);
//
// Retrieve ext id (indicate no exts if GetExtID not exported)
//
if (!(pLookupEntry->ptProvider->apfn[SP_PHONEGETEXTENSIONID]) ||
CallSP3(
pLookupEntry->ptProvider->apfn[SP_PHONEGETEXTENSIONID],
"phoneGetExtensionID",
SP_FUNC_SYNC,
(DWORD) dwDeviceID,
(DWORD) dwSPIVersion,
(ULONG_PTR) pExtID
) != 0)
{
ZeroMemory (pExtID, sizeof (LINEEXTENSIONID));
}
}
else
{
*pdwAPIVersion = 0;
}
}
pParams->dwLineAPIVersionListOffset = 0;
pParams->dwLineExtensionIDListOffset =
pParams->dwLineAPIVersionListSize;
pParams->dwPhoneAPIVersionListOffset =
pParams->dwLineAPIVersionListSize +
pParams->dwLineExtensionIDListSize;
pParams->dwPhoneExtensionIDListOffset =
pParams->dwLineAPIVersionListSize +
pParams->dwLineExtensionIDListSize +
pParams->dwPhoneAPIVersionListSize;
*pdwNumBytesReturned =
sizeof (TAPI32_MSG) +
pParams->dwLineAPIVersionListSize +
pParams->dwLineExtensionIDListSize +
pParams->dwPhoneAPIVersionListSize +
pParams->dwPhoneExtensionIDListSize;
NegotiateAPIVersionForAllDevices_exit:
#endif
#if DBG
{
char szResult[32];
LOG((TL_TRACE,
"NegotiateAPIVersionForAllDevices: exit, result=%s",
MapResultCodeToText (pParams->lResult, szResult)
));
}
#else
LOG((TL_TRACE,
"NegotiateAPIVersionForAllDevices: exit, result=x%x",
pParams->lResult
));
#endif
return;
}
void
WINAPI
LNegotiateExtVersion(
PTCLIENT ptClient,
PLINENEGOTIATEEXTVERSION_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
DWORD dwDeviceID;
HANDLE hMutex;
TSPIPROC pfnTSPI_lineNegotiateExtVersion;
DWORD objectToDereference;
PTLINELOOKUPENTRY pLookupEntry;
if ((pParams->lResult = LINEPROLOG(
ptClient, // tClient
DEVICE_ID, // widget type
(DWORD) pParams->hLineApp, // client widget handle
&dwDeviceID, // provider widget handle
pParams->dwDeviceID, // privileges or device ID
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINENEGOTIATEEXTVERSION, // provider func index
&pfnTSPI_lineNegotiateExtVersion, // provider func pointer
NULL, // async request info
0, // client async request ID
&objectToDereference, // object to dereference
&pLookupEntry, // context
"NegotiateExtVersion" // func name
)) == 0)
{
DWORD dwSPIVersion = pLookupEntry->dwSPIVersion;
if (!IsAPIVersionInRange(
pParams->dwAPIVersion,
dwSPIVersion
))
{
pParams->lResult = LINEERR_INCOMPATIBLEAPIVERSION;
goto LNegotiateExtVersion_epilog;
}
if ((pParams->lResult = CallSP5(
pfnTSPI_lineNegotiateExtVersion,
"lineNegotiateExtVersion",
SP_FUNC_SYNC,
(DWORD) dwDeviceID,
(DWORD) dwSPIVersion,
(DWORD) pParams->dwExtLowVersion,
(DWORD) pParams->dwExtHighVersion,
(ULONG_PTR) &pParams->dwExtVersion
)) == 0)
{
if (pParams->dwExtVersion == 0)
{
pParams->lResult = LINEERR_INCOMPATIBLEEXTVERSION;
}
else
{
*pdwNumBytesReturned = sizeof (LINENEGOTIATEEXTVERSION_PARAMS);
}
}
}
LNegotiateExtVersion_epilog:
LINEEPILOGSYNC(
&pParams->lResult,
hMutex,
bCloseMutex,
objectToDereference,
"NegotiateExtVersion"
);
}
VOID
PASCAL
xxxLOpen(
PTCLIENT ptClient,
PLINEOPEN_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned,
BOOL bLineMapper
)
{
BOOL bCloseMutex,
bOpenedtLine = FALSE,
bDecrExtVerCountOnError = FALSE,
bReleasetLineMutex = FALSE,
bFreeCallParams = FALSE;
LONG lResult;
HLINE hLine;
DWORD dwDeviceID;
HANDLE hMutex;
PTLINE ptLine = NULL;
DWORD objectToDereference;
PTPROVIDER ptProvider = NULL;
PTLINECLIENT ptLineClient = NULL;
PTLINELOOKUPENTRY pLookupEntry;
LPLINECALLPARAMS pCallParams = NULL;
TCHAR szClsid[40];
HANDLE hLookupEntryMutex = NULL;
szClsid[0] = 0;
if ((lResult = LINEPROLOG(
ptClient, // tClient
DEVICE_ID, // widget type
(DWORD) pParams->hLineApp, // client widget handle
&dwDeviceID, // provider widget handle
pParams->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
&objectToDereference, // object to dereference
&pLookupEntry, // context
(bLineMapper ? "Open(LINEMAPPER)" : "Open")
// func name
)) == 0)
{
DWORD dwPrivileges = pParams->dwPrivileges,
dwAPIVersion = pParams->dwAPIVersion,
dwExtVersion = pParams->dwExtVersion,
dwMediaModes, dwNumProxyRequestTypes,
dwRegisteredProxys,
*pdwProxyRequestTypes,
i;
PTLINEAPP ptLineApp;
BOOL bDuplicateOK = FALSE;
//
// Check if the global reinit flag is set
//
if (TapiGlobals.dwFlags & TAPIGLOBALS_REINIT)
{
lResult = LINEERR_REINIT;
goto xxxLOpen_cleanup;
}
//
// Validate params
//
if (!IsAPIVersionInRange(
dwAPIVersion,
pLookupEntry->dwSPIVersion
))
{
lResult = LINEERR_INCOMPATIBLEAPIVERSION;
goto xxxLOpen_cleanup;
}
ptProvider = pLookupEntry->ptProvider;
#define VALID_LOPEN_BITS (LINECALLPRIVILEGE_NONE | \
LINECALLPRIVILEGE_MONITOR | \
LINECALLPRIVILEGE_OWNER | \
LINEOPENOPTION_SINGLEADDRESS | \
LINEOPENOPTION_PROXY)
#define VALID_PRIV_BITS (LINECALLPRIVILEGE_NONE | \
LINECALLPRIVILEGE_MONITOR | \
LINECALLPRIVILEGE_OWNER)
if (!(dwPrivileges & VALID_PRIV_BITS) ||
(dwPrivileges & ~VALID_LOPEN_BITS) ||
((dwPrivileges & LINECALLPRIVILEGE_NONE) &&
(dwPrivileges & (LINECALLPRIVILEGE_MONITOR |
LINECALLPRIVILEGE_OWNER))))
{
lResult = LINEERR_INVALPRIVSELECT;
goto xxxLOpen_cleanup;
}
if (dwPrivileges & (LINEOPENOPTION_SINGLEADDRESS |
LINEOPENOPTION_PROXY) ||
bLineMapper)
{
pCallParams = (LPLINECALLPARAMS)
(pParams->dwCallParamsOffset == TAPI_NO_DATA ?
NULL : pDataBuf + pParams->dwCallParamsOffset);
if (!pCallParams)
{
lResult = LINEERR_INVALPOINTER;
goto xxxLOpen_cleanup;
}
//
// Verify size/offset/string params given our input buffer/size
//
if (IsBadStructParam(
dwParamsBufferSize,
pDataBuf,
pParams->dwCallParamsOffset
))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
goto xxxLOpen_cleanup;
}
if ((lResult = ValidateCallParams(
pCallParams,
&pCallParams,
dwAPIVersion,
pLookupEntry->dwSPIVersion,
pParams->dwAsciiCallParamsCodePage
)))
{
lResult = LINEERR_INVALPOINTER;
goto xxxLOpen_cleanup;
}
if (pCallParams != (LPLINECALLPARAMS)
(pDataBuf + pParams->dwCallParamsOffset))
{
bFreeCallParams = TRUE;
}
if ((dwPrivileges & LINEOPENOPTION_SINGLEADDRESS) &&
(pCallParams->dwAddressMode != LINEADDRESSMODE_ADDRESSID))
{
LOG((TL_ERROR,
"lineOpen(SINGLEADDRESS): callParams.dwAddressMode" \
"!= ADDRESSID"
));
lResult = LINEERR_INVALCALLPARAMS;
goto xxxLOpen_cleanup;
}
if (dwPrivileges & LINEOPENOPTION_PROXY)
{
//
// Verify the array of DWORDs (request types) in the
// DevSpecific var field
//
dwNumProxyRequestTypes =
(pCallParams->dwDevSpecificSize & 0xfffc) /
sizeof (DWORD);
if (dwNumProxyRequestTypes == 0 ||
dwNumProxyRequestTypes > LINEPROXYREQUEST_LASTVALUE)
{
LOG((TL_ERROR,
"lineOpen(PROXY): inval proxy request type array "\
"size (callParams.dwDevSpecificSize=x%x)",
pCallParams->dwDevSpecificSize
));
lResult = LINEERR_INVALCALLPARAMS;
goto xxxLOpen_cleanup;
}
//
// Per the TAPI (Proxy) server publishing:
//
// If the HIWORD of dwDevSpecificSize is non-zero
// immediately after the dwDevSpecificSize/Offset
// field, there is a zero terminated CLSID field
// of the proxy server
//
if (HIWORD(pCallParams->dwDevSpecificSize))
{
LPTSTR lpsz;
lpsz = (LPTSTR) (((LPBYTE) pCallParams) +
pCallParams->dwDevSpecificOffset +
LOWORD(pCallParams->dwDevSpecificSize));
pCallParams->dwDevSpecificSize =
LOWORD(pCallParams->dwDevSpecificSize);
if (_tcslen (lpsz) > sizeof(szClsid) / sizeof(TCHAR))
{
lResult = LINEERR_INVALCALLPARAMS;
goto xxxLOpen_cleanup;
}
_tcscpy (szClsid, lpsz);
}
pdwProxyRequestTypes = (LPDWORD) (((LPBYTE) pCallParams) +
pCallParams->dwDevSpecificOffset);
for (i = 0; i < dwNumProxyRequestTypes; i++)
{
if (*(pdwProxyRequestTypes + i) == 0 ||
*(pdwProxyRequestTypes + i) >
LINEPROXYREQUEST_LASTVALUE)
{
LOG((TL_ERROR,
"lineOpen(PROXY): inval proxy request type "\
"(x%x)",
*(pdwProxyRequestTypes + i)
));
lResult = LINEERR_INVALCALLPARAMS;
goto xxxLOpen_cleanup;
}
}
}
}
if ((dwPrivileges & LINECALLPRIVILEGE_OWNER))
{
DWORD dwAllMediaModes;
dwMediaModes = pParams->dwMediaModes;
switch (dwAPIVersion)
{
case TAPI_VERSION1_0:
dwAllMediaModes = AllMediaModes1_0;
break;
case TAPI_VERSION1_4:
case TAPI_VERSION2_0:
dwAllMediaModes = AllMediaModes1_4;
break;
//case TAPI_VERSION2_1:
//case TAPI_VERSION2_2:
default: //case TAPI_VERSION_CURRENT:
dwAllMediaModes = AllMediaModes2_1;
break;
}
if ((dwMediaModes == 0) ||
(dwMediaModes & (0x00ffffff & ~dwAllMediaModes)))
{
lResult = LINEERR_INVALMEDIAMODE;
goto xxxLOpen_cleanup;
}
}
else
{
dwMediaModes = 0;
}
//
// Create & init a tLineClient & associated resources
//
if (!(ptLineClient = ServerAlloc (sizeof(TLINECLIENT))))
{
lResult = LINEERR_NOMEM;
goto xxxLOpen_cleanup;
}
LOG((TL_TRACE, "lineOpen: calling NewObject. ptLineClient %p", ptLineClient));
if (!(ptLineClient->hLine = (HLINE) NewObject(
ghHandleTable,
ptLineClient,
0
)))
{
ptLineClient = NULL;
ServerFree (ptLineClient);
lResult = LINEERR_NOMEM;
goto xxxLOpen_cleanup;
}
LOG((TL_TRACE, "lineOpen: NewObject returned %p", ptLineClient->hLine));
ptLineClient->ptClient = ptClient;
ptLineClient->hRemoteLine = (pParams->hRemoteLine ?
(DWORD) pParams->hRemoteLine : ptLineClient->hLine);
ptLineClient->dwAPIVersion = dwAPIVersion;
ptLineClient->dwPrivileges = dwPrivileges;
ptLineClient->dwMediaModes = dwMediaModes;
ptLineClient->OpenContext = pParams->OpenContext;
ptLineClient->dwAddressID =
(dwPrivileges & LINEOPENOPTION_SINGLEADDRESS ?
pCallParams->dwAddressID : 0xffffffff);
LOG((TL_INFO, "lineOpen: OpenContext %p", pParams->OpenContext));
//
// Duplicate the handle to tLine's mutex
// Grab the mutex using the duplicate handle then start doing the open
//
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 )
{
bReleasetLineMutex = FALSE;
lResult = LINEERR_OPERATIONFAILED;
goto xxxLOpen_cleanup;
}
xxxLOpen_waitForMutex:
if (WaitForSingleObject (hLookupEntryMutex, INFINITE)
!= WAIT_OBJECT_0)
{
bReleasetLineMutex = FALSE;
lResult = LINEERR_OPERATIONFAILED;
goto xxxLOpen_cleanup;
}
bReleasetLineMutex = TRUE;
//
// If the tLine is in the process of being destroyed then spin
// until it's been completely destroyed (DestroytLine() will
// NULLify pLookupEntry->ptLine when it's finished). Make sure
// to release the mutex while sleeping so we don't block
// DestroytLine.
//
try
{
while (pLookupEntry->ptLine &&
pLookupEntry->ptLine->dwKey != TLINE_KEY)
{
ReleaseMutex (hLookupEntryMutex);
Sleep (0);
goto xxxLOpen_waitForMutex;
}
}
myexcept
{
// If here pLookupEntry->ptLine was NULLified, safe to continue
}
//
// Check if the line has been removed
//
if (pLookupEntry->bRemoved)
{
lResult = LINEERR_BADDEVICEID;
goto xxxLOpen_cleanup;
}
//
// Validate ext ver as appropriate
//
if (dwExtVersion != 0 &&
(!IsValidLineExtVersion (dwDeviceID, dwExtVersion) ||
ptProvider->apfn[SP_LINESELECTEXTVERSION] == NULL))
{
if ( ptProvider->apfn[SP_LINESELECTEXTVERSION] == NULL)
{
LOG((TL_ERROR,
"The provider does not support TSPI_lineSelectExtVersion" \
" - that's a problem"
));
}
else
{
LOG((TL_ERROR,
"Bad ExtVersion was passed in - that's a problem"
));
}
lResult = LINEERR_INCOMPATIBLEEXTVERSION;
goto xxxLOpen_cleanup;
}
//
// If line isn't open already then try to open it
//
if (!(ptLine = pLookupEntry->ptLine))
{
if (!(ptLine = ServerAlloc (sizeof(TLINE))))
{
lResult = LINEERR_NOMEM;
goto xxxLOpen_cleanup;
}
LOG((TL_TRACE, "xxxLOpen: calling NewObject ptLine %p", ptLine));
if (!(ptLine->hLine = (HLINE) NewObject(
ghHandleTable,
(LPVOID) ptLine,
NULL
)))
{
ServerFree (ptLine);
lResult = LINEERR_NOMEM;
goto xxxLOpen_cleanup;
}
ptLine->dwKey = TINCOMPLETELINE_KEY;
ptLine->hMutex = pLookupEntry->hMutex;
ptLine->ptProvider = ptProvider;
ptLine->dwDeviceID = dwDeviceID;
ptLine->dwSPIVersion = pLookupEntry->dwSPIVersion;
{
//
// Hack Alert!
//
// We need to pass the privileges,etc through to
// remote sp, so we make this a special case
//
ULONG_PTR aParams[5];
ULONG_PTR param;
if (ptProvider == pRemoteSP)
{
aParams[0] = (ULONG_PTR) ptLine->hLine;
aParams[1] = pParams->dwPrivileges;
aParams[2] = pParams->dwMediaModes;
aParams[3] = (ULONG_PTR) pCallParams;
aParams[4] = dwExtVersion;
param = (ULONG_PTR) aParams;
}
else
{
param = (ULONG_PTR) ptLine->hLine;
}
if (ptProvider->apfn[SP_LINEOPEN] == NULL)
{
lResult = LINEERR_OPERATIONUNAVAIL;
}
if (lResult != S_OK ||
(lResult = CallSP5(
ptProvider->apfn[SP_LINEOPEN],
"lineOpen",
SP_FUNC_SYNC,
(DWORD) dwDeviceID,
(ULONG_PTR) param,
(ULONG_PTR) &ptLine->hdLine,
(DWORD) pLookupEntry->dwSPIVersion,
(ULONG_PTR) LineEventProcSP
)) != 0)
{
DereferenceObject(
ghHandleTable,
ptLine->hLine,
1
);
lResult = (bLineMapper ? LINEERR_OPERATIONFAILED :
lResult);
goto xxxLOpen_cleanup;
}
bOpenedtLine = TRUE;
}
if (ptProvider->apfn[SP_LINEGETNUMADDRESSIDS] == NULL)
{
lResult = LINEERR_OPERATIONUNAVAIL;
goto xxxLOpen_cleanup;
}
CallSP2(
ptProvider->apfn[SP_LINEGETNUMADDRESSIDS],
"lineGetNumAddressIDs",
SP_FUNC_SYNC,
(ULONG_PTR) ptLine->hdLine,
(ULONG_PTR) &ptLine->dwNumAddresses
);
// PERF
PerfBlock.dwLinesInUse++;
}
//
// If line is already opened & client is trying to register
// as a proxy then see if there's any conflicts with existing
// proxys
//
else if (dwPrivileges & LINEOPENOPTION_PROXY)
{
for (i = 0; i < dwNumProxyRequestTypes; i++)
{
DWORD dwProxyRequestType = *(pdwProxyRequestTypes + i);
if (ptLine->apProxys[dwProxyRequestType] != NULL)
{
lResult = LINEERR_NOTREGISTERED;
goto xxxLOpen_cleanup;
}
}
}
ptLineClient->ptLine = ptLine;
//
// Verify the specified addr if appropriate
//
if ((dwPrivileges & LINEOPENOPTION_SINGLEADDRESS) &&
(ptLineClient->dwAddressID >= ptLine->dwNumAddresses))
{
lResult = LINEERR_INVALADDRESSID;
goto xxxLOpen_cleanup;
}
//
// 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 this fails, and we're processing a
// LINEMAPPER request, then return a generic error so the
// caller will try the next device.
//
if (dwExtVersion)
{
if (ptLine->dwExtVersionCount == 0)
{
if (ptProvider != pRemoteSP &&
ptProvider->apfn[SP_LINESELECTEXTVERSION] == NULL)
{
lResult = LINEERR_OPERATIONUNAVAIL;
goto xxxLOpen_cleanup;
}
if (ptProvider != pRemoteSP &&
(lResult = CallSP2(
ptProvider->apfn[SP_LINESELECTEXTVERSION],
"lineSelectExtVersion",
SP_FUNC_SYNC,
(ULONG_PTR) ptLine->hdLine,
(DWORD) dwExtVersion
)) != 0)
{
lResult = (bLineMapper ? LINEERR_OPERATIONFAILED :
lResult);
goto xxxLOpen_cleanup;
}
ptLine->dwExtVersion = dwExtVersion;
}
ptLineClient->dwExtVersion = dwExtVersion;
ptLine->dwExtVersionCount++;
bDecrExtVerCountOnError = TRUE;
}
//
// If we're processing a LINEMAPPER request, check to see if the
// device supports capabilities requested by client. If not,
// return a generic error so the caller will try the next device.
//
if (bLineMapper)
{
if (ptProvider->apfn[SP_LINECONDITIONALMEDIADETECTION] == NULL ||
CallSP3(
ptProvider->apfn[SP_LINECONDITIONALMEDIADETECTION],
"lineConditionalMediaDetection",
SP_FUNC_SYNC,
(ULONG_PTR) ptLine->hdLine,
(DWORD) dwMediaModes | ptLine->dwOpenMediaModes,
(ULONG_PTR) pCallParams
) != 0)
{
PerfBlock.dwLinesInUse--;
lResult = LINEERR_OPERATIONFAILED;
goto xxxLOpen_cleanup;
}
}
//
// If the client is requesting OWNER privileges (it's interested
// in incoming calls of the specified media mode(s)), then check
// to see if it wants incoming calls of a media mode(s) other
// than that the device has already agreed to indicate, and ask
// the driver if it can support looking for all of them at the
// same time. If this fails, and we're processing a LINEMAPPER
// request, then return a generic error so the caller will try
// the next device.
//
if (pParams->dwPrivileges & LINECALLPRIVILEGE_OWNER)
{
if ((dwMediaModes & ptLine->dwOpenMediaModes) != dwMediaModes)
{
DWORD dwUnionMediaModes = dwMediaModes |
ptLine->dwOpenMediaModes;
if (ptProvider->apfn[SP_LINESETDEFAULTMEDIADETECTION])
{
if ((lResult = CallSP2(
ptProvider->apfn[SP_LINESETDEFAULTMEDIADETECTION],
"lineSetDefaultMediaDetection",
SP_FUNC_SYNC,
(ULONG_PTR) ptLine->hdLine,
(DWORD) dwUnionMediaModes
)) != 0)
{
lResult = (bLineMapper ? LINEERR_OPERATIONFAILED :
lResult);
PerfBlock.dwLinesInUse--;
goto xxxLOpen_cleanup;
}
}
else
{
lResult = LINEERR_OPERATIONUNAVAIL;
PerfBlock.dwLinesInUse--;
goto xxxLOpen_cleanup;
}
ptLine->dwOpenMediaModes = dwUnionMediaModes;
}
}
//
// Set the proxy ptrs if appropriate
//
if (dwPrivileges & LINEOPENOPTION_PROXY)
{
for (i = 0; i < dwNumProxyRequestTypes; i++)
{
ptLine->apProxys[*(pdwProxyRequestTypes + i)] =
ptLineClient;
}
}
//
// What proxys have opened now ?
//
for(
i = LINEPROXYREQUEST_SETAGENTGROUP, dwRegisteredProxys = 0;
i <= LINEPROXYREQUEST_LASTVALUE;
i++
)
{
if (ptLine->apProxys[i] != NULL)
{
//
// Munge them all into a DWORD (if we ever
// get more that 32 we'll have to do an
// additional test)
//
dwRegisteredProxys |= ( 1<<i );
}
}
//
// Add the tLineClient to the tLine's list & increment the
// number of opens
//
if ((ptLineClient->pNextSametLine = ptLine->ptLineClients))
{
ptLineClient->pNextSametLine->pPrevSametLine = ptLineClient;
}
ptLine->ptLineClients = ptLineClient;
ptLine->dwNumOpens++;
if (bOpenedtLine)
{
pLookupEntry->ptLine = ptLine;
ptLine->dwKey = TLINE_KEY;
}
ReleaseMutex (hLookupEntryMutex);
bReleasetLineMutex = FALSE;
//
// Safely add the new tLineClient to the tLineApp's list.
//
{
LOG((TL_TRACE, "xxxLOpen: adding ptLineClient [%p] to tLineApp's [%p] list", ptLineClient, pParams->hLineApp));
if ((ptLineApp = WaitForExclusiveLineAppAccess(
pParams->hLineApp,
ptClient
)))
{
if (ptLineApp->dwAPIVersion <= TAPI_VERSION3_0)
{
FillMemory (
ptLineClient->adwEventSubMasks,
sizeof(DWORD) * EM_NUM_MASKS,
(BYTE) 0xff
);
}
else
{
CopyMemory (
ptLineClient->adwEventSubMasks,
ptLineApp->adwEventSubMasks,
sizeof(DWORD) * EM_NUM_MASKS
);
}
if ((ptLineClient->pNextSametLineApp =
ptLineApp->ptLineClients))
{
ptLineClient->pNextSametLineApp->pPrevSametLineApp =
ptLineClient;
}
ptLineApp->ptLineClients = ptLineClient;
//
// Note: it's important to mark the newtLineClient as
// valid way down here because another thread could be
// simultaneously trying to do an unconditional
// DestroytLine (due to receiving a LINE_CLOSE, etc.)
// and we want to make sure the tLineClient is in both
// tLine's & tLineApp's lists before DestroytLine calls
// DestroytLineClient which'll try to yank the tLineClient
// out of these lists.
//
hLine = ptLineClient->hLine;
ptLineClient->ptLineApp = ptLineApp;
ptLineClient->dwKey = TLINECLIENT_KEY;
UNLOCKTLINEAPP(ptLineApp);
//
// Alert other clients that another open has occured
//
SendMsgToLineClients(
ptLine,
ptLineClient,
LINE_LINEDEVSTATE,
LINEDEVSTATE_OPEN,
0,
0
);
//
// Alert other clients that a proxy open has occured
//
if (dwPrivileges & LINEOPENOPTION_PROXY)
{
// One message per LINEPROXYREQUEST_ type
for (i = 0; i < dwNumProxyRequestTypes; i++)
{
LOG((TL_INFO,
"tell clients proxy %02X opened",
*(pdwProxyRequestTypes + i)
));
SendMsgToLineClients(
ptLine,
ptLineClient,
LINE_PROXYSTATUS,
LINEPROXYSTATUS_OPEN,
*(pdwProxyRequestTypes + i),// LINEPROXYREQUEST_xx
0
);
}
//
// Now see if we have all the ones required by
// TAPI3.0 for an ACD proxy
//
if ((dwRegisteredProxys & AllRequiredACDProxyRequests3_0)
== AllRequiredACDProxyRequests3_0)
{
LOG((TL_INFO,
"tell clients that all proxys needed " \
"for TAPI3.0 ACD are open"
));
SendMsgToLineClients(
ptLine,
ptLineClient,
LINE_PROXYSTATUS,
LINEPROXYSTATUS_ALLOPENFORACD,
0,
0
);
}
//
// If we are given a proxy server CLSID, register
// the proxy server in DS, error not considered
// critical here
//
if (*szClsid != 0)
{
ptLineClient->szProxyClsid = ServerAlloc (
(_tcslen (szClsid) + 1) * sizeof(TCHAR)
);
if (ptLineClient->szProxyClsid)
{
_tcscpy (ptLineClient->szProxyClsid, szClsid);
OnProxyLineOpen (szClsid);
}
}
}
//
// Fill in the return values
//
LOG((TL_TRACE, "xxxLOpen returning hLine of %p", hLine));
pParams->hLine = hLine;
*pdwNumBytesReturned = sizeof (LINEOPEN_PARAMS);
//
// (Now we need to return the call params if this
// is a remote client)
//
// This was for some 2.1 kludge which didn't make
// any sense, so i've chg'd to indicate NO_DATA
// so nothing gets copied back on the client side.
//
// DanKn, Aug 6 '98
//
if (IS_REMOTE_CLIENT (ptClient))
{
pParams->dwCallParamsReturnOffset = TAPI_NO_DATA;
}
}
else
{
//
// If here the app handle is bad, & we've some special
// case cleanup to do. Since the tLineClient is not
// in the tLineApp's list, we can't simply call
// DestroytLine(Client) to clean things up, since the
// pointer-resetting code will blow up. So we'll
// grab the tLine's mutex and explicitly remove the
// new tLineClient from it's list, then do a conditional
// shutdown on the tLine (in case any other clients
// have come along & opened it). Also deselect the
// ext version and/or decrement the ext version count
// as appropriate.
//
// Note: keep in mind that a LINE_CLOSE might be being
// processed by another thread (if so, it will be
// spinning on trying to destroy the tLineClient
// which isn't valid at this point)
//
lResult = LINEERR_INVALAPPHANDLE;
WaitForSingleObject (hLookupEntryMutex, INFINITE);
if (ptLineClient->pNextSametLine)
{
ptLineClient->pNextSametLine->pPrevSametLine =
ptLineClient->pPrevSametLine;
}
if (ptLineClient->pPrevSametLine)
{
ptLineClient->pPrevSametLine->pNextSametLine =
ptLineClient->pNextSametLine;
}
else
{
ptLine->ptLineClients = ptLineClient->pNextSametLine;
}
ptLine->dwNumOpens--;
if (bDecrExtVerCountOnError == TRUE)
{
ptLine->dwExtVersionCount--;
if (ptLine->dwExtVersionCount == 0)
{
ptLine->dwExtVersion = 0;
if (ptProvider->apfn[SP_LINESELECTEXTVERSION])
{
CallSP2(
ptProvider->apfn[SP_LINESELECTEXTVERSION],
"lineSelectExtVersion",
SP_FUNC_SYNC,
(ULONG_PTR) ptLine->hdLine,
(DWORD) 0
);
}
}
}
ReleaseMutex (hLookupEntryMutex);
DestroytLine (ptLine, FALSE); // conditional destroy
bOpenedtLine = FALSE; // so we don't do err handling below
}
}
CloseHandle (hLookupEntryMutex);
}
xxxLOpen_cleanup:
if (bReleasetLineMutex)
{
if (lResult != 0)
{
if (bDecrExtVerCountOnError == TRUE)
{
ptLine->dwExtVersionCount--;
if (ptLine->dwExtVersionCount == 0)
{
ptLine->dwExtVersion = 0;
if (ptProvider->apfn[SP_LINESELECTEXTVERSION])
{
CallSP2(
ptProvider->apfn[SP_LINESELECTEXTVERSION],
"lineSelectExtVersion",
SP_FUNC_SYNC,
(ULONG_PTR) ptLine->hdLine,
(DWORD) 0
);
}
}
}
if (bOpenedtLine == TRUE && ptProvider->apfn[SP_LINECLOSE])
{
CallSP1(
ptProvider->apfn[SP_LINECLOSE],
"lineClose",
SP_FUNC_SYNC,
(ULONG_PTR) ptLine->hdLine
);
}
}
ReleaseMutex (hLookupEntryMutex);
CloseHandle (hLookupEntryMutex);
}
if ((pParams->lResult = lResult) != 0)
{
if (ptLineClient)
{
DereferenceObject (ghHandleTable, ptLineClient->hLine, 1);
}
if (bOpenedtLine)
{
DereferenceObject (ghHandleTable, ptLine->hLine, 1);
}
}
if (bFreeCallParams)
{
ServerFree (pCallParams);
}
LINEEPILOGSYNC(
&pParams->lResult,
hMutex,
bCloseMutex,
objectToDereference,
(bLineMapper ? "Open(LINEMAPPER)" : "Open")
);
}
void
WINAPI
LOpen(
PTCLIENT ptClient,
PLINEOPEN_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
if (pParams->dwDeviceID != LINEMAPPER)
{
xxxLOpen(
ptClient,
pParams,
dwParamsBufferSize,
pDataBuf,
pdwNumBytesReturned,
FALSE
);
}
else
{
//
// Try to open each line device, starting with device 0, until
// either we find a device that'll handle the capabilities
// requested by the client or we run out of devices. If we
// encounter a certain subset of parameter errors the first time
// we call xxxLOpen we want to return these back to the app
// immediately to aid debugging (rather than always returning
// LINEMAPPERFAILED).
//
for(
pParams->dwDeviceID = 0;
pParams->dwDeviceID < TapiGlobals.dwNumLines;
pParams->dwDeviceID++
)
{
xxxLOpen(
ptClient,
pParams,
dwParamsBufferSize,
pDataBuf,
pdwNumBytesReturned,
TRUE
);
if (pParams->dwDeviceID == 0)
{
switch (pParams->lResult)
{
case LINEERR_BADDEVICEID: // 0 line devices
case LINEERR_INVALAPPHANDLE:
case LINEERR_INVALCALLPARAMS:
case LINEERR_INVALMEDIAMODE:
case LINEERR_INVALPOINTER: // no call params, etc
case LINEERR_INVALPRIVSELECT:
case LINEERR_REINIT:
case LINEERR_UNINITIALIZED:
return;
default:
break;
}
}
if (pParams->lResult == 0)
{
break;
}
}
if (pParams->dwDeviceID >= TapiGlobals.dwNumLines)
{
pParams->lResult = LINEERR_LINEMAPPERFAILED;
}
}
}
void
LPark_PostProcess(
PASYNCREQUESTINFO pAsyncRequestInfo,
PASYNCEVENTMSG pAsyncEventMsg,
LPVOID *ppBuf
)
{
//
// Note: pAsyncEventMsg->dwParam1 & dwParam2 are reserved for
// the request ID and result, respectively
//
PASYNCEVENTMSG pNewAsyncEventMsg = (PASYNCEVENTMSG)
pAsyncRequestInfo->dwParam1;
LPVARSTRING pNonDirAddress = (LPVARSTRING) (pNewAsyncEventMsg + 1);
CopyMemory (pNewAsyncEventMsg, pAsyncEventMsg, sizeof (ASYNCEVENTMSG));
*ppBuf = (LPVOID) pNewAsyncEventMsg;
if (pAsyncEventMsg->Param2 == 0) // success
{
//
// Add the used size of the non-dir addr, & keep the total
// length of the msg DWORD-aligned
//
pNewAsyncEventMsg->TotalSize +=
((pNonDirAddress->dwUsedSize + TALIGN_COUNT) & TALIGN_MASK);
pNewAsyncEventMsg->Param3 =
DWORD_CAST(pAsyncRequestInfo->dwParam2,__FILE__,__LINE__); // hpNonDirAddr
pNewAsyncEventMsg->Param4 = pNonDirAddress->dwUsedSize;
}
}
void
WINAPI
LPark(
PTCLIENT ptClient,
PLINEPARK_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
LONG lRequestID;
HANDLE hMutex;
HDRVCALL hdCall;
TSPIPROC pfnTSPI_linePark;
DWORD objectToDereference;
PTCALLCLIENT ptCallClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
//
// Verify size/offset/string params given our input buffer/size
//
if ((pParams->dwParkMode == LINEPARKMODE_DIRECTED) &&
IsBadStringParam(
dwParamsBufferSize,
pDataBuf,
pParams->dwDirAddressOffset
))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HCALL, // widget type
(DWORD) pParams->hCall, // client widget handle
(LPVOID) &hdCall, // provider widget handle
LINECALLPRIVILEGE_OWNER, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINEPARK, // provider func index
&pfnTSPI_linePark, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptCallClient, // context
"Park" // func name
)) > 0)
{
LPBYTE pBuf;
LPVARSTRING pNonDirAddress;
if (pParams->dwParkMode == LINEPARKMODE_NONDIRECTED)
{
if (pParams->dwNonDirAddressTotalSize < sizeof (VARSTRING))
{
lRequestID = LINEERR_STRUCTURETOOSMALL;
goto LPark_return;
}
if (!(pBuf = ServerAlloc(
(pParams->dwNonDirAddressTotalSize +
sizeof (ASYNCEVENTMSG) + TALIGN_COUNT) & TALIGN_MASK
)))
{
lRequestID = LINEERR_NOMEM;
goto LPark_return;
}
pNonDirAddress = (LPVARSTRING) (pBuf + sizeof (ASYNCEVENTMSG));
pNonDirAddress->dwTotalSize = pParams->dwNonDirAddressTotalSize;
pNonDirAddress->dwNeededSize =
pNonDirAddress->dwUsedSize = sizeof (VARSTRING);
pAsyncRequestInfo->pfnPostProcess = LPark_PostProcess;
pAsyncRequestInfo->dwParam1 = (ULONG_PTR) pBuf;
pAsyncRequestInfo->dwParam2 = pParams->hpNonDirAddress;
pAsyncRequestInfo->hfnClientPostProcessProc =
pParams->hfnPostProcessProc;
}
else if (pParams->dwParkMode == LINEPARKMODE_DIRECTED)
{
pNonDirAddress = (LPVARSTRING) NULL;
}
else
{
lRequestID = LINEERR_INVALPARKMODE;
goto LPark_return;
}
pParams->lResult = CallSP5(
pfnTSPI_linePark,
"linePark",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdCall,
(DWORD) pParams->dwParkMode,
(ULONG_PTR) (pParams->dwParkMode == LINEPARKMODE_NONDIRECTED ?
NULL : pDataBuf + pParams->dwDirAddressOffset),
(ULONG_PTR) pNonDirAddress
);
}
LPark_return:
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"Park"
);
}
void
WINAPI
LPickup(
PTCLIENT ptClient,
PLINEPICKUP_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
LONG lRequestID;
HANDLE hMutex;
HDRVLINE hdLine;
TSPIPROC pfnTSPI_linePickup;
DWORD objectToDereference;
PTLINECLIENT ptLineClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
//
// Verify size/offset/string params given our input buffer/size
//
if (((pParams->dwDestAddressOffset != TAPI_NO_DATA) &&
IsBadStringParam(
dwParamsBufferSize,
pDataBuf,
pParams->dwDestAddressOffset
)) ||
((pParams->dwGroupIDOffset != TAPI_NO_DATA) &&
IsBadStringParam(
dwParamsBufferSize,
pDataBuf,
pParams->dwGroupIDOffset
)))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HLINE, // widget type
(DWORD) pParams->hLine, // client widget handle
(LPVOID) &hdLine, // provider widget handle
0, // privileges or device ID
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINEPICKUP, // provider func index
&pfnTSPI_linePickup, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptLineClient, // context
"Pickup" // func name
)) > 0)
{
PTCALL ptCall;
HCALL hCall = 0;
PTCALLCLIENT ptCallClient;
if (CreatetCallAndClient(
ptLineClient,
&ptCall,
&ptCallClient,
NULL,
&hCall,
NULL
) != 0)
{
lRequestID = LINEERR_NOMEM;
goto LPickup_return;
}
pAsyncRequestInfo->pfnPostProcess = LMakeCall_PostProcess;
pAsyncRequestInfo->htXxx = (ULONG_PTR)ptCallClient->ptLineClient->ptLine->hLine;
pAsyncRequestInfo->dwParam1 = (ULONG_PTR) ptCall;
pAsyncRequestInfo->dwParam2 = pParams->hpCall;
pAsyncRequestInfo->dwParam5 = (ULONG_PTR)hCall;
pAsyncRequestInfo->hfnClientPostProcessProc =
pParams->hfnPostProcessProc;
pParams->lResult = CallSP7(
pfnTSPI_linePickup,
"linePickup",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdLine,
(DWORD) pParams->dwAddressID,
(ULONG_PTR) hCall,
(ULONG_PTR) &ptCall->hdCall,
(ULONG_PTR) (pParams->dwDestAddressOffset == TAPI_NO_DATA ? 0 :
pDataBuf + pParams->dwDestAddressOffset),
(ULONG_PTR) (pParams->dwGroupIDOffset == TAPI_NO_DATA ? 0 :
pDataBuf + pParams->dwGroupIDOffset)
);
SetDrvCallFlags(
hCall,
DCF_SPIRETURNED | (IS_LRESULT_NOTERROR(pParams->lResult) ?
DCF_DRVCALLVALID : 0)
);
}
LPickup_return:
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"Pickup"
);
}
void
WINAPI
LPrepareAddToConference(
PTCLIENT ptClient,
PLINEPREPAREADDTOCONFERENCE_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
LONG lRequestID;
HANDLE hMutex;
HDRVCALL hdConfCall;
TSPIPROC pfnTSPI_linePrepareAddToConference;
DWORD objectToDereference;
PTCALLCLIENT ptConfCallClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HCALL, // widget type
(DWORD) pParams->hConfCall, // client widget handle
(LPVOID) &hdConfCall, // provider widget handle
LINECALLPRIVILEGE_OWNER, // privileges or device ID
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINEPREPAREADDTOCONFERENCE, // provider func index
&pfnTSPI_linePrepareAddToConference,// provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptConfCallClient, // context
"PrepareAddToConference" // func name
)) > 0)
{
LONG lResult;
PTCALL ptConsultCall;
HCALL hConsultCall;
PTCALLCLIENT ptConsultCallClient;
PTLINECLIENT ptLineClient;
LPLINECALLPARAMS pCallParamsApp, pCallParamsSP;
//
// Verify size/offset/string params given our input buffer/size
//
if ((pParams->dwCallParamsOffset != TAPI_NO_DATA) &&
IsBadStructParam(
dwParamsBufferSize,
pDataBuf,
pParams->dwCallParamsOffset
))
{
lRequestID = LINEERR_STRUCTURETOOSMALL;
goto LPrepareAddToConference_return;
}
pCallParamsApp = (LPLINECALLPARAMS)
(pParams->dwCallParamsOffset == TAPI_NO_DATA ?
0 : pDataBuf + pParams->dwCallParamsOffset);
try
{
//
// Safely get the ptLineClient
//
ptLineClient = ptConfCallClient->ptLineClient;
//
// Make sure the hConfCall is really a conf parent
//
{
PTCALL ptCall;
ptCall = (PTCALL) ptConfCallClient->ptCall;
if ((ptCall->pConfList)->aptCalls[0] != ptCall)
{
lRequestID = LINEERR_INVALCONFCALLHANDLE;
goto LPrepareAddToConference_return;
}
}
}
myexcept
{
//
// If here the conf call was destroyed
//
lRequestID = LINEERR_INVALCONFCALLHANDLE;
goto LPrepareAddToConference_return;
}
if (pCallParamsApp)
{
DWORD dwAPIVersion, dwSPIVersion;
if (GetLineVersions(
ptLineClient,
&dwAPIVersion,
&dwSPIVersion
) != 0)
{
lRequestID = LINEERR_INVALCONFCALLHANDLE;
goto LPrepareAddToConference_return;
}
if ((lResult = ValidateCallParams(
pCallParamsApp,
&pCallParamsSP,
dwAPIVersion,
dwSPIVersion,
pParams->dwAsciiCallParamsCodePage
)) != 0)
{
lRequestID = lResult;
goto LPrepareAddToConference_return;
}
}
else
{
pCallParamsSP = (LPLINECALLPARAMS) NULL;
}
if (CreatetCallAndClient(
ptLineClient,
&ptConsultCall,
&ptConsultCallClient,
pCallParamsSP,
&hConsultCall,
NULL
) != 0)
{
lRequestID = LINEERR_NOMEM;
goto LPrepareAddToConference_freeCallParams;
}
pAsyncRequestInfo->pfnPostProcess = LMakeCall_PostProcess;
pAsyncRequestInfo->htXxx = (ULONG_PTR)ptConsultCallClient->ptLineClient->ptLine->hLine;
pAsyncRequestInfo->dwParam1 = (ULONG_PTR) ptConsultCall;
pAsyncRequestInfo->dwParam2 = pParams->hpConsultCall;
pAsyncRequestInfo->dwParam5 = (ULONG_PTR)hConsultCall;
pAsyncRequestInfo->hfnClientPostProcessProc =
pParams->hfnPostProcessProc;
pParams->lResult = CallSP5(
pfnTSPI_linePrepareAddToConference,
"linePrepareAddToConference",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdConfCall,
(ULONG_PTR) hConsultCall,
(ULONG_PTR) &ptConsultCall->hdCall,
(ULONG_PTR) pCallParamsSP
);
SetDrvCallFlags(
hConsultCall,
DCF_SPIRETURNED | (IS_LRESULT_NOTERROR(pParams->lResult) ?
DCF_DRVCALLVALID : 0)
);
LPrepareAddToConference_freeCallParams:
if (pCallParamsSP != pCallParamsApp)
{
ServerFree (pCallParamsSP);
}
}
LPrepareAddToConference_return:
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"PrepareAddToConference"
);
}
void
WINAPI
LProxyMessage(
PTCLIENT ptClient,
PLINEPROXYMESSAGE_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
HANDLE hMutex;
HDRVLINE hdLine;
DWORD objectToDereference;
PTLINECLIENT ptLineClient;
if ((pParams->lResult = LINEPROLOG(
ptClient, // tClient
ANY_RT_HLINE, // widget type
(DWORD) pParams->hLine, // client widget handle
(LPVOID) &hdLine, // provider widget handle
0, // privileges or device ID
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_NONE, // provider func index
NULL, // provider func pointer
NULL, // async request info
0, // client async request ID
&objectToDereference, // object to dereference
&ptLineClient, // context
"ProxyMessage" // func name
)) == 0)
{
DWORD dwMsg = pParams->dwMsg, i;
PTCALL ptCall;
PTLINE ptLine;
TPOINTERLIST clientList, *pClientList = &clientList;
ASYNCEVENTMSG msg[2];
//
// Verify params
//
try
{
ptLine = ptLineClient->ptLine;
if (!(ptLineClient->dwPrivileges & LINEOPENOPTION_PROXY))
{
pParams->lResult = LINEERR_NOTREGISTERED;
goto LProxyMessage_epilog;
}
}
myexcept
{
pParams->lResult = LINEERR_INVALLINEHANDLE;
goto LProxyMessage_epilog;
}
switch (dwMsg)
{
case LINE_AGENTSTATUS:
// ignore the hCall param
if (pParams->dwParam1 >= ptLine->dwNumAddresses)
{
LOG((TL_ERROR,
"ERROR: lineProxyMessage (AGENTSTATUS): dwParam1 " \
"bad addr ID (=x%x, num addrs=x%x)",
pParams->dwParam1,
ptLine->dwNumAddresses
));
pParams->lResult = LINEERR_INVALPARAM;
goto LProxyMessage_epilog;
}
else if (pParams->dwParam2 == 0 ||
pParams->dwParam2 & ~AllAgentStatus)
{
LOG((TL_ERROR,
"ERROR: lineProxyMessage (AGENTSTATUS): dwParam2 " \
"(=x%x) bad LINEAGENTSTATUS_ flags",
pParams->dwParam2
));
pParams->lResult = LINEERR_INVALPARAM;
goto LProxyMessage_epilog;
}
else if (pParams->dwParam2 & LINEAGENTSTATUS_STATE)
{
if (!IsOnlyOneBitSetInDWORD (pParams->dwParam3) ||
pParams->dwParam3 & ~AllAgentStates)
{
LOG((TL_ERROR,
"ERROR: lineProxyMessage (AGENTSTATUS): " \
"dwParam3 (=x%x) bad LINEAGENTSTATE_ flags",
pParams->dwParam3
));
pParams->lResult = LINEERR_INVALPARAM;
goto LProxyMessage_epilog;
}
}
else if (pParams->dwParam3 != 0)
{
// don't bother complaining about a non-zero dwParam3
pParams->dwParam3 = 0;
}
break;
case LINE_AGENTSPECIFIC:
// ignore dwParam1, dwParam2, & dwParam3 (app-specific)
if (pParams->hCall)
{
PTCALLCLIENT ptCallClient;
if (!(ptCallClient = ReferenceCall(
pParams->hCall,
ptClient
)))
{
pParams->lResult = LINEERR_INVALCALLHANDLE;
goto LProxyMessage_epilog;
}
ptCall = ptCallClient->ptCall;
DereferenceObject (ghHandleTable, pParams->hCall, 1);
goto LProxyMessage_fwdMsgToCallClients;
}
break;
case LINE_AGENTSESSIONSTATUS:
// ignore the hCall param
// ignore the dwParam1 , it's the agent handle
if (pParams->dwParam2 == 0 ||
pParams->dwParam2 & ~AllAgentSessionStatus)
{
LOG((TL_ERROR,
"ERROR: lineProxyMessage (AGENTSESSIONSTATUS): dwParam2 " \
"(=x%x) bad LINEAGENTSESSIONSTATUS_ flags",
pParams->dwParam2
));
pParams->lResult = LINEERR_INVALPARAM;
goto LProxyMessage_epilog;
}
else if (pParams->dwParam2 & LINEAGENTSESSIONSTATUS_STATE)
{
if (!IsOnlyOneBitSetInDWORD (pParams->dwParam3) ||
pParams->dwParam3 & ~AllAgentSessionStates)
{
LOG((TL_ERROR,
"ERROR: lineProxyMessage (AGENTSESSIONSTATUS): " \
"dwParam3 (=x%x) bad LINEAGENTSESSIONSTATE_ flags",
pParams->dwParam3
));
pParams->lResult = LINEERR_INVALPARAM;
goto LProxyMessage_epilog;
}
}
else if (pParams->dwParam3 != 0)
{
// don't bother complaining about a non-zero dwParam3
pParams->dwParam3 = 0;
}
break;
case LINE_AGENTSTATUSEX:
// ignore the hCall param
// ignore the dwParam1 , it's the agent handle
if (pParams->dwParam2 == 0 ||
pParams->dwParam2 & ~AllAgentStatusEx)
{
LOG((TL_ERROR,
"ERROR: lineProxyMessage (AGENTSTATUSEX): dwParam2 " \
"(=x%x) bad LINEAGENTSTATUSEX_ flags",
pParams->dwParam2
));
pParams->lResult = LINEERR_INVALPARAM;
goto LProxyMessage_epilog;
}
else if (pParams->dwParam2 & LINEAGENTSESSIONSTATUS_STATE)
{
if (!IsOnlyOneBitSetInDWORD (pParams->dwParam3) ||
pParams->dwParam3 & ~AllAgentStatesEx)
{
LOG((TL_ERROR,
"ERROR: lineProxyMessage (AGENTSTATUSEX): " \
"dwParam3 (=x%x) bad LINEAGENTSTATEEX_ flags",
pParams->dwParam3
));
pParams->lResult = LINEERR_INVALPARAM;
goto LProxyMessage_epilog;
}
}
else if (pParams->dwParam3 != 0)
{
// don't bother complaining about a non-zero dwParam3
pParams->dwParam3 = 0;
}
break;
case LINE_QUEUESTATUS:
// ignore the hCall param
// ignore the dwParam1 , it's the queue handle
if (pParams->dwParam2 == 0 ||
pParams->dwParam2 & ~AllQueueStatus)
{
LOG((TL_ERROR,
"ERROR: lineProxyMessage (QUEUESTATUS): dwParam2 " \
"(=x%x) bad LINEQUEUESTATUS_ flags",
pParams->dwParam2
));
pParams->lResult = LINEERR_INVALPARAM;
goto LProxyMessage_epilog;
}
else if (pParams->dwParam3 != 0)
{
// don't bother complaining about a non-zero dwParam3
pParams->dwParam3 = 0;
}
break;
case LINE_GROUPSTATUS:
// ignore the hCall param
if (pParams->dwParam1 == 0 ||
pParams->dwParam1 & ~AllGroupStatus)
{
LOG((TL_ERROR,
"ERROR: lineProxyMessage (GROUPSTATUS): dwParam1 " \
"(=x%x) bad LINEQUEUESTATUS_ flags",
pParams->dwParam1
));
pParams->lResult = LINEERR_INVALPARAM;
goto LProxyMessage_epilog;
}
else if (pParams->dwParam2 != 0)
{
// don't bother complaining about a non-zero dwParam2
pParams->dwParam2 = 0;
}
else if (pParams->dwParam3 != 0)
{
// don't bother complaining about a non-zero dwParam3
pParams->dwParam3 = 0;
}
break;
default:
LOG((TL_ERROR,
"ERROR : lineProxyMessage: inval dwMsg (=x%x)",
pParams->dwMsg
));
pParams->lResult = LINEERR_INVALPARAM;
goto LProxyMessage_epilog;
} // switch (dwMsg)
//
// Fwd this msg on to all line's clients who say they support
// >= TAPI_VERSION2_0 (not including the proxy's line client)
//
if ((pParams->lResult = GetLineClientListFromLine(
ptLine,
&pClientList
)) != 0)
{
goto LProxyMessage_epilog;
}
msg->TotalSize = sizeof (ASYNCEVENTMSG);
msg->fnPostProcessProcHandle = 0;
msg->Msg = dwMsg;
msg->Param1 = pParams->dwParam1;
msg->Param2 = pParams->dwParam2;
msg->Param3 = pParams->dwParam3;
msg->Param4 = 0;
for (i = 0; i < pClientList->dwNumUsedEntries; i++)
{
PTLINECLIENT ptLineClient2 = (PTLINECLIENT)
pClientList->aEntries[i];
if (ptLineClient2 != ptLineClient)
{
try
{
if (ptLineClient2->ptLineApp->dwAPIVersion >=
TAPI_VERSION2_0)
{
if (FMsgDisabled (
ptLineClient2->ptLineApp->dwAPIVersion,
ptLineClient2->adwEventSubMasks,
dwMsg,
pParams->dwParam1
))
{
continue;
}
msg->InitContext =
ptLineClient2->ptLineApp->InitContext;
msg->hDevice = ptLineClient2->hRemoteLine;
msg->OpenContext = ptLineClient2->OpenContext;
//
// Now a final check to make sure all the
// params are valid before sending the msg
//
{
PTCLIENT ptClient = ptLineClient2->ptClient;
if (ptLineClient2->dwKey == TLINECLIENT_KEY)
{
WriteEventBuffer (ptClient, msg);
}
}
}
}
myexcept
{
// just continue
}
}
}
goto LProxyMessage_freeClientList;
//
// Fwd this msg on to all call's clients who say they support
// >= TAPI_VERSION2_0 (not including the proxy's line client)
//
LProxyMessage_fwdMsgToCallClients:
if ((pParams->lResult = GetCallClientListFromCall(
ptCall,
&pClientList
)) != 0)
{
goto LProxyMessage_epilog;
}
msg->TotalSize = sizeof (ASYNCEVENTMSG) + sizeof (HCALLHUB);
msg->fnPostProcessProcHandle = 0;
msg->Msg = dwMsg;
msg->Param1 = pParams->dwParam1;
msg->Param2 = pParams->dwParam2;
msg->Param3 = pParams->dwParam3;
for (i = 0; i < pClientList->dwNumUsedEntries; i++)
{
PTCALLCLIENT ptCallClient = (PTCALLCLIENT)
pClientList->aEntries[i];
try
{
if (ptCallClient->hCall != pParams->hCall)
{
PTLINEAPP ptLineApp;
ptLineApp = ptCallClient->ptLineClient->ptLineApp;
if (ptLineApp->dwAPIVersion >= TAPI_VERSION2_0)
{
if (FMsgDisabled (
ptCallClient->ptLineClient->ptLineApp->dwAPIVersion,
ptCallClient->adwEventSubMasks,
dwMsg,
pParams->dwParam1
))
{
continue;
}
msg->InitContext = ptLineApp->InitContext;
msg->hDevice = ptCallClient->hCall;
msg->OpenContext =
ptCallClient->ptLineClient->OpenContext;
msg->Param4 =
ptCallClient->ptLineClient->hRemoteLine;
*((LPHCALLHUB)(&msg->Param4 + 1)) =
(ptCallClient->ptCallHubClient)?
ptCallClient->ptCallHubClient->hCallHub :
(HCALLHUB)(ULONG_PTR)NULL;
//
// Now a final check to make sure all the
// params are valid before sending the msg
//
{
PTCLIENT ptClient = ptCallClient->ptClient;
if (ptCallClient->dwKey == TCALLCLIENT_KEY)
{
WriteEventBuffer (ptClient, msg);
}
}
}
}
}
myexcept
{
// just continue
}
}
LProxyMessage_freeClientList:
if (pClientList != &clientList)
{
ServerFree (pClientList);
}
}
LProxyMessage_epilog:
LINEEPILOGSYNC(
&pParams->lResult,
hMutex,
bCloseMutex,
objectToDereference,
"ProxyMessage"
);
}
void
WINAPI
LProxyResponse(
PTCLIENT ptClient,
PLINEPROXYRESPONSE_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
HANDLE hMutex;
HDRVLINE hdLine;
DWORD objectToDereference;
PTLINECLIENT pProxy;
if ((pParams->lResult = LINEPROLOG(
ptClient, // tClient
ANY_RT_HLINE, // widget type
pParams->hLine, // client widget handle
(LPVOID) &hdLine, // provider widget handle
0, // privileges or device ID
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_NONE, // provider func index
NULL, // provider func pointer
NULL, // async request info
0, // client async request ID
&objectToDereference, // object to dereference
&pProxy, // context
"ProxyResponse" // func name
)) == 0)
{
PASYNCREQUESTINFO pAsyncRequestInfo;
//
// The dwInstance param is the dwLocalRequestID for the
// AsyncRequestInfo struct. Note that the dwKey value of
// this struct was reset to == pProxy->hLine in
// CreateProxyRequest().
//
if (!(pAsyncRequestInfo = ReferenceObject(
ghHandleTable,
pParams->dwInstance,
pParams->hLine
)))
{
pParams->dwResult = LINEERR_OPERATIONFAILED;
goto LProxyResponse_Epilog;
}
//
// Safely remove the proxy request from the list of pending requests
//
if (WaitForExclusiveLineClientAccess (pProxy))
{
if (pAsyncRequestInfo->dwKey == pParams->hLine)
{
pAsyncRequestInfo->dwKey = TASYNC_KEY;
if (pAsyncRequestInfo->dwParam5)
{
((PASYNCREQUESTINFO) pAsyncRequestInfo->dwParam5)->dwParam4 =
pAsyncRequestInfo->dwParam4;
}
if (pAsyncRequestInfo->dwParam4)
{
((PASYNCREQUESTINFO) pAsyncRequestInfo->dwParam4)->dwParam5 =
pAsyncRequestInfo->dwParam5;
}
else
{
pProxy->pPendingProxyRequests = (PASYNCREQUESTINFO)
pAsyncRequestInfo->dwParam5;
}
UNLOCKTLINECLIENT(pProxy);
}
else
{
//
// Another thread must have simultaneously been
// completing this request, so fail gracefully
//
UNLOCKTLINECLIENT(pProxy);
DereferenceObject (ghHandleTable, pParams->dwInstance, 1);
pParams->dwResult = LINEERR_OPERATIONFAILED;
goto LProxyResponse_Epilog;
}
}
else
{
DereferenceObject (ghHandleTable, pParams->dwInstance, 1);
pParams->dwResult = LINEERR_INVALLINEHANDLE;
goto LProxyResponse_Epilog;
}
//
// If this is a proxy request where there's data to be returned
// to the client (aside from the result) then we want to alloc
// a buffer & fill it with the data. We'll make it look like a
// DevSpecific request that just completed, and have the DevSpecfic
// post process routine deal with it.
//
// Make sure buffers are 64-bit aligned
//
if (pParams->dwProxyResponseOffset != TAPI_NO_DATA &&
pParams->dwResult == 0)
{
DWORD dwSize;
LPBYTE pBuf;
LPLINEPROXYREQUEST pProxyRequest = (LPLINEPROXYREQUEST)
( pDataBuf + pParams->dwProxyResponseOffset );
switch (pProxyRequest->dwRequestType)
{
case LINEPROXYREQUEST_AGENTSPECIFIC:
{
dwSize = pProxyRequest->AgentSpecific.dwSize;
if (!(pBuf = ServerAlloc(
sizeof (ASYNCEVENTMSG) + ((dwSize + 7) & 0xfffffff8)
)))
{
pParams->dwResult = LINEERR_NOMEM;
goto LProxyResponse_completeRequest;
}
CopyMemory(
pBuf + sizeof (ASYNCEVENTMSG),
pProxyRequest->AgentSpecific.Params,
dwSize
);
break;
}
case LINEPROXYREQUEST_CREATEAGENT:
case LINEPROXYREQUEST_CREATEAGENTSESSION:
{
//
// Proces both of these together. the handle is
// the first member of both structures
//
dwSize = sizeof (HAGENT);
pBuf = ServerAlloc(
sizeof(ASYNCEVENTMSG) + ((dwSize + 7) & 0xfffffff8)
);
if ( NULL == pBuf )
{
pParams->dwResult = LINEERR_NOMEM;
goto LProxyResponse_completeRequest;
}
CopyMemory(
pBuf + sizeof(ASYNCEVENTMSG),
&(pProxyRequest->CreateAgent.hAgent),
dwSize
);
break;
}
case LINEPROXYREQUEST_GETQUEUELIST:
{
dwSize = pProxyRequest->GetQueueList.QueueList.dwUsedSize;
pBuf = ServerAlloc(
sizeof(ASYNCEVENTMSG) + ((dwSize + 7) & 0xfffffff8)
);
if ( NULL == pBuf )
{
pParams->dwResult = LINEERR_NOMEM;
goto LProxyResponse_completeRequest;
}
CopyMemory(
pBuf + sizeof(ASYNCEVENTMSG),
&(pProxyRequest->GetQueueList.QueueList),
dwSize
);
break;
}
case LINEPROXYREQUEST_GETGROUPLIST:
{
dwSize = pProxyRequest->GetGroupList.GroupList.dwUsedSize;
pBuf = ServerAlloc(
sizeof(ASYNCEVENTMSG) + ((dwSize + 7) & 0xfffffff8)
);
if ( NULL == pBuf )
{
pParams->dwResult = LINEERR_NOMEM;
goto LProxyResponse_completeRequest;
}
CopyMemory(
pBuf + sizeof(ASYNCEVENTMSG),
&(pProxyRequest->GetGroupList.GroupList),
dwSize
);
break;
}
case LINEPROXYREQUEST_GETAGENTCAPS:
case LINEPROXYREQUEST_GETAGENTSTATUS:
case LINEPROXYREQUEST_GETAGENTACTIVITYLIST:
case LINEPROXYREQUEST_GETAGENTGROUPLIST:
case LINEPROXYREQUEST_GETAGENTINFO:
case LINEPROXYREQUEST_GETAGENTSESSIONLIST:
case LINEPROXYREQUEST_SETAGENTSESSIONSTATE:
case LINEPROXYREQUEST_GETAGENTSESSIONINFO:
case LINEPROXYREQUEST_GETQUEUEINFO:
{
dwSize = pProxyRequest->GetAgentCaps.AgentCaps.dwUsedSize;
if (!(pBuf = ServerAlloc(
sizeof (ASYNCEVENTMSG) + ((dwSize + 7) & 0xfffffff8)
)))
{
pParams->dwResult = LINEERR_NOMEM;
goto LProxyResponse_completeRequest;
}
CopyMemory(
pBuf + sizeof (ASYNCEVENTMSG),
&pProxyRequest->GetAgentCaps.AgentCaps,
dwSize
);
break;
}
default:
LOG((TL_ERROR,
"LProxyResponse: unrecognized proxy request type (x%x)",
pProxyRequest->dwRequestType
));
pParams->dwResult = LINEERR_OPERATIONFAILED;
goto LProxyResponse_completeRequest;
}
//
// Check to see if the size of the data we're copying back is
// larger than the size of client's buffer
//
if (dwSize > pAsyncRequestInfo->dwParam2)
{
LOG((TL_ERROR,
"LProxyResponse: data size too large (exp<=x%x,act=x%x)",
pAsyncRequestInfo->dwParam2,
dwSize
));
ServerFree (pBuf);
pParams->dwResult = LINEERR_OPERATIONFAILED;
goto LProxyResponse_completeRequest;
}
pAsyncRequestInfo->pfnPostProcess = LDevSpecific_PostProcess;
pAsyncRequestInfo->dwParam2 = dwSize;
pAsyncRequestInfo->dwParam3 = (ULONG_PTR) pBuf;
}
//
// Now call the deferred completion proc with the "request id"
// & result, just like a provider would
//
LProxyResponse_completeRequest:
CompletionProcSP(
pAsyncRequestInfo->dwLocalRequestID,
pParams->dwResult
);
DereferenceObject (ghHandleTable, pParams->dwInstance, 1);
}
LProxyResponse_Epilog:
LINEEPILOGSYNC(
&pParams->lResult,
hMutex,
bCloseMutex,
objectToDereference,
"ProxyResponse"
);
}
void
WINAPI
LRedirect(
PTCLIENT ptClient,
PLINEREDIRECT_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
LONG lRequestID;
HANDLE hMutex;
HDRVCALL hdCall;
TSPIPROC pfnTSPI_lineRedirect;
DWORD objectToDereference;
PTCALLCLIENT ptCallClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
//
// Verify size/offset/string params given our input buffer/size
//
if (IsBadStringParam(
dwParamsBufferSize,
pDataBuf,
pParams->dwDestAddressOffset
))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HCALL, // widget type
(DWORD) pParams->hCall, // client widget handle
(LPVOID) &hdCall, // provider widget handle
LINECALLPRIVILEGE_OWNER, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINEREDIRECT, // provider func index
&pfnTSPI_lineRedirect, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptCallClient, // context
"Redirect" // func name
)) > 0)
{
pParams->lResult = CallSP4(
pfnTSPI_lineRedirect,
"lineRedirect",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdCall,
(ULONG_PTR) (pDataBuf + pParams->dwDestAddressOffset),
(DWORD) pParams->dwCountryCode
);
}
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"Redirect"
);
}
void
WINAPI
LRegisterRequestRecipient(
PTCLIENT ptClient,
PLINEREGISTERREQUESTRECIPIENT_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
PTLINEAPP ptLineApp;
if ((ptLineApp = WaitForExclusiveLineAppAccess(
pParams->hLineApp,
ptClient
)))
{
DWORD dwRequestMode = pParams->dwRequestMode;
if (!(dwRequestMode &
(LINEREQUESTMODE_MAKECALL | LINEREQUESTMODE_MEDIACALL)) ||
(dwRequestMode &
(~(LINEREQUESTMODE_MAKECALL | LINEREQUESTMODE_MEDIACALL))))
{
pParams->lResult = LINEERR_INVALREQUESTMODE;
goto LRegisterRequestRecipient_myReleaseMutex;
}
if (pParams->bEnable)
{
//
// If app wants MEDIACALL requests see if already registered
//
if ((dwRequestMode & LINEREQUESTMODE_MEDIACALL) &&
ptLineApp->bReqMediaCallRecipient)
{
LOG((TL_ERROR, "App is already registered for mediacall"));
pParams->lResult = LINEERR_OPERATIONFAILED;
goto LRegisterRequestRecipient_myReleaseMutex;
}
//
// If app wants MAKECALL requests see if already registered,
// then prepare a request recipient object & add it to the
// global list
//
if (dwRequestMode & LINEREQUESTMODE_MAKECALL)
{
if (!ptLineApp->pRequestRecipient)
{
//
// Add to request recipient list
//
PTREQUESTRECIPIENT pRequestRecipient;
if (!(pRequestRecipient= (PTREQUESTRECIPIENT) ServerAlloc(
sizeof (TREQUESTRECIPIENT)
)))
{
LOG((TL_ERROR, "Failed alloc for requestrecip struct"));
pParams->lResult = LINEERR_NOMEM;
goto LRegisterRequestRecipient_myReleaseMutex;
}
pRequestRecipient->ptLineApp = ptLineApp;
pRequestRecipient->dwRegistrationInstance =
pParams->dwRegistrationInstance;
EnterCriticalSection (&gPriorityListCritSec);
if ((pRequestRecipient->pNext =
TapiGlobals.pRequestRecipients))
{
pRequestRecipient->pNext->pPrev = pRequestRecipient;
}
TapiGlobals.pRequestRecipients = pRequestRecipient;
LeaveCriticalSection (&gPriorityListCritSec);
ptLineApp->pRequestRecipient = pRequestRecipient;
TapiGlobals.pHighestPriorityRequestRecipient =
GetHighestPriorityRequestRecipient();
if (TapiGlobals.pRequestMakeCallList)
{
NotifyHighestPriorityRequestRecipient();
}
}
else // already registered
{
LOG((TL_ERROR, "App is already registered for makecall"));
pParams->lResult = LINEERR_OPERATIONFAILED;
goto LRegisterRequestRecipient_myReleaseMutex;
}
}
//
// Now register app for MEDIACALL reqs as appropriate
//
ptLineApp->bReqMediaCallRecipient =
(dwRequestMode & LINEREQUESTMODE_MEDIACALL ?
1 : ptLineApp->bReqMediaCallRecipient);
}
else
{
//
// If apps doesn't want MEDIACALL requests see if not registered
//
if ((dwRequestMode & LINEREQUESTMODE_MEDIACALL) &&
!ptLineApp->bReqMediaCallRecipient)
{
LOG((TL_ERROR, "App is not registered for mediacall"));
pParams->lResult = LINEERR_OPERATIONFAILED;
goto LRegisterRequestRecipient_myReleaseMutex;
}
//
// If app doesn't want MAKECALL requests see if already
// registered, then remove it's request recipient object
// from the global list
//
if (dwRequestMode & LINEREQUESTMODE_MAKECALL)
{
if (ptLineApp->pRequestRecipient)
{
//
// Remove from request recipient list
//
PTREQUESTRECIPIENT pRequestRecipient =
ptLineApp->pRequestRecipient;
EnterCriticalSection (&gPriorityListCritSec);
if (pRequestRecipient->pNext)
{
pRequestRecipient->pNext->pPrev =
pRequestRecipient->pPrev;
}
if (pRequestRecipient->pPrev)
{
pRequestRecipient->pPrev->pNext =
pRequestRecipient->pNext;
}
else
{
TapiGlobals.pRequestRecipients =
pRequestRecipient->pNext;
}
LeaveCriticalSection (&gPriorityListCritSec);
ServerFree (pRequestRecipient);
ptLineApp->pRequestRecipient = NULL;
//
// Reset the highest priority request recipient, then check
// to see if there's any pending request make calls
//
TapiGlobals.pHighestPriorityRequestRecipient =
GetHighestPriorityRequestRecipient();
if (TapiGlobals.pRequestMakeCallList)
{
if (TapiGlobals.pHighestPriorityRequestRecipient)
{
NotifyHighestPriorityRequestRecipient();
}
else
{
//
// We couldn't start a request recipient so
// nuke all pending request make calls
//
PTREQUESTMAKECALL pRequestMakeCall,
pNextRequestMakeCall;
pRequestMakeCall =
TapiGlobals.pRequestMakeCallList;
TapiGlobals.pRequestMakeCallList =
TapiGlobals.pRequestMakeCallListEnd = NULL;
while (pRequestMakeCall)
{
pNextRequestMakeCall = pRequestMakeCall->pNext;
ServerFree (pRequestMakeCall);
pRequestMakeCall = pNextRequestMakeCall;
}
LOG((TL_INFO,
"LRegisterRequestRecipient: deleting " \
"pending MakeCall requests"
));
}
}
}
else // not registered
{
LOG((TL_ERROR, "App is not registered for makecall"));
pParams->lResult = LINEERR_OPERATIONFAILED;
}
}
//
// Now deregister app for MEDIACALL reqs as appropriate
//
ptLineApp->bReqMediaCallRecipient =
(dwRequestMode & LINEREQUESTMODE_MEDIACALL ?
0 : ptLineApp->bReqMediaCallRecipient);
}
LRegisterRequestRecipient_myReleaseMutex:
UNLOCKTLINEAPP(ptLineApp);
}
else
{
pParams->lResult = (TapiGlobals.dwNumLineInits == 0 ?
LINEERR_UNINITIALIZED : LINEERR_INVALAPPHANDLE);
}
#if DBG
{
char szResult[32];
LOG((TL_TRACE,
"lineRegisterRequestRecipient: exit, returning %s",
MapResultCodeToText (pParams->lResult, szResult)
));
}
#else
LOG((TL_TRACE,
"lineRegisterRequestRecipient: exit, returning x%x",
pParams->lResult
));
#endif
return;
}
void
WINAPI
LReleaseUserUserInfo(
PTCLIENT ptClient,
PLINEDIAL_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
LONG lRequestID;
HANDLE hMutex;
HDRVCALL hdCall;
TSPIPROC pfnTSPI_lineReleaseUserUserInfo;
DWORD objectToDereference;
PTCALLCLIENT ptCallClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HCALL, // widget type
(DWORD) pParams->hCall, // client widget handle
(LPVOID) &hdCall, // provider widget handle
LINECALLPRIVILEGE_OWNER, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINERELEASEUSERUSERINFO, // provider func index
&pfnTSPI_lineReleaseUserUserInfo, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptCallClient, // context
"ReleaseUserUserInfo" // func name
)) > 0)
{
pParams->lResult = CallSP2(
pfnTSPI_lineReleaseUserUserInfo,
"lineReleaseUserUserInfo",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdCall
);
}
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"ReleaseUserUserInfo"
);
}
void
LRemoveFromConference_PostProcess(
PASYNCREQUESTINFO pAsyncRequestInfo,
PASYNCEVENTMSG pAsyncEventMsg,
LPVOID *ppBuf
)
{
if (pAsyncEventMsg->Param2 == 0)
{
PTCALL ptCall = (PTCALL) pAsyncRequestInfo->dwParam1;
SetCallConfList (ptCall, (PTCONFERENCELIST) NULL, FALSE);
}
}
void
WINAPI
LRemoveFromConference(
PTCLIENT ptClient,
PLINEREMOVEFROMCONFERENCE_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
LONG lRequestID;
HANDLE hMutex;
HDRVCALL hdCall;
TSPIPROC pfnTSPI_lineRemoveFromConference;
DWORD objectToDereference;
PTCALLCLIENT ptCallClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HCALL, // widget type
(DWORD) pParams->hCall, // client widget handle
(LPVOID) &hdCall, // provider widget handle
LINECALLPRIVILEGE_OWNER, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINEREMOVEFROMCONFERENCE,// provider func index
&pfnTSPI_lineRemoveFromConference, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptCallClient, // context
"RemoveFromConference" // func name
)) > 0)
{
PTCALL ptCall;
//
// Safely make sure the call is currently conferenced &
// that it's not a conf parent
//
try
{
PTCONFERENCELIST pConfList;
ptCall = ptCallClient->ptCall;
pConfList = ptCall->pConfList;
if (!pConfList ||
(pConfList == (LPVOID) LongToPtr(0xffffffff)) ||
(pConfList->aptCalls[0] == ptCall))
{
lRequestID = LINEERR_INVALCALLSTATE;
goto LRemoveFromConference_return;
}
}
myexcept
{
lRequestID = LINEERR_INVALCALLHANDLE;
goto LRemoveFromConference_return;
}
//
// Set up the async request struct & call the SP
//
pAsyncRequestInfo->pfnPostProcess = LRemoveFromConference_PostProcess;
pAsyncRequestInfo->dwParam1 = (ULONG_PTR) ptCall;
pParams->lResult = CallSP2(
pfnTSPI_lineRemoveFromConference,
"lineRemoveFromConference",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdCall
);
}
LRemoveFromConference_return:
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"RemoveFromConference"
);
}
void
WINAPI
LSecureCall(
PTCLIENT ptClient,
PLINESECURECALL_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
LONG lRequestID;
HANDLE hMutex;
HDRVCALL hdCall;
DWORD objectToDereference;
TSPIPROC pfnTSPI_lineSecureCall;
PTCALLCLIENT ptCallClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HCALL, // widget type
(DWORD) pParams->hCall, // client widget handle
(LPVOID) &hdCall, // provider widget handle
LINECALLPRIVILEGE_OWNER, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINESECURECALL, // provider func index
&pfnTSPI_lineSecureCall, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptCallClient, // context
"SecureCall" // func name
)) > 0)
{
pParams->lResult = CallSP2(
pfnTSPI_lineSecureCall,
"lineSecureCall",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdCall
);
}
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"SecureCall"
);
}
void
WINAPI
LSelectExtVersion(
PTCLIENT ptClient,
PLINESELECTEXTVERSION_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex, bCloseMutex2;
HANDLE hMutex, hMutex2;
HDRVLINE hdLine;
TSPIPROC pfnTSPI_lineSelectExtVersion;
DWORD objectToDereference;
PTLINECLIENT ptLineClient;
if ((pParams->lResult = LINEPROLOG(
ptClient, // tClient
ANY_RT_HLINE, // widget type
pParams->hLine, // client widget handle
(LPVOID) &hdLine, // provider widget handle
0, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINESELECTEXTVERSION, // provider func index
&pfnTSPI_lineSelectExtVersion, // provider func pointer
NULL, // async request info
0, // client async request ID
&objectToDereference, // object to dereference
&ptLineClient, // context
"SelectExtVersion" // func name
)) == 0)
{
if (WaitForExclusivetLineAccess(
ptLineClient->ptLine,
&hMutex2,
&bCloseMutex2,
INFINITE
))
{
if (IsValidLineExtVersion(
ptLineClient->ptLine->dwDeviceID,
pParams->dwExtVersion
))
{
if (pParams->dwExtVersion)
{
if (ptLineClient->ptLine->dwExtVersionCount ||
(pParams->lResult = CallSP2(
pfnTSPI_lineSelectExtVersion,
"lineSelectExtVersion",
SP_FUNC_SYNC,
(ULONG_PTR) hdLine,
(DWORD) pParams->dwExtVersion
)) == 0)
{
ptLineClient->dwExtVersion =
ptLineClient->ptLine->dwExtVersion =
pParams->dwExtVersion;
ptLineClient->ptLine->dwExtVersionCount++;
}
}
else if (ptLineClient->ptLine->dwExtVersionCount)
{
if (--ptLineClient->ptLine->dwExtVersionCount == 0)
{
CallSP2(
pfnTSPI_lineSelectExtVersion,
"lineSelectExtVersion",
SP_FUNC_SYNC,
(ULONG_PTR) hdLine,
(DWORD) 0
);
ptLineClient->ptLine->dwExtVersion = 0;
}
ptLineClient->dwExtVersion = 0;
}
}
else
{
pParams->lResult = LINEERR_INCOMPATIBLEEXTVERSION;
}
MyReleaseMutex (hMutex2, bCloseMutex2);
}
else
{
pParams->lResult = LINEERR_INVALLINEHANDLE;
}
}
LINEEPILOGSYNC(
&pParams->lResult,
hMutex,
bCloseMutex,
objectToDereference,
"SetDefaultMediaDetection"
);
}
void
WINAPI
LSendUserUserInfo(
PTCLIENT ptClient,
PLINESENDUSERUSERINFO_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
LONG lRequestID;
HANDLE hMutex;
HDRVCALL hdCall;
TSPIPROC pfnTSPI_lineSendUserUserInfo;
DWORD objectToDereference;
PTCALLCLIENT ptCallClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
//
// Verify size/offset/string params given our input buffer/size
//
if ((pParams->dwUserUserInfoOffset != TAPI_NO_DATA) &&
ISBADSIZEOFFSET(
dwParamsBufferSize,
0,
pParams->dwSize,
pParams->dwUserUserInfoOffset,
sizeof(DWORD),
"LSendUserUserInfo",
"pParams->UserUserInfo"
))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HCALL, // widget type
(DWORD) pParams->hCall, // client widget handle
(LPVOID) &hdCall, // provider widget handle
LINECALLPRIVILEGE_OWNER, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINESENDUSERUSERINFO, // provider func index
&pfnTSPI_lineSendUserUserInfo, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptCallClient, // context
"SendUserUserInfo" // func name
)) > 0)
{
pParams->lResult = CallSP4(
pfnTSPI_lineSendUserUserInfo,
"lineSendUserUserInfo",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdCall,
(ULONG_PTR) (pParams->dwUserUserInfoOffset == TAPI_NO_DATA ? NULL :
pDataBuf + pParams->dwUserUserInfoOffset),
(DWORD) (pParams->dwUserUserInfoOffset == TAPI_NO_DATA ? 0 :
pParams->dwSize)
);
}
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"SendUserUserInfo"
);
}
void
WINAPI
LSetAppPriority(
PTCLIENT ptClient,
PLINESETAPPPRIORITY_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
DWORD dwMediaMode = pParams->dwMediaMode,
dwRequestMode = pParams->dwRequestMode,
dwPriority = pParams->dwPriority;
//
// Verify size/offset/string params given our input buffer/size
//
if (IsBadStringParam(
dwParamsBufferSize,
pDataBuf,
pParams->dwAppNameOffset
))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if (dwMediaMode == 0)
{
if ((dwRequestMode != LINEREQUESTMODE_MAKECALL) &&
(dwRequestMode != LINEREQUESTMODE_MEDIACALL))
{
pParams->lResult = LINEERR_INVALREQUESTMODE;
goto LSetAppPriority_return;
}
}
else if ( dwMediaMode & ~AllMediaModes2_1 )
{
pParams->lResult = LINEERR_INVALMEDIAMODE;
goto LSetAppPriority_return;
}
if ((dwPriority & 0xfffffffe))
{
pParams->lResult = LINEERR_INVALPARAM;
goto LSetAppPriority_return;
}
if ((dwMediaMode & 0x00ffffff) || (dwMediaMode == 0))
{
WCHAR szModuleName[MAX_PATH];
WCHAR *pszCurrentPriorityList, **ppszCurrentPriorityList;
WCHAR *pszLocationInPriorityList;
DWORD dwAppNameLength;
DWORD dwCount;
szModuleName[0] = '"';
wcsncpy(szModuleName + 1,
(PWSTR)(pDataBuf + pParams->dwAppNameOffset),
MAX_PATH - 2);
szModuleName[MAX_PATH - 1] = '\0';
_wcsupr(szModuleName + 1);
dwAppNameLength = (DWORD) lstrlenW(szModuleName);
//
// Enter the pri list critical section before we start munging
//
EnterCriticalSection (&gPriorityListCritSec);
//
// Determine which of the priority lists we want to look at
//
if (dwMediaMode & 0x00ffffff)
{
pszCurrentPriorityList = NULL;
ppszCurrentPriorityList = NULL;
for(
dwCount = 0;
dwCount < TapiGlobals.dwUsedPriorityLists;
dwCount++
)
{
// did we find it?
if (dwMediaMode == TapiGlobals.pPriLists[dwCount].dwMediaModes)
{
ppszCurrentPriorityList =
&(TapiGlobals.pPriLists[dwCount].pszPriList);
pszCurrentPriorityList = *ppszCurrentPriorityList;
break;
}
}
// did we find it?
if (NULL == ppszCurrentPriorityList)
{
// are we setting
if (pParams->dwPriority != 0)
{
// do we need to alloc more space?
if (TapiGlobals.dwUsedPriorityLists ==
TapiGlobals.dwTotalPriorityLists)
{
PRILISTSTRUCT * pNewList;
pNewList = (PRILISTSTRUCT *)ServerAlloc(
sizeof (PRILISTSTRUCT) *
TapiGlobals.dwTotalPriorityLists * 2
);
if (NULL == pNewList)
{
LOG((TL_ERROR, "Alloc failed in LineSetAppPriority"));
pParams->lResult = LINEERR_NOMEM;
goto LSetAppPriority_return;
}
CopyMemory(
pNewList,
TapiGlobals.pPriLists,
sizeof( PRILISTSTRUCT ) *
TapiGlobals.dwUsedPriorityLists
);
ServerFree(TapiGlobals.pPriLists);
TapiGlobals.pPriLists = pNewList;
TapiGlobals.dwTotalPriorityLists *= 2;
}
TapiGlobals.pPriLists[TapiGlobals.dwUsedPriorityLists].
dwMediaModes = dwMediaMode;
ppszCurrentPriorityList = &(TapiGlobals.pPriLists
[TapiGlobals.dwUsedPriorityLists].pszPriList);
pszCurrentPriorityList = *ppszCurrentPriorityList;
TapiGlobals.dwUsedPriorityLists++;
}
}
}
else
{
ppszCurrentPriorityList = (dwRequestMode==LINEREQUESTMODE_MAKECALL
? &TapiGlobals.pszReqMakeCallPriList :
&TapiGlobals.pszReqMediaCallPriList);
pszCurrentPriorityList = *ppszCurrentPriorityList;
}
LOG((TL_INFO,
"LSetAppPri: priList=%ls",
(pszCurrentPriorityList ? pszCurrentPriorityList : L"<empty>")
));
//
// Add app to priority list
//
if (pParams->dwPriority)
{
if (pszCurrentPriorityList &&
(pszLocationInPriorityList = wcsstr(
pszCurrentPriorityList,
szModuleName
)))
{
//
// App already in list. If app not currently at front of
// list then move it to front.
//
if (pszLocationInPriorityList != pszCurrentPriorityList)
{
MoveMemory(
pszCurrentPriorityList + dwAppNameLength,
pszCurrentPriorityList,
(pszLocationInPriorityList - pszCurrentPriorityList) *
sizeof(WCHAR)
);
wcscpy(pszCurrentPriorityList, szModuleName);
pszCurrentPriorityList[dwAppNameLength] = '"';
}
}
else
{
//
// App not in list, so create a new list
//
WCHAR *pszNewPriorityList;
if (!(pszNewPriorityList = ServerAlloc(
sizeof(WCHAR) *
(dwAppNameLength + (pszCurrentPriorityList ?
lstrlenW(pszCurrentPriorityList) : 0) +
1) // for terminating NULL
)))
{
pParams->lResult = LINEERR_NOMEM;
}
else
{
wcscpy(pszNewPriorityList, szModuleName);
if (pszCurrentPriorityList)
{
wcscat(pszNewPriorityList, pszCurrentPriorityList);
ServerFree (pszCurrentPriorityList);
}
*ppszCurrentPriorityList = pszNewPriorityList;
}
}
}
//
// Remove app from priority list for specified media mode
//
// Note: We currently do not alloc a smaller buffer to store
// the new list in, we just use the existing one.
//
else
{
if (pszCurrentPriorityList &&
(pszLocationInPriorityList = wcsstr(
pszCurrentPriorityList,
szModuleName
)))
{
if (*(pszLocationInPriorityList + dwAppNameLength) != 0)
{
//
// This is not the last app in the list, so move
// following apps up one notch in the list
//
wcscpy(
pszLocationInPriorityList,
pszLocationInPriorityList + dwAppNameLength
);
}
else if (pszLocationInPriorityList == pszCurrentPriorityList)
{
//
// This is the only app in the list, so free the buffer
// & set the global pointer to NULL
//
ServerFree (pszCurrentPriorityList);
*ppszCurrentPriorityList = NULL;
}
else
{
//
// This is the last app in the list, so just mark this as
// the end of the list
//
*pszLocationInPriorityList = 0;
}
}
}
//
// We're done munging, so leave the pri list crit sec
//
LeaveCriticalSection (&gPriorityListCritSec);
}
LSetAppPriority_return:
LOG((TL_TRACE,
"LineEpilogSync (lineSetAppPriority) exit, returning x%x",
pParams->lResult
));
}
void
WINAPI
LSetAgentActivity(
PTCLIENT ptClient,
PLINESETAGENTACTIVITY_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
LONG lRequestID;
HANDLE hMutex;
HDRVLINE hdLine;
DWORD objectToDereference;
PTLINECLIENT ptLineClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HLINE, // widget type
pParams->hLine, // client widget handle
(LPVOID) &hdLine, // provider widget handle
0, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
0, // provider func index
NULL, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptLineClient, // context
"SetAgentActivity" // func name
)) > 0)
{
LONG lResult;
DWORD dwDeviceID;
PTLINECLIENT pProxy;
if ((lResult = FindProxy(
ptLineClient,
pParams->dwAddressID,
LINEPROXYREQUEST_SETAGENTACTIVITY,
&pProxy,
&dwDeviceID,
0 // API ver wasn't checked in 2.0
)))
{
lRequestID = lResult;
goto LSetAgentActivity_epilog;
}
//
// First check to see if there's a (local) proxy registered
// for this type of request on this line. If so, build a
// request & send it to the proxy.
//
if (pProxy)
{
LONG lResult;
PPROXYREQUESTWRAPPER pProxyRequestWrapper;
if ((lResult = CreateProxyRequest(
pProxy,
LINEPROXYREQUEST_SETAGENTACTIVITY,
2 * sizeof (DWORD),
pAsyncRequestInfo,
&pProxyRequestWrapper
)))
{
lRequestID = lResult;
goto LSetAgentActivity_epilog;
}
pProxyRequestWrapper->ProxyRequest.SetAgentActivity.dwAddressID =
pParams->dwAddressID;
pProxyRequestWrapper->ProxyRequest.SetAgentActivity.dwActivityID =
pParams->dwActivityID;
if ((lResult = SendProxyRequest(
pProxy,
pProxyRequestWrapper,
pAsyncRequestInfo
)))
{
lRequestID = lResult;
goto LSetAgentActivity_epilog;
}
else // success
{
pParams->lResult = (LONG) pAsyncRequestInfo->dwLocalRequestID;
}
}
//
// There's no proxy, so check to see if line is remote and
// call remotesp if so
//
else if ((GetLineLookupEntry (dwDeviceID))->bRemote)
{
pParams->lResult = CallSP4(
pRemoteSP->apfn[SP_LINESETAGENTACTIVITY],
"lineSetAgentActivity",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdLine,
(DWORD) pParams->dwAddressID,
(DWORD) pParams->dwActivityID
);
}
//
// There's no registered proxy & line is not remote, so fail
//
else
{
lRequestID = LINEERR_OPERATIONUNAVAIL;
}
}
LSetAgentActivity_epilog:
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"SetAgentActivity"
);
}
void
WINAPI
LSetAgentGroup(
PTCLIENT ptClient,
PLINESETAGENTGROUP_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
LONG lRequestID;
HANDLE hMutex;
HDRVLINE hdLine;
DWORD objectToDereference;
PTLINECLIENT ptLineClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HLINE, // widget type
pParams->hLine, // client widget handle
(LPVOID) &hdLine, // provider widget handle
0, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
0, // provider func index
NULL, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptLineClient, // context
"SetAgentGroup" // func name
)) > 0)
{
LONG lResult;
DWORD dwDeviceID;
PTLINECLIENT pProxy;
LPLINEAGENTGROUPLIST pGroupList = (LPLINEAGENTGROUPLIST)
(pDataBuf + pParams->dwAgentGroupListOffset);
//
// Verify size/offset/string params given our input buffer/size
//
if (IsBadStructParam(
dwParamsBufferSize,
pDataBuf,
pParams->dwAgentGroupListOffset
))
{
lRequestID = LINEERR_STRUCTURETOOSMALL;
goto LSetAgentGroup_epilog;
}
//
// Param verification...
//
{
DWORD dwTotalSize = pGroupList->dwTotalSize;
if (dwTotalSize < sizeof (LINEAGENTGROUPLIST))
{
lRequestID = LINEERR_STRUCTURETOOSMALL;
goto LSetAgentGroup_epilog;
}
if (ISBADSIZEOFFSET(
dwTotalSize,
sizeof (LINEAGENTGROUPLIST),
pGroupList->dwListSize,
pGroupList->dwListOffset,
guiAlignmentFaultEnabled? sizeof(DWORD) : 0,
"lineSetAgentGroup",
"List"
))
{
lRequestID = LINEERR_INVALAGENTGROUP;
goto LSetAgentGroup_epilog;
}
if (pGroupList->dwNumEntries >
((dwTotalSize - sizeof (LINEAGENTGROUPLIST)) /
sizeof (LINEAGENTGROUPENTRY)))
{
lRequestID = LINEERR_INVALAGENTGROUP;
goto LSetAgentGroup_epilog;
}
}
if ((lResult = FindProxy(
ptLineClient,
pParams->dwAddressID,
LINEPROXYREQUEST_SETAGENTGROUP,
&pProxy,
&dwDeviceID,
0 // API ver wasn't checked in 2.0
)))
{
lRequestID = lResult;
goto LSetAgentGroup_epilog;
}
//
// First check to see if there's a (local) proxy registered
// for this type of request on this line. If so, build a
// request & send it to the proxy.
//
if (pProxy)
{
LONG lResult;
PPROXYREQUESTWRAPPER pProxyRequestWrapper;
if ((lResult = CreateProxyRequest(
pProxy,
LINEPROXYREQUEST_SETAGENTGROUP,
sizeof (DWORD) + pGroupList->dwTotalSize,
pAsyncRequestInfo,
&pProxyRequestWrapper
)))
{
lRequestID = lResult;
goto LSetAgentGroup_epilog;
}
pProxyRequestWrapper->ProxyRequest.SetAgentGroup.dwAddressID =
pParams->dwAddressID;
CopyMemory(
&pProxyRequestWrapper->ProxyRequest.SetAgentGroup.GroupList,
pGroupList,
pGroupList->dwTotalSize
);
if ((lResult = SendProxyRequest(
pProxy,
pProxyRequestWrapper,
pAsyncRequestInfo
)))
{
lRequestID = lResult;
goto LSetAgentGroup_epilog;
}
else // success
{
pParams->lResult = (LONG) pAsyncRequestInfo->dwLocalRequestID;
}
}
//
// There's no proxy, so check to see if line is remote and
// call remotesp if so
//
else if ((GetLineLookupEntry (dwDeviceID))->bRemote)
{
pParams->lResult = CallSP4(
pRemoteSP->apfn[SP_LINESETAGENTGROUP],
"lineSetAgentGroup",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdLine,
(DWORD) pParams->dwAddressID,
(ULONG_PTR) pGroupList
);
}
//
// There's no registered proxy & line is not remote, so fail
//
else
{
lRequestID = LINEERR_OPERATIONUNAVAIL;
}
}
LSetAgentGroup_epilog:
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"SetAgentGroup"
);
}
void
WINAPI
LSetAgentMeasurementPeriod(
PTCLIENT ptClient,
PLINESETAGENTMEASUREMENTPERIOD_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
LONG lRequestID;
HANDLE hMutex;
HDRVLINE hdLine;
DWORD objectToDereference;
PTLINECLIENT ptLineClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HLINE, // widget type
pParams->hLine, // client widget handle
(LPVOID) &hdLine, // provider widget handle
0, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
0, // provider func index
NULL, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptLineClient, // context
"SetAgentMeasurementPeriod" // func name
)) > 0)
{
LONG lResult;
DWORD dwDeviceID;
PTLINECLIENT pProxy;
if ((lResult = FindProxy(
ptLineClient,
0,
LINEPROXYREQUEST_SETAGENTMEASUREMENTPERIOD,
&pProxy,
&dwDeviceID,
TAPI_VERSION2_2
)))
{
lRequestID = lResult;
goto LSetAgentMeasurementPeriod_epilog;
}
// Measurement period must be > 0
if (pParams->dwMeasurementPeriod == 0)
{
lRequestID = LINEERR_INVALPARAM;
goto LSetAgentMeasurementPeriod_epilog;
}
//
// First check to see if there's a (local) proxy registered
// for this type of request on this line. If so, build a
// request & send it to the proxy.
//
if (pProxy)
{
LONG lResult;
PPROXYREQUESTWRAPPER pProxyRequestWrapper;
if ((lResult = CreateProxyRequest(
pProxy,
LINEPROXYREQUEST_SETAGENTMEASUREMENTPERIOD,
sizeof (DWORD) + sizeof (HAGENT),
pAsyncRequestInfo,
&pProxyRequestWrapper
)))
{
lRequestID = lResult;
goto LSetAgentMeasurementPeriod_epilog;
}
pProxyRequestWrapper->ProxyRequest.
SetAgentMeasurementPeriod.hAgent = pParams->hAgent;
pProxyRequestWrapper->ProxyRequest.
SetAgentMeasurementPeriod.dwMeasurementPeriod =
pParams->dwMeasurementPeriod;
if ((lResult = SendProxyRequest(
pProxy,
pProxyRequestWrapper,
pAsyncRequestInfo
)))
{
lRequestID = lResult;
goto LSetAgentMeasurementPeriod_epilog;
}
else // success
{
pParams->lResult = (LONG) pAsyncRequestInfo->dwLocalRequestID;
}
}
//
// There's no proxy, so check to see if line is remote and
// call remotesp if so
//
else if ((GetLineLookupEntry (dwDeviceID))->bRemote)
{
pParams->lResult = CallSP4(
pRemoteSP->apfn[SP_LINESETAGENTMEASUREMENTPERIOD],
"lineSetAgentMeasurementPeriod",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdLine,
(DWORD) pParams->hAgent,
(DWORD) pParams->dwMeasurementPeriod
);
}
//
// There's no registered proxy & line is not remote, so fail
//
else
{
lRequestID = LINEERR_OPERATIONUNAVAIL;
}
}
LSetAgentMeasurementPeriod_epilog:
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"SetAgentMeasurementPeriod"
);
}
void
WINAPI
LSetAgentSessionState(
PTCLIENT ptClient,
PLINESETAGENTSESSIONSTATE_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
LONG lRequestID;
HANDLE hMutex;
HDRVLINE hdLine;
DWORD objectToDereference;
PTLINECLIENT ptLineClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HLINE, // widget type
pParams->hLine, // client widget handle
(LPVOID) &hdLine, // provider widget handle
0, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
0, // provider func index
NULL, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptLineClient, // context
"SetAgentSessionState" // func name
)) > 0)
{
LONG lResult;
DWORD dwDeviceID;
DWORD dwAgentState = pParams->dwAgentState;
DWORD dwNextAgentState = pParams->dwNextAgentState;
PTLINECLIENT pProxy;
//
// Param verification...
//
if (dwAgentState == 0 && dwNextAgentState == 0)
{
lRequestID = LINEERR_INVALAGENTSESSIONSTATE;
goto LSetAgentSessionState_epilog;
}
if (dwAgentState != 0 &&
(!IsOnlyOneBitSetInDWORD (dwAgentState) ||
dwAgentState & ~AllAgentSessionStates))
{
lRequestID = LINEERR_INVALAGENTSESSIONSTATE;
goto LSetAgentSessionState_epilog;
}
if (dwNextAgentState != 0 &&
(!IsOnlyOneBitSetInDWORD (dwNextAgentState) ||
dwNextAgentState & ~AllAgentSessionStates))
{
lRequestID = LINEERR_INVALAGENTSESSIONSTATE;
goto LSetAgentSessionState_epilog;
}
if ((lResult = FindProxy(
ptLineClient,
0,
LINEPROXYREQUEST_SETAGENTSESSIONSTATE,
&pProxy,
&dwDeviceID,
TAPI_VERSION2_2
)))
{
lRequestID = lResult;
goto LSetAgentSessionState_epilog;
}
//
// First check to see if there's a (local) proxy registered
// for this type of request on this line. If so, build a
// request & send it to the proxy.
//
if (pProxy)
{
LONG lResult;
PPROXYREQUESTWRAPPER pProxyRequestWrapper;
if ((lResult = CreateProxyRequest(
pProxy,
LINEPROXYREQUEST_SETAGENTSESSIONSTATE,
2 * sizeof (DWORD) + sizeof (HAGENT),
pAsyncRequestInfo,
&pProxyRequestWrapper
)))
{
lRequestID = lResult;
goto LSetAgentSessionState_epilog;
}
pProxyRequestWrapper->ProxyRequest.
SetAgentSessionState.hAgentSession = pParams->hAgentSession;
pProxyRequestWrapper->ProxyRequest.
SetAgentSessionState.dwAgentSessionState = dwAgentState;
pProxyRequestWrapper->ProxyRequest.
SetAgentSessionState.dwNextAgentSessionState = dwNextAgentState;
if ((lResult = SendProxyRequest(
pProxy,
pProxyRequestWrapper,
pAsyncRequestInfo
)))
{
lRequestID = lResult;
goto LSetAgentSessionState_epilog;
}
else // success
{
pParams->lResult = (LONG) pAsyncRequestInfo->dwLocalRequestID;
}
}
//
// There's no proxy, so check to see if line is remote and
// call remotesp if so
//
else if ((GetLineLookupEntry (dwDeviceID))->bRemote)
{
pParams->lResult = CallSP5(
pRemoteSP->apfn[SP_LINESETAGENTSESSIONSTATE],
"lineSetAgentSessionState",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdLine,
(DWORD) pParams->hAgentSession,
(DWORD) pParams->dwAgentState,
(DWORD) pParams->dwNextAgentState
);
}
//
// There's no registered proxy & line is not remote, so fail
//
else
{
lRequestID = LINEERR_OPERATIONUNAVAIL;
}
}
LSetAgentSessionState_epilog:
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"SetAgentSessionState"
);
}
void
WINAPI
LSetAgentState(
PTCLIENT ptClient,
PLINESETAGENTSTATE_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
LONG lRequestID;
HANDLE hMutex;
HDRVLINE hdLine;
DWORD objectToDereference;
PTLINECLIENT ptLineClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HLINE, // widget type
pParams->hLine, // client widget handle
(LPVOID) &hdLine, // provider widget handle
0, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
0, // provider func index
NULL, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptLineClient, // context
"SetAgentState" // func name
)) > 0)
{
LONG lResult;
DWORD dwDeviceID,
dwAddressID = pParams->dwAddressID,
dwAgentState = pParams->dwAgentState,
dwNextAgentState = pParams->dwNextAgentState;
PTLINECLIENT pProxy;
//
// Param verification...
//
if (dwAgentState == 0 && dwNextAgentState == 0)
{
lRequestID = LINEERR_INVALAGENTSTATE;
goto LSetAgentState_epilog;
}
if (dwAgentState != 0 &&
(!IsOnlyOneBitSetInDWORD (dwAgentState) ||
dwAgentState & ~AllAgentStates))
{
lRequestID = LINEERR_INVALAGENTSTATE;
goto LSetAgentState_epilog;
}
if (dwNextAgentState != 0 &&
(!IsOnlyOneBitSetInDWORD (dwNextAgentState) ||
dwNextAgentState & ~AllAgentStates))
{
lRequestID = LINEERR_INVALAGENTSTATE;
goto LSetAgentState_epilog;
}
if ((lResult = FindProxy(
ptLineClient,
dwAddressID,
LINEPROXYREQUEST_SETAGENTSTATE,
&pProxy,
&dwDeviceID,
0 // API ver wasn't checked in 2.0
)))
{
lRequestID = lResult;
goto LSetAgentState_epilog;
}
//
// First check to see if there's a (local) proxy registered
// for this type of request on this line. If so, build a
// request & send it to the proxy.
//
if (pProxy)
{
LONG lResult;
PPROXYREQUESTWRAPPER pProxyRequestWrapper;
if ((lResult = CreateProxyRequest(
pProxy,
LINEPROXYREQUEST_SETAGENTSTATE,
3 * sizeof (DWORD),
pAsyncRequestInfo,
&pProxyRequestWrapper
)))
{
lRequestID = lResult;
goto LSetAgentState_epilog;
}
pProxyRequestWrapper->ProxyRequest.SetAgentState.dwAddressID =
dwAddressID;
pProxyRequestWrapper->ProxyRequest.SetAgentState.dwAgentState =
dwAgentState;
pProxyRequestWrapper->ProxyRequest.SetAgentState.dwNextAgentState =
dwNextAgentState;
if ((lResult = SendProxyRequest(
pProxy,
pProxyRequestWrapper,
pAsyncRequestInfo
)))
{
lRequestID = lResult;
goto LSetAgentState_epilog;
}
else // success
{
pParams->lResult = (LONG) pAsyncRequestInfo->dwLocalRequestID;
}
}
//
// There's no proxy, so check to see if line is remote and
// call remotesp if so
//
else if ((GetLineLookupEntry (dwDeviceID))->bRemote)
{
pParams->lResult = CallSP5(
pRemoteSP->apfn[SP_LINESETAGENTSTATE],
"lineSetAgentState",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdLine,
(DWORD) dwAddressID,
(DWORD) dwAgentState,
(DWORD) dwNextAgentState
);
}
//
// There's no registered proxy & line is not remote, so fail
//
else
{
lRequestID = LINEERR_OPERATIONUNAVAIL;
}
}
LSetAgentState_epilog:
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"SetAgentState"
);
}
void
WINAPI
LSetAgentStateEx(
PTCLIENT ptClient,
PLINESETAGENTSTATEEX_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
LONG lRequestID;
HANDLE hMutex;
HDRVLINE hdLine;
DWORD objectToDereference;
PTLINECLIENT ptLineClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HLINE, // widget type
pParams->hLine, // client widget handle
(LPVOID) &hdLine, // provider widget handle
0, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
0, // provider func index
NULL, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptLineClient, // context
"SetAgentStateEx" // func name
)) > 0)
{
LONG lResult;
DWORD dwDeviceID;
DWORD dwAgentState = pParams->dwAgentState;
DWORD dwNextAgentState = pParams->dwNextAgentState;
PTLINECLIENT pProxy;
//
// Param verification...
//
if (dwAgentState == 0 && dwNextAgentState == 0)
{
lRequestID = LINEERR_INVALAGENTSTATE;
goto LSetAgentStateEx_epilog;
}
if (dwAgentState != 0 &&
(!IsOnlyOneBitSetInDWORD (dwAgentState) ||
dwAgentState & ~AllAgentStatesEx))
{
lRequestID = LINEERR_INVALAGENTSTATE;
goto LSetAgentStateEx_epilog;
}
if (dwNextAgentState != 0 &&
(!IsOnlyOneBitSetInDWORD (dwNextAgentState) ||
dwNextAgentState & ~AllAgentStatesEx))
{
lRequestID = LINEERR_INVALAGENTSTATE;
goto LSetAgentStateEx_epilog;
}
//
// Find Proxy
//
if ((lResult = FindProxy(
ptLineClient,
0,
LINEPROXYREQUEST_SETAGENTSTATEEX,
&pProxy,
&dwDeviceID,
TAPI_VERSION2_2
)))
{
lRequestID = lResult;
goto LSetAgentStateEx_epilog;
}
//
// First check to see if there's a (local) proxy registered
// for this type of request on this line. If so, build a
// request & send it to the proxy.
//
if (pProxy)
{
LONG lResult;
PPROXYREQUESTWRAPPER pProxyRequestWrapper;
if ((lResult = CreateProxyRequest(
pProxy,
LINEPROXYREQUEST_SETAGENTSTATEEX,
2 * sizeof (DWORD) + sizeof (HAGENT),
pAsyncRequestInfo,
&pProxyRequestWrapper
)))
{
lRequestID = lResult;
goto LSetAgentStateEx_epilog;
}
pProxyRequestWrapper->ProxyRequest.SetAgentStateEx.hAgent = pParams->hAgent;
pProxyRequestWrapper->ProxyRequest.SetAgentStateEx.dwAgentState = dwAgentState;
pProxyRequestWrapper->ProxyRequest.SetAgentStateEx.dwNextAgentState = dwNextAgentState;
if ((lResult = SendProxyRequest(
pProxy,
pProxyRequestWrapper,
pAsyncRequestInfo
)))
{
lRequestID = lResult;
goto LSetAgentStateEx_epilog;
}
else // success
{
pParams->lResult = (LONG) pAsyncRequestInfo->dwLocalRequestID;
}
}
//
// There's no proxy, so check to see if line is remote and
// call remotesp if so
//
else if ((GetLineLookupEntry (dwDeviceID))->bRemote)
{
pParams->lResult = CallSP5(
pRemoteSP->apfn[SP_LINESETAGENTSTATEEX],
"lineSetAgentStateEx",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdLine,
(DWORD) pParams->hAgent,
(DWORD) dwAgentState,
(DWORD) dwNextAgentState
);
}
//
// There's no registered proxy & line is not remote, so fail
//
else
{
lRequestID = LINEERR_OPERATIONUNAVAIL;
}
}
LSetAgentStateEx_epilog:
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"SetAgentStateEx"
);
}
void
WINAPI
LSetAppSpecific(
PTCLIENT ptClient,
PLINESETAPPSPECIFIC_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
HANDLE hMutex;
HDRVCALL hdCall;
TSPIPROC pfnTSPI_lineSetAppSpecific;
DWORD objectToDereference;
PTCALLCLIENT ptCallClient;
if ((pParams->lResult = LINEPROLOG(
ptClient, // tClient
ANY_RT_HCALL, // widget type
pParams->hCall, // client widget handle
(LPVOID) &hdCall, // provider widget handle
LINECALLPRIVILEGE_OWNER, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINESETAPPSPECIFIC, // provider func index
&pfnTSPI_lineSetAppSpecific,// provider func pointer
NULL, // async request info
0, // client async request ID
&objectToDereference, // object to dereference
&ptCallClient, // context
"SetAppSpecific" // func name
)) == 0)
{
pParams->lResult = CallSP2(
pfnTSPI_lineSetAppSpecific,
"lineSetAppSpecific",
SP_FUNC_SYNC,
(ULONG_PTR) hdCall,
(DWORD) pParams->dwAppSpecific
);
}
LINEEPILOGSYNC(
&pParams->lResult,
hMutex,
bCloseMutex,
objectToDereference,
"SetAppSpecific"
);
}
void
WINAPI
LSetCallData(
PTCLIENT ptClient,
PLINESETCALLDATA_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
LONG lRequestID;
HANDLE hMutex;
HDRVCALL hdCall;
TSPIPROC pfnTSPI_lineSetCallData;
DWORD objectToDereference;
PTCALLCLIENT ptCallClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
//
// Verify size/offset/string params given our input buffer/size
//
if (ISBADSIZEOFFSET(
dwParamsBufferSize,
0,
pParams->dwCallDataSize,
pParams->dwCallDataOffset,
sizeof(DWORD),
"LSetCallData",
"pParams->CallData"
))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HCALL, // widget type
pParams->hCall, // client widget handle
(LPVOID) &hdCall, // provider widget handle
LINECALLPRIVILEGE_OWNER, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINESETCALLDATA, // provider func index
&pfnTSPI_lineSetCallData, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptCallClient, // context
"SetCallData" // func name
)) > 0)
{
pParams->lResult = CallSP4(
pfnTSPI_lineSetCallData,
"lineSetCallData",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdCall,
(ULONG_PTR) (pParams->dwCallDataSize ?
pDataBuf + pParams->dwCallDataOffset : NULL),
(DWORD) pParams->dwCallDataSize
);
}
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"SetCallData"
);
}
void
WINAPI
LSetCallHubTracking(
PTCLIENT ptClient,
PLINESETCALLHUBTRACKING_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
HANDLE hMutex;
HDRVLINE hdLine;
TSPIPROC pfnTSPI_lineSetCallHubTracking;
DWORD objectToDereference;
PTLINECLIENT ptLineClient;
//
// Verify size/offset/string params given our input buffer/size
//
if (IsBadStructParam(
dwParamsBufferSize,
pDataBuf,
pParams->dwTrackingInfoOffset
))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if ((pParams->lResult =LINEPROLOG(
ptClient, // tClient
ANY_RT_HLINE, // widget type
pParams->hLine, // client widget handle
(LPVOID) &hdLine, // provider widget handle
0, // privileges or device ID
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINESETCALLHUBTRACKING, // provider func index
&pfnTSPI_lineSetCallHubTracking,// provider func pointer
NULL, // async request info
0, // client async request ID
&objectToDereference, // object to dereference
&ptLineClient, // context
"SetCallHubTracking" // func name
)) == 0 ||
(pParams->lResult == LINEERR_OPERATIONUNAVAIL))
{
BOOL bOwnMutex, bSetSPTracking;
DWORD dwNewSPTracking;
PTLINE ptLine;
PTLINELOOKUPENTRY pLookupEntry;
LPLINECALLHUBTRACKINGINFO pTrackingInfo;
if (pParams->lResult == LINEERR_OPERATIONUNAVAIL)
{
pParams->lResult = 0;
pfnTSPI_lineSetCallHubTracking = (TSPIPROC) NULL;
}
//
// Check validity of tracking info structure
//
pTrackingInfo = (LPLINECALLHUBTRACKINGINFO)
(pDataBuf + pParams->dwTrackingInfoOffset);
if (pTrackingInfo->dwTotalSize < sizeof (LINECALLHUBTRACKINGINFO))
{
pParams->lResult = LINEERR_STRUCTURETOOSMALL;
goto LSetCallHubTracking_epilog;
}
//
// Check for invalid options
//
switch (pTrackingInfo->dwCurrentTracking)
{
case LINECALLHUBTRACKING_NONE:
case LINECALLHUBTRACKING_ALLCALLS:
break;
case (LINECALLHUBTRACKING_ALLCALLS |LINECALLHUBTRACKING_PROVIDERLEVEL):
if (!pfnTSPI_lineSetCallHubTracking)
{
pParams->lResult = LINEERR_INVALPARAM;
goto LSetCallHubTracking_epilog;
}
break;
default:
pParams->lResult = LINEERR_INVALPARAM;
goto LSetCallHubTracking_epilog;
}
//
// Safely get exclusive access to the tLine, then check if:
//
// * new tLineClient tracking state equals current tLineClient
// tracking state, in which case we can simply return success, or
//
// * new tLineClient tracking state has no net effect on the
// driver's line tracking state due to the existing number
// of trackers, in which case we can simply adjust the current
// number of trackers and return success, or
//
// * (otherwise) we need to inform driver of new tracking state
//
bOwnMutex = FALSE;
try
{
pLookupEntry = GetLineLookupEntry(
ptLineClient->ptLine->dwDeviceID
);
if (!pLookupEntry)
{
pParams->lResult = LINEERR_INVALLINEHANDLE;
goto LSetCallHubTracking_epilog;
}
WaitForSingleObject (pLookupEntry->hMutex, INFINITE);
bOwnMutex = TRUE;
if ((ptLineClient->dwKey != TLINECLIENT_KEY) ||
!(ptLine = pLookupEntry->ptLine))
{
ReleaseMutex (pLookupEntry->hMutex);
pParams->lResult = LINEERR_INVALLINEHANDLE;
goto LSetCallHubTracking_epilog;
}
}
except (EXCEPTION_EXECUTE_HANDLER)
{
if (bOwnMutex)
{
ReleaseMutex (pLookupEntry->hMutex);
}
pParams->lResult = LINEERR_INVALLINEHANDLE;
goto LSetCallHubTracking_epilog;
}
if (pTrackingInfo->dwCurrentTracking ==
ptLineClient->dwCurrentTracking)
{
goto LSetCallHubTracking_releaseMutex;
}
bSetSPTracking = FALSE;
switch (pTrackingInfo->dwCurrentTracking)
{
case LINECALLHUBTRACKING_NONE:
case LINECALLHUBTRACKING_ALLCALLS:
if (ptLineClient->dwCurrentTracking &
LINECALLHUBTRACKING_PROVIDERLEVEL)
{
if (ptLine->dwNumCallHubTrackersSPLevel == 1)
{
//
// We're the only one with SP-level tracking
// currently enabled, so call SP to turn OFF
// tracking
//
bSetSPTracking = TRUE;
dwNewSPTracking = LINECALLHUBTRACKING_NONE;
}
}
break;
default : // CALLHUBTRACKING_ALLCALLS | CALLHUBTRACKING_PROVIDERLEVEL
if (ptLine->dwNumCallHubTrackersSPLevel > 0)
{
//
// We're the only one with SP-level tracking
// currently enabled, so call SP to turn ON
// tracking
//
bSetSPTracking = TRUE;
dwNewSPTracking = LINECALLHUBTRACKING_ALLCALLS |
LINECALLHUBTRACKING_PROVIDERLEVEL;
}
break;
}
if (bSetSPTracking && pfnTSPI_lineSetCallHubTracking)
{
LINECALLHUBTRACKINGINFO info;
info.dwTotalSize =
info.dwNeededSize =
info.dwUsedSize = sizeof (info);
info.dwAvailableTracking = 0;
info.dwCurrentTracking = dwNewSPTracking;
pParams->lResult = CallSP2(
pfnTSPI_lineSetCallHubTracking,
"lineSetCallHubTracking",
SP_FUNC_SYNC,
(ULONG_PTR) hdLine,
(ULONG_PTR) &info
);
}
if (pParams->lResult == 0)
{
switch (pTrackingInfo->dwCurrentTracking)
{
case LINECALLHUBTRACKING_NONE:
ptLine->dwNumCallHubTrackers--;
if (ptLineClient->dwCurrentTracking &
LINECALLHUBTRACKING_PROVIDERLEVEL)
{
ptLine->dwNumCallHubTrackersSPLevel--;
}
break;
case LINECALLHUBTRACKING_ALLCALLS:
if (ptLineClient->dwCurrentTracking ==
LINECALLHUBTRACKING_NONE)
{
ptLine->dwNumCallHubTrackers++;
}
else
{
ptLine->dwNumCallHubTrackersSPLevel--;
}
break;
default: // CALLHUBTRACKING_ALLCALLS |CALLHUBTRACKING_PROVIDERLEVEL
if (ptLineClient->dwCurrentTracking ==
LINECALLHUBTRACKING_NONE)
{
ptLine->dwNumCallHubTrackers++;
}
ptLine->dwNumCallHubTrackersSPLevel++;
break;
}
ptLineClient->dwCurrentTracking = pTrackingInfo->dwCurrentTracking;
}
LSetCallHubTracking_releaseMutex:
ReleaseMutex (ptLine->hMutex);
}
LSetCallHubTracking_epilog:
LINEEPILOGSYNC(
&pParams->lResult,
hMutex,
bCloseMutex,
objectToDereference,
"SetCallHubTracking"
);
}
void
WINAPI
LSetCallParams(
PTCLIENT ptClient,
PLINESETCALLPARAMS_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
LONG lRequestID;
HANDLE hMutex;
HDRVCALL hdCall;
TSPIPROC pfnTSPI_lineSetCallParams;
DWORD objectToDereference;
PTCALLCLIENT ptCallClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
//
// Verify size/offset/string params given our input buffer/size
//
if ((pParams->dwDialParamsOffset != TAPI_NO_DATA) &&
ISBADSIZEOFFSET(
dwParamsBufferSize,
0,
sizeof (LINEDIALPARAMS),
pParams->dwDialParamsOffset,
sizeof(DWORD),
"LSetCallParams",
"pParams->DialParams"
))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HCALL, // widget type
pParams->hCall, // client widget handle
(LPVOID) &hdCall, // provider widget handle
LINECALLPRIVILEGE_OWNER, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINESETCALLPARAMS, // provider func index
&pfnTSPI_lineSetCallParams, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptCallClient, // context
"SetCallParams" // func name
)) > 0)
{
DWORD dwAPIVersion, dwAllBearerModes,
dwBearerMode = pParams->dwBearerMode;
//
// Safely get the API ver associated with this call & make sure
// no invalid bearer modes are specified (high 16 bearer mode
// bits are extensions)
//
try
{
dwAPIVersion = ptCallClient->ptLineClient->dwAPIVersion;
}
myexcept
{
lRequestID = LINEERR_INVALCALLHANDLE;
goto LSetCallParams_epilog;
}
switch (dwAPIVersion)
{
case TAPI_VERSION1_0:
dwAllBearerModes = AllBearerModes1_0;
break;
case TAPI_VERSION1_4:
dwAllBearerModes = AllBearerModes1_4;
break;
case TAPI_VERSION2_0:
case TAPI_VERSION2_1:
case TAPI_VERSION2_2:
case TAPI_VERSION3_0:
case TAPI_VERSION_CURRENT:
dwAllBearerModes = AllBearerModes2_0;
break;
default:
lRequestID = LINEERR_INVALBEARERMODE;
goto LSetCallParams_epilog;
}
if (!IsOnlyOneBitSetInDWORD(dwBearerMode) ||
(dwBearerMode & ~(dwAllBearerModes | 0xffff0000)))
{
lRequestID = LINEERR_INVALBEARERMODE;
goto LSetCallParams_epilog;
}
pParams->lResult = CallSP6(
pfnTSPI_lineSetCallParams,
"lineSetCallParams",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdCall,
(DWORD) pParams->dwBearerMode,
(DWORD) pParams->dwMinRate,
(DWORD) pParams->dwMaxRate,
(ULONG_PTR) (pParams->dwDialParamsOffset == TAPI_NO_DATA ? NULL :
pDataBuf + pParams->dwDialParamsOffset)
);
}
LSetCallParams_epilog:
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"SetCallParams"
);
}
void
WINAPI
LSetCallPrivilege(
PTCLIENT ptClient,
PLINESETCALLPRIVILEGE_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
PTCALL ptCall;
PTCALLCLIENT ptCallClient;
if (!(ptCallClient = ReferenceObject(
ghHandleTable,
pParams->hCall,
TCALLCLIENT_KEY
)))
{
pParams->lResult = (TapiGlobals.dwNumLineInits ?
LINEERR_INVALCALLHANDLE : LINEERR_UNINITIALIZED);
goto LSetCallPrivilege_epilog;
}
//
// Don't both with LineProlog, since we need a try/except
// to get the ptCall anyway
//
try
{
ptCall = ptCallClient->ptCall;
if (ptCallClient->dwKey != TCALLCLIENT_KEY ||
ptCallClient->ptClient != ptClient)
{
pParams->lResult = (TapiGlobals.dwNumLineInits ?
LINEERR_INVALCALLHANDLE : LINEERR_UNINITIALIZED);
goto LSetCallPrivilege_Dereference;
}
}
myexcept
{
pParams->lResult = (TapiGlobals.dwNumLineInits ?
LINEERR_INVALCALLHANDLE : LINEERR_UNINITIALIZED);
goto LSetCallPrivilege_Dereference;
}
if ((pParams->dwPrivilege != LINECALLPRIVILEGE_MONITOR) &&
(pParams->dwPrivilege != LINECALLPRIVILEGE_OWNER))
{
pParams->lResult = LINEERR_INVALCALLPRIVILEGE;
goto LSetCallPrivilege_Dereference;
}
if (WaitForExclusivetCallAccess (ptCall, TCALL_KEY))
{
//
// Make sure the tCallClient is still valid
//
try
{
if (ptCallClient->dwKey != TCALLCLIENT_KEY)
{
pParams->lResult = LINEERR_INVALCALLHANDLE;
goto LSetCallPrivilege_UnlocktCall;
}
}
myexcept
{
pParams->lResult = LINEERR_INVALCALLHANDLE;
goto LSetCallPrivilege_UnlocktCall;
}
if (pParams->dwPrivilege != ptCallClient->dwPrivilege)
{
// if (ptCallClient->dwPrivilege == LINECALLPRIVILEGE_OWNER &&
// ptCall->dwNumOwners == 1 &&
// ptCall->dwCallState != LINECALLSTATE_IDLE)
// {
// pParams->lResult = LINEERR_INVALCALLSTATE;
// goto LSetCallPrivilege_releaseMutex;
// }
if (pParams->dwPrivilege == LINECALLPRIVILEGE_OWNER)
{
ptCall->dwNumOwners++;
ptCall->dwNumMonitors--;
}
else
{
ptCall->dwNumOwners--;
ptCall->dwNumMonitors++;
}
ptCallClient->dwPrivilege = pParams->dwPrivilege;
UNLOCKTCALL(ptCall);
SendMsgToCallClients(
ptCall,
ptCallClient,
LINE_CALLINFO,
LINECALLINFOSTATE_NUMMONITORS |
(pParams->dwPrivilege == LINECALLPRIVILEGE_OWNER ?
LINECALLINFOSTATE_NUMOWNERINCR :
LINECALLINFOSTATE_NUMOWNERDECR),
0,
0
);
}
else
{
LSetCallPrivilege_UnlocktCall:
UNLOCKTCALL(ptCall);
}
}
else
{
pParams->lResult = LINEERR_INVALCALLHANDLE;
}
LSetCallPrivilege_Dereference:
DereferenceObject (ghHandleTable, pParams->hCall, 1);
LSetCallPrivilege_epilog:
#if DBG
{
char szResult[32];
LOG((TL_TRACE,
"LineEpilogSync: (lineSetCallPrivilege) exit, result=%s",
MapResultCodeToText (pParams->lResult, szResult)
));
}
#else
LOG((TL_TRACE,
"LineEpilogSync: (lineSetCallPrivilege) exit, result=x%x",
pParams->lResult
));
#endif
return;
}
void
WINAPI
LSetCallQualityOfService(
PTCLIENT ptClient,
PLINESETCALLQUALITYOFSERVICE_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
LONG lRequestID;
HANDLE hMutex;
HDRVCALL hdCall;
TSPIPROC pfnTSPI_lineSetCallQualityOfService;
DWORD objectToDereference;
PTCALLCLIENT ptCallClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
//
// Verify size/offset/string params given our input buffer/size
//
if (ISBADSIZEOFFSET(
dwParamsBufferSize,
0,
pParams->dwSendingFlowspecSize,
pParams->dwSendingFlowspecOffset,
sizeof(DWORD),
"LSetCallQualityOfService",
"pParams->SendingFlowspec"
) ||
ISBADSIZEOFFSET(
dwParamsBufferSize,
0,
pParams->dwReceivingFlowspecSize,
pParams->dwReceivingFlowspecOffset,
sizeof(DWORD),
"LSetCallQualityOfService",
"pParams->ReceivingFlowspec"
))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HCALL, // widget type
pParams->hCall, // client widget handle
(LPVOID) &hdCall, // provider widget handle
LINECALLPRIVILEGE_OWNER, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINESETCALLQUALITYOFSERVICE, // provider func index
&pfnTSPI_lineSetCallQualityOfService, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptCallClient, // context
"SetCallQualityOfService" // func name
)) > 0)
{
pParams->lResult = CallSP6(
pfnTSPI_lineSetCallQualityOfService,
"lineSetCallQualityOfService",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdCall,
(ULONG_PTR) (pDataBuf + pParams->dwSendingFlowspecOffset),
(DWORD) pParams->dwSendingFlowspecSize,
(ULONG_PTR) (pDataBuf + pParams->dwReceivingFlowspecOffset),
(DWORD) pParams->dwReceivingFlowspecSize
);
}
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"SetCallQualityOfService"
);
}
void
WINAPI
LSetCallTreatment(
PTCLIENT ptClient,
PLINESETCALLTREATMENT_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
LONG lRequestID;
HANDLE hMutex;
HDRVCALL hdCall;
TSPIPROC pfnTSPI_lineSetCallTreatment;
DWORD objectToDereference;
PTCALLCLIENT ptCallClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HCALL, // widget type
pParams->hCall, // client widget handle
(LPVOID) &hdCall, // provider widget handle
LINECALLPRIVILEGE_OWNER, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINESETCALLTREATMENT, // provider func index
&pfnTSPI_lineSetCallTreatment, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptCallClient, // context
"SetCallTreatment" // func name
)) > 0)
{
if (pParams->dwTreatment == 0 ||
(pParams->dwTreatment > LINECALLTREATMENT_MUSIC &&
pParams->dwTreatment < 0x100))
{
lRequestID = LINEERR_INVALPARAM;
goto LSetCallTreatment_epilog;
}
pParams->lResult = CallSP3(
pfnTSPI_lineSetCallTreatment,
"lineSetCallTreatment",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdCall,
(DWORD) pParams->dwTreatment
);
}
LSetCallTreatment_epilog:
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"SetCallTreatment"
);
}
void
WINAPI
LSetDefaultMediaDetection(
PTCLIENT ptClient,
PLINESETDEFAULTMEDIADETECTION_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
HANDLE hMutex;
HDRVLINE hdLine;
TSPIPROC pfnTSPI_lineSetDefaultMediaDetection;
DWORD objectToDereference;
PTLINECLIENT ptLineClient;
if ((pParams->lResult = LINEPROLOG(
ptClient, // tClient
ANY_RT_HLINE, // widget type
pParams->hLine, // client widget handle
(LPVOID) &hdLine, // provider widget handle
0, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINESETDEFAULTMEDIADETECTION, // provider func index
&pfnTSPI_lineSetDefaultMediaDetection, // provider func pointer
NULL, // async request info
0, // client async request ID
&objectToDereference, // object to dereference
&ptLineClient, // context
"SetDefaultMediaDetection" // func name
)) == 0)
{
DWORD dwMediaModes = pParams->dwMediaModes;
PTLINE ptLine;
ptLine = ptLineClient->ptLine;
if ((dwMediaModes & ptLine->dwOpenMediaModes) != dwMediaModes)
{
DWORD dwUnionMediaModes = dwMediaModes |
ptLine->dwOpenMediaModes;
if ((pParams->lResult = CallSP2(
pfnTSPI_lineSetDefaultMediaDetection,
"lineSetDefaultMediaDetection",
SP_FUNC_SYNC,
(ULONG_PTR) hdLine,
(DWORD) dwUnionMediaModes
)) == 0)
{
ptLine->dwOpenMediaModes = dwUnionMediaModes;
}
}
if (pParams->lResult == 0)
{
//
// For remote clients, give the monitor privilege. It doesn't
// matter if we do with (except for increased network traffic),
// because tapisrv on the client will filter out anything
// the client clients don't want.
//
if (IS_REMOTE_CLIENT (ptClient))
{
ptLineClient->dwPrivileges = (dwMediaModes ?
LINECALLPRIVILEGE_MONITOR | LINECALLPRIVILEGE_OWNER :
LINECALLPRIVILEGE_NONE);
}
else
{
ptLineClient->dwPrivileges = (dwMediaModes ?
LINECALLPRIVILEGE_OWNER : LINECALLPRIVILEGE_NONE);
}
ptLineClient->dwMediaModes = dwMediaModes;
}
}
LINEEPILOGSYNC(
&pParams->lResult,
hMutex,
bCloseMutex,
objectToDereference,
"SetDefaultMediaDetection"
);
}
void
WINAPI
LSetDevConfig(
PTCLIENT ptClient,
PLINESETDEVCONFIG_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
DWORD dwDeviceID;
HANDLE hMutex;
TSPIPROC pfnTSPI_lineSetDevConfig;
DWORD objectToDereference;
PTLINELOOKUPENTRY pLookupEntry;
//
// Verify size/offset/string params given our input buffer/size
//
if (ISBADSIZEOFFSET(
dwParamsBufferSize,
0,
pParams->dwSize,
pParams->dwDeviceConfigOffset,
sizeof(DWORD),
"LSetDevConfig",
"pParams->DeviceConfig"
) ||
IsBadStringParam(
dwParamsBufferSize,
pDataBuf,
pParams->dwDeviceClassOffset
))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if ((pParams->lResult = LINEPROLOG(
ptClient, // tClient
DEVICE_ID, // widget type
0, // client widget handle
&dwDeviceID, // provider widget handle
pParams->dwDeviceID, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINESETDEVCONFIG, // provider func index
&pfnTSPI_lineSetDevConfig, // provider func pointer
NULL, // async request info
0, // client async request ID
&objectToDereference, // object to dereference
&pLookupEntry, // context
"SetDevConfig" // func name
)) == 0)
{
pParams->lResult = CallSP4(
pfnTSPI_lineSetDevConfig,
"lineSetDevConfig",
SP_FUNC_SYNC,
(DWORD) dwDeviceID,
(ULONG_PTR) (pParams->dwSize ?
pDataBuf + pParams->dwDeviceConfigOffset : NULL),
(DWORD) pParams->dwSize,
(ULONG_PTR) (pDataBuf + pParams->dwDeviceClassOffset)
);
}
LINEEPILOGSYNC(
&pParams->lResult,
hMutex,
bCloseMutex,
objectToDereference,
"SetDevConfig"
);
}
void
WINAPI
LSetLineDevStatus(
PTCLIENT ptClient,
PLINESETLINEDEVSTATUS_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
LONG lRequestID;
HANDLE hMutex;
HDRVLINE hdLine;
TSPIPROC pfnTSPI_lineSetLineDevStatus;
DWORD objectToDereference;
PTLINECLIENT ptLineClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HLINE, // widget type
pParams->hLine, // client widget handle
(LPVOID) &hdLine, // provider widget handle
0, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINESETLINEDEVSTATUS, // provider func index
&pfnTSPI_lineSetLineDevStatus, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptLineClient, // context
"SetLineDevStatus" // func name
)) > 0)
{
#define AllLineDevStatusFlags \
(LINEDEVSTATUSFLAGS_CONNECTED | \
LINEDEVSTATUSFLAGS_MSGWAIT | \
LINEDEVSTATUSFLAGS_INSERVICE | \
LINEDEVSTATUSFLAGS_LOCKED)
if (pParams->dwStatusToChange == 0 ||
(pParams->dwStatusToChange & ~AllLineDevStatusFlags) != 0)
{
lRequestID = LINEERR_INVALLINESTATE;
}
else
{
pParams->lResult = CallSP4(
pfnTSPI_lineSetLineDevStatus,
"lineSetLineDevStatus",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdLine,
(DWORD) pParams->dwStatusToChange,
(DWORD) pParams->fStatus
);
}
}
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"SetLineDevStatus"
);
}
void
WINAPI
LSetMediaControl(
PTCLIENT ptClient,
PLINESETMEDIACONTROL_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
DWORD dwWidgetType, hWidget, dwPrivilege;
HANDLE hMutex;
LPVOID context;
TSPIPROC pfnTSPI_lineSetMediaControl;
DWORD objectToDereference;
ULONG_PTR hdWidget;
//
// Verify size/offset/string params given our input buffer/size
//
if (((pParams->dwDigitListOffset != TAPI_NO_DATA) &&
ISBADSIZEOFFSET(
dwParamsBufferSize,
0,
pParams->dwDigitListNumEntries,
// actually dwNumEntries * sizeof(LINEMEDIACONTROLDIGIT)
pParams->dwDigitListOffset,
sizeof(DWORD),
"LSetMediaControl",
"pParams->DigitList"
)) ||
((pParams->dwMediaListOffset != TAPI_NO_DATA) &&
ISBADSIZEOFFSET(
dwParamsBufferSize,
0,
pParams->dwMediaListNumEntries,
// actually dwNumEntries * sizeof(LINEMEDIACONTROLMEDIA)
pParams->dwMediaListOffset,
sizeof(DWORD),
"LSetMediaControl",
"pParams->MediaList"
)) ||
((pParams->dwToneListOffset != TAPI_NO_DATA) &&
ISBADSIZEOFFSET(
dwParamsBufferSize,
0,
pParams->dwToneListNumEntries,
// actually dwNumEntries * sizeof(LINEMEDIACONTROLTONE)
pParams->dwToneListOffset,
sizeof(DWORD),
"LSetMediaControl",
"pParams->ToneList"
)) ||
((pParams->dwCallStateListOffset != TAPI_NO_DATA) &&
ISBADSIZEOFFSET(
dwParamsBufferSize,
0,
pParams->dwCallStateListNumEntries,
// actually dwNumEntries *sizeof(LINEMEDIACONTROLCALLSTATE)
pParams->dwCallStateListOffset,
sizeof(DWORD),
"LSetMediaControl",
"pParams->CallStateList"
)))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if (pParams->dwSelect == LINECALLSELECT_CALL)
{
dwWidgetType = ANY_RT_HCALL;
hWidget = (DWORD) pParams->hCall;
dwPrivilege = LINECALLPRIVILEGE_OWNER;
}
else
{
dwWidgetType = ANY_RT_HLINE;
hWidget = (DWORD) pParams->hLine;
dwPrivilege = 0;
}
if ((pParams->lResult = LINEPROLOG(
ptClient, // tClient
dwWidgetType, // widget type
(DWORD) hWidget, // client widget handle
(LPVOID) &hdWidget, // provider widget handle
dwPrivilege, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINESETMEDIACONTROL, // provider func index
&pfnTSPI_lineSetMediaControl, // provider func pointer
NULL, // async request info
0, // client async request ID
&objectToDereference, // object to dereference
&context, // context
"SetMediaControl" // func name
)) == 0)
{
if (!IsOnlyOneBitSetInDWORD (pParams->dwSelect) ||
(pParams->dwSelect & ~AllCallSelect))
{
pParams->lResult = LINEERR_INVALCALLSELECT;
goto LSetMediaControl_epilog;
}
pParams->lResult = CallSP12(
pfnTSPI_lineSetMediaControl,
"lineSetMediaControl",
SP_FUNC_SYNC,
(ULONG_PTR) (pParams->dwSelect == LINECALLSELECT_CALL ?
0 : hdWidget),
(DWORD) pParams->dwAddressID,
(ULONG_PTR) (pParams->dwSelect == LINECALLSELECT_CALL ?
hdWidget : 0),
(DWORD) pParams->dwSelect,
(ULONG_PTR) (pParams->dwDigitListOffset == TAPI_NO_DATA ? NULL :
pDataBuf + pParams->dwDigitListOffset),
(DWORD) pParams->dwDigitListNumEntries /
sizeof(LINEMEDIACONTROLDIGIT),
(ULONG_PTR) (pParams->dwMediaListOffset == TAPI_NO_DATA ? NULL :
pDataBuf + pParams->dwMediaListOffset),
(DWORD) pParams->dwMediaListNumEntries /
sizeof(LINEMEDIACONTROLMEDIA),
(ULONG_PTR) (pParams->dwToneListOffset == TAPI_NO_DATA ? NULL :
pDataBuf + pParams->dwToneListOffset),
(DWORD) pParams->dwToneListNumEntries /
sizeof(LINEMEDIACONTROLTONE),
(ULONG_PTR) (pParams->dwCallStateListOffset == TAPI_NO_DATA ? NULL :
pDataBuf + pParams->dwCallStateListOffset),
(DWORD) pParams->dwCallStateListNumEntries /
sizeof(LINEMEDIACONTROLCALLSTATE)
);
}
LSetMediaControl_epilog:
LINEEPILOGSYNC(
&pParams->lResult,
hMutex,
bCloseMutex,
objectToDereference,
"SetMediaControl"
);
}
void
WINAPI
LSetMediaMode(
PTCLIENT ptClient,
PLINESETMEDIAMODE_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
DWORD dwAPIVersion, dwSPIVersion, dwAllMediaModes;
HANDLE hMutex;
HDRVCALL hdCall;
TSPIPROC pfnTSPI_lineSetMediaMode;
DWORD objectToDereference;
PTCALLCLIENT ptCallClient;
if ((pParams->lResult = LINEPROLOG(
ptClient, // tClient
ANY_RT_HCALL, // widget type
(DWORD) pParams->hCall, // client widget handle
(LPVOID) &hdCall, // provider widget handle
LINECALLPRIVILEGE_OWNER, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINESETMEDIAMODE, // provider func index
&pfnTSPI_lineSetMediaMode, // provider func pointer
NULL, // async request info
0, // client async request ID
&objectToDereference, // object to dereference
&ptCallClient, // context
"SetMediaMode" // func name
)) == 0)
{
try
{
dwAPIVersion = ptCallClient->ptLineClient->dwAPIVersion;
dwSPIVersion = ptCallClient->ptLineClient->ptLine->dwSPIVersion;
if (ptCallClient->dwKey != TCALLCLIENT_KEY)
{
pParams->lResult = LINEERR_INVALCALLHANDLE;
goto LSetMediaMode_epilog;
}
}
myexcept
{
pParams->lResult = LINEERR_INVALCALLHANDLE;
goto LSetMediaMode_epilog;
}
//
// Check for 0 media mode, and if > 1 bit set without UNKNOWN bit
//
if ( (dwAPIVersion <= TAPI_VERSION2_1 ) &&
!IsOnlyOneBitSetInDWORD (pParams->dwMediaModes) &&
!(pParams->dwMediaModes & LINEMEDIAMODE_UNKNOWN))
{
LOG((TL_ERROR,
"LSetMediaMode: error, >1 media mode selected without " \
"UNKNOWN flag (APIVer=x%x)",
dwAPIVersion
));
pParams->lResult = LINEERR_INVALMEDIAMODE;
goto LSetMediaMode_epilog;
}
//
// Now the harder checks
//
switch (dwAPIVersion)
{
case TAPI_VERSION1_0:
dwAllMediaModes = AllMediaModes1_0;
break;
case TAPI_VERSION1_4:
case TAPI_VERSION2_0:
dwAllMediaModes = AllMediaModes1_4;
break;
//case TAPI_VERSION2_1:
//case TAPI_VERSION2_2:
default: //case TAPI_VERSION_CURRENT:
dwAllMediaModes = AllMediaModes2_1;
break;
}
if ((pParams->dwMediaModes & (dwAllMediaModes ^ 0x00ffffff)) ||
(pParams->dwMediaModes == 0))
{
pParams->lResult = LINEERR_INVALMEDIAMODE;
goto LSetMediaMode_epilog;
}
pParams->lResult = CallSP2(
pfnTSPI_lineSetMediaMode,
"lineSetMediaMode",
SP_FUNC_SYNC,
(ULONG_PTR) hdCall,
(DWORD) pParams->dwMediaModes
);
}
LSetMediaMode_epilog:
LINEEPILOGSYNC(
&pParams->lResult,
hMutex,
bCloseMutex,
objectToDereference,
"SetMediaMode"
);
}
void
WINAPI
LSetNumRings(
PTCLIENT ptClient,
PLINESETNUMRINGS_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
HANDLE hMutex;
HDRVLINE hdLine;
DWORD objectToDereference;
PTLINECLIENT ptLineClient;
if ((pParams->lResult = LINEPROLOG(
ptClient, // tClient
ANY_RT_HLINE, // widget type
(DWORD) pParams->hLine, // client widget handle
(LPVOID) &hdLine, // provider widget handle
0, // privileges or device ID
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_NONE, // provider func index
NULL, // provider func pointer
NULL, // async request info
0, // client async request ID
&objectToDereference, // object to dereference
&ptLineClient, // context
"SetNumRings" // func name
)) == 0)
{
if (WaitForExclusiveLineClientAccess (ptLineClient))
{
DWORD dwNumAddresses = ptLineClient->ptLine->dwNumAddresses;
if (pParams->dwAddressID >= dwNumAddresses)
{
pParams->lResult = LINEERR_INVALADDRESSID;
goto LSetNumRings_releaseMutex;
}
if (ptLineClient->aNumRings == NULL)
{
if (!(ptLineClient->aNumRings = ServerAlloc(
dwNumAddresses * sizeof (DWORD)
)))
{
pParams->lResult = LINEERR_NOMEM;
goto LSetNumRings_releaseMutex;
}
FillMemory(
ptLineClient->aNumRings,
dwNumAddresses * sizeof (DWORD),
0xff
);
}
ptLineClient->aNumRings[pParams->dwAddressID] =
pParams->dwNumRings;
LSetNumRings_releaseMutex:
UNLOCKTLINECLIENT(ptLineClient);
}
else
{
pParams->lResult = LINEERR_INVALLINEHANDLE;
}
}
LINEEPILOGSYNC(
&pParams->lResult,
hMutex,
bCloseMutex,
objectToDereference,
"SetNumRings"
);
}
void
WINAPI
LSetQueueMeasurementPeriod(
PTCLIENT ptClient,
PLINESETQUEUEMEASUREMENTPERIOD_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
LONG lRequestID;
HANDLE hMutex;
HDRVLINE hdLine;
DWORD objectToDereference;
PTLINECLIENT ptLineClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HLINE, // widget type
(DWORD) pParams->hLine, // client widget handle
(LPVOID) &hdLine, // provider widget handle
0, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
0, // provider func index
NULL, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptLineClient, // context
"SetQueueMeasurementPeriod" // func name
)) > 0)
{
LONG lResult;
DWORD dwDeviceID;
PTLINECLIENT pProxy;
if ((lResult = FindProxy(
ptLineClient,
0,
LINEPROXYREQUEST_SETQUEUEMEASUREMENTPERIOD,
&pProxy,
&dwDeviceID,
TAPI_VERSION2_2
)))
{
lRequestID = lResult;
goto LSetQueueMeasurementPeriod_epilog;
}
// Measurement period must be > 0
if (pParams->dwMeasurementPeriod == 0)
{
lRequestID = LINEERR_INVALPARAM;
goto LSetQueueMeasurementPeriod_epilog;
}
//
// First check to see if there's a (local) proxy registered
// for this type of request on this line. If so, build a
// request & send it to the proxy.
//
if (pProxy)
{
LONG lResult;
PPROXYREQUESTWRAPPER pProxyRequestWrapper;
if ((lResult = CreateProxyRequest(
pProxy,
LINEPROXYREQUEST_SETQUEUEMEASUREMENTPERIOD,
2 * sizeof (DWORD),
pAsyncRequestInfo,
&pProxyRequestWrapper
)))
{
lRequestID = lResult;
goto LSetQueueMeasurementPeriod_epilog;
}
pProxyRequestWrapper->ProxyRequest.
SetQueueMeasurementPeriod.dwQueueID = pParams->dwQueueID;
pProxyRequestWrapper->ProxyRequest.
SetQueueMeasurementPeriod.dwMeasurementPeriod =
pParams->dwMeasurementPeriod;
if ((lResult = SendProxyRequest(
pProxy,
pProxyRequestWrapper,
pAsyncRequestInfo
)))
{
lRequestID = lResult;
goto LSetQueueMeasurementPeriod_epilog;
}
else // success
{
pParams->lResult = (LONG) pAsyncRequestInfo->dwLocalRequestID;
}
}
//
// There's no proxy, so check to see if line is remote and
// call remotesp if so
//
else if ((GetLineLookupEntry (dwDeviceID))->bRemote)
{
pParams->lResult = CallSP4(
pRemoteSP->apfn[SP_LINESETQUEUEMEASUREMENTPERIOD],
"lineSetQueueMeasurementPeriod",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdLine,
(DWORD) pParams->dwQueueID,
(DWORD) pParams->dwMeasurementPeriod
);
}
//
// There's no registered proxy & line is not remote, so fail
//
else
{
lRequestID = LINEERR_OPERATIONUNAVAIL;
}
}
LSetQueueMeasurementPeriod_epilog:
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"SetQueueManagementPeriod"
);
}
void
WINAPI
LSetStatusMessages(
PTCLIENT ptClient,
PLINESETSTATUSMESSAGES_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex, bCloseMutex2;
HANDLE hMutex, hMutex2;
HDRVLINE hdLine;
TSPIPROC pfnTSPI_lineSetStatusMessages;
DWORD objectToDereference;
PTLINECLIENT ptLineClient, ptLineClient2;
if ((pParams->lResult = LINEPROLOG(
ptClient, // tClient
ANY_RT_HLINE, // widget type
(DWORD) pParams->hLine, // client widget handle
(LPVOID) &hdLine, // provider widget handle
0, // privileges or device ID
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINESETSTATUSMESSAGES, // provider func index
&pfnTSPI_lineSetStatusMessages, // provider func pointer
NULL, // async request info
0, // client async request ID
&objectToDereference, // object to dereference
&ptLineClient, // context
"SetStatusMessages" // func name
)) == 0)
{
DWORD dwAPIVersion, dwUnionLineStates, dwUnionAddressStates;
PTLINE ptLine;
//
// Safely get the ptLine & api version
//
try
{
ptLine = ptLineClient->ptLine;
dwAPIVersion = ptLineClient->dwAPIVersion;
if (ptLineClient->dwKey != TLINECLIENT_KEY)
{
pParams->lResult = LINEERR_INVALLINEHANDLE;
goto LSetStatusMessages_epilog;
}
}
myexcept
{
pParams->lResult = LINEERR_INVALLINEHANDLE;
goto LSetStatusMessages_epilog;
}
//
// Validate the params
//
{
DWORD dwValidLineStates, dwValidAddressStates;
switch (dwAPIVersion)
{
case TAPI_VERSION1_0:
dwValidLineStates = AllLineStates1_0;
dwValidAddressStates = AllAddressStates1_0;
break;
default:
dwValidLineStates = AllLineStates1_4;
dwValidAddressStates = AllAddressStates1_4;
break;
}
if (pParams->dwLineStates & ~dwValidLineStates)
{
pParams->lResult = LINEERR_INVALLINESTATE;
goto LSetStatusMessages_epilog;
}
if (pParams->dwAddressStates & ~dwValidAddressStates)
{
pParams->lResult = LINEERR_INVALADDRESSSTATE;
goto LSetStatusMessages_epilog;
}
}
//
// Make sure the REINIT bit is always set
//
pParams->dwLineStates |= LINEDEVSTATE_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
//
dwUnionLineStates = pParams->dwLineStates;
dwUnionAddressStates = pParams->dwAddressStates;
waitForExclAccess:
if (WaitForExclusivetLineAccess(
ptLine,
&hMutex2,
&bCloseMutex2,
INFINITE
))
{
if (ptLine->dwBusy)
{
MyReleaseMutex (hMutex2, bCloseMutex2);
Sleep (50);
goto waitForExclAccess;
}
for(
ptLineClient2 = ptLine->ptLineClients;
ptLineClient2;
ptLineClient2 = ptLineClient2->pNextSametLine
)
{
if (ptLineClient2 != ptLineClient)
{
dwUnionLineStates |= ptLineClient2->dwLineStates;
dwUnionAddressStates |= ptLineClient2->dwAddressStates;
}
}
if ((dwUnionLineStates != ptLine->dwUnionLineStates) ||
(dwUnionAddressStates != ptLine->dwUnionAddressStates))
{
ptLine->dwBusy = 1;
MyReleaseMutex (hMutex2, bCloseMutex2);
pParams->lResult = CallSP3(
pfnTSPI_lineSetStatusMessages,
"lineSetStatusMessages",
SP_FUNC_SYNC,
(ULONG_PTR) hdLine,
(DWORD) dwUnionLineStates,
(DWORD) dwUnionAddressStates
);
if (WaitForExclusivetLineAccess(
ptLine,
&hMutex2,
&bCloseMutex2,
INFINITE
))
{
ptLine->dwBusy = 0;
if (pParams->lResult == 0)
{
ptLine->dwUnionLineStates = dwUnionLineStates;
ptLine->dwUnionAddressStates = dwUnionAddressStates;
}
MyReleaseMutex (hMutex2, bCloseMutex2);
}
else
{
pParams->lResult = LINEERR_INVALLINEHANDLE;
}
}
else
{
MyReleaseMutex (hMutex2, bCloseMutex2);
}
if (pParams->lResult == 0)
{
if (WaitForExclusiveLineClientAccess (ptLineClient))
{
ptLineClient->dwLineStates = pParams->dwLineStates;
ptLineClient->dwAddressStates = pParams->dwAddressStates;
UNLOCKTLINECLIENT (ptLineClient);
}
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 = LINEERR_INVALLINEHANDLE;
}
}
}
else
{
pParams->lResult = LINEERR_INVALLINEHANDLE;
}
}
LSetStatusMessages_epilog:
LINEEPILOGSYNC(
&pParams->lResult,
hMutex,
bCloseMutex,
objectToDereference,
"SetStatusMessages"
);
}
void
WINAPI
LSetTerminal(
PTCLIENT ptClient,
PLINESETTERMINAL_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
LONG lRequestID;
DWORD dwWidgetType, hWidget, dwPrivilege,
dwSelect = pParams->dwSelect;
HANDLE hMutex;
LPVOID context;
TSPIPROC pfnTSPI_lineSetTerminal;
DWORD objectToDereference;
ULONG_PTR hdWidget;
PASYNCREQUESTINFO pAsyncRequestInfo;
if (dwSelect == LINECALLSELECT_CALL)
{
dwWidgetType = ANY_RT_HCALL;
hWidget = (DWORD) pParams->hCall;
dwPrivilege = LINECALLPRIVILEGE_MONITOR;
}
else
{
dwWidgetType = ANY_RT_HLINE;
hWidget = (DWORD) pParams->hLine;
dwPrivilege = 0;
}
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
dwWidgetType, // widget type
hWidget, // client widget handle
&hdWidget, // provider widget handle
dwPrivilege, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINESETTERMINAL, // provider func index
&pfnTSPI_lineSetTerminal, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&context, // context
"SetTerminal" // func name
)) > 0)
{
DWORD dwTerminalModes = pParams->dwTerminalModes;
if (!IsOnlyOneBitSetInDWORD (dwSelect) ||
(dwSelect & ~AllCallSelects))
{
lRequestID = LINEERR_INVALCALLSELECT;
goto LSetTerminal_epilog;
}
if (dwTerminalModes == 0 ||
(dwTerminalModes & (~AllTerminalModes)))
{
lRequestID = LINEERR_INVALTERMINALMODE;
goto LSetTerminal_epilog;
}
pParams->lResult = CallSP8(
pfnTSPI_lineSetTerminal,
"lineSetTerminal",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) (dwWidgetType == ANY_RT_HLINE ? hdWidget : 0),
(DWORD) pParams->dwAddressID,
(ULONG_PTR) (dwWidgetType == ANY_RT_HCALL ? hdWidget : 0),
(DWORD) dwSelect,
(DWORD) dwTerminalModes,
(DWORD) pParams->dwTerminalID,
(DWORD) pParams->bEnable
);
}
LSetTerminal_epilog:
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"SetTerminal"
);
}
void
LSetupConference_PostProcess(
PASYNCREQUESTINFO pAsyncRequestInfo,
PASYNCEVENTMSG pAsyncEventMsg,
LPVOID *ppBuf
)
{
PTCALL ptConfCall = (PTCALL) pAsyncRequestInfo->dwParam1,
ptConsultCall = (PTCALL) pAsyncRequestInfo->dwParam3,
ptCall = (PTCALL) pAsyncRequestInfo->dwParam5;
HCALL hpConfCall = DWORD_CAST(pAsyncRequestInfo->dwParam2,__FILE__,__LINE__);
HCALL hpConsultCall = DWORD_CAST(pAsyncRequestInfo->dwParam4,__FILE__,__LINE__);
PTCALLCLIENT ptConfCallClient, ptConsultCallClient;
// LSetupConference_PostProcess: mutex on confCall too?
//
// Actually, this may be ok as is- the consult call is
// positioned before the conf call in the tline's list,
// so if we can safely access the former we ought to be
// able to safely access the latter too
if (WaitForExclusivetCallAccess (ptConsultCall, TINCOMPLETECALL_KEY))
{
HCALL hConsultCallThen = (HCALL)*(&pAsyncRequestInfo->dwParam5 + 2);
PTCALL ptConsultCallThen;
//
// Check to make sure this is the call we think it is (that the
// pointer wasn't freed by a previous call to lineClose/Shutdown
// and realloc'd for use as a ptCall again)
//
if (ptConsultCall->hCall != hConsultCallThen)
{
UNLOCKTCALL(ptConsultCall);
goto LSetupConference_PostProcess_bad_ptConsultCall;
}
ptConfCallClient = ptConfCall->ptCallClients;
ptConsultCallClient = ptConsultCall->ptCallClients;
if (pAsyncEventMsg->Param2 == 0) // success
{
PTCONFERENCELIST pConfList = ptConfCall->pConfList;
//
// Check to see if the app closed the line & left us with
// 0 call clients (in which case it'll also be taking care of
// cleaning up this tCall too)
//
if (ptConsultCall->ptCallClients == NULL)
{
UNLOCKTCALL(ptConsultCall);
ptConfCallClient = (PTCALLCLIENT) NULL;
ptConsultCallClient = (PTCALLCLIENT) NULL;
if (pAsyncEventMsg->Param2 == 0)
{
pAsyncEventMsg->Param2 = LINEERR_INVALLINEHANDLE;
}
goto LSetupConference_PostProcess_initMsgParams;
}
//
// Retrieve the various call IDs, then check if call
// client was destroyed by another thread (due to
// lineClose/Shutdown) while we were getting the call ID.
// If so, we'll need to clean up the tCall, since we know
// the other thread didn't do it because GetCallIDs marks
// the call as a zombie.
//
// Note that we can't use GetCallIDs() because we need
// to get id's for two calls at once
//
{
PTPROVIDER ptProvider = ptConfCall->ptProvider;
ptConfCall->dwKey =
ptConsultCall->dwKey = TZOMBIECALL_KEY;
UNLOCKTCALL (ptConsultCall);
if (ptProvider->apfn[SP_LINEGETCALLIDS])
{
CallSP4(
ptProvider->apfn[SP_LINEGETCALLIDS],
"lineGetCalIDs",
SP_FUNC_SYNC,
(ULONG_PTR) ptConfCall->hdCall,
(ULONG_PTR) &ptConfCall->dwAddressID,
(ULONG_PTR) &ptConfCall->dwCallID,
(ULONG_PTR) &ptConfCall->dwRelatedCallID
);
CallSP4(
ptProvider->apfn[SP_LINEGETCALLIDS],
"lineGetCalIDs",
SP_FUNC_SYNC,
(ULONG_PTR) ptConsultCall->hdCall,
(ULONG_PTR) &ptConsultCall->dwAddressID,
(ULONG_PTR) &ptConsultCall->dwCallID,
(ULONG_PTR) &ptConsultCall->dwRelatedCallID
);
}
else
{
DWORD dwSPIVersion, dwFixedSizeSP;
LINECALLINFO callInfo;
//
// Determine the fixed size of the structure expected
// by the SP
//
dwSPIVersion = ((PTLINE) ptConfCall->ptLine)->dwSPIVersion;
switch (dwSPIVersion)
{
case TAPI_VERSION1_0:
case TAPI_VERSION1_4:
dwFixedSizeSP = 296; // 69 * sizeof(DWORD)
// + sizeof (HLINE)
// + sizeof (LINEDIALPARAMS)
break;
case TAPI_VERSION2_0:
case TAPI_VERSION2_1:
case TAPI_VERSION2_2:
dwFixedSizeSP = 324; // 76 * sizeof(DWORD)
// + sizeof (HLINE)
// + sizeof (LINEDIALPARAMS)
break;
default: // (fix ppc build wrn) case TAPI_VERSION_CURRENT:
dwFixedSizeSP = sizeof (LINECALLINFO);
break;
}
InitTapiStruct(
&callInfo,
dwFixedSizeSP,
dwFixedSizeSP,
TRUE
);
if (ptProvider->apfn[SP_LINEGETCALLINFO] == NULL)
{
LOCKTCALL (ptConsultCall);
goto LSetupConference_PostProcess_cleanupCalls;
}
CallSP2(
ptProvider->apfn[SP_LINEGETCALLINFO],
"lineGetCallInfo",
SP_FUNC_SYNC,
(ULONG_PTR) ptConfCall->hdCall,
(ULONG_PTR) &callInfo
);
ptConfCall->dwAddressID = callInfo.dwAddressID;
ptConfCall->dwCallID = callInfo.dwCallID;
ptConfCall->dwRelatedCallID = callInfo.dwRelatedCallID;
InitTapiStruct(
&callInfo,
dwFixedSizeSP,
dwFixedSizeSP,
TRUE
);
CallSP2(
ptProvider->apfn[SP_LINEGETCALLINFO],
"lineGetCallInfo",
SP_FUNC_SYNC,
(ULONG_PTR) ptConsultCall->hdCall,
(ULONG_PTR) &callInfo
);
ptConsultCall->dwAddressID = callInfo.dwAddressID;
ptConsultCall->dwCallID = callInfo.dwCallID;
ptConsultCall->dwRelatedCallID = callInfo.dwRelatedCallID;
}
LOCKTCALL (ptConsultCall);
}
if (!ptConsultCall->ptCallClients)
{
goto LSetupConference_PostProcess_cleanupCalls;
}
//
// Indicate the various call IDs in the adwParams[] field of
// the ASYNCEVENTMSG.
//
// Make sure to increment the dwTotalSize of the ASYNCEVENTMSG
// as appropriate. We rely on the fact that CompletionProc()
// calls us with an AsyncEventMsg buffer that is big enough to
// handle a few extra DWORDs.
//
pAsyncEventMsg->Param3 = ptConfCallClient->hCall;
*(&pAsyncEventMsg->Param4 + 1) = ptConsultCallClient->hCall;
pAsyncEventMsg->TotalSize +=
6 * sizeof (pAsyncEventMsg->Param1);
*(&pAsyncEventMsg->Param4 + 3) = ptConfCall->dwAddressID;
*(&pAsyncEventMsg->Param4 + 4) = ptConfCall->dwCallID;
*(&pAsyncEventMsg->Param4 + 5) = ptConfCall->dwRelatedCallID;
*(&pAsyncEventMsg->Param4 + 6) = ptConsultCall->dwAddressID;
*(&pAsyncEventMsg->Param4 + 7) = ptConsultCall->dwCallID;
*(&pAsyncEventMsg->Param4 + 8) = ptConsultCall->dwRelatedCallID;
//
// Mark the calls as valid, the release the mutex
//
ptConfCall->dwKey =
ptConsultCall->dwKey = TCALL_KEY;
ptConfCallClient->dwKey =
ptConsultCallClient->dwKey = TCALLCLIENT_KEY;
pConfList->dwKey = TCONFLIST_KEY;
UNLOCKTCALL(ptConsultCall);
//
// Create monitor tCallClients
//
if (ptConsultCallThen = ReferenceObject(ghHandleTable, hConsultCallThen, TCALL_KEY))
{
if (ptConsultCallThen == ptConsultCall)
{
CreateCallMonitors (ptConfCall, FALSE);
CreateCallMonitors (ptConsultCall, FALSE);
}
DereferenceObject(ghHandleTable, hConsultCallThen, 1);
}
}
else // error
{
LSetupConference_PostProcess_cleanupCalls:
//
// Invalidate the tCalls, & if there's still tCallClients
// (might have already been destroyed by a lineClose/Shutdown
// in another thread) invalidate them too. Then unlock the
// tCalls & remove the object(s) from the list(s).
//
ptConfCall->dwKey = ptConsultCall->dwKey = INVAL_KEY;
if (ptConfCall->ptCallClients)
{
ptConfCallClient->dwKey = INVAL_KEY;
ptConfCall->lActiveFastCallClients--;
}
else
{
ptConfCallClient = NULL;
}
if (ptConsultCall->ptCallClients)
{
ptConsultCallClient->dwKey = INVAL_KEY;
ptConsultCall->lActiveFastCallClients--;
}
else
{
ptConsultCallClient = NULL;
}
UNLOCKTCALL(ptConsultCall);
RemoveCallFromLineList (ptConfCall);
RemoveCallFromLineList (ptConsultCall);
if (ptConfCallClient)
{
DereferenceObject (ghHandleTable, ptConfCallClient->hCall, 1);
RemoveCallClientFromLineClientList (ptConfCallClient);
}
if (ptConsultCallClient)
{
DereferenceObject (ghHandleTable,ptConsultCallClient->hCall,1);
RemoveCallClientFromLineClientList (ptConsultCallClient);
}
//
// Make sure all fast call clients cleaned up before free tCalls
//
while ((ptConfCall->lActiveFastCallClients != 0) ||
(ptConsultCall->lActiveFastCallClients != 0))
{
Sleep (5);
}
FreetCall (ptConsultCall);
if (ptCall)
{
SetCallConfList (ptCall, NULL, FALSE);
}
ServerFree (ptConfCall->pConfList);
FreetCall (ptConfCall);
}
}
else
{
//
// If here we can assume that the call was already destroyed
// and just fail the request
//
LSetupConference_PostProcess_bad_ptConsultCall:
if (pAsyncEventMsg->Param2 == 0)
{
pAsyncEventMsg->Param2 = LINEERR_OPERATIONFAILED;
}
}
LSetupConference_PostProcess_initMsgParams:
//
// Fill in the params to pass to client (important to remotesp in both
// the success & fail cases so it can either init or clean up drvCall)
//
// Make sure to increment the dwTotalSize of the ASYNCEVENTMSG
// as appropriate. We rely on the fact that CompletionProc()
// calls us with an AsyncEventMsg buffer that is big enough to
// handle a few extra DWORDs.
//
pAsyncEventMsg->Param4 = hpConfCall;
pAsyncEventMsg->TotalSize += 2 * sizeof (pAsyncEventMsg->Param1);
*(&pAsyncEventMsg->Param4 + 2) = hpConsultCall;
}
void
WINAPI
LSetupConference(
PTCLIENT ptClient,
PLINESETUPCONFERENCE_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
LONG lRequestID;
DWORD dwPrivilege = LINECALLPRIVILEGE_OWNER;
HCALL hCall = pParams->hCall;
HLINE hLine = pParams->hLine;
HANDLE hMutex;
LPVOID context;
TSPIPROC pfnTSPI_lineSetupConference;
DWORD objectToDereference;
ULONG_PTR hdXxx;
PASYNCREQUESTINFO pAsyncRequestInfo;
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
(hCall ? ANY_RT_HCALL : ANY_RT_HLINE), // widget type
(hCall ? (DWORD) hCall : (DWORD) hLine),// client widget handle
(LPVOID) &hdXxx, // provider widget handle
(hCall ? dwPrivilege : 0), // privileges or device ID
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when done
SP_LINESETUPCONFERENCE, // provider func index
&pfnTSPI_lineSetupConference, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&context, // context
"SetupConference" // func name
)) > 0)
{
LONG lResult;
DWORD dwNumParties;
PTCALL ptCall, ptConfCall, ptConsultCall;
HCALL hConfCall, hConsultCall;
PTCALLCLIENT ptConfCallClient, ptConsultCallClient;
PTLINECLIENT ptLineClient;
LPLINECALLPARAMS pCallParamsApp, pCallParamsSP;
PTCONFERENCELIST pConfList;
//
// Verify size/offset/string params given our input buffer/size
//
if ((pParams->dwCallParamsOffset != TAPI_NO_DATA) &&
IsBadStructParam(
dwParamsBufferSize,
pDataBuf,
pParams->dwCallParamsOffset
))
{
lRequestID = LINEERR_STRUCTURETOOSMALL;
goto LSetupConference_return;
}
//
// We need two more async request info params than are available,
// so we'll realloc a larger buf & work with it
//
{
PASYNCREQUESTINFO pAsyncRequestInfo2;
if (!(pAsyncRequestInfo2 = ServerAlloc(
sizeof (ASYNCREQUESTINFO) + 2 * sizeof (ULONG_PTR)
)))
{
lRequestID = LINEERR_NOMEM;
goto LSetupConference_return;
}
CopyMemory(
pAsyncRequestInfo2,
pAsyncRequestInfo,
sizeof (ASYNCREQUESTINFO)
);
pAsyncRequestInfo2->dwLocalRequestID = (DWORD)NewObject(
ghHandleTable,
pAsyncRequestInfo2,
NULL
);
// The following lines are to be removed for BUG 258501(xzhang).
// When called from RemoteSP, dwRemoteRequestID is used by the RemoteSP
// to identify the async request, if set to dwLocalRequestID, RemoteSP
// will get an invalid request ID and discard the call event notification.
/* if (lRequestID != (LONG) pAsyncRequestInfo->dwLocalRequestID)
{
lRequestID = (LONG)
(pAsyncRequestInfo2->dwRemoteRequestID =
pAsyncRequestInfo2->dwLocalRequestID);
}
*/
DereferenceObject(
ghHandleTable,
pAsyncRequestInfo->dwLocalRequestID,
1
);
pAsyncRequestInfo = pAsyncRequestInfo2;
}
pCallParamsApp = (LPLINECALLPARAMS)
(pParams->dwCallParamsOffset == TAPI_NO_DATA ?
0 : (pDataBuf + pParams->dwCallParamsOffset));
//
// Reference the tLineClient if not already
//
if (hCall)
{
try
{
hLine = ((PTCALLCLIENT) context)->ptLineClient->hLine;
}
myexcept
{
lRequestID = LINEERR_OPERATIONFAILED;
goto LSetupConference_return;
}
if (!(ptLineClient = ReferenceObject(
ghHandleTable,
hLine,
TLINECLIENT_KEY
)))
{
lRequestID = LINEERR_INVALCALLHANDLE;
goto LSetupConference_return;
}
}
else
{
ptLineClient = (PTLINECLIENT) context;
}
if (pCallParamsApp)
{
DWORD dwAPIVersion, dwSPIVersion;
try
{
dwAPIVersion = ptLineClient->dwAPIVersion;
dwSPIVersion = ptLineClient->ptLine->dwSPIVersion;
}
myexcept
{
lRequestID = LINEERR_OPERATIONFAILED;
goto LSetupConference_Dereference;
}
if ((lResult = ValidateCallParams(
pCallParamsApp,
&pCallParamsSP,
dwAPIVersion,
dwSPIVersion,
pParams->dwAsciiCallParamsCodePage
)) != 0)
{
lRequestID = lResult;
goto LSetupConference_Dereference;
}
}
else
{
pCallParamsSP = (LPLINECALLPARAMS) NULL;
}
dwNumParties = (pParams->dwNumParties > DEF_NUM_CONF_LIST_ENTRIES ?
pParams->dwNumParties : DEF_NUM_CONF_LIST_ENTRIES);
if (!(pConfList = (PTCONFERENCELIST) ServerAlloc(
sizeof (TCONFERENCELIST) + dwNumParties * sizeof(PTCALL)
)))
{
lRequestID = LINEERR_NOMEM;
goto LSetupConference_freeCallParams;
}
pConfList->dwNumTotalEntries = dwNumParties + 1;
pConfList->dwNumUsedEntries = 1;
if (hCall)
{
try
{
ptCall = ((PTCALLCLIENT) context)->ptCall;
}
myexcept
{
lResult = LINEERR_INVALCALLHANDLE;
goto LSetupConference_freeConfList;
}
if ((lResult = SetCallConfList (ptCall, pConfList, FALSE)) != 0)
{
goto LSetupConference_freeConfList;
}
}
else
{
ptCall = NULL;
}
if ((lResult = CreatetCallAndClient(
ptLineClient,
&ptConfCall,
&ptConfCallClient,
pCallParamsSP,
&hConfCall,
NULL
)) == 0)
{
pConfList->aptCalls[0] = ptConfCall;
if ((lResult = CreatetCallAndClient(
ptLineClient,
&ptConsultCall,
&ptConsultCallClient,
NULL,
&hConsultCall,
ptConfCall
) == 0))
{
ptConfCall->pConfList = pConfList;
pAsyncRequestInfo->pfnPostProcess =
LSetupConference_PostProcess;
pAsyncRequestInfo->htXxx = (ULONG_PTR)ptConfCallClient->ptLineClient->ptLine->hLine;
pAsyncRequestInfo->dwParam1 = (ULONG_PTR) ptConfCall;
pAsyncRequestInfo->dwParam2 = pParams->hpConfCall;
pAsyncRequestInfo->dwParam3 = (ULONG_PTR) ptConsultCall;
pAsyncRequestInfo->dwParam4 = pParams->hpConsultCall;
pAsyncRequestInfo->dwParam5 = (ULONG_PTR) ptCall;
*(&pAsyncRequestInfo->dwParam5 + 1) = (ULONG_PTR)hConfCall;
*(&pAsyncRequestInfo->dwParam5 + 2) = (ULONG_PTR)hConsultCall;
pAsyncRequestInfo->hfnClientPostProcessProc =
pParams->hfnPostProcessProc;
goto LSetupConference_callSP;
}
SetDrvCallFlags (hConfCall, DCF_SPIRETURNED);
DestroytCall (ptConfCall);
}
LSetupConference_freeConfList:
ServerFree (pConfList);
lRequestID = lResult;
goto LSetupConference_freeCallParams;
LSetupConference_callSP:
pParams->lResult = CallSP9(
pfnTSPI_lineSetupConference,
"lineSetupConference",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) (hCall ? hdXxx : 0), // hdCall
(ULONG_PTR) (hCall ? 0 : hdXxx), // hdLine
(ULONG_PTR) hConfCall,
(ULONG_PTR) &ptConfCall->hdCall,
(ULONG_PTR) hConsultCall,
(ULONG_PTR) &ptConsultCall->hdCall,
(DWORD) pParams->dwNumParties,
(ULONG_PTR) pCallParamsSP
);
SetDrvCallFlags(
hConfCall,
DCF_SPIRETURNED | (IS_LRESULT_NOTERROR(pParams->lResult) ?
DCF_DRVCALLVALID : 0)
);
SetDrvCallFlags(
hConsultCall,
DCF_SPIRETURNED | (IS_LRESULT_NOTERROR(pParams->lResult) ?
DCF_DRVCALLVALID : 0)
);
LSetupConference_freeCallParams:
if (pCallParamsSP != pCallParamsApp)
{
ServerFree (pCallParamsSP);
}
LSetupConference_Dereference:
if (hCall)
{
DereferenceObject (ghHandleTable, hLine, 1);
}
}
LSetupConference_return:
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"SetupConference"
);
}
void
WINAPI
LSetupTransfer(
PTCLIENT ptClient,
PLINESETUPTRANSFER_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
LONG lRequestID;
HANDLE hMutex;
HDRVCALL hdCall;
TSPIPROC pfnTSPI_lineSetupTransfer;
DWORD objectToDereference;
PTCALLCLIENT ptCallClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HCALL, // widget type
(DWORD) pParams->hCall, // client widget handle
(LPVOID) &hdCall, // provider widget handle
LINECALLPRIVILEGE_OWNER, // privileges or device ID
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINESETUPTRANSFER, // provider func index
&pfnTSPI_lineSetupTransfer, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptCallClient, // context
"SetupTransfer" // func name
)) > 0)
{
LONG lResult;
HLINE hLine;
PTCALL ptConsultCall;
HCALL hConsultCall;
PTCALLCLIENT ptConsultCallClient;
PTLINECLIENT ptLineClient;
LPLINECALLPARAMS pCallParamsApp, pCallParamsSP;
//
// Verify size/offset/string params given our input buffer/size
//
if ((pParams->dwCallParamsOffset != TAPI_NO_DATA) &&
IsBadStructParam(
dwParamsBufferSize,
pDataBuf,
pParams->dwCallParamsOffset
))
{
lRequestID = LINEERR_STRUCTURETOOSMALL;
goto LSetupTransfer_return;
}
//
// Reference the tLineClient
//
try
{
hLine = ptCallClient->ptLineClient->hLine;
}
myexcept
{
lRequestID = LINEERR_INVALCALLHANDLE;
goto LSetupTransfer_return;
}
if (!(ptLineClient = ReferenceObject(
ghHandleTable,
hLine,
TLINECLIENT_KEY
)))
{
lRequestID = LINEERR_INVALCALLHANDLE;
goto LSetupTransfer_return;
}
pCallParamsApp = (LPLINECALLPARAMS)
(pParams->dwCallParamsOffset == TAPI_NO_DATA ?
0 : (pDataBuf + pParams->dwCallParamsOffset));
if (pCallParamsApp)
{
DWORD dwAPIVersion, dwSPIVersion;
dwAPIVersion = ptLineClient->dwAPIVersion;
try
{
dwSPIVersion = ptLineClient->ptLine->dwSPIVersion;
}
myexcept
{
lRequestID = LINEERR_OPERATIONFAILED;
goto LSetupTransfer_Dereference;
}
if ((lResult = ValidateCallParams(
pCallParamsApp,
&pCallParamsSP,
dwAPIVersion,
dwSPIVersion,
pParams->dwAsciiCallParamsCodePage
)) != 0)
{
lRequestID = lResult;
goto LSetupTransfer_Dereference;
}
}
else
{
pCallParamsSP = (LPLINECALLPARAMS) NULL;
}
if (CreatetCallAndClient(
ptLineClient,
&ptConsultCall,
&ptConsultCallClient,
NULL,
&hConsultCall,
NULL
) != 0)
{
lRequestID = LINEERR_NOMEM;
goto LSetupTransfer_freeCallParams;
}
pAsyncRequestInfo->pfnPostProcess = LMakeCall_PostProcess;
pAsyncRequestInfo->htXxx = (ULONG_PTR)ptConsultCallClient->ptLineClient->ptLine->hLine;
pAsyncRequestInfo->dwParam1 = (ULONG_PTR) ptConsultCall;
pAsyncRequestInfo->dwParam2 = pParams->hpConsultCall;
pAsyncRequestInfo->dwParam5 = (ULONG_PTR)hConsultCall;
pAsyncRequestInfo->hfnClientPostProcessProc =
pParams->hfnPostProcessProc;
pParams->lResult = CallSP5(
pfnTSPI_lineSetupTransfer,
"lineSetupTransfer",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdCall,
(ULONG_PTR) hConsultCall,
(ULONG_PTR) &ptConsultCall->hdCall,
(ULONG_PTR) pCallParamsSP
);
SetDrvCallFlags(
hConsultCall,
DCF_SPIRETURNED | (IS_LRESULT_NOTERROR(pParams->lResult) ?
DCF_DRVCALLVALID : 0)
);
LSetupTransfer_freeCallParams:
if (pCallParamsSP != pCallParamsApp)
{
ServerFree (pCallParamsSP);
}
LSetupTransfer_Dereference:
DereferenceObject (ghHandleTable, hLine, 1);
}
LSetupTransfer_return:
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"SetupTransfer"
);
}
void
WINAPI
LShutdown(
PTCLIENT ptClient,
PLINESHUTDOWN_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
pParams->lResult = DestroytLineApp ((HLINEAPP) pParams->hLineApp);
#if DBG
{
char szResult[32];
LOG((TL_TRACE,
"lineShutdown: exit, result=%s",
MapResultCodeToText (pParams->lResult, szResult)
));
}
#else
LOG((TL_TRACE,
"lineShutdown: exit, result=x%x",
pParams->lResult
));
#endif
}
void
WINAPI
LSwapHold(
PTCLIENT ptClient,
PLINESWAPHOLD_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
LONG lRequestID;
HANDLE hMutex;
HDRVCALL hdActiveCall;
TSPIPROC pfnTSPI_lineSwapHold;
DWORD objectToDereference;
PTCALLCLIENT ptActiveCallClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HCALL, // widget type
pParams->hActiveCall, // client widget handle
(LPVOID) &hdActiveCall, // provider widget handle
LINECALLPRIVILEGE_OWNER, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINESWAPHOLD, // provider func index
&pfnTSPI_lineSwapHold, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptActiveCallClient, // context
"SwapHold" // func name
)) > 0)
{
HDRVCALL hdHeldCall;
PTCALLCLIENT ptHeldCallClient;
//
// Verify held call
//
if (!(ptHeldCallClient = ReferenceObject(
ghHandleTable,
pParams->hHeldCall,
TCALLCLIENT_KEY
)))
{
lRequestID = LINEERR_INVALCALLHANDLE;
goto LSwapHold_epilog;
}
if (ptHeldCallClient->ptClient != ptClient)
{
lRequestID = LINEERR_INVALCALLHANDLE;
goto LSwapHold_Dereference;
}
//
// Safely verify that client has owner privilege to held call,
// and that calls are on same tLine
//
try
{
if (!(ptHeldCallClient->dwPrivilege & LINECALLPRIVILEGE_OWNER))
{
lRequestID = LINEERR_NOTOWNER;
goto LSwapHold_Dereference;
}
if (ptHeldCallClient->ptCall->ptLine !=
ptActiveCallClient->ptCall->ptLine)
{
lRequestID = LINEERR_INVALCALLHANDLE;
goto LSwapHold_Dereference;
}
hdHeldCall = ptHeldCallClient->ptCall->hdCall;
}
myexcept
{
lRequestID = LINEERR_INVALCALLHANDLE;
goto LSwapHold_Dereference;
}
//
// Are they the same call?
//
if (hdActiveCall == hdHeldCall)
{
lRequestID = LINEERR_INVALCALLHANDLE;
goto LSwapHold_Dereference;
}
pParams->lResult = CallSP3(
pfnTSPI_lineSwapHold,
"lineSwapHold",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdActiveCall,
(ULONG_PTR) hdHeldCall
);
LSwapHold_Dereference:
DereferenceObject (ghHandleTable, pParams->hHeldCall, 1);
}
LSwapHold_epilog:
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"SwapHold"
);
}
void
WINAPI
LUncompleteCall(
PTCLIENT ptClient,
PLINEUNCOMPLETECALL_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
LONG lRequestID;
HANDLE hMutex;
HDRVLINE hdLine;
TSPIPROC pfnTSPI_lineUncompleteCall;
DWORD objectToDereference;
PTLINECLIENT ptLineClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HLINE, // widget type
(DWORD) pParams->hLine, // client widget handle
(LPVOID) &hdLine, // provider widget handle
0, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINEUNCOMPLETECALL, // provider func index
&pfnTSPI_lineUncompleteCall,// provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptLineClient, // context
"UncompleteCall" // func name
)) > 0)
{
pParams->lResult = CallSP3(
pfnTSPI_lineUncompleteCall,
"lineUncompleteCall",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdLine,
(DWORD) pParams->dwCompletionID
);
}
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"UncompleteCall"
);
}
void
WINAPI
LUnhold(
PTCLIENT ptClient,
PLINEUNHOLD_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
LONG lRequestID;
HANDLE hMutex;
HDRVCALL hdCall;
TSPIPROC pfnTSPI_lineUnhold;
DWORD objectToDereference;
PTCALLCLIENT ptCallClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HCALL, // widget type
(DWORD) pParams->hCall, // client widget handle
(LPVOID) &hdCall, // provider widget handle
LINECALLPRIVILEGE_OWNER, // req'd privileges (call only)
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINEUNHOLD, // provider func index
&pfnTSPI_lineUnhold, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptCallClient, // context
"Unhold" // func name
)) > 0)
{
pParams->lResult = CallSP2(
pfnTSPI_lineUnhold,
"lineUnhold",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdCall
);
}
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"Unhold"
);
}
void
WINAPI
LUnpark(
PTCLIENT ptClient,
PLINEUNPARK_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
LONG lRequestID;
HANDLE hMutex;
HDRVLINE hdLine;
TSPIPROC pfnTSPI_lineUnpark;
DWORD objectToDereference;
PTLINECLIENT ptLineClient;
PASYNCREQUESTINFO pAsyncRequestInfo;
//
// Verify size/offset/string params given our input buffer/size
//
if (IsBadStringParam(
dwParamsBufferSize,
pDataBuf,
pParams->dwDestAddressOffset
))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if ((lRequestID = LINEPROLOG(
ptClient, // tClient
ANY_RT_HLINE, // widget type
(DWORD) pParams->hLine, // client widget handle
(LPVOID) &hdLine, // provider widget handle
0, // privileges or device ID
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINEUNPARK, // provider func index
&pfnTSPI_lineUnpark, // provider func pointer
&pAsyncRequestInfo, // async request info
pParams->dwRemoteRequestID, // client async request ID
&objectToDereference, // object to dereference
&ptLineClient, // context
"Unpark" // func name
)) > 0)
{
PTCALL ptCall;
HCALL hCall;
PTCALLCLIENT ptCallClient;
if (CreatetCallAndClient(
ptLineClient,
&ptCall,
&ptCallClient,
NULL,
&hCall,
NULL
) != 0)
{
lRequestID = LINEERR_NOMEM;
goto LUnpark_return;
}
pAsyncRequestInfo->pfnPostProcess = LMakeCall_PostProcess;
pAsyncRequestInfo->htXxx = (ULONG_PTR)ptCallClient->ptLineClient->ptLine->hLine;
pAsyncRequestInfo->dwParam1 = (ULONG_PTR) ptCall;
pAsyncRequestInfo->dwParam2 = pParams->hpCall;
pAsyncRequestInfo->dwParam5 = (ULONG_PTR)hCall;
pAsyncRequestInfo->hfnClientPostProcessProc =
pParams->hfnPostProcessProc;
pParams->lResult = CallSP6(
pfnTSPI_lineUnpark,
"lineUnpark",
SP_FUNC_ASYNC,
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
(ULONG_PTR) hdLine,
(DWORD) pParams->dwAddressID,
(ULONG_PTR) hCall,
(ULONG_PTR) &ptCall->hdCall,
(ULONG_PTR) (pDataBuf + pParams->dwDestAddressOffset)
);
SetDrvCallFlags(
hCall,
DCF_SPIRETURNED | (IS_LRESULT_NOTERROR(pParams->lResult) ? DCF_DRVCALLVALID : 0)
);
}
LUnpark_return:
LINEEPILOGASYNC(
&pParams->lResult,
lRequestID,
hMutex,
bCloseMutex,
pAsyncRequestInfo,
objectToDereference,
"Unpark"
);
}
void
WINAPI
TAllocNewID(
PTCLIENT ptClient,
P_ALLOCNEWID_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
HKEY hKey;
HKEY hKey2;
DWORD dwDataSize;
DWORD dwDataType;
DWORD dwNewID;
DWORD dwDisposition;
RegCreateKeyEx(
HKEY_LOCAL_MACHINE,
gszRegKeyTelephony,
0,
TEXT(""),
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
0,
&hKey2,
&dwDisposition
);
RegCreateKeyEx(
hKey2,
gszLocations,
0,
TEXT(""),
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
0,
&hKey,
&dwDisposition
);
dwDataSize = sizeof(DWORD);
//
// Use 1 as the first ID.
//
pParams->dwNewID = 1;
RegQueryValueEx(
hKey,
gszNextID,
0,
&dwDataType,
(LPBYTE)&pParams->dwNewID,
&dwDataSize
);
dwNewID = pParams->dwNewID + 1;
RegSetValueEx(
hKey,
gszNextID,
0,
REG_DWORD,
(LPBYTE)&dwNewID,
sizeof(DWORD)
);
RegCloseKey( hKey );
RegCloseKey( hKey2);
*pdwNumBytesReturned = sizeof(ALLOCNEWID_PARAMS);
return;
}
#define MAX_KEY_LENGTH 256
DWORD RegDeleteKeyNT(HKEY hStartKey , LPCTSTR pKeyName )
{
DWORD dwRtn, dwSubKeyLength;
LPTSTR pSubKey = NULL;
TCHAR szSubKey[MAX_KEY_LENGTH]; // (256) this should be dynamic.
HKEY hKey;
// Do not allow NULL or empty key name
if ( pKeyName && lstrlen(pKeyName))
{
if( (dwRtn=RegOpenKeyEx(hStartKey,pKeyName,
0, KEY_ENUMERATE_SUB_KEYS | DELETE, &hKey )) == ERROR_SUCCESS)
{
while (dwRtn == ERROR_SUCCESS )
{
dwSubKeyLength = MAX_KEY_LENGTH;
dwRtn=RegEnumKeyEx(
hKey,
0, // always index zero
szSubKey,
&dwSubKeyLength,
NULL,
NULL,
NULL,
NULL
);
if(dwRtn == ERROR_NO_MORE_ITEMS)
{
dwRtn = RegDeleteKey(hStartKey, pKeyName);
break;
}
else if(dwRtn == ERROR_SUCCESS)
dwRtn=RegDeleteKeyNT(hKey, szSubKey);
}
RegCloseKey(hKey);
// Do not save return code because error
// has already occurred
}
}
else
dwRtn = ERROR_BADKEY;
return dwRtn;
}
void
WINAPI
TWriteLocations(
PTCLIENT ptClient,
PW_LOCATIONS_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
DWORD dwLocationID;
DWORD dwCount,dwCount2,dwError;
DWORD dwDisposition;
DWORD dwNumEntries,dwNumRules;
DWORD dwVersion;
TCHAR szCurrentLocationKey[256];
TCHAR szCurrentRuleKey[256];
HKEY hAllLocationsKey = NULL;
HKEY hLocationKey;
HKEY hAllAreaCodeRulesKey;
HKEY hAreaCodeRuleKey;
HKEY hTelephonyKey;
HKEY hUTelephonyKey;
HKEY hUAllLocationsKey = NULL;
HANDLE CurrentUserKey;
PLOCATIONLIST pLocationList = NULL;
PLOCATION pLocation = NULL;
PAREACODERULE pAreaCodeRule = NULL;
BOOL bRelMutex = FALSE;
HANDLE hProvidersMutex;
LOG((TL_TRACE, "TWriteLocations: enter"));
hProvidersMutex = CreateMutex (
NULL,
FALSE,
TEXT("TapisrvProviderListMutex")
);
if (NULL == hProvidersMutex)
{
LOG((TL_ERROR,
"WriteLocation: CreateMutex failed, err=%d",
GetLastError()
));
goto ExitHere;
}
WaitForSingleObject (hProvidersMutex, INFINITE);
bRelMutex = TRUE;
dwVersion = TAPI_LOCATION_LIST_VERSION;
if (RegCreateKeyEx(
HKEY_LOCAL_MACHINE,
gszRegKeyTelephony,
0,
TEXT(""),
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
0,
&hTelephonyKey,
&dwDisposition
) != ERROR_SUCCESS)
{
goto ExitHere;
}
if (RegCreateKeyEx(
hTelephonyKey,
gszLocations,
0,
TEXT(""),
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
0,
&hAllLocationsKey,
&dwDisposition
) != ERROR_SUCCESS)
{
RegCloseKey(hTelephonyKey);
goto ExitHere;
}
RegSetValueEx( hAllLocationsKey,
gszLocationListVersion,
0,
REG_DWORD,
(BYTE *)&dwVersion,
sizeof(dwVersion)
);
RegCloseKey( hTelephonyKey );
/////////////////////////////////////////////////////
// Now open clients key
//
if ((dwError=RpcImpersonateClient (0)) != RPC_S_OK)
{
LOG((TL_ERROR,
"WriteLocation: RpcImpersonateClient failed, err=%d",
dwError
));
goto ExitHere;
}
else
{
if (RtlOpenCurrentUser(KEY_ALL_ACCESS, &CurrentUserKey)
!= ERROR_SUCCESS)
{
RpcRevertToSelf();
goto ExitHere;
}
dwError = RegCreateKeyEx(
CurrentUserKey,
gszRegKeyTelephony,
0,
TEXT(""),
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
0,
&hUTelephonyKey,
&dwDisposition
);
if ( dwError != ERROR_SUCCESS )
{
LOG((TL_ERROR, "Registry can't create/open Users telephony key"));
NtClose(CurrentUserKey);
RpcRevertToSelf();
goto ExitHere;
}
NtClose(CurrentUserKey);
dwError = RegCreateKeyEx(
hUTelephonyKey,
gszLocations,
0,
TEXT(""),
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
0,
&hUAllLocationsKey,
&dwDisposition
);
if ( dwError != ERROR_SUCCESS )
{
LOG((TL_ERROR, "Registry can't create/open Users Locations key"));
RegCloseKey( hUTelephonyKey );
RpcRevertToSelf();
goto ExitHere;
}
RegSetValueEx( hUAllLocationsKey,
gszLocationListVersion,
0,
REG_DWORD,
(BYTE *)&dwVersion,
sizeof(dwVersion)
);
RegCloseKey( hUTelephonyKey );
RpcRevertToSelf();
}
pLocationList = (PLOCATIONLIST)(pDataBuf + pParams->dwLocationListOffset);
if ( pParams->dwChangedFlags & CHANGEDFLAGS_CURLOCATIONCHANGED )
{
RegSetValueEx(
hAllLocationsKey,
gszCurrentID,
0,
REG_DWORD,
(LPBYTE)&pLocationList->dwCurrentLocationID,
sizeof(DWORD)
);
}
// Find position of 1st LOCATION structure in the LOCATIONLIST structure
pLocation = (PLOCATION) ((BYTE*)(pLocationList) + pLocationList->dwLocationListOffset );
// Number of locations ?
dwNumEntries = pLocationList->dwNumLocationsInList;
for (dwCount = 0; dwCount < dwNumEntries ; dwCount++)
{
//Form key name for this location
dwLocationID = pLocation->dwPermanentLocationID;
wsprintf(szCurrentLocationKey, TEXT("Location%d"), dwLocationID);
// Is Entry to be deleted from reg ?
if(pLocation->dwLocationNameSize > sizeof(WCHAR) &&
*(WCHAR *)((BYTE*)(pLocation) +
pLocation->dwLocationNameOffset) != 0) // not just NULL
{
LOG((TL_INFO, "Location - write %s",szCurrentLocationKey));
// Create or open key for this location
dwError = RegCreateKeyEx(
hAllLocationsKey,
szCurrentLocationKey,
0,
TEXT(""),
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
0,
&hLocationKey,
&dwDisposition
);
if (dwError == ERROR_SUCCESS)
{
// Country ID
if(RegSetValueEx(
hLocationKey,
gszCountry,
0,
REG_DWORD,
(LPBYTE)&pLocation->dwCountryID,
sizeof(DWORD)
) != ERROR_SUCCESS)
{
LOG((TL_ERROR, "Location - can't write country"));
}
// Options (flags)
if(RegSetValueEx(
hLocationKey,
gszFlags,
0,
REG_DWORD,
(LPBYTE)&pLocation->dwOptions,
sizeof(DWORD)
) != ERROR_SUCCESS)
{
LOG((TL_ERROR, "Location - can't write Flags"));
}
// Name
if(TAPIRegSetValueExW(
hLocationKey,
gszNameW,
0,
REG_SZ,
(BYTE*)(pLocation) + pLocation->dwLocationNameOffset,
pLocation->dwLocationNameSize
) != ERROR_SUCCESS)
{
LOG((TL_ERROR, "Location - can't write Name"));
}
// AreaCode
if(TAPIRegSetValueExW(
hLocationKey,
gszAreaCodeW,
0,
REG_SZ,
(BYTE*)(pLocation) + pLocation->dwAreaCodeOffset,
pLocation->dwAreaCodeSize
) != ERROR_SUCCESS)
{
LOG((TL_ERROR, "Location - can't write area code"));
}
// CallWaiting
if(TAPIRegSetValueExW(
hLocationKey,
gszDisableCallWaitingW,
0,
REG_SZ,
(BYTE*)(pLocation) + pLocation->dwCancelCallWaitingOffset,
pLocation->dwCancelCallWaitingSize
) != ERROR_SUCCESS)
{
LOG((TL_ERROR, "Location - can't write call waiting"));
}
// LD Carrier Code
if(TAPIRegSetValueExW(
hLocationKey,
gszLongDistanceCarrierCodeW,
0,
REG_SZ,
(BYTE*)(pLocation) + pLocation->dwLongDistanceCarrierCodeOffset,
pLocation->dwLongDistanceCarrierCodeSize
) != ERROR_SUCCESS)
{
LOG((TL_ERROR, "Location - can't write LD carrier code"));
}
// International Carrier Code
if(TAPIRegSetValueExW(
hLocationKey,
gszInternationalCarrierCodeW,
0,
REG_SZ,
(BYTE*)(pLocation) + pLocation->dwInternationalCarrierCodeOffset,
pLocation->dwInternationalCarrierCodeSize
) != ERROR_SUCCESS)
{
LOG((TL_ERROR, "Location - can't write International carrier code"));
}
// LD Access
if(TAPIRegSetValueExW(
hLocationKey,
gszLongDistanceAccessW,
0,
REG_SZ,
(BYTE*)(pLocation) + pLocation->dwLongDistanceAccessCodeOffset,
pLocation->dwLongDistanceAccessCodeSize
) != ERROR_SUCCESS)
{
LOG((TL_ERROR, "Location - can't write LD access code"));
}
// Local Access
if(TAPIRegSetValueExW(
hLocationKey,
gszOutsideAccessW,
0,
REG_SZ,
(BYTE*)(pLocation) + pLocation->dwLocalAccessCodeOffset,
pLocation->dwLocalAccessCodeSize
) != ERROR_SUCCESS)
{
LOG((TL_ERROR, "Location - can't write Local access code"));
}
// if this is an existing key then delete all the subkeys
RegDeleteKeyNT(hLocationKey, gszAreaCodeRules );
// create or open the AreaCodeRules key
dwError = RegCreateKeyEx(
hLocationKey,
gszAreaCodeRules,
0,
TEXT(""),
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
0,
&hAllAreaCodeRulesKey,
&dwDisposition
);
if (dwError == ERROR_SUCCESS)
{
// Find position of 1st AREACODERULE structure in the LOCATION structure
pAreaCodeRule = (PAREACODERULE) ((BYTE*)(pLocation)
+ pLocation->dwAreaCodeRulesListOffset );
dwNumRules = pLocation->dwNumAreaCodeRules;
for (dwCount2 = 0; dwCount2 != dwNumRules; dwCount2++)
{
//Form key name for this aea code rule
wsprintf(szCurrentRuleKey, TEXT("Rule%d"),dwCount2);
// create or open this Area Code Rule Key
dwError = RegCreateKeyEx(
hAllAreaCodeRulesKey,
szCurrentRuleKey,
0,
TEXT(""),
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
0,
&hAreaCodeRuleKey,
&dwDisposition
);
if (dwError == ERROR_SUCCESS)
{
// Pull Dataout of AREACODERULE structure
// Options (flags)
if(RegSetValueEx(
hAreaCodeRuleKey,
gszFlags,
0,
REG_DWORD,
(LPBYTE)&pAreaCodeRule->dwOptions,
sizeof(DWORD)
) != ERROR_SUCCESS)
{
LOG((TL_ERROR, "Area code rule - can't write Flags"));
}
// AreaCode to call
if(TAPIRegSetValueExW(
hAreaCodeRuleKey,
gszAreaCodeToCallW,
0,
REG_SZ,
(BYTE*)(pLocation) + pAreaCodeRule->dwAreaCodeOffset,
pAreaCodeRule->dwAreaCodeSize
) != ERROR_SUCCESS)
{
LOG((TL_ERROR, "Area code rule - can't write Area code to call"));
}
//Number to Dial
if(TAPIRegSetValueExW(
hAreaCodeRuleKey,
gszNumberToDialW,
0,
REG_SZ,
(BYTE*)(pLocation) + pAreaCodeRule->dwNumberToDialOffset,
pAreaCodeRule->dwNumberToDialSize
) != ERROR_SUCCESS)
{
LOG((TL_ERROR, "Area code rule - can't write Number to dial"));
}
//Prefixes List
if(TAPIRegSetValueExW(
hAreaCodeRuleKey,
gszPrefixesW,
0,
REG_MULTI_SZ,
(BYTE*)(pLocation) + pAreaCodeRule->dwPrefixesListOffset,
pAreaCodeRule->dwPrefixesListSize
) != ERROR_SUCCESS)
{
LOG((TL_ERROR, "Area code rule - can't write Prefixes"));
}
RegCloseKey( hAreaCodeRuleKey ); // Don't need this key anymore...
}
else
{
LOG((TL_ERROR, "can't create/open hAreaCodeRuleKey"));
}
pAreaCodeRule++;
}
RegCloseKey(hAllAreaCodeRulesKey);
}
else
{
LOG((TL_ERROR, "can't create/open hAllAreaCodeRulesKey"));
}
RegCloseKey(hLocationKey);
/////////////////////////////////////////////////////
// Now do clients location entry
//
// Create or open key for this location
dwError = RegCreateKeyEx(
hUAllLocationsKey,
szCurrentLocationKey,
0,
TEXT(""),
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
0,
&hLocationKey,
&dwDisposition
);
if (dwError == ERROR_SUCCESS)
{
// CallingCard
if(RegSetValueEx(
hLocationKey,
gszCallingCard,
0,
REG_DWORD,
(LPBYTE)&pLocation->dwPreferredCardID,
sizeof(DWORD)
) != ERROR_SUCCESS)
{
LOG((TL_ERROR, "location - can't user preferred card"));
}
RegCloseKey( hLocationKey ); // Don't need this key anymore...
}
}
else
{
LOG((TL_ERROR, "can't create/open hLocationKey"));
}
}
else //Delete this location entry
{
LOG((TL_ERROR, "Location - delete %s",szCurrentLocationKey));
RegDeleteKeyNT( hAllLocationsKey, szCurrentLocationKey );
/////////////////////////////////////////////////////
// Now do clients location entry
//
RegDeleteKey(hUAllLocationsKey, szCurrentLocationKey);
}
// Try next location in list
//pEntry++;
pLocation = (PLOCATION) ((BYTE*)(pLocation) + pLocation->dwUsedSize);
}
//
// We're inside "if (dwChangedFlags)", so we know _something_ changed...
//
LOG((TL_TRACE, "Sending LINE_LINEDEVSTATE/LINEDEVSTATE_TRANSLATECHANGE msg"));
SendAMsgToAllLineApps(
0x80010004, // (OR with 0x80000000 for >= version)
LINE_LINEDEVSTATE,
LINEDEVSTATE_TRANSLATECHANGE,
0,
0
);
SendAMsgToAllLineApps(
0x00010003,
LINE_LINEDEVSTATE,
LINEDEVSTATE_REINIT,
LINE_LINEDEVSTATE,
LINEDEVSTATE_TRANSLATECHANGE
);
LOG((TL_TRACE, "TWriteLocations: exit"));
ExitHere:
if (hAllLocationsKey != NULL)
{
RegCloseKey(hAllLocationsKey);
}
if (hUAllLocationsKey != NULL)
{
RegCloseKey(hUAllLocationsKey);
}
if (bRelMutex && hProvidersMutex)
{
ReleaseMutex (hProvidersMutex);
CloseHandle (hProvidersMutex);
}
return;
}
void
WINAPI
TReadLocations(
PTCLIENT ptClient,
PR_LOCATIONS_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
PLOCATIONLIST pLocationList = (PLOCATIONLIST)(pDataBuf);
UINT n;
UINT nNumLocations;
UINT nCurrentLocationID;
TCHAR szCurrentLocationKey[256]; // Holds "LOCATIONxx" during reads
TCHAR szAreaCodeRuleKey[256]; // Holds "Rulexx" during reads
DWORD dwDataSize,dwKeySize;
DWORD dwNumLocationKeys=0;
DWORD dwMaxLocationKeyLength=0;
DWORD dwNumAreaCodeKeys=0;
DWORD dwMaxAreaCodeKeyLength=0;
DWORD dwDataType;
DWORD dwNeededSize = 0;
DWORD dwCount, dwCount2;
DWORD dwError;
HKEY hAllLocationsKey;
HKEY hLocationKey;
HKEY hAllAreaCodeRulesKey;
HKEY hAreaCodeRuleKey;
HKEY hTelephonyKey;
HKEY hUTelephonyKey;
HKEY hUserAllLocationsKey;
HANDLE CurrentUserKey;
BOOL bRelMutex = FALSE;
HANDLE hProvidersMutex;
LOG((TL_TRACE, "TReadLocations: enter"));
//
// Verify size/offset/string params given our input buffer/size
//
if (pParams->dwLocationsTotalSize > dwParamsBufferSize)
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if ( pParams->dwParmsToCheckFlags & CHECKPARMS_DWHLINEAPP )
{
if ( 0 == pParams->dwhLineApp )
{
//
// NULL is valid for these functions...
//
}
else
{
if ( !IsValidLineApp((HLINEAPP)pParams->dwhLineApp, ptClient) )
{
LOG((TL_ERROR, "0x%lx is not a valid hLineApp", pParams->dwhLineApp));
pParams->lResult = LINEERR_INVALAPPHANDLE;
goto CLEANUP_ERROR;
}
}
}
if ( pParams->dwParmsToCheckFlags & CHECKPARMS_DWDEVICEID )
{
if ( pParams->dwhLineApp
&&
(pParams->dwDeviceID != 0)
&&
(pParams->dwDeviceID >= TapiGlobals.dwNumLines)
)
{
LOG((TL_ERROR, "%ld is not a valid dwDeviceID", pParams->dwDeviceID));
pParams->lResult = LINEERR_BADDEVICEID;
goto CLEANUP_ERROR;
}
}
if ( pParams->dwParmsToCheckFlags & CHECKPARMS_DWAPIVERSION )
{
switch (pParams->dwAPIVersion)
{
case TAPI_VERSION_CURRENT:
case TAPI_VERSION3_0:
case TAPI_VERSION2_2:
case TAPI_VERSION2_1:
case TAPI_VERSION2_0:
case TAPI_VERSION1_4:
case TAPI_VERSION1_0:
break;
default:
LOG((TL_ERROR,
"TReadLocations: invalid API version x%x",
pParams->dwAPIVersion
));
pParams->lResult = LINEERR_INCOMPATIBLEAPIVERSION;
goto CLEANUP_ERROR;
}
}
if ( pParams->dwParmsToCheckFlags & CHECKPARMS_ONLY )
{
LOG((TL_INFO, "TReadLocations: Check only, no data transfer"));
pParams->lResult = 0;
if (pParams->dwLocationsTotalSize >= 3 * sizeof(DWORD))
{
pLocationList->dwTotalSize = pParams->dwLocationsTotalSize;
pLocationList->dwNeededSize =
pLocationList->dwUsedSize = 3 * sizeof(DWORD);
*pdwNumBytesReturned = sizeof (TAPI32_MSG) + (3 * sizeof(DWORD));
}
else
{
*pdwNumBytesReturned = sizeof (TAPI32_MSG);
}
pParams->dwLocationsOffset = 0;
goto CLEANUP_ERROR;
}
hProvidersMutex = CreateMutex (
NULL,
FALSE,
TEXT("TapisrvProviderListMutex")
);
if (NULL == hProvidersMutex)
{
LOG((TL_ERROR,
"TReadLocations: CreateMutex failed, err=%d",
GetLastError()
));
pParams->lResult = LINEERR_OPERATIONFAILED;
goto CLEANUP_ERROR;
}
WaitForSingleObject (hProvidersMutex, INFINITE);
bRelMutex = TRUE;
dwError = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
gszRegKeyTelephony,
0,
KEY_READ,
&hTelephonyKey
);
if (dwError == ERROR_SUCCESS)
{
dwError = RegOpenKeyEx(
hTelephonyKey,
gszLocations,
0,
KEY_READ,
&hAllLocationsKey
);
RegCloseKey( hTelephonyKey ); // Don't need this key anymore...
}
if ( dwError != ERROR_SUCCESS )
{
LOG((TL_ERROR, "ReadLocation: Registry can't open Locations key"));
pParams->lResult = LINEERR_INIFILECORRUPT;
goto CLEANUP_ERROR;
}
// Test the version of the Machine Locations key. Upgrade if necessary.
if(IsLocationListInOldFormat(hAllLocationsKey))
{
LOG((TL_INFO, "ReadLocation: Upgrade the Machine Locations key"));
dwError = ConvertLocations();
if(dwError != ERROR_SUCCESS)
{
LOG((TL_ERROR, "ReadLocation: Cannot convert the Machine Locations key"));
}
}
/////////////////////////////////////////////////////
// Now open clients key
//
if ((dwError=RpcImpersonateClient (0)) != RPC_S_OK)
{
LOG((TL_ERROR,
"ReadLocation: RpcImpersonateClient failed, err=%d",
dwError
));
pParams->lResult = LINEERR_OPERATIONFAILED;
goto CLEANUP_ERROR;
}
else
{
RtlOpenCurrentUser(KEY_ALL_ACCESS, &CurrentUserKey);
dwError = RegOpenKeyEx(
CurrentUserKey,
gszRegKeyTelephony,
0,
KEY_READ,
&hUTelephonyKey
);
if ( dwError != ERROR_SUCCESS )
{
LOG((TL_ERROR, " Registry can't open Users Locations key"));
RpcRevertToSelf();
RegCloseKey( hAllLocationsKey );
NtClose(CurrentUserKey);
pParams->lResult = LINEERR_OPERATIONFAILED;
goto CLEANUP_ERROR;
}
if (RegOpenKeyEx(
hUTelephonyKey,
gszLocations,
0,
KEY_READ,
&hUserAllLocationsKey
) != ERROR_SUCCESS)
{
hUserAllLocationsKey = NULL;
}
RegCloseKey( hUTelephonyKey ); // Don't need this key anymore...
RpcRevertToSelf();
// Test the version of the User Locations key. Upgrade if necessary.
if(hUserAllLocationsKey && IsLocationListInOldFormat(hUserAllLocationsKey))
{
dwError = ConvertUserLocations(CurrentUserKey);
if(dwError != ERROR_SUCCESS)
{
LOG((TL_ERROR, " Cannot convert the User Locations key"));
}
}
NtClose(CurrentUserKey);
}
dwDataSize = sizeof(nCurrentLocationID);
nCurrentLocationID = 0;
RegQueryValueEx(
hAllLocationsKey,
gszCurrentID,
0,
&dwDataType,
(LPBYTE)&nCurrentLocationID,
&dwDataSize
);
// query some info about the Locations key in order to allocate memory
RegQueryInfoKey(hAllLocationsKey,
NULL,
NULL,
NULL,
&dwNumLocationKeys,
&dwMaxLocationKeyLength,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
);
//
// It's _REALLY_ bad if NumLocations is zero for any
// reason. Should probably fail the function on the spot...
//
if ( 0 == dwNumLocationKeys )
{
LOG((TL_ERROR, " Registry says there are 0 locations"));
pParams->lResult = LINEERR_INIFILECORRUPT;
RegCloseKey( hAllLocationsKey );
if (hUserAllLocationsKey)
{
RegCloseKey(hUserAllLocationsKey);
}
goto CLEANUP_ERROR;
}
// Need to work out need size, so start with static part of list
dwNeededSize = ALIGN(sizeof(LOCATIONLIST));
// go though locations to work out needed size
for (dwCount=0; dwCount < dwNumLocationKeys ; dwCount++)
{
dwKeySize = sizeof(szCurrentLocationKey)/sizeof(TCHAR);
dwError = RegEnumKeyEx( hAllLocationsKey,
dwCount,
szCurrentLocationKey,
&dwKeySize,
NULL,
NULL,
NULL,
NULL
);
if(dwError == ERROR_NO_MORE_ITEMS)
{
break;
}
if (dwError != ERROR_SUCCESS )
{
continue;
}
// Open this Location Key
dwError = RegOpenKeyEx(
hAllLocationsKey,
szCurrentLocationKey,
0,
KEY_ALL_ACCESS,
&hLocationKey
);
if (dwError == ERROR_SUCCESS)
{
//Static part then strings
dwNeededSize += ALIGN(sizeof(LOCATION));
// Name
if (TAPIRegQueryValueExW(
hLocationKey,
gszNameW,
NULL,
NULL,
NULL,
&dwDataSize
) != ERROR_SUCCESS)
{
dwDataSize = sizeof(WCHAR);
}
dwNeededSize += ALIGN(dwDataSize);
// AreaCode
if (TAPIRegQueryValueExW(
hLocationKey,
gszAreaCodeW,
NULL,
NULL,
NULL,
&dwDataSize
) != ERROR_SUCCESS)
{
dwDataSize = sizeof(WCHAR);
}
dwNeededSize += ALIGN(dwDataSize);
//CallWaiting
if (TAPIRegQueryValueExW(
hLocationKey,
gszDisableCallWaitingW,
NULL,
NULL,
NULL,
&dwDataSize
) != ERROR_SUCCESS)
{
dwDataSize = sizeof(WCHAR);
}
dwNeededSize += ALIGN(dwDataSize);
//LD Carrier
if (TAPIRegQueryValueExW(
hLocationKey,
gszLongDistanceCarrierCodeW,
NULL,
NULL,
NULL,
&dwDataSize
) != ERROR_SUCCESS)
{
dwDataSize = sizeof(WCHAR);
}
dwNeededSize += ALIGN(dwDataSize);
//International Carrier
if (TAPIRegQueryValueExW(
hLocationKey,
gszInternationalCarrierCodeW,
NULL,
NULL,
NULL,
&dwDataSize
) != ERROR_SUCCESS)
{
dwDataSize = sizeof(WCHAR);
}
dwNeededSize += ALIGN(dwDataSize);
//LD Access
if (TAPIRegQueryValueExW(
hLocationKey,
gszLongDistanceAccessW,
NULL,
NULL,
NULL,
&dwDataSize
) != ERROR_SUCCESS)
{
dwDataSize = sizeof(WCHAR);
}
dwNeededSize += ALIGN(dwDataSize);
//Local Access
if (TAPIRegQueryValueExW(
hLocationKey,
gszOutsideAccessW,
NULL,
NULL,
NULL,
&dwDataSize
) != ERROR_SUCCESS)
{
dwDataSize = sizeof(WCHAR);
}
dwNeededSize += ALIGN(dwDataSize);
dwError = RegOpenKeyEx( hLocationKey,
gszAreaCodeRules,
0,
KEY_READ,
&hAllAreaCodeRulesKey
);
if (dwError == ERROR_SUCCESS)
{
// query info about the AreaCodeRules key
RegQueryInfoKey(hAllAreaCodeRulesKey,
NULL,
NULL,
NULL,
&dwNumAreaCodeKeys,
&dwMaxAreaCodeKeyLength,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
);
// go though this location's area code rules
for (dwCount2=0; dwCount2 < dwNumAreaCodeKeys; dwCount2++)
{
dwKeySize = sizeof(szAreaCodeRuleKey)/sizeof(TCHAR);
dwError = RegEnumKeyEx( hAllAreaCodeRulesKey,
dwCount2,
szAreaCodeRuleKey,
&dwKeySize,
NULL,
NULL,
NULL,
NULL
);
if(dwError == ERROR_NO_MORE_ITEMS)
{
break;
}
if (dwError != ERROR_SUCCESS )
{
continue;
}
// Open this Aeea Code Rule Key
dwError = RegOpenKeyEx(
hAllAreaCodeRulesKey,
szAreaCodeRuleKey,
0,
KEY_ALL_ACCESS,
&hAreaCodeRuleKey
);
if (dwError == ERROR_SUCCESS)
{
//Static part then strings
dwNeededSize += ALIGN(sizeof(AREACODERULE));
// AreaCode to call
TAPIRegQueryValueExW(
hAreaCodeRuleKey,
gszAreaCodeToCallW,
NULL,
NULL,
NULL,
&dwDataSize
);
dwNeededSize += ALIGN(dwDataSize);
//Number to Dial
TAPIRegQueryValueExW(
hAreaCodeRuleKey,
gszNumberToDialW,
NULL,
NULL,
NULL,
&dwDataSize
);
dwNeededSize += ALIGN(dwDataSize);
//Number to Dial
TAPIRegQueryValueExW(
hAreaCodeRuleKey,
gszPrefixesW,
NULL,
NULL,
NULL,
&dwDataSize
);
dwNeededSize += ALIGN(dwDataSize);
RegCloseKey( hAreaCodeRuleKey ); // Don't need this key anymore...
}
}
RegCloseKey( hAllAreaCodeRulesKey ); // Don't need this key anymore...
}
}
RegCloseKey( hLocationKey ); // Don't need this key anymore...
}
//
// Do we have enough space?
//
if ( pParams->dwLocationsTotalSize < dwNeededSize )
{
LOG((TL_ERROR, "(0x%08lx) is not enough room for sizeof( 0x%08lx )",
pParams->dwLocationsTotalSize, dwNeededSize ));
//
// Buffer not large enough
//
pLocationList->dwTotalSize = pParams->dwLocationsTotalSize;
pLocationList->dwNeededSize = dwNeededSize;
pLocationList->dwUsedSize = sizeof(LOCATIONLIST);
pLocationList->dwNumLocationsInList = 0;
pLocationList->dwLocationListSize = 0;
pLocationList->dwLocationListOffset = 0;
pParams->lResult = 0;
pParams->dwLocationsOffset = 0;
}
else // Big enough buffer, now fill it
{
DWORD dwLocationOffset, dwOffset;
PLOCATION pLocation;
PAREACODERULE pAreaCodeRule;
DWORD dwMaxValueLength;
// buffer size
pLocationList->dwTotalSize = pParams->dwLocationsTotalSize;
pLocationList->dwNeededSize = dwNeededSize;
pLocationList->dwUsedSize = dwNeededSize;
// Results
pParams->lResult = 0;
pParams->dwLocationsOffset = 0;
pLocationList->dwCurrentLocationID = nCurrentLocationID;
pLocationList->dwNumLocationsAvailable = dwNumLocationKeys;
//list size & offset
dwLocationOffset = ALIGN(sizeof(LOCATIONLIST));
pLocationList->dwNumLocationsInList = dwNumLocationKeys;
pLocationList->dwLocationListSize = dwNeededSize - sizeof(LOCATIONLIST);
pLocationList->dwLocationListOffset = dwLocationOffset;
// go through locations
for (dwCount=0; dwCount < dwNumLocationKeys ; dwCount++)
{
dwKeySize = dwMaxLocationKeyLength + 1;
dwError = RegEnumKeyEx( hAllLocationsKey,
dwCount,
szCurrentLocationKey,
&dwKeySize,
NULL,
NULL,
NULL,
NULL
);
if(dwError == ERROR_NO_MORE_ITEMS)
{
break;
}
pLocation = (PLOCATION)(((LPBYTE)pLocationList) + dwLocationOffset);
// Open this Location Key
dwError = RegOpenKeyEx(
hAllLocationsKey,
szCurrentLocationKey,
0,
KEY_ALL_ACCESS,
&hLocationKey
);
if (dwError == ERROR_SUCCESS)
{
LOG((TL_INFO, "Location - read %S",szCurrentLocationKey));
// Find out how big is our biggest value
dwMaxValueLength = 256;
RegQueryInfoKey(hLocationKey,0,0,0,0,0,0,0,0,&dwMaxValueLength,0,0);
/////////////////////////////////////////////////////////////////////
// Process fized part of Location info
dwOffset = ALIGN(sizeof(LOCATION));
//pLocation->dwPreferredCardID = m_dwPreferredCardID;
// Location ID (is included in the key name)
pLocation->dwPermanentLocationID = 0;
if(dwKeySize >= ARRAYSIZE(gszLocation)) // minimum a Location_ key
{
pLocation->dwPermanentLocationID = (DWORD)_ttol(szCurrentLocationKey + (ARRAYSIZE(gszLocation))-1);
}
else
{
LOG((TL_ERROR, "location - can't determine ID"));
}
// Country ID
dwDataSize = sizeof(DWORD);
pLocation->dwCountryID = 1;
if(RegQueryValueEx(
hLocationKey,
gszCountry,
0,
&dwDataType,
(LPBYTE)&pLocation->dwCountryID,
&dwDataSize
) != ERROR_SUCCESS)
{
LOG((TL_ERROR, "location - can't read CountryID"));
}
// Options (flags)
dwDataSize = sizeof(DWORD);
pLocation->dwOptions = 0;
if(RegQueryValueEx(
hLocationKey,
gszFlags,
0,
&dwDataType,
(LPBYTE)&pLocation->dwOptions,
&dwDataSize
) != ERROR_SUCCESS)
{
LOG((TL_ERROR, "location - can't read Flags"));
}
// Name
pLocation->dwLocationNameSize = dwMaxValueLength;
if(TAPIRegQueryValueExW(
hLocationKey,
gszNameW,
NULL,
NULL,
(LPBYTE)pLocation + dwOffset,
&pLocation->dwLocationNameSize
) != ERROR_SUCCESS)
{
LOG((TL_ERROR, "location - can't read Name"));
*(LPWSTR)((LPBYTE)pLocation + dwOffset) = 0;
pLocation->dwLocationNameSize = sizeof(WCHAR);
}
pLocation->dwLocationNameOffset = dwOffset;
dwOffset += ALIGN(pLocation->dwLocationNameSize);
// AreaCode
pLocation->dwAreaCodeSize = dwMaxValueLength;
if(TAPIRegQueryValueExW(
hLocationKey,
gszAreaCodeW,
NULL,
NULL,
(LPBYTE)pLocation + dwOffset,
&pLocation->dwAreaCodeSize
) != ERROR_SUCCESS)
{
LOG((TL_ERROR, "location - can't read Area code"));
*(LPWSTR)((LPBYTE)pLocation + dwOffset) = 0;
pLocation->dwAreaCodeSize = sizeof(WCHAR);
}
pLocation->dwAreaCodeOffset = dwOffset;
dwOffset += ALIGN(pLocation->dwAreaCodeSize);
// CallWaiting
pLocation->dwCancelCallWaitingSize = dwMaxValueLength;
if(TAPIRegQueryValueExW(
hLocationKey,
gszDisableCallWaitingW,
NULL,
NULL,
(LPBYTE)pLocation + dwOffset,
&pLocation->dwCancelCallWaitingSize
) != ERROR_SUCCESS)
{
LOG((TL_ERROR, "location - can't read Callwaiting"));
*(LPWSTR)((LPBYTE)pLocation + dwOffset) = 0;
pLocation->dwCancelCallWaitingSize = sizeof(WCHAR);
}
pLocation->dwCancelCallWaitingOffset = dwOffset;
dwOffset += ALIGN(pLocation->dwCancelCallWaitingSize);
// LD Carrier
pLocation->dwLongDistanceCarrierCodeSize = dwMaxValueLength;
if(TAPIRegQueryValueExW(
hLocationKey,
gszLongDistanceCarrierCodeW,
NULL,
NULL,
(LPBYTE)pLocation + dwOffset,
&pLocation->dwLongDistanceCarrierCodeSize
) != ERROR_SUCCESS)
{
LOG((TL_ERROR, "location - can't read LD carrier code"));
*(LPWSTR)((LPBYTE)pLocation + dwOffset) = 0;
pLocation->dwLongDistanceCarrierCodeSize = sizeof(WCHAR);
}
pLocation->dwLongDistanceCarrierCodeOffset = dwOffset;
dwOffset += ALIGN(pLocation->dwLongDistanceCarrierCodeSize);
// International Carrier
pLocation->dwInternationalCarrierCodeSize = dwMaxValueLength;
if(TAPIRegQueryValueExW(
hLocationKey,
gszInternationalCarrierCodeW,
NULL,
NULL,
(LPBYTE)pLocation + dwOffset,
&pLocation->dwInternationalCarrierCodeSize
) != ERROR_SUCCESS)
{
LOG((TL_ERROR, "location - can't read International carrier code"));
*(LPWSTR)((LPBYTE)pLocation + dwOffset) = 0;
pLocation->dwInternationalCarrierCodeSize = sizeof(WCHAR);
}
pLocation->dwInternationalCarrierCodeOffset = dwOffset;
dwOffset += ALIGN(pLocation->dwInternationalCarrierCodeSize);
// LD Access
pLocation->dwLongDistanceAccessCodeSize = dwMaxValueLength;
if(TAPIRegQueryValueExW(
hLocationKey,
gszLongDistanceAccessW,
NULL,
NULL,
(LPBYTE)pLocation + dwOffset,
&pLocation->dwLongDistanceAccessCodeSize
) != ERROR_SUCCESS)
{
LOG((TL_ERROR, "location - can't read LD access code"));
*(LPWSTR)((LPBYTE)pLocation + dwOffset) = 0;
pLocation->dwLongDistanceAccessCodeSize = sizeof(WCHAR);
}
pLocation->dwLongDistanceAccessCodeOffset = dwOffset;
dwOffset += ALIGN(pLocation->dwLongDistanceAccessCodeSize);
// Local Access
pLocation->dwLocalAccessCodeSize = dwMaxValueLength;
if(TAPIRegQueryValueExW(
hLocationKey,
gszOutsideAccessW,
NULL,
NULL,
(LPBYTE)pLocation + dwOffset,
&pLocation->dwLocalAccessCodeSize
) != ERROR_SUCCESS)
{
LOG((TL_ERROR, "location - can't read local access code"));
*(LPWSTR)((LPBYTE)pLocation + dwOffset) = 0;
pLocation->dwLocalAccessCodeSize = sizeof(WCHAR);
}
pLocation->dwLocalAccessCodeOffset = dwOffset;
dwOffset += ALIGN(pLocation->dwLocalAccessCodeSize);
///////////////////////////////////////////////////////////////////
// Do the Area Code Rules
dwError = RegOpenKeyEx( hLocationKey,
gszAreaCodeRules,
0,
KEY_READ,
&hAllAreaCodeRulesKey
);
if (dwError == ERROR_SUCCESS)
{
// Find out how many keys & how long is a key
RegQueryInfoKey(hAllAreaCodeRulesKey,0,0,0,&dwNumAreaCodeKeys,&dwMaxAreaCodeKeyLength,0,0,0,0,0,0);
pLocation->dwNumAreaCodeRules = dwNumAreaCodeKeys;
// pLocation->dwAreaCodeRulesListSize;
pLocation->dwAreaCodeRulesListOffset = dwOffset;
// point to the 1st rule
pAreaCodeRule = (PAREACODERULE)(((LPBYTE)pLocation) + dwOffset);
//point strings past rule area
dwOffset += ALIGN(( sizeof(AREACODERULE) * dwNumAreaCodeKeys ));
// go though this location's area code rules
for (dwCount2=0; dwCount2 < dwNumAreaCodeKeys; dwCount2++)
{
dwKeySize = dwMaxAreaCodeKeyLength + 1;
dwError = RegEnumKeyEx( hAllAreaCodeRulesKey,
dwCount2,
szAreaCodeRuleKey,
&dwKeySize,
NULL,
NULL,
NULL,
NULL
);
if(dwError == ERROR_NO_MORE_ITEMS)
{
break;
}
if(dwError != ERROR_SUCCESS)
{
continue;
}
// Open this Area Code Rule Key
dwError = RegOpenKeyEx(
hAllAreaCodeRulesKey,
szAreaCodeRuleKey,
0,
KEY_ALL_ACCESS,
&hAreaCodeRuleKey
);
if (dwError == ERROR_SUCCESS)
{
LOG((TL_ERROR, "ReadLocation - areacode %s",szAreaCodeRuleKey));
// Find out how big is our biggest value
RegQueryInfoKey(hAreaCodeRuleKey,0,0,0,0,0,0,0,0,&dwMaxValueLength,0,0);
//Static part then strings
dwDataSize = sizeof(DWORD);
pAreaCodeRule->dwOptions = 0;
if(RegQueryValueEx(
hAreaCodeRuleKey,
gszFlags,
0,
&dwDataType,
(LPBYTE)&pAreaCodeRule->dwOptions,
&dwDataSize
) != ERROR_SUCCESS)
{
LOG((TL_ERROR, "Area code rule - can't read Flags"));
}
// AreaCode to call
pAreaCodeRule->dwAreaCodeSize = dwMaxValueLength;
if(TAPIRegQueryValueExW(
hAreaCodeRuleKey,
gszAreaCodeToCallW,
NULL,
NULL,
(LPBYTE)pLocation + dwOffset,
&pAreaCodeRule->dwAreaCodeSize
) != ERROR_SUCCESS)
{
LOG((TL_ERROR, "Area code rule - can't read Area code to call"));
}
pAreaCodeRule->dwAreaCodeOffset = dwOffset;
dwOffset += ALIGN(pAreaCodeRule->dwAreaCodeSize);
//Number to Dial
pAreaCodeRule->dwNumberToDialSize = dwMaxValueLength;
if(TAPIRegQueryValueExW(
hAreaCodeRuleKey,
gszNumberToDialW,
NULL,
NULL,
(LPBYTE)pLocation + dwOffset,
&pAreaCodeRule->dwNumberToDialSize
) != ERROR_SUCCESS)
{
LOG((TL_ERROR, "Area code rule - can't read number to dial"));
}
pAreaCodeRule->dwNumberToDialOffset = dwOffset;
dwOffset += ALIGN(pAreaCodeRule->dwNumberToDialSize);
//Prefixes List
pAreaCodeRule->dwPrefixesListSize = dwMaxValueLength;
if(TAPIRegQueryValueExW(
hAreaCodeRuleKey,
gszPrefixesW,
NULL,
NULL,
(LPBYTE)pLocation + dwOffset,
&pAreaCodeRule->dwPrefixesListSize
) != ERROR_SUCCESS)
{
LOG((TL_ERROR, "Area code rule - can't read prefixes"));
}
pAreaCodeRule->dwPrefixesListOffset = dwOffset;
dwOffset += ALIGN(pAreaCodeRule->dwPrefixesListSize);
RegCloseKey( hAreaCodeRuleKey ); // Don't need this key anymore...
pAreaCodeRule++;
}
}
RegCloseKey( hAllAreaCodeRulesKey ); // Don't need this key anymore...
}
// offset gives how many bytes we used
pLocation->dwUsedSize = dwOffset;
dwLocationOffset += dwOffset;
}
RegCloseKey( hLocationKey );
/////////////////////////////////////////////////////
// Now do clients location entry
//
pLocation->dwPreferredCardID = 0;
if (hUserAllLocationsKey)
{
// Open this Location Key
dwError = RegOpenKeyEx(
hUserAllLocationsKey,
szCurrentLocationKey,
0,
KEY_ALL_ACCESS,
&hLocationKey
);
if (dwError == ERROR_SUCCESS)
{
// Preferred Card ID
dwDataSize = sizeof(DWORD);
if(RegQueryValueEx(
hLocationKey,
gszCallingCard,
0,
&dwDataType,
(LPBYTE)&pLocation->dwPreferredCardID,
&dwDataSize
) != ERROR_SUCCESS)
{
LOG((TL_ERROR, "location - can't read users PreferredCardID"));
}
RegCloseKey( hLocationKey ); // Don't need this key anymore...
}
else
{
LOG((TL_ERROR, "location - can't read users location key"));
}
}
}
}
*pdwNumBytesReturned = sizeof (TAPI32_MSG) + pLocationList->dwUsedSize;
RegCloseKey(hAllLocationsKey);
if (hUserAllLocationsKey)
{
RegCloseKey(hUserAllLocationsKey);
}
CLEANUP_ERROR:
#if DBG
{
char szResult[32];
LOG((TL_TRACE,
"TReadLocations: exit, result=%s",
MapResultCodeToText (pParams->lResult, szResult)
));
}
#else
LOG((TL_TRACE,
"TReadLocations: exit, result=x%x",
pParams->lResult
));
#endif
if (bRelMutex && hProvidersMutex)
{
ReleaseMutex (hProvidersMutex);
CloseHandle (hProvidersMutex);
}
return;
}
void
WINAPI
LReceiveMSPData(
PTCLIENT ptClient,
PLINERECEIVEMSPDATA_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
TSPIPROC pfnTSPI_lineReceiveMSPData;
PTPROVIDER ptProvider;
PTLINECLIENT ptLineClient;
PTCALLCLIENT ptCallClient = NULL;
HDRVMSPLINE hdMSPLine;
HDRVCALL hdCall;
HDRVLINE hdLine;
//
// Verify size/offset/string params given our input buffer/size
//
if (ISBADSIZEOFFSET(
dwParamsBufferSize,
0,
pParams->dwBufferSize,
pParams->dwBufferOffset,
sizeof(DWORD),
"LReceiveMSPData",
"pParams->Buffer"
))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if (!(ptLineClient = ReferenceObject(
ghHandleTable,
pParams->hLine,
TLINECLIENT_KEY
)))
{
pParams->lResult = LINEERR_INVALLINEHANDLE;
return;
}
if (pParams->hCall)
{
if (!(ptCallClient = ReferenceObject(
ghHandleTable,
pParams->hCall,
TCALLCLIENT_KEY
)))
{
DereferenceObject (ghHandleTable, pParams->hLine, 1);
pParams->lResult = LINEERR_INVALCALLHANDLE;
return;
}
}
hdMSPLine = ptLineClient->hdMSPLine;
try
{
hdLine = ptLineClient->ptLine->hdLine;
ptProvider = ptLineClient->ptLine->ptProvider;
hdCall = (ptCallClient ? ptCallClient->ptCall->hdCall : 0);
if (ptLineClient->dwKey != TLINECLIENT_KEY)
{
pParams->lResult = LINEERR_INVALLINEHANDLE;
}
}
myexcept
{
pParams->lResult = LINEERR_INVALCALLHANDLE;
}
DereferenceObject (ghHandleTable, pParams->hLine, 1);
if (ptCallClient)
{
DereferenceObject (ghHandleTable, pParams->hCall, 1);
}
if (pParams->lResult == 0)
{
if ((pfnTSPI_lineReceiveMSPData =
ptProvider->apfn[SP_LINERECEIVEMSPDATA]))
{
PBYTE pTemp = pDataBuf + pParams->dwBufferOffset;
#ifdef _WIN64
if (!(ALIGNED (pTemp)))
{
pTemp = ServerAlloc (pParams->dwBufferSize);
if (NULL == pTemp)
{
pParams->lResult = LINEERR_NOMEM;
goto LReceiveMSPData_Return;
}
CopyMemory (pTemp, pDataBuf + pParams->dwBufferOffset, pParams->dwBufferSize);
}
#endif //_WIN64
pParams->lResult = CallSP5(
pfnTSPI_lineReceiveMSPData,
"lineReceiveMSPData",
SP_FUNC_SYNC,
(ULONG_PTR) hdLine,
(ULONG_PTR) hdCall,
(ULONG_PTR) hdMSPLine,
(ULONG_PTR) pTemp,
(DWORD) pParams->dwBufferSize
);
#ifdef _WIN64
if (pTemp != pDataBuf + pParams->dwBufferOffset)
{
ServerFree (pTemp);
}
#endif //_WIN64
}
else
{
pParams->lResult = LINEERR_OPERATIONUNAVAIL;
}
}
#ifdef _WIN64
LReceiveMSPData_Return:
#endif //_WIN64
{
char szResult[32];
#if DBG
LOG((TL_TRACE,
"ReceiveMSPData: exit, result=%s",
MapResultCodeToText (pParams->lResult, szResult)
));
#else
LOG((TL_TRACE,
"ReceiveMSPData: exit, result=x%x",
pParams->lResult
));
#endif //DBG
}
}
void
WINAPI
LMSPIdentify(
PTCLIENT ptClient,
PLINEMSPIDENTIFY_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
DWORD dwDeviceID = pParams->dwDeviceID;
HANDLE hMutex;
TSPIPROC pfnTSPI_lineMSPIdentify;
DWORD objectToDereference;
PTLINELOOKUPENTRY pLookupEntry;
//
// Verify size/offset/string params given our input buffer/size
//
if (dwParamsBufferSize < sizeof (GUID))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if ((pParams->lResult = LINEPROLOG(
ptClient, // tClient
DEVICE_ID, // widget type
0, // client widget handle
(LPVOID) &dwDeviceID, // provider widget handle
pParams->dwDeviceID, // privileges or deviceID
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_LINEMSPIDENTIFY, // provider func index
&pfnTSPI_lineMSPIdentify, // provider func pointer
NULL, // async request info
0, // client async request ID
&objectToDereference, // object to dereference
&pLookupEntry, // context
"MSPIdentify" // func name
)) == 0)
{
if ((pParams->lResult = CallSP2(
pfnTSPI_lineMSPIdentify,
"lineMSPIdentify",
SP_FUNC_SYNC,
(DWORD) dwDeviceID,
(ULONG_PTR) pDataBuf
)) == 0)
{
pParams->dwCLSIDOffset = 0;
pParams->dwCLSIDSize = sizeof (GUID);
*pdwNumBytesReturned = sizeof (TAPI32_MSG) + pParams->dwCLSIDSize;
}
}
LINEEPILOGSYNC(
&pParams->lResult,
hMutex,
bCloseMutex,
objectToDereference,
"MSPIdentify"
);
}
void
WINAPI
PrivateFactoryIdentify(
PTCLIENT ptClient,
PPRIVATEFACTORYIDENTIFY_PARAMS pParams,
DWORD dwParamsBufferSize,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
BOOL bCloseMutex;
DWORD dwDeviceID = pParams->dwDeviceID;
HANDLE hMutex;
TSPIPROC pfnTSPI_providerPrivateFactoryIdentify;
DWORD objectToDereference;
PTLINELOOKUPENTRY pLookupEntry;
//
// Verify size/offset/string params given our input buffer/size
//
if (dwParamsBufferSize < sizeof (GUID))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
return;
}
if ((pParams->lResult = LINEPROLOG(
ptClient, // tClient
DEVICE_ID, // widget type
0, // client widget handle
(LPVOID) &dwDeviceID, // provider widget handle
pParams->dwDeviceID, // privileges or deviceID
&hMutex, // mutex handle
&bCloseMutex, // close hMutex when finished
SP_PROVIDERPRIVATEFACTORYIDENTIFY, // provider func index
&pfnTSPI_providerPrivateFactoryIdentify, // provider func pointer
NULL, // async request info
0, // client async request ID
&objectToDereference, // object to dereference
&pLookupEntry, // context
"PrivateFactoryIdentify" // func name
)) == 0)
{
if ((pParams->lResult = CallSP2(
pfnTSPI_providerPrivateFactoryIdentify,
"providerPrivateFactoryIdentify",
SP_FUNC_SYNC,
(DWORD) dwDeviceID,
(ULONG_PTR) pDataBuf
)) == 0)
{
pParams->dwCLSIDOffset = 0;
pParams->dwCLSIDSize = sizeof (GUID);
*pdwNumBytesReturned = sizeof (TAPI32_MSG) + pParams->dwCLSIDSize;
}
}
LINEEPILOGSYNC(
&pParams->lResult,
hMutex,
bCloseMutex,
objectToDereference,
"PrivateFactoryIdentify"
);
}
LPBYTE
NewToOldLineforwardlist(
LPLINEFORWARDLIST pFwdList3_1
)
{
DWORD dwOffset3_0, dwOffset3_1, i;
DWORD dwTotalSize;
DWORD dwSizeofLFwdList3_0 = sizeof (LINEFORWARDLIST) - 2 * sizeof(DWORD);
DWORD dwSizeofLFwd3_0 = sizeof (LINEFORWARD) - 2 * sizeof(DWORD);
LPLINEFORWARD pFwdEntry3_1 = NULL;
LPBYTE pFwdEntry3_0 = NULL;
LPBYTE pFwdList3_0 = NULL;
//
// Alloc a buffer for storing the converted FORWARDLIST
//
dwTotalSize = pFwdList3_1->dwTotalSize - 2 * sizeof(DWORD) * pFwdList3_1->dwNumEntries;
pFwdList3_0 = ServerAlloc (dwTotalSize);
if (!pFwdList3_0)
return NULL;
memset (pFwdList3_0, 0, dwTotalSize);
((LPLINEFORWARDLIST)pFwdList3_0)->dwTotalSize = dwTotalSize;
((LPLINEFORWARDLIST)pFwdList3_0)->dwNumEntries = pFwdList3_1->dwNumEntries;
dwOffset3_1 = sizeof (LINEFORWARDLIST) +
(pFwdList3_1->dwNumEntries - 1) * sizeof (LINEFORWARD);
dwOffset3_0 = dwSizeofLFwdList3_0 +
(pFwdList3_1->dwNumEntries - 1) * dwSizeofLFwd3_0;
CopyMemory (pFwdList3_0 + dwOffset3_0, (LPBYTE)pFwdList3_1 + dwOffset3_1,
pFwdList3_1->dwTotalSize - dwOffset3_1);
pFwdEntry3_1 = pFwdList3_1->ForwardList;
pFwdEntry3_0 = (LPBYTE)((LPLINEFORWARDLIST)pFwdList3_0)->ForwardList;
for (i = 0; i < pFwdList3_1->dwNumEntries; i++, pFwdEntry3_1++)
{
CopyMemory (pFwdEntry3_0, pFwdEntry3_1, dwSizeofLFwd3_0);
if (pFwdEntry3_1->dwCallerAddressSize)
{
((LPLINEFORWARD)pFwdEntry3_0)->dwCallerAddressOffset =
pFwdEntry3_1->dwCallerAddressOffset - 2 * sizeof(DWORD) * pFwdList3_1->dwNumEntries;
}
if (pFwdEntry3_1->dwDestAddressSize)
{
((LPLINEFORWARD)pFwdEntry3_0)->dwDestAddressOffset =
pFwdEntry3_1->dwDestAddressOffset - 2 * sizeof(DWORD) * pFwdList3_1->dwNumEntries;
}
pFwdEntry3_0 += dwSizeofLFwd3_0;
}
return pFwdList3_0;
}
LPLINEFORWARDLIST
OldToNewLineforwardlist(
LPLINEFORWARDLIST pFwdList3_0
)
{
DWORD dwOffset3_0, dwOffset3_1, i;
DWORD dwSizeofLFwdList3_0 = sizeof (LINEFORWARDLIST) - 2 * sizeof(DWORD);
DWORD dwSizeofLFwd3_0 = sizeof (LINEFORWARD) - 2 * sizeof(DWORD);
DWORD dwTotalSize;
LPLINEFORWARD pFwdEntry3_1 = NULL;
LPBYTE pFwdEntry3_0 = NULL;
LPLINEFORWARDLIST pFwdList3_1 = NULL;
//
// Alloc a buffer for storing the converted FORWARDLIST
//
dwTotalSize = pFwdList3_0->dwTotalSize + 2 * sizeof(DWORD) * pFwdList3_0->dwNumEntries;
pFwdList3_1 = ServerAlloc (dwTotalSize);
if (!pFwdList3_1)
return NULL;
memset (pFwdList3_1, 0, dwTotalSize);
pFwdList3_1->dwTotalSize = dwTotalSize;
pFwdList3_1->dwNumEntries = pFwdList3_0->dwNumEntries;
dwOffset3_1 = sizeof (LINEFORWARDLIST) +
(pFwdList3_0->dwNumEntries - 1) * sizeof (LINEFORWARD);
dwOffset3_0 = dwSizeofLFwdList3_0 +
(pFwdList3_0->dwNumEntries - 1) * dwSizeofLFwd3_0;
CopyMemory ((LPBYTE)pFwdList3_1 + dwOffset3_1, (LPBYTE)pFwdList3_0 + dwOffset3_0,
pFwdList3_0->dwTotalSize - dwOffset3_0);
pFwdEntry3_1 = pFwdList3_1->ForwardList;
pFwdEntry3_0 = (LPBYTE)(pFwdList3_0->ForwardList);
for (i = 0; i < pFwdList3_0->dwNumEntries; i++, pFwdEntry3_1++)
{
CopyMemory (pFwdEntry3_1, pFwdEntry3_0, dwSizeofLFwd3_0);
if ( ((LPLINEFORWARD)pFwdEntry3_0)->dwCallerAddressSize )
{
pFwdEntry3_1->dwCallerAddressOffset =
((LPLINEFORWARD)pFwdEntry3_0)->dwCallerAddressOffset +
2 * sizeof(DWORD) * pFwdList3_0->dwNumEntries;
}
if ( ((LPLINEFORWARD)pFwdEntry3_0)->dwDestAddressSize )
{
pFwdEntry3_1->dwDestAddressOffset =
((LPLINEFORWARD)pFwdEntry3_0)->dwDestAddressOffset +
2 * sizeof(DWORD) * pFwdList3_0->dwNumEntries;
}
pFwdEntry3_0 += dwSizeofLFwd3_0;
}
return pFwdList3_1;
}
LPWSTR WaveDeviceIdToStringId(DWORD dwDeviceId, LPWSTR pwszDeviceType)
{
LPWSTR pwszStringID = NULL;
DWORD dwSize;
DWORD_PTR dwParam;
if (!pwszDeviceType)
return NULL;
do
{
if ( !_wcsicmp(pwszDeviceType, L"wave/in") )
{
HWAVEIN hWaveIn;
*(DWORD_PTR*)&hWaveIn = dwDeviceId;
// get the needed size
if (MMSYSERR_NOERROR != waveInMessage(
hWaveIn,
DRV_QUERYSTRINGIDSIZE,
(DWORD_PTR)&dwSize,
0))
break;
assert (dwSize != 0);
pwszStringID = ServerAlloc (dwSize);
if(!pwszStringID)
break;
dwParam = dwSize;
// get the wave string ID
if (MMSYSERR_NOERROR != waveInMessage(
hWaveIn,
DRV_QUERYSTRINGID,
(DWORD_PTR)pwszStringID,
dwParam))
{
ServerFree(pwszStringID);
pwszStringID = NULL;
}
} else if (!_wcsicmp(pwszDeviceType, L"wave/out"))
{
HWAVEOUT hWaveOut;
*(DWORD_PTR*)&hWaveOut = dwDeviceId;
// get the needed size
if (MMSYSERR_NOERROR != waveOutMessage(
hWaveOut,
DRV_QUERYSTRINGIDSIZE,
(DWORD_PTR)&dwSize,
0))
break;
assert (dwSize != 0);
pwszStringID = ServerAlloc (dwSize);
if(!pwszStringID)
break;
dwParam = dwSize;
// get the wave string ID
if (MMSYSERR_NOERROR != waveOutMessage(
hWaveOut,
DRV_QUERYSTRINGID,
(DWORD_PTR)pwszStringID,
dwParam))
{
ServerFree(pwszStringID);
pwszStringID = NULL;
}
} else if (!_wcsicmp(pwszDeviceType, L"midi/in"))
{
HMIDIIN hMidiIn;
*(DWORD_PTR*)&hMidiIn = dwDeviceId;
// get the needed size
if (MMSYSERR_NOERROR != midiInMessage(
hMidiIn,
DRV_QUERYSTRINGIDSIZE,
(DWORD_PTR)&dwSize,
0))
break;
assert (dwSize != 0);
pwszStringID = ServerAlloc (dwSize);
if(!pwszStringID)
break;
dwParam = dwSize;
// get the wave string ID
if (MMSYSERR_NOERROR != midiInMessage(
hMidiIn,
DRV_QUERYSTRINGID,
(DWORD_PTR)pwszStringID,
dwParam))
{
ServerFree(pwszStringID);
pwszStringID = NULL;
}
} else if (!_wcsicmp(pwszDeviceType, L"midi/out"))
{
HMIDIOUT hMidiOut;
*(DWORD_PTR*)&hMidiOut = dwDeviceId;
// get the needed size
if (MMSYSERR_NOERROR != midiOutMessage(
hMidiOut,
DRV_QUERYSTRINGIDSIZE,
(DWORD_PTR)&dwSize,
0))
break;
assert (dwSize != 0);
pwszStringID = ServerAlloc (dwSize);
if(!pwszStringID)
break;
dwParam = dwSize;
// get the wave string ID
if (MMSYSERR_NOERROR != midiOutMessage(
hMidiOut,
DRV_QUERYSTRINGID,
(DWORD_PTR)pwszStringID,
dwParam))
{
ServerFree(pwszStringID);
pwszStringID = NULL;
}
}
} while (0);
return pwszStringID;
}