mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
34455 lines
997 KiB
34455 lines
997 KiB
/*++ 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 0x00000110
|
|
|
|
#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;
|
|
}
|
|
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
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] * 2
|
|
);
|
|
|
|
*(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(
|
|
PTCALL ptCall,
|
|
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.
|
|
//
|
|
//
|
|
|
|
LOCKTCALL (ptCall);
|
|
|
|
try
|
|
{
|
|
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));
|
|
}
|
|
}
|
|
myexcept
|
|
{
|
|
}
|
|
|
|
UNLOCKTCALL (ptCall);
|
|
}
|
|
|
|
|
|
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
|
|
{
|
|
// 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,
|
|
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)
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// If this call has an associated call (i.e. this func is being
|
|
// called during the processing of a lineSetupConference request)
|
|
// then we want to make sure we get an htCall which maps to the
|
|
// same SPEventHandlerThread as that of the associated call.
|
|
// This is necessary on MP boxes (or any time we create > 1
|
|
// SPEventHandlerThread) to prevent call state, etc msgs for
|
|
// a call being processed (by thread A) prior to the call-creation
|
|
// completion msg being processed (by thread B).
|
|
//
|
|
|
|
if (ptCallAssociate && (gdwNumSPEventHandlerThreads > 1))
|
|
{
|
|
ptCall->hCall = (HCALL) NewObjectEx(
|
|
ghHandleTable,
|
|
ptCall,
|
|
NULL,
|
|
gdwNumSPEventHandlerThreads,
|
|
(DWORD) MAP_HANDLE_TO_SP_EVENT_QUEUE_ID(
|
|
(ULONG_PTR) ptLine->hLine
|
|
)
|
|
);
|
|
}
|
|
else
|
|
{
|
|
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));
|
|
|
|
|
|
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,
|
|
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,
|
|
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;
|
|
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;
|
|
|
|
|
|
pEntry->ptCallHubClients = NULL;
|
|
|
|
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;
|
|
PTLINELOOKUPENTRY pEntry;
|
|
|
|
pEntry = GetLineLookupEntry (ptLine->dwDeviceID);
|
|
|
|
if (ptProvider->dwTSPIOptions & LINETSPIOPTION_NONREENTRANT)
|
|
{
|
|
WaitForSingleObject (ptProvider->hMutex, INFINITE);
|
|
}
|
|
|
|
if ( ptProvider->apfn[SP_LINECLOSE] &&
|
|
pEntry &&
|
|
!pEntry->bRemoved
|
|
)
|
|
{
|
|
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) ¶ms,
|
|
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;
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
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 = (PTLINE)htLine;
|
|
|
|
if (NULL == ptLine)
|
|
{
|
|
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__)
|
|
);
|
|
}
|
|
|
|
break;
|
|
}
|
|
case LINE_AGENTSPECIFIC:
|
|
|
|
if (htCall)
|
|
{
|
|
SendMsgToCallClients(
|
|
(PTCALL)htCall,
|
|
NULL,
|
|
LINE_AGENTSPECIFIC,
|
|
DWORD_CAST(Param1,__FILE__,__LINE__),
|
|
DWORD_CAST(Param2,__FILE__,__LINE__),
|
|
DWORD_CAST(Param3,__FILE__,__LINE__)
|
|
);
|
|
|
|
}
|
|
else
|
|
{
|
|
PTLINE ptLine = (PTLINE)htLine;
|
|
|
|
|
|
SendMsgToLineClients(
|
|
ptLine,
|
|
NULL,
|
|
LINE_AGENTSPECIFIC,
|
|
DWORD_CAST(Param1,__FILE__,__LINE__),
|
|
DWORD_CAST(Param2,__FILE__,__LINE__),
|
|
DWORD_CAST(Param3,__FILE__,__LINE__)
|
|
);
|
|
}
|
|
|
|
break;
|
|
|
|
case LINE_CLOSE:
|
|
{
|
|
PTLINE ptLine = (PTLINE)htLine;
|
|
DWORD dwKey;
|
|
|
|
try
|
|
{
|
|
dwKey = ptLine->dwKey;
|
|
}
|
|
myexcept
|
|
{
|
|
dwKey = 0;
|
|
}
|
|
|
|
if (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 (dwKey == TLINE_KEY)
|
|
{
|
|
DestroytLine (ptLine, TRUE); // unconditional destroy
|
|
}
|
|
|
|
break;
|
|
}
|
|
case LINE_CALLDEVSPECIFIC:
|
|
case LINE_CALLDEVSPECIFICFEATURE:
|
|
case LINE_CALLINFO:
|
|
{
|
|
PTCALL ptCall = (PTCALL)htCall;
|
|
|
|
if (NULL == htCall)
|
|
{
|
|
return;
|
|
}
|
|
|
|
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__)
|
|
);
|
|
|
|
break;
|
|
}
|
|
case LINE_MONITORDIGITS:
|
|
case LINE_MONITORMEDIA:
|
|
{
|
|
PTCALL ptCall = (PTCALL)htCall;
|
|
|
|
if (NULL == htCall)
|
|
{
|
|
return;
|
|
}
|
|
|
|
SendMsgToCallClients(
|
|
ptCall,
|
|
NULL,
|
|
dwMsg,
|
|
DWORD_CAST(Param1,__FILE__,__LINE__),
|
|
DWORD_CAST(Param2,__FILE__,__LINE__),
|
|
(Param3 ? DWORD_CAST(Param3,__FILE__,__LINE__) : GetTickCount())
|
|
);
|
|
|
|
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 = (PTCALL)htCall;
|
|
TPOINTERLIST fastCallClientList,
|
|
*pCallClientList = &fastCallClientList;
|
|
TPOINTERLIST fastConfCallClientList,
|
|
*pConfCallClientList = NULL;
|
|
|
|
LOG((TL_EVENT, "LineEventProc: LINE_CALLSTATE event x%lx", Param1));
|
|
|
|
|
|
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)htLine;
|
|
|
|
|
|
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);
|
|
goto LINE_CALLSTATE_break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
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)
|
|
{
|
|
if (!ptCall->pConfList)
|
|
{
|
|
PTCALL ptConfCall = (PTCALL)Param2;
|
|
PTCONFERENCELIST pConfList;
|
|
|
|
|
|
ptCall->pConfList = (LPVOID) LongToPtr(0xffffffff);
|
|
|
|
UNLOCKTCALL(ptCall);
|
|
|
|
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;
|
|
}
|
|
|
|
SetCallConfList (ptCall, pConfList, TRUE);
|
|
|
|
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:
|
|
|
|
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 = (PTCALL)htCall;
|
|
|
|
|
|
SendMsgToCallClients(
|
|
ptCall,
|
|
NULL,
|
|
dwMsg,
|
|
DWORD_CAST(Param1,__FILE__,__LINE__),
|
|
0,
|
|
DWORD_CAST(Param3,__FILE__,__LINE__)
|
|
);
|
|
|
|
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 = (PTLINE)htLine;
|
|
|
|
|
|
if (NULL != ptLine)
|
|
{
|
|
if (CreatetCall(
|
|
ptLine,
|
|
TRUE,
|
|
(HDRVCALL) Param1,
|
|
&ptCall,
|
|
NULL,
|
|
NULL
|
|
|
|
) != 0)
|
|
{
|
|
ptCall = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ptCall = NULL;
|
|
}
|
|
|
|
*((LPHTAPICALL) Param2) = (HTAPICALL)ptCall;
|
|
|
|
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 = (PTCALL)htCall;
|
|
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 ( NULL == ptLineClient )
|
|
{
|
|
SendBufferMsgToCallClients(
|
|
ptCall,
|
|
NULL,
|
|
LINE_SENDMSPDATA,
|
|
0,
|
|
DWORD_CAST(Param3,__FILE__,__LINE__),
|
|
(LPBYTE)Param2
|
|
);
|
|
|
|
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 );
|
|
}
|
|
}
|
|
|
|
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 = (PTCALL)htCall;
|
|
TPOINTERLIST clientList, *pclientList = &clientList;
|
|
int i;
|
|
|
|
if (0 == htCall)
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case LINE_DEVSPECIFICEX:
|
|
{
|
|
PTLINE ptLine = (PTLINE)htLine;
|
|
|
|
|
|
SendBufferMsgToLineClients(
|
|
ptLine,
|
|
NULL,
|
|
LINE_DEVSPECIFICEX,
|
|
DWORD_CAST(Param1,__FILE__,__LINE__),
|
|
DWORD_CAST(Param2,__FILE__,__LINE__),
|
|
(LPBYTE) Param3
|
|
);
|
|
|
|
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
|
|
));
|
|
}
|
|
}
|
|
#else
|
|
LOG((TL_TRACE, "LineEventProcSP - enter"));
|
|
LOG((TL_INFO,
|
|
"HTapiLine=%p, HTapiCall=%p, msg=%lx, P1=x%x, P2=x%x, P3=x%x",
|
|
htLine,
|
|
htCall,
|
|
dwMsg,
|
|
Param1,
|
|
Param2,
|
|
Param3
|
|
));
|
|
|
|
#endif
|
|
|
|
|
|
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,
|
|
ptConsultCall = (PTCALL) pAsyncRequestInfo->dwParam4;
|
|
PTCALL ptCallThen = (PTCALL) 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 != ptCallThen)
|
|
{
|
|
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 == ptConfCall)
|
|
{
|
|
CreateCallMonitors (ptConfCall, FALSE);
|
|
}
|
|
}
|
|
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;
|
|
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,
|
|
NULL
|
|
|
|
)) == 0)
|
|
{
|
|
//htConfCall = ptConfCall->htCall;
|
|
pAsyncRequestInfo->dwParam5 = (ULONG_PTR)ptConfCall;
|
|
|
|
ptConfCall->pConfList = pConfList;
|
|
|
|
pConfList->aptCalls[0] = ptConfCall;
|
|
|
|
pAsyncRequestInfo->htXxx = (ULONG_PTR) ptConfCallClient->ptLineClient->ptLine;
|
|
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) ptConfCall,
|
|
(ULONG_PTR) (ptConfCall ? &ptConfCall->hdCall : 0),
|
|
(DWORD) pParams->dwTransferMode
|
|
);
|
|
|
|
if (ptConfCall)
|
|
{
|
|
SetDrvCallFlags(
|
|
ptConfCall,
|
|
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;
|
|
//HTAPICALL htConsultCall;
|
|
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 * sizeof (WCHAR)
|
|
);
|
|
|
|
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 * sizeof (WCHAR)
|
|
);
|
|
|
|
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,
|
|
NULL
|
|
|
|
) != 0)
|
|
{
|
|
lRequestID = LINEERR_NOMEM;
|
|
goto LForward_freeCallParams;
|
|
}
|
|
|
|
//htConsultCall = ptConsultCall->htCall;
|
|
|
|
pAsyncRequestInfo->pfnPostProcess = LMakeCall_PostProcess;
|
|
pAsyncRequestInfo->htXxx = (ULONG_PTR)ptConsultCallClient->ptLineClient->ptLine;
|
|
pAsyncRequestInfo->dwParam1 = (ULONG_PTR) ptConsultCall;
|
|
pAsyncRequestInfo->dwParam2 = pParams->hpConsultCall;
|
|
pAsyncRequestInfo->dwParam3 = 1; // special case for post-process proc
|
|
pAsyncRequestInfo->dwParam5 = (ULONG_PTR)ptConsultCall;
|
|
|
|
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) ptConsultCall,
|
|
(ULONG_PTR) &ptConsultCall->hdCall,
|
|
(ULONG_PTR) pCallParamsSP
|
|
);
|
|
|
|
SetDrvCallFlags(
|
|
ptConsultCall,
|
|
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] = '"';
|
|
wcscpy(szModuleName + 1, (PWSTR)(pDataBuf + pParams->dwAppNameOffset));
|
|
_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;
|
|
|
|
#ifdef MEMPHIS
|
|
DWORD iNum16BitProviders;
|
|
#endif
|
|
|
|
|
|
//
|
|
// 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
|
|
);
|
|
}
|
|
|
|
|
|
#ifdef MEMPHIS
|
|
|
|
// add in the 16 bit providers
|
|
|
|
iNum16BitProviders = GetPrivateProfileInt(
|
|
"PROVIDERS", //szProviders,
|
|
gszNumProviders,
|
|
0,
|
|
"TELEPHON.INI"//szTelephonIni
|
|
);
|
|
|
|
LOG((TL_INFO, "Number of 16 bit providers %d", iNum16BitProviders));
|
|
|
|
#endif
|
|
|
|
#ifdef MEMPHIS
|
|
dwNeededSize = dwFixedSizeClient +
|
|
((iNumProviders + iNum16BitProviders) * sizeof (LINEPROVIDERENTRY));
|
|
#else
|
|
dwNeededSize = dwFixedSizeClient +
|
|
(iNumProviders * sizeof (LINEPROVIDERENTRY));
|
|
#endif
|
|
|
|
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++;
|
|
}
|
|
}
|
|
|
|
#ifdef MEMPHIS
|
|
|
|
for (i = 0; i < iNum16BitProviders; i++)
|
|
{
|
|
CHAR szProviderXxxN[32];
|
|
DWORD dwNameLen;
|
|
DWORD dwNewSize;
|
|
|
|
|
|
wsprintf(szProviderXxxN, "%s%d", gszProviderFilename, i);
|
|
|
|
dwNameLen = MAX_PATH;
|
|
|
|
dwNameLen = 1 + GetPrivateProfileString(
|
|
"PROVIDERS", //gszProviders,
|
|
szProviderXxxN,
|
|
"",
|
|
buf,
|
|
dwNameLen,
|
|
"TELEPHON.INI"//szTelephonIni
|
|
);
|
|
|
|
dwNewSize = sizeof(WCHAR) * (MultiByteToWideChar(
|
|
GetACP(),
|
|
MB_PRECOMPOSED,
|
|
(LPCSTR)buf,
|
|
dwNameLen,
|
|
bufw,
|
|
MAX_PATH - 1
|
|
));
|
|
|
|
dwNeededSize += dwNewSize;
|
|
|
|
if (dwTotalSize >= dwNeededSize)
|
|
{
|
|
wsprintf(szProviderXxxN, "%s%d", gszProviderID, i);
|
|
|
|
pProviderEntry->dwPermanentProviderID = GetPrivateProfileInt(
|
|
"PROVIDERS",
|
|
szProviderXxxN,
|
|
0,
|
|
"TELEPHON.INI"
|
|
);
|
|
|
|
pProviderEntry->dwProviderFilenameSize = dwNewSize;
|
|
pProviderEntry->dwProviderFilenameOffset =
|
|
pVarData - ((LPBYTE) pProviderList);
|
|
|
|
CopyMemory (pVarData, bufw, dwNewSize);
|
|
|
|
pVarData += dwNewSize;
|
|
|
|
pProviderEntry++;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
ServerFree (bufw);
|
|
|
|
pProviderList->dwTotalSize = dwTotalSize;
|
|
pProviderList->dwNeededSize = dwNeededSize;
|
|
|
|
if (dwTotalSize >= dwNeededSize)
|
|
{
|
|
pProviderList->dwUsedSize = dwNeededSize;
|
|
#ifdef MEMPHIS
|
|
pProviderList->dwNumProviders = (DWORD) iNumProviders +
|
|
iNum16BitProviders;
|
|
pProviderList->dwProviderListSize = (DWORD)
|
|
((iNumProviders + iNum16BitProviders) * sizeof(LINEPROVIDERENTRY));
|
|
#else
|
|
pProviderList->dwNumProviders = (DWORD) iNumProviders;
|
|
pProviderList->dwProviderListSize =
|
|
(DWORD) (iNumProviders * sizeof (LINEPROVIDERENTRY));
|
|
#endif
|
|
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;
|
|
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
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)ptLine,
|
|
(HTAPICALL)ptCall,
|
|
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 = (PTCALL) 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 != ptCallThen)
|
|
{
|
|
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 == ptCall)
|
|
{
|
|
CreateCallMonitors (ptCall, FALSE);
|
|
}
|
|
}
|
|
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;
|
|
//HTAPICALL htCall;
|
|
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,
|
|
NULL
|
|
|
|
) != 0)
|
|
{
|
|
LOG((TL_ERROR, "LMakeCall: CreatetCallAndClient failed. LINEERR_NOMEM"));
|
|
|
|
lRequestID = LINEERR_NOMEM;
|
|
goto LMakeCall_freeCallParams;
|
|
}
|
|
|
|
//htCall = ptCall->hCall;
|
|
|
|
pAsyncRequestInfo->pfnPostProcess = LMakeCall_PostProcess;
|
|
pAsyncRequestInfo->htXxx = (ULONG_PTR)ptCallClient->ptLineClient->ptLine;
|
|
pAsyncRequestInfo->dwParam1 = (ULONG_PTR) ptCall;
|
|
pAsyncRequestInfo->dwParam2 = pParams->hpCall;
|
|
pAsyncRequestInfo->dwParam5 = (ULONG_PTR)ptCall;
|
|
|
|
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) ptCall,
|
|
(ULONG_PTR) &ptCall->hdCall,
|
|
(ULONG_PTR) lpszDestAddress,
|
|
(DWORD) pParams->dwCountryCode,
|
|
(ULONG_PTR) pCallParamsSP
|
|
);
|
|
|
|
LOG((TL_ERROR, "LMakeCall: CallSP7 returnded %lx", pParams->lResult));
|
|
|
|
|
|
SetDrvCallFlags(
|
|
ptCall,
|
|
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;
|
|
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;
|
|
}
|
|
|
|
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;
|
|
//HTAPICALL htCall;
|
|
PTCALLCLIENT ptCallClient;
|
|
|
|
|
|
if (CreatetCallAndClient(
|
|
ptLineClient,
|
|
&ptCall,
|
|
&ptCallClient,
|
|
NULL,
|
|
NULL
|
|
|
|
) != 0)
|
|
{
|
|
lRequestID = LINEERR_NOMEM;
|
|
goto LPickup_return;
|
|
}
|
|
|
|
//htCall = ptCall->hCall;
|
|
|
|
pAsyncRequestInfo->pfnPostProcess = LMakeCall_PostProcess;
|
|
pAsyncRequestInfo->htXxx = (ULONG_PTR)ptCallClient->ptLineClient->ptLine;
|
|
pAsyncRequestInfo->dwParam1 = (ULONG_PTR) ptCall;
|
|
pAsyncRequestInfo->dwParam2 = pParams->hpCall;
|
|
pAsyncRequestInfo->dwParam5 = (ULONG_PTR)ptCall;
|
|
|
|
pAsyncRequestInfo->hfnClientPostProcessProc =
|
|
pParams->hfnPostProcessProc;
|
|
|
|
pParams->lResult = CallSP7(
|
|
pfnTSPI_linePickup,
|
|
"linePickup",
|
|
SP_FUNC_ASYNC,
|
|
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
|
|
(ULONG_PTR) hdLine,
|
|
(DWORD) pParams->dwAddressID,
|
|
(ULONG_PTR) ptCall,
|
|
(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(
|
|
ptCall,
|
|
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;
|
|
//HTAPICALL htConsultCall;
|
|
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,
|
|
NULL
|
|
|
|
) != 0)
|
|
{
|
|
lRequestID = LINEERR_NOMEM;
|
|
goto LPrepareAddToConference_freeCallParams;
|
|
}
|
|
|
|
//htConsultCall = ptConsultCall->htCall;
|
|
|
|
pAsyncRequestInfo->pfnPostProcess = LMakeCall_PostProcess;
|
|
pAsyncRequestInfo->htXxx = (ULONG_PTR)ptConsultCallClient->ptLineClient->ptLine;
|
|
pAsyncRequestInfo->dwParam1 = (ULONG_PTR) ptConsultCall;
|
|
pAsyncRequestInfo->dwParam2 = pParams->hpConsultCall;
|
|
pAsyncRequestInfo->dwParam5 = (ULONG_PTR)ptConsultCall;
|
|
|
|
pAsyncRequestInfo->hfnClientPostProcessProc =
|
|
pParams->hfnPostProcessProc;
|
|
|
|
pParams->lResult = CallSP5(
|
|
pfnTSPI_linePrepareAddToConference,
|
|
"linePrepareAddToConference",
|
|
SP_FUNC_ASYNC,
|
|
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
|
|
(ULONG_PTR) hdConfCall,
|
|
(ULONG_PTR) ptConsultCall,
|
|
(ULONG_PTR) &ptConsultCall->hdCall,
|
|
(ULONG_PTR) pCallParamsSP
|
|
);
|
|
|
|
SetDrvCallFlags(
|
|
ptConsultCall,
|
|
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] = '"';
|
|
wcscpy(szModuleName + 1, (PWSTR)(pDataBuf + pParams->dwAppNameOffset));
|
|
_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))
|
|
{
|
|
PTCALL ptConsultCallThen = (PTCALL)*(&pAsyncRequestInfo->dwParam5 + 2);
|
|
|
|
//
|
|
// 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 != ptConsultCallThen)
|
|
{
|
|
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 == ptConsultCall)
|
|
{
|
|
CreateCallMonitors (ptConfCall, FALSE);
|
|
CreateCallMonitors (ptConsultCall, FALSE);
|
|
}
|
|
}
|
|
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;
|
|
//HTAPICALL htConfCall, htConsultCall;
|
|
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,
|
|
NULL
|
|
|
|
)) == 0)
|
|
{
|
|
//htConfCall = ptConfCall->htCall;
|
|
|
|
pConfList->aptCalls[0] = ptConfCall;
|
|
|
|
if ((lResult = CreatetCallAndClient(
|
|
ptLineClient,
|
|
&ptConsultCall,
|
|
&ptConsultCallClient,
|
|
NULL,
|
|
ptConfCall
|
|
|
|
) == 0))
|
|
{
|
|
//htConsultCall = ptConsultCall->htCall;
|
|
|
|
ptConfCall->pConfList = pConfList;
|
|
|
|
pAsyncRequestInfo->pfnPostProcess =
|
|
LSetupConference_PostProcess;
|
|
pAsyncRequestInfo->htXxx = (ULONG_PTR)ptConfCallClient->ptLineClient->ptLine;
|
|
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)ptConfCall;
|
|
*(&pAsyncRequestInfo->dwParam5 + 2) = (ULONG_PTR)ptConsultCall;
|
|
|
|
pAsyncRequestInfo->hfnClientPostProcessProc =
|
|
pParams->hfnPostProcessProc;
|
|
|
|
goto LSetupConference_callSP;
|
|
}
|
|
|
|
SetDrvCallFlags (ptConfCall, 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) ptConfCall,
|
|
(ULONG_PTR) &ptConfCall->hdCall,
|
|
(ULONG_PTR) ptConsultCall,
|
|
(ULONG_PTR) &ptConsultCall->hdCall,
|
|
(DWORD) pParams->dwNumParties,
|
|
(ULONG_PTR) pCallParamsSP
|
|
);
|
|
|
|
SetDrvCallFlags(
|
|
ptConfCall,
|
|
DCF_SPIRETURNED | (IS_LRESULT_NOTERROR(pParams->lResult) ?
|
|
DCF_DRVCALLVALID : 0)
|
|
);
|
|
|
|
SetDrvCallFlags(
|
|
ptConsultCall,
|
|
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;
|
|
//HTAPICALL htConsultCall;
|
|
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,
|
|
NULL
|
|
|
|
) != 0)
|
|
{
|
|
lRequestID = LINEERR_NOMEM;
|
|
goto LSetupTransfer_freeCallParams;
|
|
}
|
|
|
|
//htConsultCall = ptConsultCall->htCall;
|
|
|
|
pAsyncRequestInfo->pfnPostProcess = LMakeCall_PostProcess;
|
|
pAsyncRequestInfo->htXxx = (ULONG_PTR)ptConsultCallClient->ptLineClient->ptLine;
|
|
pAsyncRequestInfo->dwParam1 = (ULONG_PTR) ptConsultCall;
|
|
pAsyncRequestInfo->dwParam2 = pParams->hpConsultCall;
|
|
pAsyncRequestInfo->dwParam5 = (ULONG_PTR)ptConsultCall;
|
|
|
|
pAsyncRequestInfo->hfnClientPostProcessProc =
|
|
pParams->hfnPostProcessProc;
|
|
|
|
pParams->lResult = CallSP5(
|
|
pfnTSPI_lineSetupTransfer,
|
|
"lineSetupTransfer",
|
|
SP_FUNC_ASYNC,
|
|
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
|
|
(ULONG_PTR) hdCall,
|
|
(ULONG_PTR) ptConsultCall,
|
|
(ULONG_PTR) &ptConsultCall->hdCall,
|
|
(ULONG_PTR) pCallParamsSP
|
|
);
|
|
|
|
SetDrvCallFlags(
|
|
ptConsultCall,
|
|
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;
|
|
//HTAPICALL htCall;
|
|
PTCALLCLIENT ptCallClient;
|
|
|
|
|
|
if (CreatetCallAndClient(
|
|
ptLineClient,
|
|
&ptCall,
|
|
&ptCallClient,
|
|
NULL,
|
|
NULL
|
|
|
|
) != 0)
|
|
{
|
|
lRequestID = LINEERR_NOMEM;
|
|
goto LUnpark_return;
|
|
}
|
|
|
|
//htCall = ptCall->hCall;
|
|
|
|
pAsyncRequestInfo->pfnPostProcess = LMakeCall_PostProcess;
|
|
pAsyncRequestInfo->htXxx = (ULONG_PTR)ptCallClient->ptLineClient->ptLine;
|
|
pAsyncRequestInfo->dwParam1 = (ULONG_PTR) ptCall;
|
|
pAsyncRequestInfo->dwParam2 = pParams->hpCall;
|
|
pAsyncRequestInfo->dwParam5 = (ULONG_PTR)ptCall;
|
|
|
|
pAsyncRequestInfo->hfnClientPostProcessProc =
|
|
pParams->hfnPostProcessProc;
|
|
|
|
pParams->lResult = CallSP6(
|
|
pfnTSPI_lineUnpark,
|
|
"lineUnpark",
|
|
SP_FUNC_ASYNC,
|
|
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
|
|
(ULONG_PTR) hdLine,
|
|
(DWORD) pParams->dwAddressID,
|
|
(ULONG_PTR) ptCall,
|
|
(ULONG_PTR) &ptCall->hdCall,
|
|
(ULONG_PTR) (pDataBuf + pParams->dwDestAddressOffset)
|
|
);
|
|
|
|
SetDrvCallFlags(
|
|
ptCall,
|
|
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
|
|
));
|
|
}
|
|
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
|
|
));
|
|
}
|
|
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;
|
|
#if 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
|
|
);
|
|
#if WIN64
|
|
if (pTemp != pDataBuf + pParams->dwBufferOffset)
|
|
{
|
|
ServerFree (pTemp);
|
|
}
|
|
#endif //WIN64
|
|
}
|
|
else
|
|
{
|
|
pParams->lResult = LINEERR_OPERATIONUNAVAIL;
|
|
}
|
|
}
|
|
|
|
#if 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;
|
|
|
|
}
|